mirror of
https://github.com/ZiZc3/VLC.git
synced 2026-10-18 14:01:38 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cf91edcf1e | ||
|
|
36d8450e37 | ||
|
|
f109ef6410 | ||
|
|
71306c9256 | ||
|
|
d46be6a68f | ||
|
|
86bb7d474a | ||
|
|
a4d877b24d | ||
|
|
d8050026b6 | ||
|
|
6b11ce8147 | ||
|
|
ebe77db666 | ||
|
|
7b4e2d2ffe | ||
|
|
9aaeb373e9 | ||
|
|
c72b75db4f | ||
|
|
82f942e8d6 | ||
|
|
6613c82e5d | ||
|
|
2e211f289e | ||
|
|
016a7421d9 | ||
|
|
3ed7996194 | ||
|
|
19a422b8b8 | ||
|
|
f3253020a6 | ||
|
|
4d80319bb9 | ||
|
|
e652a10d78 | ||
|
|
72f186e209 | ||
|
|
38c6fcb250 | ||
|
|
c6d14e166e |
No files matched your search
@@ -10,7 +10,7 @@
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<img alt="Version" src="https://img.shields.io/badge/version-0.1-f37a2b">
|
||||
<img alt="Version" src="https://img.shields.io/badge/version-0.4-f37a2b">
|
||||
<img alt="Platform" src="https://img.shields.io/badge/platform-PS5-1f1f1f">
|
||||
<img alt="VLC" src="https://img.shields.io/badge/libvlc-3.0.24-ff8800">
|
||||
<img alt="Renderer" src="https://img.shields.io/badge/renderer-Vulkan%20(RADV)-c0561b">
|
||||
@@ -21,13 +21,15 @@
|
||||
|
||||
## Features
|
||||
|
||||
- Plays nearly anything VLC plays: H.264, HEVC (8 and 10-bit), AV1, VP9, VC-1, MPEG-2 and more, up to 4K, with every common audio format, including TrueHD and DTS-HD.
|
||||
- **Library** with Home, Videos, Music and Browse: thumbnails, Continue watching, Favourites and search.
|
||||
- Plays nearly anything VLC plays: H.264, HEVC (8 and 10-bit), AV1, VP9, VC-1, MPEG-2 and more, up to 4K, with every common audio format, including TrueHD, DTS-HD and Opus.
|
||||
- **Hardware decoding** on the PS5's video chip for H.264 and HEVC up to 4K, 10-bit HDR included.
|
||||
- **HDR**: HDR10 and HLG go to an HDR TV as HDR, and are tone mapped with natural colours on an SDR one. Dolby Vision files play as their HDR10 base.
|
||||
- **Library** with Home, Videos, Music, Playlists and Browse: thumbnails, Continue watching, Favourites and search.
|
||||
- **Playlists**: make your own, add any video or song from anywhere with Options, reorder them; covers made from their videos; `.m3u` files on your drives play too.
|
||||
- **Subtitles** in every script, styled ASS/SSA, size and colour, delay, plus **OpenSubtitles** downloads.
|
||||
- **5.1 / 7.1 surround**, equalizer, night mode and audio delay.
|
||||
- **Network**: SMB shares, DLNA servers, network links (HTTP, HLS, DASH…), free TV channels and internet radio.
|
||||
- **PC/Phone page**: open `http://<ps5-ip>:8080` to send files to the PS5, use your pc or phone as a remote.
|
||||
- **Phone & PC page**: open `http://<ps5-ip>:8080` in any browser to send files to the PS5, download them back to your phone or PC, or add your OpenSubtitles key.
|
||||
- Music mode with covers and a visualizer, a photo viewer, DVD / Blu-ray folders, and ZIP / RAR / 7z archives.
|
||||
- Two looks (**Classic** and **Modern**) and **16 languages**.
|
||||
|
||||
@@ -82,7 +84,7 @@ Optional full access. With etaHEN, OnionHEN or the Helper, VLC can lift its sand
|
||||
| `/mnt/usb0` … `/mnt/usb7`, `/mnt/ext0` | USB and extended storage |
|
||||
| `/data/homebrew/PPSA85300/vlc-ps5.log` | Log of the last session (attach it when reporting a problem) |
|
||||
|
||||
## VLC Features
|
||||
## All VLC Features
|
||||
|
||||
✅ In the app.
|
||||
|
||||
@@ -102,9 +104,11 @@ Optional full access. With etaHEN, OnionHEN or the Helper, VLC can lift its sand
|
||||
| 360° videos (look around with the right stick) | ✅ |
|
||||
| Frame-by-frame step | ✅ |
|
||||
| Screenshots to PNG | ✅ |
|
||||
| Hardware decoding (H.264 / HEVC / VP9 up to 4K) | Not yet |
|
||||
| HDR → SDR tone mapping | Not yet |
|
||||
| HDR10 output to the TV | Not yet |
|
||||
| Hardware decoding (H.264 / HEVC) | ✅ |
|
||||
| HDR → SDR tone mapping | ✅ |
|
||||
| HDR10 output to the TV | ✅ |
|
||||
| Hardware decoding (VP9 up to 4K) | ✅ |
|
||||
| Upscaling up to 4K (FSR 1, Lanczos, Anime4K etc) | Not yet |
|
||||
|
||||
### 🔊 Audio
|
||||
|
||||
@@ -188,6 +192,7 @@ Optional full access. With etaHEN, OnionHEN or the Helper, VLC can lift its sand
|
||||
|---|---|
|
||||
| DVD folders and ISOs with menus | ✅ |
|
||||
| Blu-ray folders and ISOs (unprotected) | ✅ |
|
||||
| Blu-ray Java (BD-J) menus | ❌ Java Blu-ray menus not supported |
|
||||
| ZIP, RAR and 7z archives open like folders | ✅ |
|
||||
|
||||
## Building
|
||||
|
||||
Binary file not shown.
+67
-10
@@ -146,13 +146,11 @@ About VLC = حول VLC
|
||||
PS5 port = نسخة PS5
|
||||
VideoLAN and the VLC contributors = VideoLAN والمساهمون في VLC
|
||||
Built with = بُني باستخدام
|
||||
GPLv2+. An unofficial port, not affiliated with VideoLAN or Sony. = GPLv2+. نسخة غير رسمية، لا علاقة لها بـ VideoLAN أو Sony.
|
||||
GPL-3.0. An unofficial port, not affiliated with VideoLAN or Sony. = GPL-3.0. نسخة غير رسمية، لا علاقة لها بـ VideoLAN أو Sony.
|
||||
Resume = استئناف
|
||||
Audio, subtitles and more = الصوت والترجمة والمزيد
|
||||
Phone remote = التحكم من الهاتف
|
||||
Settings = الإعدادات
|
||||
Stop playback = إيقاف التشغيل
|
||||
Send files from a phone = إرسال ملفات من الهاتف
|
||||
Rescan media = إعادة فحص الوسائط
|
||||
Options = الخيارات
|
||||
Found %zu files = عُثر على %zu ملف
|
||||
@@ -188,7 +186,7 @@ Writes VLC's warnings and stats to vlc-ps5.log, for bug reports = يكتب تح
|
||||
What VLC can read on this console = ما يستطيع VLC قراءته على هذا الجهاز
|
||||
Starts VLC again: it then sees drives plugged in since (when sandboxed) = يعيد تشغيل VLC: فيرى الوحدات الموصلة بعد ذلك (في الوضع المعزول)
|
||||
Version, credits and licences = الإصدار والشكر والتراخيص
|
||||
The page that sends files and works as a remote, on your home network = الصفحة التي ترسل الملفات وتعمل كجهاز تحكم، على شبكتك المنزلية
|
||||
The page that sends files and takes your OpenSubtitles key, on your home network = الصفحة التي ترسل الملفات وتستقبل مفتاح OpenSubtitles، على شبكتك المنزلية
|
||||
Classic: panels and folders like a desktop player. Modern: black, VLC 4 style. VLC restarts = كلاسيكي: ألواح ومجلدات كمشغل سطح المكتب. حديث: أسود بنمط VLC 4. يُعاد تشغيل VLC
|
||||
Your own free OpenSubtitles API key (and account), here or from the phone page = مفتاح OpenSubtitles API المجاني الخاص بك (والحساب)، هنا أو من صفحة الهاتف
|
||||
The language of VLC's menus = لغة قوائم VLC
|
||||
@@ -228,16 +226,13 @@ Back right = خلفي يمين
|
||||
Each speaker plays a tone in turn. If one comes from the wrong place, tell us which. = كل سماعة تصدر نغمة بالتناوب. إن جاءت إحداها من مكان خاطئ، أخبرنا أيها.
|
||||
Stop going round = إيقاف الجولة
|
||||
Go round = بدء الجولة
|
||||
Send files from your phone = أرسل ملفات من هاتفك
|
||||
Phone access is off. Turn it on in Settings > System. = الوصول من الهاتف متوقف. فعّله من الإعدادات > النظام.
|
||||
The PS5 isn't connected to a network. Connect it, then come back. = جهاز PS5 غير متصل بشبكة. صِله ثم عد.
|
||||
On a phone or computer on the same Wi-Fi, open this address in the browser: = على هاتف أو حاسوب في شبكة Wi-Fi نفسها، افتح هذا العنوان في المتصفح:
|
||||
Send videos, music and subtitles to the PS5 = أرسل الفيديو والموسيقى والترجمات إلى PS5
|
||||
Use it as a remote while something plays = استخدمه كجهاز تحكم أثناء التشغيل
|
||||
Add your OpenSubtitles API key = أضف مفتاح OpenSubtitles API الخاص بك
|
||||
Receiving %s = جارٍ استلام %s
|
||||
Volume %d%% = الصوت %d%%
|
||||
OpenSubtitles key received from your phone = استُلم مفتاح OpenSubtitles من هاتفك
|
||||
A file arrived from your phone = وصل ملف من هاتفك
|
||||
VLC media folder = مجلد وسائط VLC
|
||||
USB drive %d = وحدة USB %d
|
||||
USB drive (%s) = وحدة USB (%s)
|
||||
@@ -387,12 +382,10 @@ The API key works = مفتاح API يعمل
|
||||
Checking the key = التحقق من المفتاح
|
||||
The server didn't answer. = لم يرد الخادم.
|
||||
Couldn't open this place. = تعذر فتح هذا المكان.
|
||||
File = الملف
|
||||
Folder = المجلد
|
||||
Bitrate = معدل البت
|
||||
Container = الحاوية
|
||||
Video = الفيديو
|
||||
Track = مسار
|
||||
White = أبيض
|
||||
Yellow = أصفر
|
||||
Cyan = سماوي
|
||||
@@ -512,3 +505,67 @@ Skip = تخطٍّ
|
||||
Start = ابدأ
|
||||
Run setup again = إعادة الإعداد الأولي
|
||||
Language, look and playback, chosen again = اختيار اللغة والمظهر والتشغيل من جديد
|
||||
Send files from a phone or PC = إرسال ملفات من الهاتف أو الكمبيوتر
|
||||
Send files from your phone or PC = أرسل ملفات من هاتفك أو الكمبيوتر
|
||||
OpenSubtitles key received from your phone or PC = استُلم مفتاح OpenSubtitles من هاتفك أو الكمبيوتر
|
||||
A file arrived from your phone or PC = وصل ملف من هاتفك أو الكمبيوتر
|
||||
File = ملف
|
||||
%s file = ملف %s
|
||||
OpenSubtitles refused this API key = رفض OpenSubtitles مفتاح API هذا
|
||||
New playlist = قائمة تشغيل جديدة
|
||||
Made in VLC = أُنشئت في VLC
|
||||
Where = المكان
|
||||
1 item = عنصر واحد
|
||||
Removed from %s = أُزيل من %s
|
||||
This playlist is empty = قائمة التشغيل هذه فارغة
|
||||
Create = إنشاء
|
||||
Play all = تشغيل الكل
|
||||
Remove = إزالة
|
||||
Move = نقل
|
||||
Add to playlist = إضافة إلى قائمة تشغيل
|
||||
Rename playlist = إعادة تسمية قائمة التشغيل
|
||||
Delete playlist = حذف قائمة التشغيل
|
||||
Name the playlist = سمِّ قائمة التشغيل
|
||||
%s goes in first = %s يُضاف أولاً
|
||||
Type a name = اكتب اسمًا
|
||||
Made %s = أُنشئت %s
|
||||
Added to %s = أُضيف إلى %s
|
||||
Already in %s = موجود في %s بالفعل
|
||||
Save = حفظ
|
||||
%d playlists = %d قوائم تشغيل
|
||||
Saved in the media folder's Playlists, as a file VLC on a computer opens too = تُحفظ في مجلد Playlists داخل مجلد الوسائط، كملف يفتحه VLC على الكمبيوتر أيضًا
|
||||
A playlist with this name is already there, or the disk can't be written = توجد قائمة تشغيل بهذا الاسم، أو لا يمكن الكتابة على القرص
|
||||
Then add videos and songs from anywhere with the Options menu = ثم أضف الفيديوهات والأغاني من أي مكان عبر قائمة الخيارات
|
||||
Open the Options menu on a video or song and choose Add to playlist = افتح قائمة الخيارات على فيديو أو أغنية واختر إضافة إلى قائمة تشغيل
|
||||
stereo = ستيريو
|
||||
Chapter %d = الفصل %d
|
||||
Audio %d = الصوت %d
|
||||
Fonts: Selawik, Inter, Noto, DejaVu (OFL). TV lists: iptv-org. Radio: radio-browser.info. Subtitles: OpenSubtitles.com. = الخطوط: Selawik وInter وNoto وDejaVu (OFL). قوائم القنوات: iptv-org. الراديو: radio-browser.info. الترجمات: OpenSubtitles.com.
|
||||
15 min = 15 دقيقة
|
||||
30 min = 30 دقيقة
|
||||
45 min = 45 دقيقة
|
||||
60 min = 60 دقيقة
|
||||
90 min = 90 دقيقة
|
||||
Sign in to the share = تسجيل الدخول إلى المشاركة
|
||||
%s needs a user name and password. = يطلب %s اسم مستخدم وكلمة مرور.
|
||||
A Windows PC takes its own account; a NAS, the user you made on it. = كمبيوتر ويندوز يقبل حسابه نفسه، وجهاز NAS يقبل المستخدم الذي أنشأته عليه.
|
||||
Track %d = المسار %d
|
||||
Track = مسار
|
||||
Disc menu = قائمة القرص
|
||||
Pop-up menu = القائمة المنبثقة
|
||||
Blu-ray region = منطقة Blu-ray
|
||||
Region %s = المنطقة %s
|
||||
Blu-ray region: from the next disc you open = منطقة Blu-ray: من القرص التالي الذي تفتحه
|
||||
A: the Americas and East Asia. B: Europe, Africa and Oceania. C: China, Russia and India = A: الأمريكتان وشرق آسيا. B: أوروبا وأفريقيا وأوقيانوسيا. C: الصين وروسيا والهند
|
||||
Add a subtitle file = إضافة ملف ترجمة
|
||||
Pick a subtitle file = اختر ملف ترجمة
|
||||
Subtitles: %s = الترجمة: %s
|
||||
Couldn't load that subtitle file = تعذّر تحميل ملف الترجمة هذا
|
||||
That isn't a subtitle file (.srt, .ass, .vtt...) = هذا ليس ملف ترجمة (.srt و.ass و.vtt...)
|
||||
Java Blu-ray discs (BD-J) aren't supported on the PS5 = أقراص Blu-ray التي تعمل بـ Java (BD-J) غير مدعومة على PS5
|
||||
Hardware decoding = فك الترميز بالعتاد
|
||||
The console's video chip. Off: the processor decodes, slower for 4K = شريحة الفيديو في الجهاز. عند الإيقاف: يفك المعالج الترميز، وهو أبطأ مع 4K
|
||||
Looking for channels and stations… = جارٍ البحث عن القنوات والمحطات…
|
||||
Hardware decoding: from the next video = فك الترميز بالعتاد: من الفيديو التالي
|
||||
Match frame rate = مطابقة معدل الإطارات
|
||||
Films play at their own 24, 25 or 50 Hz: smoother pans. Some TVs go black a moment = تُعرض الأفلام بترددها الأصلي 24 أو 25 أو 50 هرتز: حركة أنعم. بعض أجهزة التلفاز تسودّ لحظة
|
||||
+67
-10
@@ -146,13 +146,11 @@ About VLC = Über VLC
|
||||
PS5 port = PS5-Portierung
|
||||
VideoLAN and the VLC contributors = VideoLAN und die VLC-Mitwirkenden
|
||||
Built with = Erstellt mit
|
||||
GPLv2+. An unofficial port, not affiliated with VideoLAN or Sony. = GPLv2+. Eine inoffizielle Portierung, nicht mit VideoLAN oder Sony verbunden.
|
||||
GPL-3.0. An unofficial port, not affiliated with VideoLAN or Sony. = GPL-3.0. Eine inoffizielle Portierung, nicht mit VideoLAN oder Sony verbunden.
|
||||
Resume = Fortsetzen
|
||||
Audio, subtitles and more = Audio, Untertitel und mehr
|
||||
Phone remote = Handy-Fernbedienung
|
||||
Settings = Einstellungen
|
||||
Stop playback = Wiedergabe beenden
|
||||
Send files from a phone = Dateien vom Handy senden
|
||||
Rescan media = Medien neu einlesen
|
||||
Options = Optionen
|
||||
Found %zu files = %zu Dateien gefunden
|
||||
@@ -188,7 +186,7 @@ Writes VLC's warnings and stats to vlc-ps5.log, for bug reports = Schreibt VLCs
|
||||
What VLC can read on this console = Was VLC auf dieser Konsole lesen kann
|
||||
Starts VLC again: it then sees drives plugged in since (when sandboxed) = Startet VLC neu: Dann sieht es seitdem angeschlossene Laufwerke (in der Sandbox)
|
||||
Version, credits and licences = Version, Mitwirkende und Lizenzen
|
||||
The page that sends files and works as a remote, on your home network = Die Seite, die Dateien sendet und als Fernbedienung dient, in deinem Heimnetz
|
||||
The page that sends files and takes your OpenSubtitles key, on your home network = Die Seite, die Dateien sendet und deinen OpenSubtitles-Schlüssel annimmt, in deinem Heimnetz
|
||||
Classic: panels and folders like a desktop player. Modern: black, VLC 4 style. VLC restarts = Klassisch: Bereiche und Ordner wie ein Desktop-Player. Modern: schwarz, im Stil von VLC 4. VLC startet neu
|
||||
Your own free OpenSubtitles API key (and account), here or from the phone page = Dein eigener kostenloser OpenSubtitles-API-Schlüssel (und Konto), hier oder über die Handy-Seite
|
||||
The language of VLC's menus = Die Sprache der VLC-Menüs
|
||||
@@ -228,16 +226,13 @@ Back right = Hinten rechts
|
||||
Each speaker plays a tone in turn. If one comes from the wrong place, tell us which. = Jeder Lautsprecher spielt nacheinander einen Ton. Kommt einer von der falschen Stelle, sag uns welcher.
|
||||
Stop going round = Runde stoppen
|
||||
Go round = Runde starten
|
||||
Send files from your phone = Dateien vom Handy senden
|
||||
Phone access is off. Turn it on in Settings > System. = Der Handy-Zugriff ist aus. Schalte ihn unter Einstellungen > System ein.
|
||||
The PS5 isn't connected to a network. Connect it, then come back. = Die PS5 ist mit keinem Netzwerk verbunden. Verbinde sie und komm dann zurück.
|
||||
On a phone or computer on the same Wi-Fi, open this address in the browser: = Öffne auf einem Handy oder Computer im selben WLAN diese Adresse im Browser:
|
||||
Send videos, music and subtitles to the PS5 = Sende Videos, Musik und Untertitel an die PS5
|
||||
Use it as a remote while something plays = Nutze es während der Wiedergabe als Fernbedienung
|
||||
Add your OpenSubtitles API key = Deinen OpenSubtitles-API-Schlüssel hinzufügen
|
||||
Receiving %s = Empfange %s
|
||||
Volume %d%% = Lautstärke %d %%
|
||||
OpenSubtitles key received from your phone = OpenSubtitles-Schlüssel vom Handy empfangen
|
||||
A file arrived from your phone = Eine Datei ist vom Handy angekommen
|
||||
VLC media folder = VLC-Medienordner
|
||||
USB drive %d = USB-Laufwerk %d
|
||||
USB drive (%s) = USB-Laufwerk (%s)
|
||||
@@ -387,12 +382,10 @@ The API key works = Der API-Schlüssel funktioniert
|
||||
Checking the key = Schlüsselprüfung
|
||||
The server didn't answer. = Der Server hat nicht geantwortet.
|
||||
Couldn't open this place. = Dieser Ort konnte nicht geöffnet werden.
|
||||
File = Datei
|
||||
Folder = Ordner
|
||||
Bitrate = Bitrate
|
||||
Container = Container
|
||||
Video = Video
|
||||
Track = Spur
|
||||
White = Weiß
|
||||
Yellow = Gelb
|
||||
Cyan = Cyan
|
||||
@@ -512,3 +505,67 @@ Skip = Überspringen
|
||||
Start = Start
|
||||
Run setup again = Einrichtung wiederholen
|
||||
Language, look and playback, chosen again = Sprache, Aussehen und Wiedergabe neu wählen
|
||||
Send files from a phone or PC = Dateien vom Handy oder PC senden
|
||||
Send files from your phone or PC = Dateien vom Handy oder PC senden
|
||||
OpenSubtitles key received from your phone or PC = OpenSubtitles-Schlüssel vom Handy oder PC empfangen
|
||||
A file arrived from your phone or PC = Eine Datei ist vom Handy oder PC angekommen
|
||||
File = Datei
|
||||
%s file = %s-Datei
|
||||
OpenSubtitles refused this API key = OpenSubtitles hat diesen API-Schlüssel abgelehnt
|
||||
New playlist = Neue Playlist
|
||||
Made in VLC = In VLC erstellt
|
||||
Where = Ort
|
||||
1 item = 1 Element
|
||||
Removed from %s = Aus %s entfernt
|
||||
This playlist is empty = Diese Playlist ist leer
|
||||
Create = Erstellen
|
||||
Play all = Alle abspielen
|
||||
Remove = Entfernen
|
||||
Move = Verschieben
|
||||
Add to playlist = Zur Playlist hinzufügen
|
||||
Rename playlist = Playlist umbenennen
|
||||
Delete playlist = Playlist löschen
|
||||
Name the playlist = Playlist benennen
|
||||
%s goes in first = %s kommt als Erstes hinein
|
||||
Type a name = Gib einen Namen ein
|
||||
Made %s = %s erstellt
|
||||
Added to %s = Zu %s hinzugefügt
|
||||
Already in %s = Schon in %s
|
||||
Save = Speichern
|
||||
%d playlists = %d Playlists
|
||||
Saved in the media folder's Playlists, as a file VLC on a computer opens too = Gespeichert im Ordner Playlists des Medienordners, als Datei, die VLC auf dem Computer auch öffnet
|
||||
A playlist with this name is already there, or the disk can't be written = Eine Playlist mit diesem Namen gibt es schon, oder das Laufwerk ist nicht beschreibbar
|
||||
Then add videos and songs from anywhere with the Options menu = Dann Videos und Songs von überall über das Menü Optionen hinzufügen
|
||||
Open the Options menu on a video or song and choose Add to playlist = Öffne das Menü Optionen bei einem Video oder Song und wähle Zur Playlist hinzufügen
|
||||
stereo = Stereo
|
||||
Chapter %d = Kapitel %d
|
||||
Audio %d = Audio %d
|
||||
Fonts: Selawik, Inter, Noto, DejaVu (OFL). TV lists: iptv-org. Radio: radio-browser.info. Subtitles: OpenSubtitles.com. = Schriften: Selawik, Inter, Noto, DejaVu (OFL). Senderlisten: iptv-org. Radio: radio-browser.info. Untertitel: OpenSubtitles.com.
|
||||
15 min = 15 Min.
|
||||
30 min = 30 Min.
|
||||
45 min = 45 Min.
|
||||
60 min = 60 Min.
|
||||
90 min = 90 Min.
|
||||
Sign in to the share = Bei der Freigabe anmelden
|
||||
%s needs a user name and password. = %s braucht einen Benutzernamen und ein Passwort.
|
||||
A Windows PC takes its own account; a NAS, the user you made on it. = Ein Windows-PC nimmt sein eigenes Konto, ein NAS den Benutzer, den du darauf angelegt hast.
|
||||
Track %d = Spur %d
|
||||
Track = Spur
|
||||
Disc menu = Disc-Menü
|
||||
Pop-up menu = Pop-up-Menü
|
||||
Blu-ray region = Blu-ray-Region
|
||||
Region %s = Region %s
|
||||
Blu-ray region: from the next disc you open = Blu-ray-Region: ab der nächsten Disc, die du öffnest
|
||||
A: the Americas and East Asia. B: Europe, Africa and Oceania. C: China, Russia and India = A: Amerika und Ostasien. B: Europa, Afrika und Ozeanien. C: China, Russland und Indien
|
||||
Add a subtitle file = Untertiteldatei hinzufügen
|
||||
Pick a subtitle file = Untertiteldatei wählen
|
||||
Subtitles: %s = Untertitel: %s
|
||||
Couldn't load that subtitle file = Diese Untertiteldatei ließ sich nicht laden
|
||||
That isn't a subtitle file (.srt, .ass, .vtt...) = Das ist keine Untertiteldatei (.srt, .ass, .vtt...)
|
||||
Java Blu-ray discs (BD-J) aren't supported on the PS5 = Java-Blu-rays (BD-J) werden auf der PS5 nicht unterstützt
|
||||
Hardware decoding = Hardware-Dekodierung
|
||||
The console's video chip. Off: the processor decodes, slower for 4K = Der Videochip der Konsole. Aus: Der Prozessor dekodiert, langsamer bei 4K
|
||||
Looking for channels and stations… = Sender und Radiosender werden gesucht…
|
||||
Hardware decoding: from the next video = Hardware-Dekodierung: ab dem nächsten Video
|
||||
Match frame rate = Bildrate anpassen
|
||||
Films play at their own 24, 25 or 50 Hz: smoother pans. Some TVs go black a moment = Filme laufen mit ihren eigenen 24, 25 oder 50 Hz: ruhigere Schwenks. Manche Fernseher werden kurz schwarz
|
||||
+67
-10
@@ -146,13 +146,11 @@ About VLC = Acerca de VLC
|
||||
PS5 port = Versión para PS5
|
||||
VideoLAN and the VLC contributors = VideoLAN y los colaboradores de VLC
|
||||
Built with = Hecho con
|
||||
GPLv2+. An unofficial port, not affiliated with VideoLAN or Sony. = GPLv2+. Una adaptación no oficial, sin relación con VideoLAN ni Sony.
|
||||
GPL-3.0. An unofficial port, not affiliated with VideoLAN or Sony. = GPL-3.0. Una adaptación no oficial, sin relación con VideoLAN ni Sony.
|
||||
Resume = Continuar
|
||||
Audio, subtitles and more = Audio, subtítulos y más
|
||||
Phone remote = Mando desde el móvil
|
||||
Settings = Ajustes
|
||||
Stop playback = Detener la reproducción
|
||||
Send files from a phone = Enviar archivos desde un móvil
|
||||
Rescan media = Volver a buscar archivos
|
||||
Options = Opciones
|
||||
Found %zu files = %zu archivos encontrados
|
||||
@@ -188,7 +186,7 @@ Writes VLC's warnings and stats to vlc-ps5.log, for bug reports = Escribe los av
|
||||
What VLC can read on this console = Lo que VLC puede leer en esta consola
|
||||
Starts VLC again: it then sees drives plugged in since (when sandboxed) = Reinicia VLC: así ve las unidades conectadas después (en modo aislado)
|
||||
Version, credits and licences = Versión, créditos y licencias
|
||||
The page that sends files and works as a remote, on your home network = La página que envía archivos y sirve de mando, en tu red doméstica
|
||||
The page that sends files and takes your OpenSubtitles key, on your home network = La página que envía archivos y recibe tu clave de OpenSubtitles, en tu red doméstica
|
||||
Classic: panels and folders like a desktop player. Modern: black, VLC 4 style. VLC restarts = Clásico: paneles y carpetas como un reproductor de escritorio. Moderno: negro, estilo VLC 4. VLC se reinicia
|
||||
Your own free OpenSubtitles API key (and account), here or from the phone page = Tu propia clave API gratuita de OpenSubtitles (y cuenta), aquí o desde la página del móvil
|
||||
The language of VLC's menus = El idioma de los menús de VLC
|
||||
@@ -228,16 +226,13 @@ Back right = Trasero derecho
|
||||
Each speaker plays a tone in turn. If one comes from the wrong place, tell us which. = Cada altavoz emite un tono por turnos. Si alguno suena desde el lugar equivocado, dinos cuál.
|
||||
Stop going round = Detener la ronda
|
||||
Go round = Hacer la ronda
|
||||
Send files from your phone = Envía archivos desde tu móvil
|
||||
Phone access is off. Turn it on in Settings > System. = El acceso desde el móvil está desactivado. Actívalo en Ajustes > Sistema.
|
||||
The PS5 isn't connected to a network. Connect it, then come back. = La PS5 no está conectada a una red. Conéctala y vuelve.
|
||||
On a phone or computer on the same Wi-Fi, open this address in the browser: = En un móvil u ordenador de la misma Wi-Fi, abre esta dirección en el navegador:
|
||||
Send videos, music and subtitles to the PS5 = Envía vídeos, música y subtítulos a la PS5
|
||||
Use it as a remote while something plays = Úsala como mando mientras algo se reproduce
|
||||
Add your OpenSubtitles API key = Añade tu clave API de OpenSubtitles
|
||||
Receiving %s = Recibiendo %s
|
||||
Volume %d%% = Volumen %d %%
|
||||
OpenSubtitles key received from your phone = Clave de OpenSubtitles recibida desde tu móvil
|
||||
A file arrived from your phone = Ha llegado un archivo desde tu móvil
|
||||
VLC media folder = Carpeta multimedia de VLC
|
||||
USB drive %d = Unidad USB %d
|
||||
USB drive (%s) = Unidad USB (%s)
|
||||
@@ -387,12 +382,10 @@ The API key works = La clave API funciona
|
||||
Checking the key = La comprobación de la clave
|
||||
The server didn't answer. = El servidor no respondió.
|
||||
Couldn't open this place. = No se pudo abrir esta ubicación.
|
||||
File = Archivo
|
||||
Folder = Carpeta
|
||||
Bitrate = Tasa de bits
|
||||
Container = Contenedor
|
||||
Video = Vídeo
|
||||
Track = Pista
|
||||
White = Blanco
|
||||
Yellow = Amarillo
|
||||
Cyan = Cian
|
||||
@@ -512,3 +505,67 @@ Skip = Omitir
|
||||
Start = Empezar
|
||||
Run setup again = Repetir la configuración
|
||||
Language, look and playback, chosen again = Idioma, aspecto y reproducción, de nuevo
|
||||
Send files from a phone or PC = Enviar archivos desde un móvil o PC
|
||||
Send files from your phone or PC = Envía archivos desde tu móvil o PC
|
||||
OpenSubtitles key received from your phone or PC = Clave de OpenSubtitles recibida desde tu móvil o PC
|
||||
A file arrived from your phone or PC = Ha llegado un archivo desde tu móvil o PC
|
||||
File = Archivo
|
||||
%s file = Archivo %s
|
||||
OpenSubtitles refused this API key = OpenSubtitles rechazó esta clave API
|
||||
New playlist = Nueva lista de reproducción
|
||||
Made in VLC = Creada en VLC
|
||||
Where = Ubicación
|
||||
1 item = 1 elemento
|
||||
Removed from %s = Quitado de %s
|
||||
This playlist is empty = Esta lista de reproducción está vacía
|
||||
Create = Crear
|
||||
Play all = Reproducir todo
|
||||
Remove = Quitar
|
||||
Move = Mover
|
||||
Add to playlist = Añadir a una lista de reproducción
|
||||
Rename playlist = Renombrar lista de reproducción
|
||||
Delete playlist = Eliminar lista de reproducción
|
||||
Name the playlist = Ponle nombre a la lista de reproducción
|
||||
%s goes in first = %s entra primero
|
||||
Type a name = Escribe un nombre
|
||||
Made %s = Creada %s
|
||||
Added to %s = Añadido a %s
|
||||
Already in %s = Ya está en %s
|
||||
Save = Guardar
|
||||
%d playlists = %d listas de reproducción
|
||||
Saved in the media folder's Playlists, as a file VLC on a computer opens too = Se guarda en la carpeta Playlists de la carpeta de medios, como un archivo que VLC en un ordenador también abre
|
||||
A playlist with this name is already there, or the disk can't be written = Ya hay una lista de reproducción con este nombre, o no se puede escribir en el disco
|
||||
Then add videos and songs from anywhere with the Options menu = Luego añade vídeos y canciones desde cualquier sitio con el menú Opciones
|
||||
Open the Options menu on a video or song and choose Add to playlist = Abre el menú Opciones en un vídeo o una canción y elige Añadir a una lista de reproducción
|
||||
stereo = estéreo
|
||||
Chapter %d = Capítulo %d
|
||||
Audio %d = Audio %d
|
||||
Fonts: Selawik, Inter, Noto, DejaVu (OFL). TV lists: iptv-org. Radio: radio-browser.info. Subtitles: OpenSubtitles.com. = Fuentes: Selawik, Inter, Noto, DejaVu (OFL). Listas de TV: iptv-org. Radio: radio-browser.info. Subtítulos: OpenSubtitles.com.
|
||||
15 min = 15 min
|
||||
30 min = 30 min
|
||||
45 min = 45 min
|
||||
60 min = 60 min
|
||||
90 min = 90 min
|
||||
Sign in to the share = Iniciar sesión en la carpeta compartida
|
||||
%s needs a user name and password. = %s necesita un usuario y una contraseña.
|
||||
A Windows PC takes its own account; a NAS, the user you made on it. = Un PC con Windows usa su propia cuenta; un NAS, el usuario que creaste en él.
|
||||
Track %d = Pista %d
|
||||
Track = Pista
|
||||
Disc menu = Menú del disco
|
||||
Pop-up menu = Menú emergente
|
||||
Blu-ray region = Región Blu-ray
|
||||
Region %s = Región %s
|
||||
Blu-ray region: from the next disc you open = Región Blu-ray: desde el próximo disco que abras
|
||||
A: the Americas and East Asia. B: Europe, Africa and Oceania. C: China, Russia and India = A: América y Asia oriental. B: Europa, África y Oceanía. C: China, Rusia e India
|
||||
Add a subtitle file = Añadir un archivo de subtítulos
|
||||
Pick a subtitle file = Elige un archivo de subtítulos
|
||||
Subtitles: %s = Subtítulos: %s
|
||||
Couldn't load that subtitle file = No se pudo cargar ese archivo de subtítulos
|
||||
That isn't a subtitle file (.srt, .ass, .vtt...) = Eso no es un archivo de subtítulos (.srt, .ass, .vtt...)
|
||||
Java Blu-ray discs (BD-J) aren't supported on the PS5 = Los Blu-ray con Java (BD-J) no son compatibles con la PS5
|
||||
Hardware decoding = Decodificación por hardware
|
||||
The console's video chip. Off: the processor decodes, slower for 4K = El chip de vídeo de la consola. Desactivado: decodifica el procesador, más lento en 4K
|
||||
Looking for channels and stations… = Buscando canales y emisoras…
|
||||
Hardware decoding: from the next video = Decodificación por hardware: desde el próximo vídeo
|
||||
Match frame rate = Igualar la frecuencia de imagen
|
||||
Films play at their own 24, 25 or 50 Hz: smoother pans. Some TVs go black a moment = Las películas se ven a sus propios 24, 25 o 50 Hz: paneos más suaves. Algunas TV se ponen en negro un momento
|
||||
+67
-15
@@ -16,11 +16,6 @@ Stretch = Étirer
|
||||
21:9 (cinema) = 21:9 (cinéma)
|
||||
Zoom 125% = Zoom 125 %
|
||||
Off = Désactivé
|
||||
15 min = 15 min
|
||||
30 min = 30 min
|
||||
45 min = 45 min
|
||||
60 min = 60 min
|
||||
90 min = 90 min
|
||||
End of this file = Fin de ce fichier
|
||||
Continue watching = Reprendre la lecture
|
||||
Recently added = Ajoutés récemment
|
||||
@@ -151,13 +146,11 @@ About VLC = À propos de VLC
|
||||
PS5 port = Portage PS5
|
||||
VideoLAN and the VLC contributors = VideoLAN et les contributeurs de VLC
|
||||
Built with = Conçu avec
|
||||
GPLv2+. An unofficial port, not affiliated with VideoLAN or Sony. = GPLv2+. Un portage non officiel, sans lien avec VideoLAN ni Sony.
|
||||
GPL-3.0. An unofficial port, not affiliated with VideoLAN or Sony. = GPL-3.0. Un portage non officiel, sans lien avec VideoLAN ni Sony.
|
||||
Resume = Reprendre
|
||||
Audio, subtitles and more = Audio, sous-titres et plus
|
||||
Phone remote = Télécommande téléphone
|
||||
Settings = Paramètres
|
||||
Stop playback = Arrêter la lecture
|
||||
Send files from a phone = Envoyer des fichiers depuis un téléphone
|
||||
Rescan media = Réanalyser les médias
|
||||
Options = Options
|
||||
Found %zu files = %zu fichiers trouvés
|
||||
@@ -194,7 +187,7 @@ Writes VLC's warnings and stats to vlc-ps5.log, for bug reports = Écrit les ave
|
||||
What VLC can read on this console = Ce que VLC peut lire sur cette console
|
||||
Starts VLC again: it then sees drives plugged in since (when sandboxed) = Redémarre VLC : il voit alors les lecteurs branchés depuis (en mode isolé)
|
||||
Version, credits and licences = Version, crédits et licences
|
||||
The page that sends files and works as a remote, on your home network = La page qui envoie des fichiers et sert de télécommande, sur votre réseau domestique
|
||||
The page that sends files and takes your OpenSubtitles key, on your home network = La page qui envoie des fichiers et reçoit votre clé OpenSubtitles, sur votre réseau domestique
|
||||
Classic: panels and folders like a desktop player. Modern: black, VLC 4 style. VLC restarts = Classique : panneaux et dossiers comme un lecteur de bureau. Moderne : noir, style VLC 4. VLC redémarre
|
||||
Your own free OpenSubtitles API key (and account), here or from the phone page = Votre propre clé API OpenSubtitles gratuite (et compte), ici ou depuis la page du téléphone
|
||||
The language of VLC's menus = La langue des menus de VLC
|
||||
@@ -234,16 +227,13 @@ Back right = Arrière droite
|
||||
Each speaker plays a tone in turn. If one comes from the wrong place, tell us which. = Chaque enceinte joue un son à tour de rôle. Si l'un vient du mauvais endroit, dites-nous lequel.
|
||||
Stop going round = Arrêter le tour
|
||||
Go round = Faire le tour
|
||||
Send files from your phone = Envoyer des fichiers depuis votre téléphone
|
||||
Phone access is off. Turn it on in Settings > System. = L'accès téléphone est désactivé. Activez-le dans Paramètres > Système.
|
||||
The PS5 isn't connected to a network. Connect it, then come back. = La PS5 n'est pas connectée à un réseau. Connectez-la, puis revenez.
|
||||
On a phone or computer on the same Wi-Fi, open this address in the browser: = Sur un téléphone ou un ordinateur du même Wi-Fi, ouvrez cette adresse dans le navigateur :
|
||||
Send videos, music and subtitles to the PS5 = Envoyez vidéos, musique et sous-titres à la PS5
|
||||
Use it as a remote while something plays = Utilisez-la comme télécommande pendant la lecture
|
||||
Add your OpenSubtitles API key = Ajoutez votre clé API OpenSubtitles
|
||||
Receiving %s = Réception de %s
|
||||
Volume %d%% = Volume %d %%
|
||||
OpenSubtitles key received from your phone = Clé OpenSubtitles reçue depuis votre téléphone
|
||||
A file arrived from your phone = Un fichier est arrivé de votre téléphone
|
||||
VLC media folder = Dossier multimédia VLC
|
||||
USB drive %d = Clé USB %d
|
||||
USB drive (%s) = Clé USB (%s)
|
||||
@@ -393,12 +383,10 @@ The API key works = La clé API fonctionne
|
||||
Checking the key = La vérification de la clé
|
||||
The server didn't answer. = Le serveur n'a pas répondu.
|
||||
Couldn't open this place. = Impossible d'ouvrir cet emplacement.
|
||||
File = Fichier
|
||||
Folder = Dossier
|
||||
Bitrate = Débit
|
||||
Container = Conteneur
|
||||
Video = Vidéo
|
||||
Track = Piste
|
||||
White = Blanc
|
||||
Yellow = Jaune
|
||||
Cyan = Cyan
|
||||
@@ -518,3 +506,67 @@ Skip = Passer
|
||||
Start = Commencer
|
||||
Run setup again = Relancer la configuration
|
||||
Language, look and playback, chosen again = Langue, apparence et lecture, à nouveau
|
||||
Send files from a phone or PC = Envoyer des fichiers depuis un téléphone ou un PC
|
||||
Send files from your phone or PC = Envoyer des fichiers depuis votre téléphone ou PC
|
||||
OpenSubtitles key received from your phone or PC = Clé OpenSubtitles reçue depuis votre téléphone ou PC
|
||||
A file arrived from your phone or PC = Un fichier est arrivé de votre téléphone ou PC
|
||||
File = Fichier
|
||||
%s file = Fichier %s
|
||||
OpenSubtitles refused this API key = OpenSubtitles a refusé cette clé API
|
||||
New playlist = Nouvelle liste de lecture
|
||||
Made in VLC = Créée dans VLC
|
||||
Where = Emplacement
|
||||
1 item = 1 élément
|
||||
Removed from %s = Retiré de %s
|
||||
This playlist is empty = Cette liste de lecture est vide
|
||||
Create = Créer
|
||||
Play all = Tout lire
|
||||
Remove = Retirer
|
||||
Move = Déplacer
|
||||
Add to playlist = Ajouter à une liste de lecture
|
||||
Rename playlist = Renommer la liste de lecture
|
||||
Delete playlist = Supprimer la liste de lecture
|
||||
Name the playlist = Nommez la liste de lecture
|
||||
%s goes in first = %s y entre en premier
|
||||
Type a name = Saisissez un nom
|
||||
Made %s = %s créée
|
||||
Added to %s = Ajouté à %s
|
||||
Already in %s = Déjà dans %s
|
||||
Save = Enregistrer
|
||||
%d playlists = %d listes de lecture
|
||||
Saved in the media folder's Playlists, as a file VLC on a computer opens too = Enregistrée dans le dossier Playlists du dossier des médias, en fichier que VLC sur ordinateur ouvre aussi
|
||||
A playlist with this name is already there, or the disk can't be written = Une liste de lecture porte déjà ce nom, ou le disque n'est pas accessible en écriture
|
||||
Then add videos and songs from anywhere with the Options menu = Ajoutez ensuite vidéos et morceaux de partout avec le menu Options
|
||||
Open the Options menu on a video or song and choose Add to playlist = Ouvrez le menu Options sur une vidéo ou un morceau et choisissez Ajouter à une liste de lecture
|
||||
stereo = stéréo
|
||||
Chapter %d = Chapitre %d
|
||||
Audio %d = Audio %d
|
||||
Fonts: Selawik, Inter, Noto, DejaVu (OFL). TV lists: iptv-org. Radio: radio-browser.info. Subtitles: OpenSubtitles.com. = Polices : Selawik, Inter, Noto, DejaVu (OFL). Listes TV : iptv-org. Radio : radio-browser.info. Sous-titres : OpenSubtitles.com.
|
||||
15 min = 15 min
|
||||
30 min = 30 min
|
||||
45 min = 45 min
|
||||
60 min = 60 min
|
||||
90 min = 90 min
|
||||
Sign in to the share = Se connecter au partage
|
||||
%s needs a user name and password. = %s demande un nom d'utilisateur et un mot de passe.
|
||||
A Windows PC takes its own account; a NAS, the user you made on it. = Un PC Windows prend son propre compte ; un NAS, l'utilisateur que vous y avez créé.
|
||||
Track %d = Piste %d
|
||||
Track = Piste
|
||||
Disc menu = Menu du disque
|
||||
Pop-up menu = Menu contextuel
|
||||
Blu-ray region = Zone Blu-ray
|
||||
Region %s = Zone %s
|
||||
Blu-ray region: from the next disc you open = Zone Blu-ray : à partir du prochain disque ouvert
|
||||
A: the Americas and East Asia. B: Europe, Africa and Oceania. C: China, Russia and India = A : Amériques et Asie de l'Est. B : Europe, Afrique et Océanie. C : Chine, Russie et Inde
|
||||
Add a subtitle file = Ajouter un fichier de sous-titres
|
||||
Pick a subtitle file = Choisissez un fichier de sous-titres
|
||||
Subtitles: %s = Sous-titres : %s
|
||||
Couldn't load that subtitle file = Impossible de charger ce fichier de sous-titres
|
||||
That isn't a subtitle file (.srt, .ass, .vtt...) = Ce n'est pas un fichier de sous-titres (.srt, .ass, .vtt...)
|
||||
Java Blu-ray discs (BD-J) aren't supported on the PS5 = Les Blu-ray Java (BD-J) ne sont pas pris en charge sur PS5
|
||||
Hardware decoding = Décodage matériel
|
||||
The console's video chip. Off: the processor decodes, slower for 4K = La puce vidéo de la console. Désactivé : le processeur décode, plus lent en 4K
|
||||
Looking for channels and stations… = Recherche de chaînes et de stations…
|
||||
Hardware decoding: from the next video = Décodage matériel : à partir de la prochaine vidéo
|
||||
Match frame rate = Adapter la fréquence d'images
|
||||
Films play at their own 24, 25 or 50 Hz: smoother pans. Some TVs go black a moment = Les films passent à leurs propres 24, 25 ou 50 Hz : panoramiques plus fluides. Certaines TV deviennent noires un instant
|
||||
+67
-10
@@ -146,13 +146,11 @@ About VLC = Tentang VLC
|
||||
PS5 port = Port PS5
|
||||
VideoLAN and the VLC contributors = VideoLAN dan para kontributor VLC
|
||||
Built with = Dibuat dengan
|
||||
GPLv2+. An unofficial port, not affiliated with VideoLAN or Sony. = GPLv2+. Port tidak resmi, tidak berafiliasi dengan VideoLAN atau Sony.
|
||||
GPL-3.0. An unofficial port, not affiliated with VideoLAN or Sony. = GPL-3.0. Port tidak resmi, tidak berafiliasi dengan VideoLAN atau Sony.
|
||||
Resume = Lanjutkan
|
||||
Audio, subtitles and more = Audio, subtitle, dan lainnya
|
||||
Phone remote = Remote ponsel
|
||||
Settings = Pengaturan
|
||||
Stop playback = Hentikan pemutaran
|
||||
Send files from a phone = Kirim file dari ponsel
|
||||
Rescan media = Pindai ulang media
|
||||
Options = Opsi
|
||||
Found %zu files = %zu file ditemukan
|
||||
@@ -188,7 +186,7 @@ Writes VLC's warnings and stats to vlc-ps5.log, for bug reports = Menulis pering
|
||||
What VLC can read on this console = Apa yang dapat dibaca VLC di konsol ini
|
||||
Starts VLC again: it then sees drives plugged in since (when sandboxed) = Memulai ulang VLC: lalu melihat drive yang dicolokkan setelahnya (saat dibatasi)
|
||||
Version, credits and licences = Versi, kredit, dan lisensi
|
||||
The page that sends files and works as a remote, on your home network = Halaman untuk mengirim file dan menjadi remote, di jaringan rumah Anda
|
||||
The page that sends files and takes your OpenSubtitles key, on your home network = Halaman untuk mengirim file dan memasukkan kunci OpenSubtitles, di jaringan rumah Anda
|
||||
Classic: panels and folders like a desktop player. Modern: black, VLC 4 style. VLC restarts = Klasik: panel dan folder seperti pemutar desktop. Modern: hitam, gaya VLC 4. VLC dimulai ulang
|
||||
Your own free OpenSubtitles API key (and account), here or from the phone page = Kunci API OpenSubtitles gratis milik Anda (dan akun), di sini atau dari halaman ponsel
|
||||
The language of VLC's menus = Bahasa menu VLC
|
||||
@@ -228,16 +226,13 @@ Back right = Belakang kanan
|
||||
Each speaker plays a tone in turn. If one comes from the wrong place, tell us which. = Setiap speaker memutar nada bergantian. Jika ada yang terdengar dari tempat yang salah, beri tahu kami yang mana.
|
||||
Stop going round = Hentikan putaran
|
||||
Go round = Mulai putaran
|
||||
Send files from your phone = Kirim file dari ponsel Anda
|
||||
Phone access is off. Turn it on in Settings > System. = Akses ponsel mati. Nyalakan di Pengaturan > Sistem.
|
||||
The PS5 isn't connected to a network. Connect it, then come back. = PS5 tidak terhubung ke jaringan. Hubungkan, lalu kembali.
|
||||
On a phone or computer on the same Wi-Fi, open this address in the browser: = Di ponsel atau komputer pada Wi-Fi yang sama, buka alamat ini di browser:
|
||||
Send videos, music and subtitles to the PS5 = Kirim video, musik, dan subtitle ke PS5
|
||||
Use it as a remote while something plays = Gunakan sebagai remote saat ada yang diputar
|
||||
Add your OpenSubtitles API key = Tambahkan kunci API OpenSubtitles Anda
|
||||
Receiving %s = Menerima %s
|
||||
Volume %d%% = Volume %d%%
|
||||
OpenSubtitles key received from your phone = Kunci OpenSubtitles diterima dari ponsel Anda
|
||||
A file arrived from your phone = File tiba dari ponsel Anda
|
||||
VLC media folder = Folder media VLC
|
||||
USB drive %d = Drive USB %d
|
||||
USB drive (%s) = Drive USB (%s)
|
||||
@@ -387,12 +382,10 @@ The API key works = Kunci API berfungsi
|
||||
Checking the key = Pemeriksaan kunci
|
||||
The server didn't answer. = Server tidak menjawab.
|
||||
Couldn't open this place. = Tidak dapat membuka lokasi ini.
|
||||
File = File
|
||||
Folder = Folder
|
||||
Bitrate = Bitrate
|
||||
Container = Kontainer
|
||||
Video = Video
|
||||
Track = Trek
|
||||
White = Putih
|
||||
Yellow = Kuning
|
||||
Cyan = Sian
|
||||
@@ -512,3 +505,67 @@ Skip = Lewati
|
||||
Start = Mulai
|
||||
Run setup again = Jalankan penyiapan lagi
|
||||
Language, look and playback, chosen again = Bahasa, tampilan, dan pemutaran dipilih ulang
|
||||
Send files from a phone or PC = Kirim file dari ponsel atau PC
|
||||
Send files from your phone or PC = Kirim file dari ponsel atau PC Anda
|
||||
OpenSubtitles key received from your phone or PC = Kunci OpenSubtitles diterima dari ponsel atau PC Anda
|
||||
A file arrived from your phone or PC = File tiba dari ponsel atau PC Anda
|
||||
File = File
|
||||
%s file = File %s
|
||||
OpenSubtitles refused this API key = OpenSubtitles menolak kunci API ini
|
||||
New playlist = Daftar putar baru
|
||||
Made in VLC = Dibuat di VLC
|
||||
Where = Lokasi
|
||||
1 item = 1 item
|
||||
Removed from %s = Dihapus dari %s
|
||||
This playlist is empty = Daftar putar ini kosong
|
||||
Create = Buat
|
||||
Play all = Putar semua
|
||||
Remove = Hapus
|
||||
Move = Pindahkan
|
||||
Add to playlist = Tambahkan ke daftar putar
|
||||
Rename playlist = Ganti nama daftar putar
|
||||
Delete playlist = Hapus daftar putar
|
||||
Name the playlist = Beri nama daftar putar
|
||||
%s goes in first = %s masuk lebih dulu
|
||||
Type a name = Ketik nama
|
||||
Made %s = %s dibuat
|
||||
Added to %s = Ditambahkan ke %s
|
||||
Already in %s = Sudah ada di %s
|
||||
Save = Simpan
|
||||
%d playlists = %d daftar putar
|
||||
Saved in the media folder's Playlists, as a file VLC on a computer opens too = Disimpan di folder Playlists dalam folder media, sebagai file yang juga bisa dibuka VLC di komputer
|
||||
A playlist with this name is already there, or the disk can't be written = Sudah ada daftar putar dengan nama ini, atau disk tidak bisa ditulisi
|
||||
Then add videos and songs from anywhere with the Options menu = Lalu tambahkan video dan lagu dari mana saja lewat menu Opsi
|
||||
Open the Options menu on a video or song and choose Add to playlist = Buka menu Opsi pada video atau lagu lalu pilih Tambahkan ke daftar putar
|
||||
stereo = stereo
|
||||
Chapter %d = Bab %d
|
||||
Audio %d = Audio %d
|
||||
Fonts: Selawik, Inter, Noto, DejaVu (OFL). TV lists: iptv-org. Radio: radio-browser.info. Subtitles: OpenSubtitles.com. = Font: Selawik, Inter, Noto, DejaVu (OFL). Daftar TV: iptv-org. Radio: radio-browser.info. Subtitle: OpenSubtitles.com.
|
||||
15 min = 15 mnt
|
||||
30 min = 30 mnt
|
||||
45 min = 45 mnt
|
||||
60 min = 60 mnt
|
||||
90 min = 90 mnt
|
||||
Sign in to the share = Masuk ke folder berbagi
|
||||
%s needs a user name and password. = %s memerlukan nama pengguna dan kata sandi.
|
||||
A Windows PC takes its own account; a NAS, the user you made on it. = PC Windows memakai akunnya sendiri; NAS memakai pengguna yang Anda buat di sana.
|
||||
Track %d = Trek %d
|
||||
Track = Trek
|
||||
Disc menu = Menu disk
|
||||
Pop-up menu = Menu pop-up
|
||||
Blu-ray region = Region Blu-ray
|
||||
Region %s = Region %s
|
||||
Blu-ray region: from the next disc you open = Region Blu-ray: mulai dari disk berikutnya yang kamu buka
|
||||
A: the Americas and East Asia. B: Europe, Africa and Oceania. C: China, Russia and India = A: Amerika dan Asia Timur. B: Eropa, Afrika, dan Oseania. C: Tiongkok, Rusia, dan India
|
||||
Add a subtitle file = Tambahkan file subtitle
|
||||
Pick a subtitle file = Pilih file subtitle
|
||||
Subtitles: %s = Subtitle: %s
|
||||
Couldn't load that subtitle file = File subtitle itu tidak bisa dimuat
|
||||
That isn't a subtitle file (.srt, .ass, .vtt...) = Itu bukan file subtitle (.srt, .ass, .vtt...)
|
||||
Java Blu-ray discs (BD-J) aren't supported on the PS5 = Blu-ray Java (BD-J) tidak didukung di PS5
|
||||
Hardware decoding = Dekode perangkat keras
|
||||
The console's video chip. Off: the processor decodes, slower for 4K = Cip video konsol. Mati: prosesor yang mendekode, lebih lambat untuk 4K
|
||||
Looking for channels and stations… = Mencari saluran dan stasiun…
|
||||
Hardware decoding: from the next video = Dekode perangkat keras: mulai video berikutnya
|
||||
Match frame rate = Samakan laju bingkai
|
||||
Films play at their own 24, 25 or 50 Hz: smoother pans. Some TVs go black a moment = Film diputar pada 24, 25 atau 50 Hz aslinya: gerakan lebih halus. Beberapa TV gelap sesaat
|
||||
+67
-10
@@ -146,13 +146,11 @@ About VLC = Informazioni su VLC
|
||||
PS5 port = Versione PS5
|
||||
VideoLAN and the VLC contributors = VideoLAN e i collaboratori di VLC
|
||||
Built with = Realizzato con
|
||||
GPLv2+. An unofficial port, not affiliated with VideoLAN or Sony. = GPLv2+. Una versione non ufficiale, non affiliata a VideoLAN o Sony.
|
||||
GPL-3.0. An unofficial port, not affiliated with VideoLAN or Sony. = GPL-3.0. Una versione non ufficiale, non affiliata a VideoLAN o Sony.
|
||||
Resume = Riprendi
|
||||
Audio, subtitles and more = Audio, sottotitoli e altro
|
||||
Phone remote = Telecomando dal telefono
|
||||
Settings = Impostazioni
|
||||
Stop playback = Interrompi la riproduzione
|
||||
Send files from a phone = Invia file da un telefono
|
||||
Rescan media = Ricerca di nuovo i contenuti
|
||||
Options = Opzioni
|
||||
Found %zu files = %zu file trovati
|
||||
@@ -188,7 +186,7 @@ Writes VLC's warnings and stats to vlc-ps5.log, for bug reports = Scrive avvisi
|
||||
What VLC can read on this console = Cosa può leggere VLC su questa console
|
||||
Starts VLC again: it then sees drives plugged in since (when sandboxed) = Riavvia VLC: così vede le unità collegate nel frattempo (in sandbox)
|
||||
Version, credits and licences = Versione, riconoscimenti e licenze
|
||||
The page that sends files and works as a remote, on your home network = La pagina che invia file e fa da telecomando, sulla rete di casa
|
||||
The page that sends files and takes your OpenSubtitles key, on your home network = La pagina che invia file e riceve la tua chiave OpenSubtitles, sulla rete di casa
|
||||
Classic: panels and folders like a desktop player. Modern: black, VLC 4 style. VLC restarts = Classico: pannelli e cartelle come un lettore desktop. Moderno: nero, stile VLC 4. VLC si riavvia
|
||||
Your own free OpenSubtitles API key (and account), here or from the phone page = La tua chiave API gratuita di OpenSubtitles (e account), qui o dalla pagina del telefono
|
||||
The language of VLC's menus = La lingua dei menu di VLC
|
||||
@@ -228,16 +226,13 @@ Back right = Posteriore destro
|
||||
Each speaker plays a tone in turn. If one comes from the wrong place, tell us which. = Ogni altoparlante emette un tono a turno. Se uno arriva dal punto sbagliato, dicci quale.
|
||||
Stop going round = Ferma il giro
|
||||
Go round = Fai il giro
|
||||
Send files from your phone = Invia file dal tuo telefono
|
||||
Phone access is off. Turn it on in Settings > System. = L'accesso dal telefono è disattivato. Attivalo in Impostazioni > Sistema.
|
||||
The PS5 isn't connected to a network. Connect it, then come back. = La PS5 non è connessa a una rete. Connettila, poi torna qui.
|
||||
On a phone or computer on the same Wi-Fi, open this address in the browser: = Su un telefono o computer della stessa Wi-Fi, apri questo indirizzo nel browser:
|
||||
Send videos, music and subtitles to the PS5 = Invia video, musica e sottotitoli alla PS5
|
||||
Use it as a remote while something plays = Usala come telecomando durante la riproduzione
|
||||
Add your OpenSubtitles API key = Aggiungi la tua chiave API OpenSubtitles
|
||||
Receiving %s = Ricezione di %s
|
||||
Volume %d%% = Volume %d%%
|
||||
OpenSubtitles key received from your phone = Chiave OpenSubtitles ricevuta dal telefono
|
||||
A file arrived from your phone = È arrivato un file dal telefono
|
||||
VLC media folder = Cartella multimediale di VLC
|
||||
USB drive %d = Unità USB %d
|
||||
USB drive (%s) = Unità USB (%s)
|
||||
@@ -387,12 +382,10 @@ The API key works = La chiave API funziona
|
||||
Checking the key = La verifica della chiave
|
||||
The server didn't answer. = Il server non ha risposto.
|
||||
Couldn't open this place. = Impossibile aprire questa posizione.
|
||||
File = File
|
||||
Folder = Cartella
|
||||
Bitrate = Bitrate
|
||||
Container = Contenitore
|
||||
Video = Video
|
||||
Track = Traccia
|
||||
White = Bianco
|
||||
Yellow = Giallo
|
||||
Cyan = Ciano
|
||||
@@ -512,3 +505,67 @@ Skip = Salta
|
||||
Start = Inizia
|
||||
Run setup again = Ripeti la configurazione
|
||||
Language, look and playback, chosen again = Lingua, aspetto e riproduzione, di nuovo
|
||||
Send files from a phone or PC = Invia file da un telefono o PC
|
||||
Send files from your phone or PC = Invia file dal tuo telefono o PC
|
||||
OpenSubtitles key received from your phone or PC = Chiave OpenSubtitles ricevuta dal telefono o PC
|
||||
A file arrived from your phone or PC = È arrivato un file dal telefono o PC
|
||||
File = File
|
||||
%s file = File %s
|
||||
OpenSubtitles refused this API key = OpenSubtitles ha rifiutato questa chiave API
|
||||
New playlist = Nuova playlist
|
||||
Made in VLC = Creata in VLC
|
||||
Where = Posizione
|
||||
1 item = 1 elemento
|
||||
Removed from %s = Rimosso da %s
|
||||
This playlist is empty = Questa playlist è vuota
|
||||
Create = Crea
|
||||
Play all = Riproduci tutto
|
||||
Remove = Rimuovi
|
||||
Move = Sposta
|
||||
Add to playlist = Aggiungi a una playlist
|
||||
Rename playlist = Rinomina playlist
|
||||
Delete playlist = Elimina playlist
|
||||
Name the playlist = Dai un nome alla playlist
|
||||
%s goes in first = %s entra per primo
|
||||
Type a name = Scrivi un nome
|
||||
Made %s = %s creata
|
||||
Added to %s = Aggiunto a %s
|
||||
Already in %s = Già in %s
|
||||
Save = Salva
|
||||
%d playlists = %d playlist
|
||||
Saved in the media folder's Playlists, as a file VLC on a computer opens too = Salvata nella cartella Playlists della cartella dei media, come file che anche VLC sul computer apre
|
||||
A playlist with this name is already there, or the disk can't be written = Esiste già una playlist con questo nome, oppure il disco non è scrivibile
|
||||
Then add videos and songs from anywhere with the Options menu = Poi aggiungi video e brani da qualsiasi punto con il menu Opzioni
|
||||
Open the Options menu on a video or song and choose Add to playlist = Apri il menu Opzioni su un video o un brano e scegli Aggiungi a una playlist
|
||||
stereo = stereo
|
||||
Chapter %d = Capitolo %d
|
||||
Audio %d = Audio %d
|
||||
Fonts: Selawik, Inter, Noto, DejaVu (OFL). TV lists: iptv-org. Radio: radio-browser.info. Subtitles: OpenSubtitles.com. = Caratteri: Selawik, Inter, Noto, DejaVu (OFL). Elenchi TV: iptv-org. Radio: radio-browser.info. Sottotitoli: OpenSubtitles.com.
|
||||
15 min = 15 min
|
||||
30 min = 30 min
|
||||
45 min = 45 min
|
||||
60 min = 60 min
|
||||
90 min = 90 min
|
||||
Sign in to the share = Accedi alla condivisione
|
||||
%s needs a user name and password. = %s richiede nome utente e password.
|
||||
A Windows PC takes its own account; a NAS, the user you made on it. = Un PC Windows usa il proprio account; un NAS, l'utente che hai creato su di esso.
|
||||
Track %d = Traccia %d
|
||||
Track = Traccia
|
||||
Disc menu = Menu del disco
|
||||
Pop-up menu = Menu pop-up
|
||||
Blu-ray region = Area Blu-ray
|
||||
Region %s = Area %s
|
||||
Blu-ray region: from the next disc you open = Area Blu-ray: dal prossimo disco che apri
|
||||
A: the Americas and East Asia. B: Europe, Africa and Oceania. C: China, Russia and India = A: Americhe e Asia orientale. B: Europa, Africa e Oceania. C: Cina, Russia e India
|
||||
Add a subtitle file = Aggiungi un file di sottotitoli
|
||||
Pick a subtitle file = Scegli un file di sottotitoli
|
||||
Subtitles: %s = Sottotitoli: %s
|
||||
Couldn't load that subtitle file = Impossibile caricare quel file di sottotitoli
|
||||
That isn't a subtitle file (.srt, .ass, .vtt...) = Non è un file di sottotitoli (.srt, .ass, .vtt...)
|
||||
Java Blu-ray discs (BD-J) aren't supported on the PS5 = I Blu-ray Java (BD-J) non sono supportati su PS5
|
||||
Hardware decoding = Decodifica hardware
|
||||
The console's video chip. Off: the processor decodes, slower for 4K = Il chip video della console. Disattivato: decodifica il processore, più lento in 4K
|
||||
Looking for channels and stations… = Ricerca di canali e stazioni…
|
||||
Hardware decoding: from the next video = Decodifica hardware: dal prossimo video
|
||||
Match frame rate = Adatta frequenza fotogrammi
|
||||
Films play at their own 24, 25 or 50 Hz: smoother pans. Some TVs go black a moment = I film vanno ai loro 24, 25 o 50 Hz: panoramiche più fluide. Alcune TV diventano nere per un attimo
|
||||
+67
-10
@@ -146,13 +146,11 @@ About VLC = VLC について
|
||||
PS5 port = PS5 版
|
||||
VideoLAN and the VLC contributors = VideoLAN と VLC の貢献者
|
||||
Built with = 使用ソフトウェア
|
||||
GPLv2+. An unofficial port, not affiliated with VideoLAN or Sony. = GPLv2+。非公式の移植版で、VideoLAN や Sony とは関係ありません。
|
||||
GPL-3.0. An unofficial port, not affiliated with VideoLAN or Sony. = GPL-3.0。非公式の移植版で、VideoLAN や Sony とは関係ありません。
|
||||
Resume = 再開
|
||||
Audio, subtitles and more = 音声、字幕など
|
||||
Phone remote = スマホリモコン
|
||||
Settings = 設定
|
||||
Stop playback = 再生を停止
|
||||
Send files from a phone = スマホからファイルを送る
|
||||
Rescan media = メディアを再スキャン
|
||||
Options = オプション
|
||||
Found %zu files = %zu 個のファイルが見つかりました
|
||||
@@ -188,7 +186,7 @@ Writes VLC's warnings and stats to vlc-ps5.log, for bug reports = バグ報告
|
||||
What VLC can read on this console = この本体で VLC が読めるもの
|
||||
Starts VLC again: it then sees drives plugged in since (when sandboxed) = VLC を再起動:その後に接続したドライブが見えるようになります(サンドボックス時)
|
||||
Version, credits and licences = バージョン、クレジット、ライセンス
|
||||
The page that sends files and works as a remote, on your home network = ホームネットワークでファイル送信とリモコンができるページ
|
||||
The page that sends files and takes your OpenSubtitles key, on your home network = ホームネットワーク上で、ファイルを送り OpenSubtitles のキーを受け取るページ
|
||||
Classic: panels and folders like a desktop player. Modern: black, VLC 4 style. VLC restarts = クラシック:デスクトップ版のようなパネルとフォルダー。モダン:黒、VLC 4 風。VLC が再起動します
|
||||
Your own free OpenSubtitles API key (and account), here or from the phone page = あなた自身の無料 OpenSubtitles API キー(とアカウント)。ここかスマホのページから
|
||||
The language of VLC's menus = VLC のメニューの言語
|
||||
@@ -228,16 +226,13 @@ Back right = バック右
|
||||
Each speaker plays a tone in turn. If one comes from the wrong place, tell us which. = 各スピーカーが順番に音を鳴らします。違う場所から聞こえたら、どれか教えてください。
|
||||
Stop going round = 一周を止める
|
||||
Go round = 一周させる
|
||||
Send files from your phone = スマホからファイルを送る
|
||||
Phone access is off. Turn it on in Settings > System. = スマホからのアクセスはオフです。設定 > システムでオンにしてください。
|
||||
The PS5 isn't connected to a network. Connect it, then come back. = PS5 がネットワークに接続されていません。接続してから戻ってください。
|
||||
On a phone or computer on the same Wi-Fi, open this address in the browser: = 同じ Wi-Fi のスマホかパソコンのブラウザーでこのアドレスを開いてください:
|
||||
Send videos, music and subtitles to the PS5 = ビデオ、音楽、字幕を PS5 に送る
|
||||
Use it as a remote while something plays = 再生中はリモコンとして使う
|
||||
Add your OpenSubtitles API key = OpenSubtitles の API キーを追加
|
||||
Receiving %s = %s を受信中
|
||||
Volume %d%% = 音量 %d%%
|
||||
OpenSubtitles key received from your phone = スマホから OpenSubtitles のキーを受け取りました
|
||||
A file arrived from your phone = スマホからファイルが届きました
|
||||
VLC media folder = VLC メディアフォルダー
|
||||
USB drive %d = USB ドライブ %d
|
||||
USB drive (%s) = USB ドライブ(%s)
|
||||
@@ -387,12 +382,10 @@ The API key works = API キーは有効です
|
||||
Checking the key = キーの確認
|
||||
The server didn't answer. = サーバーが応答しませんでした。
|
||||
Couldn't open this place. = この場所を開けませんでした。
|
||||
File = ファイル
|
||||
Folder = フォルダー
|
||||
Bitrate = ビットレート
|
||||
Container = コンテナー
|
||||
Video = ビデオ
|
||||
Track = トラック
|
||||
White = 白
|
||||
Yellow = 黄
|
||||
Cyan = シアン
|
||||
@@ -512,3 +505,67 @@ Skip = スキップ
|
||||
Start = 開始
|
||||
Run setup again = セットアップをやり直す
|
||||
Language, look and playback, chosen again = 言語、外観、再生をもう一度選びます
|
||||
Send files from a phone or PC = スマホや PC からファイルを送る
|
||||
Send files from your phone or PC = スマホや PC からファイルを送る
|
||||
OpenSubtitles key received from your phone or PC = スマホや PC から OpenSubtitles のキーを受け取りました
|
||||
A file arrived from your phone or PC = スマホや PC からファイルが届きました
|
||||
File = ファイル
|
||||
%s file = %s ファイル
|
||||
OpenSubtitles refused this API key = OpenSubtitles がこの API キーを拒否しました
|
||||
New playlist = 新しいプレイリスト
|
||||
Made in VLC = VLC で作成
|
||||
Where = 場所
|
||||
1 item = 1 件
|
||||
Removed from %s = %s から削除しました
|
||||
This playlist is empty = このプレイリストは空です
|
||||
Create = 作成
|
||||
Play all = すべて再生
|
||||
Remove = 削除
|
||||
Move = 移動
|
||||
Add to playlist = プレイリストに追加
|
||||
Rename playlist = プレイリスト名を変更
|
||||
Delete playlist = プレイリストを削除
|
||||
Name the playlist = プレイリストの名前
|
||||
%s goes in first = 最初に %s が入ります
|
||||
Type a name = 名前を入力してください
|
||||
Made %s = %s を作成しました
|
||||
Added to %s = %s に追加しました
|
||||
Already in %s = すでに %s にあります
|
||||
Save = 保存
|
||||
%d playlists = %d 件のプレイリスト
|
||||
Saved in the media folder's Playlists, as a file VLC on a computer opens too = メディアフォルダーの Playlists に、PC の VLC でも開けるファイルとして保存されます
|
||||
A playlist with this name is already there, or the disk can't be written = 同じ名前のプレイリストがあるか、ディスクに書き込めません
|
||||
Then add videos and songs from anywhere with the Options menu = あとはどこからでもオプションメニューで動画や曲を追加できます
|
||||
Open the Options menu on a video or song and choose Add to playlist = 動画や曲でオプションメニューを開き、プレイリストに追加を選んでください
|
||||
stereo = ステレオ
|
||||
Chapter %d = チャプター %d
|
||||
Audio %d = 音声 %d
|
||||
Fonts: Selawik, Inter, Noto, DejaVu (OFL). TV lists: iptv-org. Radio: radio-browser.info. Subtitles: OpenSubtitles.com. = フォント: Selawik、Inter、Noto、DejaVu (OFL)。テレビ一覧: iptv-org。ラジオ: radio-browser.info。字幕: OpenSubtitles.com。
|
||||
15 min = 15 分
|
||||
30 min = 30 分
|
||||
45 min = 45 分
|
||||
60 min = 60 分
|
||||
90 min = 90 分
|
||||
Sign in to the share = 共有フォルダーにサインイン
|
||||
%s needs a user name and password. = %s にはユーザー名とパスワードが必要です。
|
||||
A Windows PC takes its own account; a NAS, the user you made on it. = Windows PC ならその PC のアカウント、NAS なら NAS で作ったユーザーを使います。
|
||||
Track %d = トラック %d
|
||||
Track = トラック
|
||||
Disc menu = ディスクメニュー
|
||||
Pop-up menu = ポップアップメニュー
|
||||
Blu-ray region = Blu-ray リージョン
|
||||
Region %s = リージョン %s
|
||||
Blu-ray region: from the next disc you open = Blu-ray リージョン: 次に開くディスクから
|
||||
A: the Americas and East Asia. B: Europe, Africa and Oceania. C: China, Russia and India = A: 南北アメリカと東アジア。B: ヨーロッパ、アフリカ、オセアニア。C: 中国、ロシア、インド
|
||||
Add a subtitle file = 字幕ファイルを追加
|
||||
Pick a subtitle file = 字幕ファイルを選択
|
||||
Subtitles: %s = 字幕: %s
|
||||
Couldn't load that subtitle file = その字幕ファイルを読み込めませんでした
|
||||
That isn't a subtitle file (.srt, .ass, .vtt...) = 字幕ファイルではありません (.srt、.ass、.vtt など)
|
||||
Java Blu-ray discs (BD-J) aren't supported on the PS5 = Java の Blu-ray (BD-J) は PS5 では再生できません
|
||||
Hardware decoding = ハードウェアデコード
|
||||
The console's video chip. Off: the processor decodes, slower for 4K = 本体のビデオチップ。オフ:プロセッサーでデコード(4Kでは遅くなります)
|
||||
Looking for channels and stations… = チャンネルと局を検索中…
|
||||
Hardware decoding: from the next video = ハードウェアデコード:次のビデオから
|
||||
Match frame rate = フレームレートを合わせる
|
||||
Films play at their own 24, 25 or 50 Hz: smoother pans. Some TVs go black a moment = 映画を本来の24・25・50Hzで再生し、パンが滑らかになります。一部のテレビは一瞬暗くなります
|
||||
+67
-10
@@ -146,13 +146,11 @@ About VLC = VLC 정보
|
||||
PS5 port = PS5 포팅
|
||||
VideoLAN and the VLC contributors = VideoLAN 및 VLC 기여자
|
||||
Built with = 사용한 소프트웨어
|
||||
GPLv2+. An unofficial port, not affiliated with VideoLAN or Sony. = GPLv2+. 비공식 포팅이며 VideoLAN 또는 Sony와 관련이 없습니다.
|
||||
GPL-3.0. An unofficial port, not affiliated with VideoLAN or Sony. = GPL-3.0. 비공식 포팅이며 VideoLAN 또는 Sony와 관련이 없습니다.
|
||||
Resume = 이어서 재생
|
||||
Audio, subtitles and more = 오디오, 자막 등
|
||||
Phone remote = 휴대폰 리모컨
|
||||
Settings = 설정
|
||||
Stop playback = 재생 중지
|
||||
Send files from a phone = 휴대폰에서 파일 보내기
|
||||
Rescan media = 미디어 다시 검색
|
||||
Options = 옵션
|
||||
Found %zu files = 파일 %zu개를 찾았습니다
|
||||
@@ -188,7 +186,7 @@ Writes VLC's warnings and stats to vlc-ps5.log, for bug reports = 버그 신고
|
||||
What VLC can read on this console = 이 콘솔에서 VLC가 읽을 수 있는 곳
|
||||
Starts VLC again: it then sees drives plugged in since (when sandboxed) = VLC를 다시 시작합니다. 그 사이 연결한 드라이브가 보입니다(샌드박스일 때)
|
||||
Version, credits and licences = 버전, 만든 사람, 라이선스
|
||||
The page that sends files and works as a remote, on your home network = 홈 네트워크에서 파일을 보내고 리모컨으로 쓰는 페이지
|
||||
The page that sends files and takes your OpenSubtitles key, on your home network = 홈 네트워크에서 파일을 보내고 OpenSubtitles 키를 받는 페이지
|
||||
Classic: panels and folders like a desktop player. Modern: black, VLC 4 style. VLC restarts = 클래식: 데스크톱 플레이어 같은 패널과 폴더. 모던: 검은색, VLC 4 스타일. VLC가 다시 시작됩니다
|
||||
Your own free OpenSubtitles API key (and account), here or from the phone page = 본인의 무료 OpenSubtitles API 키(및 계정). 여기서 또는 휴대폰 페이지에서
|
||||
The language of VLC's menus = VLC 메뉴의 언어
|
||||
@@ -228,16 +226,13 @@ Back right = 뒤쪽 오른쪽
|
||||
Each speaker plays a tone in turn. If one comes from the wrong place, tell us which. = 각 스피커가 차례로 소리를 냅니다. 잘못된 곳에서 들리면 어느 것인지 알려 주세요.
|
||||
Stop going round = 순회 멈추기
|
||||
Go round = 순회 시작
|
||||
Send files from your phone = 휴대폰에서 파일 보내기
|
||||
Phone access is off. Turn it on in Settings > System. = 휴대폰 접속이 꺼져 있습니다. 설정 > 시스템에서 켜세요.
|
||||
The PS5 isn't connected to a network. Connect it, then come back. = PS5가 네트워크에 연결되어 있지 않습니다. 연결한 뒤 다시 오세요.
|
||||
On a phone or computer on the same Wi-Fi, open this address in the browser: = 같은 Wi-Fi의 휴대폰이나 컴퓨터 브라우저에서 이 주소를 여세요:
|
||||
Send videos, music and subtitles to the PS5 = 비디오, 음악, 자막을 PS5로 보내기
|
||||
Use it as a remote while something plays = 재생 중에는 리모컨으로 사용
|
||||
Add your OpenSubtitles API key = OpenSubtitles API 키 추가
|
||||
Receiving %s = %s 받는 중
|
||||
Volume %d%% = 볼륨 %d%%
|
||||
OpenSubtitles key received from your phone = 휴대폰에서 OpenSubtitles 키를 받았습니다
|
||||
A file arrived from your phone = 휴대폰에서 파일이 도착했습니다
|
||||
VLC media folder = VLC 미디어 폴더
|
||||
USB drive %d = USB 드라이브 %d
|
||||
USB drive (%s) = USB 드라이브 (%s)
|
||||
@@ -387,12 +382,10 @@ The API key works = API 키가 작동합니다
|
||||
Checking the key = 키 확인
|
||||
The server didn't answer. = 서버가 응답하지 않았습니다.
|
||||
Couldn't open this place. = 이 위치를 열 수 없습니다.
|
||||
File = 파일
|
||||
Folder = 폴더
|
||||
Bitrate = 비트레이트
|
||||
Container = 컨테이너
|
||||
Video = 비디오
|
||||
Track = 트랙
|
||||
White = 흰색
|
||||
Yellow = 노란색
|
||||
Cyan = 청록색
|
||||
@@ -512,3 +505,67 @@ Skip = 건너뛰기
|
||||
Start = 시작
|
||||
Run setup again = 설정 다시 하기
|
||||
Language, look and playback, chosen again = 언어, 모양, 재생을 다시 고릅니다
|
||||
Send files from a phone or PC = 휴대폰이나 PC에서 파일 보내기
|
||||
Send files from your phone or PC = 휴대폰이나 PC에서 파일 보내기
|
||||
OpenSubtitles key received from your phone or PC = 휴대폰이나 PC에서 OpenSubtitles 키를 받았습니다
|
||||
A file arrived from your phone or PC = 휴대폰이나 PC에서 파일이 도착했습니다
|
||||
File = 파일
|
||||
%s file = %s 파일
|
||||
OpenSubtitles refused this API key = OpenSubtitles가 이 API 키를 거부했습니다
|
||||
New playlist = 새 재생목록
|
||||
Made in VLC = VLC에서 만듦
|
||||
Where = 위치
|
||||
1 item = 1개 항목
|
||||
Removed from %s = %s에서 제거됨
|
||||
This playlist is empty = 이 재생목록은 비어 있습니다
|
||||
Create = 만들기
|
||||
Play all = 모두 재생
|
||||
Remove = 제거
|
||||
Move = 이동
|
||||
Add to playlist = 재생목록에 추가
|
||||
Rename playlist = 재생목록 이름 바꾸기
|
||||
Delete playlist = 재생목록 삭제
|
||||
Name the playlist = 재생목록 이름
|
||||
%s goes in first = %s이(가) 먼저 들어갑니다
|
||||
Type a name = 이름을 입력하세요
|
||||
Made %s = %s을(를) 만들었습니다
|
||||
Added to %s = %s에 추가됨
|
||||
Already in %s = 이미 %s에 있음
|
||||
Save = 저장
|
||||
%d playlists = 재생목록 %d개
|
||||
Saved in the media folder's Playlists, as a file VLC on a computer opens too = 미디어 폴더의 Playlists에, PC의 VLC에서도 열리는 파일로 저장됩니다
|
||||
A playlist with this name is already there, or the disk can't be written = 같은 이름의 재생목록이 있거나 디스크에 쓸 수 없습니다
|
||||
Then add videos and songs from anywhere with the Options menu = 그다음 어디서든 옵션 메뉴로 동영상과 노래를 추가하세요
|
||||
Open the Options menu on a video or song and choose Add to playlist = 동영상이나 노래에서 옵션 메뉴를 열고 재생목록에 추가를 고르세요
|
||||
stereo = 스테레오
|
||||
Chapter %d = 챕터 %d
|
||||
Audio %d = 오디오 %d
|
||||
Fonts: Selawik, Inter, Noto, DejaVu (OFL). TV lists: iptv-org. Radio: radio-browser.info. Subtitles: OpenSubtitles.com. = 글꼴: Selawik, Inter, Noto, DejaVu (OFL). TV 목록: iptv-org. 라디오: radio-browser.info. 자막: OpenSubtitles.com.
|
||||
15 min = 15분
|
||||
30 min = 30분
|
||||
45 min = 45분
|
||||
60 min = 60분
|
||||
90 min = 90분
|
||||
Sign in to the share = 공유 폴더에 로그인
|
||||
%s needs a user name and password. = %s에 사용자 이름과 비밀번호가 필요합니다.
|
||||
A Windows PC takes its own account; a NAS, the user you made on it. = Windows PC는 그 PC의 계정을, NAS는 NAS에서 만든 사용자를 사용합니다.
|
||||
Track %d = 트랙 %d
|
||||
Track = 트랙
|
||||
Disc menu = 디스크 메뉴
|
||||
Pop-up menu = 팝업 메뉴
|
||||
Blu-ray region = Blu-ray 지역
|
||||
Region %s = 지역 %s
|
||||
Blu-ray region: from the next disc you open = Blu-ray 지역: 다음에 여는 디스크부터
|
||||
A: the Americas and East Asia. B: Europe, Africa and Oceania. C: China, Russia and India = A: 아메리카와 동아시아. B: 유럽, 아프리카, 오세아니아. C: 중국, 러시아, 인도
|
||||
Add a subtitle file = 자막 파일 추가
|
||||
Pick a subtitle file = 자막 파일 선택
|
||||
Subtitles: %s = 자막: %s
|
||||
Couldn't load that subtitle file = 그 자막 파일을 불러올 수 없습니다
|
||||
That isn't a subtitle file (.srt, .ass, .vtt...) = 자막 파일이 아닙니다 (.srt, .ass, .vtt...)
|
||||
Java Blu-ray discs (BD-J) aren't supported on the PS5 = Java 블루레이(BD-J)는 PS5에서 지원되지 않습니다
|
||||
Hardware decoding = 하드웨어 디코딩
|
||||
The console's video chip. Off: the processor decodes, slower for 4K = 본체의 비디오 칩. 끄면 프로세서가 디코딩하며 4K에서는 느립니다
|
||||
Looking for channels and stations… = 채널과 방송국을 찾는 중…
|
||||
Hardware decoding: from the next video = 하드웨어 디코딩: 다음 동영상부터
|
||||
Match frame rate = 프레임 속도 맞추기
|
||||
Films play at their own 24, 25 or 50 Hz: smoother pans. Some TVs go black a moment = 영화를 원래의 24, 25, 50Hz로 재생해 화면 이동이 부드럽습니다. 일부 TV는 잠시 검게 됩니다
|
||||
+67
-10
@@ -146,13 +146,11 @@ About VLC = Over VLC
|
||||
PS5 port = PS5-versie
|
||||
VideoLAN and the VLC contributors = VideoLAN en de bijdragers aan VLC
|
||||
Built with = Gemaakt met
|
||||
GPLv2+. An unofficial port, not affiliated with VideoLAN or Sony. = GPLv2+. Een onofficiële versie, niet verbonden aan VideoLAN of Sony.
|
||||
GPL-3.0. An unofficial port, not affiliated with VideoLAN or Sony. = GPL-3.0. Een onofficiële versie, niet verbonden aan VideoLAN of Sony.
|
||||
Resume = Hervatten
|
||||
Audio, subtitles and more = Audio, ondertitels en meer
|
||||
Phone remote = Telefoonafstandsbediening
|
||||
Settings = Instellingen
|
||||
Stop playback = Afspelen stoppen
|
||||
Send files from a phone = Bestanden van een telefoon sturen
|
||||
Rescan media = Media opnieuw scannen
|
||||
Options = Opties
|
||||
Found %zu files = %zu bestanden gevonden
|
||||
@@ -188,7 +186,7 @@ Writes VLC's warnings and stats to vlc-ps5.log, for bug reports = Schrijft waars
|
||||
What VLC can read on this console = Wat VLC op deze console kan lezen
|
||||
Starts VLC again: it then sees drives plugged in since (when sandboxed) = Start VLC opnieuw: dan ziet het stations die sindsdien zijn aangesloten (in de sandbox)
|
||||
Version, credits and licences = Versie, makers en licenties
|
||||
The page that sends files and works as a remote, on your home network = De pagina die bestanden stuurt en als afstandsbediening werkt, in je thuisnetwerk
|
||||
The page that sends files and takes your OpenSubtitles key, on your home network = De pagina die bestanden verstuurt en je OpenSubtitles-sleutel ontvangt, op je thuisnetwerk
|
||||
Classic: panels and folders like a desktop player. Modern: black, VLC 4 style. VLC restarts = Klassiek: panelen en mappen zoals een desktopspeler. Modern: zwart, in VLC 4-stijl. VLC start opnieuw
|
||||
Your own free OpenSubtitles API key (and account), here or from the phone page = Je eigen gratis OpenSubtitles-API-sleutel (en account), hier of via de telefoonpagina
|
||||
The language of VLC's menus = De taal van de menu's van VLC
|
||||
@@ -228,16 +226,13 @@ Back right = Rechtsachter
|
||||
Each speaker plays a tone in turn. If one comes from the wrong place, tell us which. = Elke luidspreker speelt om de beurt een toon. Komt er een van de verkeerde plek, laat ons weten welke.
|
||||
Stop going round = Ronde stoppen
|
||||
Go round = Ronde starten
|
||||
Send files from your phone = Stuur bestanden van je telefoon
|
||||
Phone access is off. Turn it on in Settings > System. = Toegang via telefoon staat uit. Zet het aan in Instellingen > Systeem.
|
||||
The PS5 isn't connected to a network. Connect it, then come back. = De PS5 is niet met een netwerk verbonden. Verbind hem en kom dan terug.
|
||||
On a phone or computer on the same Wi-Fi, open this address in the browser: = Open op een telefoon of computer in hetzelfde wifi-netwerk dit adres in de browser:
|
||||
Send videos, music and subtitles to the PS5 = Stuur video's, muziek en ondertitels naar de PS5
|
||||
Use it as a remote while something plays = Gebruik het als afstandsbediening tijdens het afspelen
|
||||
Add your OpenSubtitles API key = Voeg je OpenSubtitles-API-sleutel toe
|
||||
Receiving %s = %s ontvangen
|
||||
Volume %d%% = Volume %d%%
|
||||
OpenSubtitles key received from your phone = OpenSubtitles-sleutel van je telefoon ontvangen
|
||||
A file arrived from your phone = Er is een bestand van je telefoon binnengekomen
|
||||
VLC media folder = Mediamap van VLC
|
||||
USB drive %d = USB-station %d
|
||||
USB drive (%s) = USB-station (%s)
|
||||
@@ -387,12 +382,10 @@ The API key works = De API-sleutel werkt
|
||||
Checking the key = Sleutel controleren
|
||||
The server didn't answer. = De server antwoordde niet.
|
||||
Couldn't open this place. = Kan deze locatie niet openen.
|
||||
File = Bestand
|
||||
Folder = Map
|
||||
Bitrate = Bitrate
|
||||
Container = Container
|
||||
Video = Video
|
||||
Track = Spoor
|
||||
White = Wit
|
||||
Yellow = Geel
|
||||
Cyan = Cyaan
|
||||
@@ -512,3 +505,67 @@ Skip = Overslaan
|
||||
Start = Starten
|
||||
Run setup again = Instellen opnieuw doen
|
||||
Language, look and playback, chosen again = Taal, uiterlijk en afspelen opnieuw kiezen
|
||||
Send files from a phone or PC = Bestanden van een telefoon of pc sturen
|
||||
Send files from your phone or PC = Stuur bestanden van je telefoon of pc
|
||||
OpenSubtitles key received from your phone or PC = OpenSubtitles-sleutel van je telefoon of pc ontvangen
|
||||
A file arrived from your phone or PC = Er is een bestand van je telefoon of pc binnengekomen
|
||||
File = Bestand
|
||||
%s file = %s-bestand
|
||||
OpenSubtitles refused this API key = OpenSubtitles heeft deze API-sleutel geweigerd
|
||||
New playlist = Nieuwe afspeellijst
|
||||
Made in VLC = Gemaakt in VLC
|
||||
Where = Locatie
|
||||
1 item = 1 item
|
||||
Removed from %s = Verwijderd uit %s
|
||||
This playlist is empty = Deze afspeellijst is leeg
|
||||
Create = Maken
|
||||
Play all = Alles afspelen
|
||||
Remove = Verwijderen
|
||||
Move = Verplaatsen
|
||||
Add to playlist = Toevoegen aan afspeellijst
|
||||
Rename playlist = Afspeellijst hernoemen
|
||||
Delete playlist = Afspeellijst verwijderen
|
||||
Name the playlist = Geef de afspeellijst een naam
|
||||
%s goes in first = %s gaat er als eerste in
|
||||
Type a name = Typ een naam
|
||||
Made %s = %s gemaakt
|
||||
Added to %s = Toegevoegd aan %s
|
||||
Already in %s = Staat al in %s
|
||||
Save = Opslaan
|
||||
%d playlists = %d afspeellijsten
|
||||
Saved in the media folder's Playlists, as a file VLC on a computer opens too = Opgeslagen in de map Playlists van de mediamap, als bestand dat VLC op een computer ook opent
|
||||
A playlist with this name is already there, or the disk can't be written = Er is al een afspeellijst met deze naam, of de schijf is niet beschrijfbaar
|
||||
Then add videos and songs from anywhere with the Options menu = Voeg daarna overal video's en nummers toe via het menu Opties
|
||||
Open the Options menu on a video or song and choose Add to playlist = Open het menu Opties bij een video of nummer en kies Toevoegen aan afspeellijst
|
||||
stereo = stereo
|
||||
Chapter %d = Hoofdstuk %d
|
||||
Audio %d = Audio %d
|
||||
Fonts: Selawik, Inter, Noto, DejaVu (OFL). TV lists: iptv-org. Radio: radio-browser.info. Subtitles: OpenSubtitles.com. = Lettertypen: Selawik, Inter, Noto, DejaVu (OFL). Zenderlijsten: iptv-org. Radio: radio-browser.info. Ondertitels: OpenSubtitles.com.
|
||||
15 min = 15 min
|
||||
30 min = 30 min
|
||||
45 min = 45 min
|
||||
60 min = 60 min
|
||||
90 min = 90 min
|
||||
Sign in to the share = Aanmelden bij de share
|
||||
%s needs a user name and password. = %s vraagt om een gebruikersnaam en wachtwoord.
|
||||
A Windows PC takes its own account; a NAS, the user you made on it. = Een Windows-pc gebruikt zijn eigen account; een NAS de gebruiker die je erop hebt gemaakt.
|
||||
Track %d = Track %d
|
||||
Track = Track
|
||||
Disc menu = Schijfmenu
|
||||
Pop-up menu = Pop-upmenu
|
||||
Blu-ray region = Blu-ray-regio
|
||||
Region %s = Regio %s
|
||||
Blu-ray region: from the next disc you open = Blu-ray-regio: vanaf de volgende schijf die je opent
|
||||
A: the Americas and East Asia. B: Europe, Africa and Oceania. C: China, Russia and India = A: Amerika en Oost-Azië. B: Europa, Afrika en Oceanië. C: China, Rusland en India
|
||||
Add a subtitle file = Ondertitelbestand toevoegen
|
||||
Pick a subtitle file = Kies een ondertitelbestand
|
||||
Subtitles: %s = Ondertitels: %s
|
||||
Couldn't load that subtitle file = Dat ondertitelbestand kon niet worden geladen
|
||||
That isn't a subtitle file (.srt, .ass, .vtt...) = Dat is geen ondertitelbestand (.srt, .ass, .vtt...)
|
||||
Java Blu-ray discs (BD-J) aren't supported on the PS5 = Java-Blu-rays (BD-J) worden niet ondersteund op de PS5
|
||||
Hardware decoding = Hardwaredecodering
|
||||
The console's video chip. Off: the processor decodes, slower for 4K = De videochip van de console. Uit: de processor decodeert, trager bij 4K
|
||||
Looking for channels and stations… = Zenders en stations zoeken…
|
||||
Hardware decoding: from the next video = Hardwaredecodering: vanaf de volgende video
|
||||
Match frame rate = Beeldfrequentie aanpassen
|
||||
Films play at their own 24, 25 or 50 Hz: smoother pans. Some TVs go black a moment = Films spelen op hun eigen 24, 25 of 50 Hz: vloeiendere pans. Sommige tv's worden even zwart
|
||||
+67
-10
@@ -146,13 +146,11 @@ About VLC = O VLC
|
||||
PS5 port = Port na PS5
|
||||
VideoLAN and the VLC contributors = VideoLAN i współtwórcy VLC
|
||||
Built with = Zbudowano z
|
||||
GPLv2+. An unofficial port, not affiliated with VideoLAN or Sony. = GPLv2+. Nieoficjalny port, niezwiązany z VideoLAN ani Sony.
|
||||
GPL-3.0. An unofficial port, not affiliated with VideoLAN or Sony. = GPL-3.0. Nieoficjalny port, niezwiązany z VideoLAN ani Sony.
|
||||
Resume = Wznów
|
||||
Audio, subtitles and more = Dźwięk, napisy i więcej
|
||||
Phone remote = Pilot w telefonie
|
||||
Settings = Ustawienia
|
||||
Stop playback = Zatrzymaj odtwarzanie
|
||||
Send files from a phone = Wyślij pliki z telefonu
|
||||
Rescan media = Przeskanuj multimedia
|
||||
Options = Opcje
|
||||
Found %zu files = Znalezione pliki: %zu
|
||||
@@ -188,7 +186,7 @@ Writes VLC's warnings and stats to vlc-ps5.log, for bug reports = Zapisuje ostrz
|
||||
What VLC can read on this console = Co VLC może czytać na tej konsoli
|
||||
Starts VLC again: it then sees drives plugged in since (when sandboxed) = Uruchamia VLC ponownie: zobaczy dyski podłączone w międzyczasie (w piaskownicy)
|
||||
Version, credits and licences = Wersja, twórcy i licencje
|
||||
The page that sends files and works as a remote, on your home network = Strona do wysyłania plików i sterowania, w Twojej sieci domowej
|
||||
The page that sends files and takes your OpenSubtitles key, on your home network = Strona do wysyłania plików i podania klucza OpenSubtitles, w Twojej sieci domowej
|
||||
Classic: panels and folders like a desktop player. Modern: black, VLC 4 style. VLC restarts = Klasyczny: panele i foldery jak w odtwarzaczu na komputer. Nowoczesny: czarny, w stylu VLC 4. VLC uruchomi się ponownie
|
||||
Your own free OpenSubtitles API key (and account), here or from the phone page = Twój darmowy klucz API OpenSubtitles (i konto), tutaj lub ze strony na telefonie
|
||||
The language of VLC's menus = Język menu VLC
|
||||
@@ -228,16 +226,13 @@ Back right = Tylny prawy
|
||||
Each speaker plays a tone in turn. If one comes from the wrong place, tell us which. = Każdy głośnik po kolei odtwarza dźwięk. Jeśli któryś dochodzi z niewłaściwego miejsca, daj nam znać który.
|
||||
Stop going round = Zatrzymaj obieg
|
||||
Go round = Rozpocznij obieg
|
||||
Send files from your phone = Wyślij pliki z telefonu
|
||||
Phone access is off. Turn it on in Settings > System. = Dostęp z telefonu jest wyłączony. Włącz go w Ustawienia > System.
|
||||
The PS5 isn't connected to a network. Connect it, then come back. = PS5 nie jest połączona z siecią. Połącz ją i wróć.
|
||||
On a phone or computer on the same Wi-Fi, open this address in the browser: = Na telefonie lub komputerze w tej samej sieci Wi-Fi otwórz ten adres w przeglądarce:
|
||||
Send videos, music and subtitles to the PS5 = Wysyłaj filmy, muzykę i napisy na PS5
|
||||
Use it as a remote while something plays = Używaj jako pilota podczas odtwarzania
|
||||
Add your OpenSubtitles API key = Dodaj swój klucz API OpenSubtitles
|
||||
Receiving %s = Odbieranie: %s
|
||||
Volume %d%% = Głośność %d%%
|
||||
OpenSubtitles key received from your phone = Odebrano klucz OpenSubtitles z telefonu
|
||||
A file arrived from your phone = Z telefonu dotarł plik
|
||||
VLC media folder = Folder multimediów VLC
|
||||
USB drive %d = Dysk USB %d
|
||||
USB drive (%s) = Dysk USB (%s)
|
||||
@@ -387,12 +382,10 @@ The API key works = Klucz API działa
|
||||
Checking the key = Sprawdzanie klucza
|
||||
The server didn't answer. = Serwer nie odpowiedział.
|
||||
Couldn't open this place. = Nie udało się otworzyć tego miejsca.
|
||||
File = Plik
|
||||
Folder = Folder
|
||||
Bitrate = Przepływność
|
||||
Container = Kontener
|
||||
Video = Wideo
|
||||
Track = Ścieżka
|
||||
White = Biały
|
||||
Yellow = Żółty
|
||||
Cyan = Cyjan
|
||||
@@ -512,3 +505,67 @@ Skip = Pomiń
|
||||
Start = Start
|
||||
Run setup again = Uruchom konfigurację ponownie
|
||||
Language, look and playback, chosen again = Język, wygląd i odtwarzanie od nowa
|
||||
Send files from a phone or PC = Wyślij pliki z telefonu lub komputera
|
||||
Send files from your phone or PC = Wyślij pliki z telefonu lub komputera
|
||||
OpenSubtitles key received from your phone or PC = Odebrano klucz OpenSubtitles z telefonu lub komputera
|
||||
A file arrived from your phone or PC = Z telefonu lub komputera dotarł plik
|
||||
File = Plik
|
||||
%s file = Plik %s
|
||||
OpenSubtitles refused this API key = OpenSubtitles odrzucił ten klucz API
|
||||
New playlist = Nowa playlista
|
||||
Made in VLC = Utworzona w VLC
|
||||
Where = Miejsce
|
||||
1 item = 1 element
|
||||
Removed from %s = Usunięto z %s
|
||||
This playlist is empty = Ta playlista jest pusta
|
||||
Create = Utwórz
|
||||
Play all = Odtwórz wszystko
|
||||
Remove = Usuń
|
||||
Move = Przenieś
|
||||
Add to playlist = Dodaj do playlisty
|
||||
Rename playlist = Zmień nazwę playlisty
|
||||
Delete playlist = Usuń playlistę
|
||||
Name the playlist = Nazwij playlistę
|
||||
%s goes in first = %s trafi tam pierwszy
|
||||
Type a name = Wpisz nazwę
|
||||
Made %s = Utworzono %s
|
||||
Added to %s = Dodano do %s
|
||||
Already in %s = Już jest w %s
|
||||
Save = Zapisz
|
||||
%d playlists = Playlisty: %d
|
||||
Saved in the media folder's Playlists, as a file VLC on a computer opens too = Zapisywana w folderze Playlists folderu multimediów, jako plik, który otworzy też VLC na komputerze
|
||||
A playlist with this name is already there, or the disk can't be written = Playlista o tej nazwie już istnieje albo nie można zapisać na dysku
|
||||
Then add videos and songs from anywhere with the Options menu = Potem dodawaj filmy i utwory z dowolnego miejsca przez menu Opcje
|
||||
Open the Options menu on a video or song and choose Add to playlist = Otwórz menu Opcje na filmie lub utworze i wybierz Dodaj do playlisty
|
||||
stereo = stereo
|
||||
Chapter %d = Rozdział %d
|
||||
Audio %d = Dźwięk %d
|
||||
Fonts: Selawik, Inter, Noto, DejaVu (OFL). TV lists: iptv-org. Radio: radio-browser.info. Subtitles: OpenSubtitles.com. = Czcionki: Selawik, Inter, Noto, DejaVu (OFL). Listy TV: iptv-org. Radio: radio-browser.info. Napisy: OpenSubtitles.com.
|
||||
15 min = 15 min
|
||||
30 min = 30 min
|
||||
45 min = 45 min
|
||||
60 min = 60 min
|
||||
90 min = 90 min
|
||||
Sign in to the share = Zaloguj się do udziału
|
||||
%s needs a user name and password. = %s wymaga nazwy użytkownika i hasła.
|
||||
A Windows PC takes its own account; a NAS, the user you made on it. = Komputer z Windows przyjmuje własne konto, a NAS użytkownika, którego na nim utworzono.
|
||||
Track %d = Ścieżka %d
|
||||
Track = Ścieżka
|
||||
Disc menu = Menu płyty
|
||||
Pop-up menu = Menu podręczne
|
||||
Blu-ray region = Region Blu-ray
|
||||
Region %s = Region %s
|
||||
Blu-ray region: from the next disc you open = Region Blu-ray: od następnej otwartej płyty
|
||||
A: the Americas and East Asia. B: Europe, Africa and Oceania. C: China, Russia and India = A: Ameryki i Azja Wschodnia. B: Europa, Afryka i Oceania. C: Chiny, Rosja i Indie
|
||||
Add a subtitle file = Dodaj plik napisów
|
||||
Pick a subtitle file = Wybierz plik napisów
|
||||
Subtitles: %s = Napisy: %s
|
||||
Couldn't load that subtitle file = Nie udało się wczytać tego pliku napisów
|
||||
That isn't a subtitle file (.srt, .ass, .vtt...) = To nie jest plik napisów (.srt, .ass, .vtt...)
|
||||
Java Blu-ray discs (BD-J) aren't supported on the PS5 = Płyty Blu-ray z Javą (BD-J) nie są obsługiwane na PS5
|
||||
Hardware decoding = Dekodowanie sprzętowe
|
||||
The console's video chip. Off: the processor decodes, slower for 4K = Układ wideo konsoli. Wył.: dekoduje procesor, wolniej przy 4K
|
||||
Looking for channels and stations… = Szukanie kanałów i stacji…
|
||||
Hardware decoding: from the next video = Dekodowanie sprzętowe: od następnego filmu
|
||||
Match frame rate = Dopasuj liczbę klatek
|
||||
Films play at their own 24, 25 or 50 Hz: smoother pans. Some TVs go black a moment = Filmy grają we własnych 24, 25 lub 50 Hz: płynniejsze panoramy. Niektóre telewizory na chwilę gasną
|
||||
+67
-10
@@ -146,13 +146,11 @@ About VLC = Sobre o VLC
|
||||
PS5 port = Versão para PS5
|
||||
VideoLAN and the VLC contributors = VideoLAN e os colaboradores do VLC
|
||||
Built with = Feito com
|
||||
GPLv2+. An unofficial port, not affiliated with VideoLAN or Sony. = GPLv2+. Uma versão não oficial, sem vínculo com a VideoLAN ou a Sony.
|
||||
GPL-3.0. An unofficial port, not affiliated with VideoLAN or Sony. = GPL-3.0. Uma versão não oficial, sem vínculo com a VideoLAN ou a Sony.
|
||||
Resume = Continuar
|
||||
Audio, subtitles and more = Áudio, legendas e mais
|
||||
Phone remote = Controle pelo celular
|
||||
Settings = Configurações
|
||||
Stop playback = Parar reprodução
|
||||
Send files from a phone = Enviar arquivos de um celular
|
||||
Rescan media = Procurar mídia de novo
|
||||
Options = Opções
|
||||
Found %zu files = %zu arquivos encontrados
|
||||
@@ -188,7 +186,7 @@ Writes VLC's warnings and stats to vlc-ps5.log, for bug reports = Grava avisos e
|
||||
What VLC can read on this console = O que o VLC pode ler neste console
|
||||
Starts VLC again: it then sees drives plugged in since (when sandboxed) = Reinicia o VLC: ele passa a ver unidades conectadas depois (no modo isolado)
|
||||
Version, credits and licences = Versão, créditos e licenças
|
||||
The page that sends files and works as a remote, on your home network = A página que envia arquivos e funciona como controle, na sua rede de casa
|
||||
The page that sends files and takes your OpenSubtitles key, on your home network = A página que envia arquivos e recebe sua chave do OpenSubtitles, na sua rede doméstica
|
||||
Classic: panels and folders like a desktop player. Modern: black, VLC 4 style. VLC restarts = Clássico: painéis e pastas como um player de computador. Moderno: preto, estilo VLC 4. O VLC reinicia
|
||||
Your own free OpenSubtitles API key (and account), here or from the phone page = Sua própria chave de API gratuita do OpenSubtitles (e conta), aqui ou pela página do celular
|
||||
The language of VLC's menus = O idioma dos menus do VLC
|
||||
@@ -228,16 +226,13 @@ Back right = Traseiro direito
|
||||
Each speaker plays a tone in turn. If one comes from the wrong place, tell us which. = Cada alto-falante toca um tom por vez. Se algum vier do lugar errado, conte-nos qual.
|
||||
Stop going round = Parar a volta
|
||||
Go round = Dar a volta
|
||||
Send files from your phone = Envie arquivos do seu celular
|
||||
Phone access is off. Turn it on in Settings > System. = O acesso pelo celular está desligado. Ligue em Configurações > Sistema.
|
||||
The PS5 isn't connected to a network. Connect it, then come back. = O PS5 não está conectado a uma rede. Conecte e volte aqui.
|
||||
On a phone or computer on the same Wi-Fi, open this address in the browser: = Em um celular ou computador no mesmo Wi-Fi, abra este endereço no navegador:
|
||||
Send videos, music and subtitles to the PS5 = Envie vídeos, músicas e legendas para o PS5
|
||||
Use it as a remote while something plays = Use como controle enquanto algo toca
|
||||
Add your OpenSubtitles API key = Adicione sua chave de API do OpenSubtitles
|
||||
Receiving %s = Recebendo %s
|
||||
Volume %d%% = Volume %d%%
|
||||
OpenSubtitles key received from your phone = Chave do OpenSubtitles recebida do seu celular
|
||||
A file arrived from your phone = Chegou um arquivo do seu celular
|
||||
VLC media folder = Pasta de mídia do VLC
|
||||
USB drive %d = Pendrive %d
|
||||
USB drive (%s) = Pendrive (%s)
|
||||
@@ -387,12 +382,10 @@ The API key works = A chave de API funciona
|
||||
Checking the key = A verificação da chave
|
||||
The server didn't answer. = O servidor não respondeu.
|
||||
Couldn't open this place. = Não foi possível abrir este local.
|
||||
File = Arquivo
|
||||
Folder = Pasta
|
||||
Bitrate = Taxa de bits
|
||||
Container = Contêiner
|
||||
Video = Vídeo
|
||||
Track = Faixa
|
||||
White = Branco
|
||||
Yellow = Amarelo
|
||||
Cyan = Ciano
|
||||
@@ -512,3 +505,67 @@ Skip = Pular
|
||||
Start = Começar
|
||||
Run setup again = Refazer a configuração
|
||||
Language, look and playback, chosen again = Idioma, aparência e reprodução, de novo
|
||||
Send files from a phone or PC = Enviar arquivos de um celular ou PC
|
||||
Send files from your phone or PC = Envie arquivos do seu celular ou PC
|
||||
OpenSubtitles key received from your phone or PC = Chave do OpenSubtitles recebida do seu celular ou PC
|
||||
A file arrived from your phone or PC = Chegou um arquivo do seu celular ou PC
|
||||
File = Arquivo
|
||||
%s file = Arquivo %s
|
||||
OpenSubtitles refused this API key = O OpenSubtitles recusou esta chave de API
|
||||
New playlist = Nova playlist
|
||||
Made in VLC = Criada no VLC
|
||||
Where = Local
|
||||
1 item = 1 item
|
||||
Removed from %s = Removido de %s
|
||||
This playlist is empty = Esta playlist está vazia
|
||||
Create = Criar
|
||||
Play all = Tocar tudo
|
||||
Remove = Remover
|
||||
Move = Mover
|
||||
Add to playlist = Adicionar à playlist
|
||||
Rename playlist = Renomear playlist
|
||||
Delete playlist = Excluir playlist
|
||||
Name the playlist = Dê um nome à playlist
|
||||
%s goes in first = %s entra primeiro
|
||||
Type a name = Digite um nome
|
||||
Made %s = %s criada
|
||||
Added to %s = Adicionado a %s
|
||||
Already in %s = Já está em %s
|
||||
Save = Salvar
|
||||
%d playlists = %d playlists
|
||||
Saved in the media folder's Playlists, as a file VLC on a computer opens too = Salva na pasta Playlists da pasta de mídia, como um arquivo que o VLC no computador também abre
|
||||
A playlist with this name is already there, or the disk can't be written = Já existe uma playlist com este nome, ou não dá para gravar no disco
|
||||
Then add videos and songs from anywhere with the Options menu = Depois adicione vídeos e músicas de qualquer lugar pelo menu Opções
|
||||
Open the Options menu on a video or song and choose Add to playlist = Abra o menu Opções em um vídeo ou música e escolha Adicionar à playlist
|
||||
stereo = estéreo
|
||||
Chapter %d = Capítulo %d
|
||||
Audio %d = Áudio %d
|
||||
Fonts: Selawik, Inter, Noto, DejaVu (OFL). TV lists: iptv-org. Radio: radio-browser.info. Subtitles: OpenSubtitles.com. = Fontes: Selawik, Inter, Noto, DejaVu (OFL). Listas de TV: iptv-org. Rádio: radio-browser.info. Legendas: OpenSubtitles.com.
|
||||
15 min = 15 min
|
||||
30 min = 30 min
|
||||
45 min = 45 min
|
||||
60 min = 60 min
|
||||
90 min = 90 min
|
||||
Sign in to the share = Entrar no compartilhamento
|
||||
%s needs a user name and password. = %s pede um usuário e uma senha.
|
||||
A Windows PC takes its own account; a NAS, the user you made on it. = Um PC com Windows usa a própria conta; um NAS, o usuário que você criou nele.
|
||||
Track %d = Faixa %d
|
||||
Track = Faixa
|
||||
Disc menu = Menu do disco
|
||||
Pop-up menu = Menu pop-up
|
||||
Blu-ray region = Região do Blu-ray
|
||||
Region %s = Região %s
|
||||
Blu-ray region: from the next disc you open = Região do Blu-ray: a partir do próximo disco que você abrir
|
||||
A: the Americas and East Asia. B: Europe, Africa and Oceania. C: China, Russia and India = A: Américas e Leste Asiático. B: Europa, África e Oceania. C: China, Rússia e Índia
|
||||
Add a subtitle file = Adicionar um arquivo de legenda
|
||||
Pick a subtitle file = Escolha um arquivo de legenda
|
||||
Subtitles: %s = Legendas: %s
|
||||
Couldn't load that subtitle file = Não foi possível carregar esse arquivo de legenda
|
||||
That isn't a subtitle file (.srt, .ass, .vtt...) = Isso não é um arquivo de legenda (.srt, .ass, .vtt...)
|
||||
Java Blu-ray discs (BD-J) aren't supported on the PS5 = Blu-rays com Java (BD-J) não são compatíveis com o PS5
|
||||
Hardware decoding = Decodificação por hardware
|
||||
The console's video chip. Off: the processor decodes, slower for 4K = O chip de vídeo do console. Desligado: o processador decodifica, mais lento em 4K
|
||||
Looking for channels and stations… = Procurando canais e estações…
|
||||
Hardware decoding: from the next video = Decodificação por hardware: a partir do próximo vídeo
|
||||
Match frame rate = Igualar taxa de quadros
|
||||
Films play at their own 24, 25 or 50 Hz: smoother pans. Some TVs go black a moment = Filmes rodam nos seus próprios 24, 25 ou 50 Hz: movimentos mais suaves. Algumas TVs ficam pretas por um instante
|
||||
+67
-10
@@ -146,13 +146,11 @@ About VLC = О VLC
|
||||
PS5 port = Порт для PS5
|
||||
VideoLAN and the VLC contributors = VideoLAN и участники проекта VLC
|
||||
Built with = Создано с помощью
|
||||
GPLv2+. An unofficial port, not affiliated with VideoLAN or Sony. = GPLv2+. Неофициальный порт, не связанный с VideoLAN или Sony.
|
||||
GPL-3.0. An unofficial port, not affiliated with VideoLAN or Sony. = GPL-3.0. Неофициальный порт, не связанный с VideoLAN или Sony.
|
||||
Resume = Продолжить
|
||||
Audio, subtitles and more = Звук, субтитры и другое
|
||||
Phone remote = Пульт на телефоне
|
||||
Settings = Настройки
|
||||
Stop playback = Остановить воспроизведение
|
||||
Send files from a phone = Отправить файлы с телефона
|
||||
Rescan media = Пересканировать медиа
|
||||
Options = Параметры
|
||||
Found %zu files = Найдено файлов: %zu
|
||||
@@ -188,7 +186,7 @@ Writes VLC's warnings and stats to vlc-ps5.log, for bug reports = Записыв
|
||||
What VLC can read on this console = Что VLC может читать на этой консоли
|
||||
Starts VLC again: it then sees drives plugged in since (when sandboxed) = Перезапускает VLC: так он увидит подключённые позже диски (в песочнице)
|
||||
Version, credits and licences = Версия, авторы и лицензии
|
||||
The page that sends files and works as a remote, on your home network = Страница для отправки файлов и управления, в вашей домашней сети
|
||||
The page that sends files and takes your OpenSubtitles key, on your home network = Страница для отправки файлов и ввода ключа OpenSubtitles в вашей домашней сети
|
||||
Classic: panels and folders like a desktop player. Modern: black, VLC 4 style. VLC restarts = Классический: панели и папки как в настольном плеере. Современный: чёрный, в стиле VLC 4. VLC перезапустится
|
||||
Your own free OpenSubtitles API key (and account), here or from the phone page = Ваш бесплатный ключ API OpenSubtitles (и аккаунт), здесь или со страницы для телефона
|
||||
The language of VLC's menus = Язык меню VLC
|
||||
@@ -228,16 +226,13 @@ Back right = Задний правый
|
||||
Each speaker plays a tone in turn. If one comes from the wrong place, tell us which. = Каждый динамик по очереди издаёт сигнал. Если звук идёт не оттуда, сообщите нам какой.
|
||||
Stop going round = Остановить обход
|
||||
Go round = Начать обход
|
||||
Send files from your phone = Отправьте файлы с телефона
|
||||
Phone access is off. Turn it on in Settings > System. = Доступ с телефона выключен. Включите его в Настройки > Система.
|
||||
The PS5 isn't connected to a network. Connect it, then come back. = PS5 не подключена к сети. Подключите её и вернитесь.
|
||||
On a phone or computer on the same Wi-Fi, open this address in the browser: = На телефоне или компьютере в той же сети Wi-Fi откройте этот адрес в браузере:
|
||||
Send videos, music and subtitles to the PS5 = Отправляйте на PS5 видео, музыку и субтитры
|
||||
Use it as a remote while something plays = Используйте как пульт во время воспроизведения
|
||||
Add your OpenSubtitles API key = Добавьте свой API-ключ OpenSubtitles
|
||||
Receiving %s = Получение: %s
|
||||
Volume %d%% = Громкость %d%%
|
||||
OpenSubtitles key received from your phone = Ключ OpenSubtitles получен с телефона
|
||||
A file arrived from your phone = С телефона пришёл файл
|
||||
VLC media folder = Медиапапка VLC
|
||||
USB drive %d = USB-накопитель %d
|
||||
USB drive (%s) = USB-накопитель (%s)
|
||||
@@ -387,12 +382,10 @@ The API key works = Ключ API работает
|
||||
Checking the key = Проверка ключа
|
||||
The server didn't answer. = Сервер не ответил.
|
||||
Couldn't open this place. = Не удалось открыть это место.
|
||||
File = Файл
|
||||
Folder = Папка
|
||||
Bitrate = Битрейт
|
||||
Container = Контейнер
|
||||
Video = Видео
|
||||
Track = Дорожка
|
||||
White = Белый
|
||||
Yellow = Жёлтый
|
||||
Cyan = Голубой
|
||||
@@ -512,3 +505,67 @@ Skip = Пропустить
|
||||
Start = Начать
|
||||
Run setup again = Пройти настройку снова
|
||||
Language, look and playback, chosen again = Язык, оформление и воспроизведение заново
|
||||
Send files from a phone or PC = Отправить файлы с телефона или ПК
|
||||
Send files from your phone or PC = Отправьте файлы с телефона или ПК
|
||||
OpenSubtitles key received from your phone or PC = Ключ OpenSubtitles получен с телефона или ПК
|
||||
A file arrived from your phone or PC = С телефона или ПК пришёл файл
|
||||
File = Файл
|
||||
%s file = Файл %s
|
||||
OpenSubtitles refused this API key = OpenSubtitles отклонил этот API-ключ
|
||||
New playlist = Новый плейлист
|
||||
Made in VLC = Создан в VLC
|
||||
Where = Где
|
||||
1 item = 1 элемент
|
||||
Removed from %s = Удалено из %s
|
||||
This playlist is empty = Этот плейлист пуст
|
||||
Create = Создать
|
||||
Play all = Воспроизвести все
|
||||
Remove = Убрать
|
||||
Move = Переместить
|
||||
Add to playlist = Добавить в плейлист
|
||||
Rename playlist = Переименовать плейлист
|
||||
Delete playlist = Удалить плейлист
|
||||
Name the playlist = Назовите плейлист
|
||||
%s goes in first = Первым в него попадёт %s
|
||||
Type a name = Введите название
|
||||
Made %s = Создан %s
|
||||
Added to %s = Добавлено в %s
|
||||
Already in %s = Уже есть в %s
|
||||
Save = Сохранить
|
||||
%d playlists = Плейлистов: %d
|
||||
Saved in the media folder's Playlists, as a file VLC on a computer opens too = Сохраняется в папке Playlists папки медиа, файлом, который открывает и VLC на компьютере
|
||||
A playlist with this name is already there, or the disk can't be written = Плейлист с таким названием уже есть, или на диск нельзя записать
|
||||
Then add videos and songs from anywhere with the Options menu = Потом добавляйте видео и песни откуда угодно через меню «Параметры»
|
||||
Open the Options menu on a video or song and choose Add to playlist = Откройте меню «Параметры» на видео или песне и выберите Добавить в плейлист
|
||||
stereo = стерео
|
||||
Chapter %d = Глава %d
|
||||
Audio %d = Аудио %d
|
||||
Fonts: Selawik, Inter, Noto, DejaVu (OFL). TV lists: iptv-org. Radio: radio-browser.info. Subtitles: OpenSubtitles.com. = Шрифты: Selawik, Inter, Noto, DejaVu (OFL). Списки каналов: iptv-org. Радио: radio-browser.info. Субтитры: OpenSubtitles.com.
|
||||
15 min = 15 мин
|
||||
30 min = 30 мин
|
||||
45 min = 45 мин
|
||||
60 min = 60 мин
|
||||
90 min = 90 мин
|
||||
Sign in to the share = Вход в общую папку
|
||||
%s needs a user name and password. = %s требует имя пользователя и пароль.
|
||||
A Windows PC takes its own account; a NAS, the user you made on it. = Компьютер с Windows принимает свою учётную запись, NAS — пользователя, которого вы на нём создали.
|
||||
Track %d = Дорожка %d
|
||||
Track = Дорожка
|
||||
Disc menu = Меню диска
|
||||
Pop-up menu = Всплывающее меню
|
||||
Blu-ray region = Регион Blu-ray
|
||||
Region %s = Регион %s
|
||||
Blu-ray region: from the next disc you open = Регион Blu-ray: со следующего открытого диска
|
||||
A: the Americas and East Asia. B: Europe, Africa and Oceania. C: China, Russia and India = A: Америка и Восточная Азия. B: Европа, Африка и Океания. C: Китай, Россия и Индия
|
||||
Add a subtitle file = Добавить файл субтитров
|
||||
Pick a subtitle file = Выберите файл субтитров
|
||||
Subtitles: %s = Субтитры: %s
|
||||
Couldn't load that subtitle file = Не удалось загрузить этот файл субтитров
|
||||
That isn't a subtitle file (.srt, .ass, .vtt...) = Это не файл субтитров (.srt, .ass, .vtt...)
|
||||
Java Blu-ray discs (BD-J) aren't supported on the PS5 = Blu-ray с Java (BD-J) не поддерживаются на PS5
|
||||
Hardware decoding = Аппаратное декодирование
|
||||
The console's video chip. Off: the processor decodes, slower for 4K = Видеочип консоли. Выкл.: декодирует процессор, медленнее для 4K
|
||||
Looking for channels and stations… = Поиск каналов и станций…
|
||||
Hardware decoding: from the next video = Аппаратное декодирование: со следующего видео
|
||||
Match frame rate = Подстройка частоты кадров
|
||||
Films play at their own 24, 25 or 50 Hz: smoother pans. Some TVs go black a moment = Фильмы идут со своей частотой 24, 25 или 50 Гц: плавнее панорамы. Некоторые ТВ на миг гаснут
|
||||
+67
-10
@@ -146,13 +146,11 @@ About VLC = VLC hakkında
|
||||
PS5 port = PS5 uyarlaması
|
||||
VideoLAN and the VLC contributors = VideoLAN ve VLC katkıcıları
|
||||
Built with = Kullanılanlar
|
||||
GPLv2+. An unofficial port, not affiliated with VideoLAN or Sony. = GPLv2+. Resmî olmayan bir uyarlama; VideoLAN ya da Sony ile ilgisi yoktur.
|
||||
GPL-3.0. An unofficial port, not affiliated with VideoLAN or Sony. = GPL-3.0. Resmî olmayan bir uyarlama; VideoLAN ya da Sony ile ilgisi yoktur.
|
||||
Resume = Devam et
|
||||
Audio, subtitles and more = Ses, altyazı ve daha fazlası
|
||||
Phone remote = Telefon kumandası
|
||||
Settings = Ayarlar
|
||||
Stop playback = Oynatmayı durdur
|
||||
Send files from a phone = Telefondan dosya gönder
|
||||
Rescan media = Medyayı yeniden tara
|
||||
Options = Seçenekler
|
||||
Found %zu files = %zu dosya bulundu
|
||||
@@ -188,7 +186,7 @@ Writes VLC's warnings and stats to vlc-ps5.log, for bug reports = Hata bildiriml
|
||||
What VLC can read on this console = VLC'nin bu konsolda okuyabildikleri
|
||||
Starts VLC again: it then sees drives plugged in since (when sandboxed) = VLC'yi yeniden başlatır: böylece sonradan takılan sürücüleri görür (korumalı alanda)
|
||||
Version, credits and licences = Sürüm, emeği geçenler ve lisanslar
|
||||
The page that sends files and works as a remote, on your home network = Ev ağınızda dosya gönderen ve kumanda işlevi gören sayfa
|
||||
The page that sends files and takes your OpenSubtitles key, on your home network = Ev ağınızda dosya gönderen ve OpenSubtitles anahtarınızı alan sayfa
|
||||
Classic: panels and folders like a desktop player. Modern: black, VLC 4 style. VLC restarts = Klasik: masaüstü oynatıcı gibi paneller ve klasörler. Modern: siyah, VLC 4 tarzı. VLC yeniden başlar
|
||||
Your own free OpenSubtitles API key (and account), here or from the phone page = Kendi ücretsiz OpenSubtitles API anahtarınız (ve hesabınız), burada ya da telefon sayfasından
|
||||
The language of VLC's menus = VLC menülerinin dili
|
||||
@@ -228,16 +226,13 @@ Back right = Arka sağ
|
||||
Each speaker plays a tone in turn. If one comes from the wrong place, tell us which. = Her hoparlör sırayla bir ses çalar. Biri yanlış yerden geliyorsa hangisi olduğunu bize bildirin.
|
||||
Stop going round = Turu durdur
|
||||
Go round = Tur at
|
||||
Send files from your phone = Telefonunuzdan dosya gönderin
|
||||
Phone access is off. Turn it on in Settings > System. = Telefon erişimi kapalı. Ayarlar > Sistem bölümünden açın.
|
||||
The PS5 isn't connected to a network. Connect it, then come back. = PS5 bir ağa bağlı değil. Bağlayıp geri gelin.
|
||||
On a phone or computer on the same Wi-Fi, open this address in the browser: = Aynı Wi-Fi'deki bir telefon ya da bilgisayarda bu adresi tarayıcıda açın:
|
||||
Send videos, music and subtitles to the PS5 = PS5'e video, müzik ve altyazı gönderin
|
||||
Use it as a remote while something plays = Bir şey oynarken kumanda olarak kullanın
|
||||
Add your OpenSubtitles API key = OpenSubtitles API anahtarınızı ekleyin
|
||||
Receiving %s = %s alınıyor
|
||||
Volume %d%% = Ses %%%d
|
||||
OpenSubtitles key received from your phone = OpenSubtitles anahtarı telefonunuzdan alındı
|
||||
A file arrived from your phone = Telefonunuzdan bir dosya geldi
|
||||
VLC media folder = VLC medya klasörü
|
||||
USB drive %d = USB sürücü %d
|
||||
USB drive (%s) = USB sürücü (%s)
|
||||
@@ -387,12 +382,10 @@ The API key works = API anahtarı çalışıyor
|
||||
Checking the key = Anahtar denetimi
|
||||
The server didn't answer. = Sunucu yanıt vermedi.
|
||||
Couldn't open this place. = Bu konum açılamadı.
|
||||
File = Dosya
|
||||
Folder = Klasör
|
||||
Bitrate = Bit hızı
|
||||
Container = Kapsayıcı
|
||||
Video = Video
|
||||
Track = Parça
|
||||
White = Beyaz
|
||||
Yellow = Sarı
|
||||
Cyan = Camgöbeği
|
||||
@@ -512,3 +505,67 @@ Skip = Atla
|
||||
Start = Başla
|
||||
Run setup again = Kurulumu yeniden başlat
|
||||
Language, look and playback, chosen again = Dil, görünüm ve oynatma yeniden seçilir
|
||||
Send files from a phone or PC = Telefondan veya bilgisayardan dosya gönder
|
||||
Send files from your phone or PC = Telefonunuzdan veya bilgisayarınızdan dosya gönderin
|
||||
OpenSubtitles key received from your phone or PC = OpenSubtitles anahtarı telefonunuzdan veya bilgisayarınızdan alındı
|
||||
A file arrived from your phone or PC = Telefonunuzdan veya bilgisayarınızdan bir dosya geldi
|
||||
File = Dosya
|
||||
%s file = %s dosyası
|
||||
OpenSubtitles refused this API key = OpenSubtitles bu API anahtarını reddetti
|
||||
New playlist = Yeni çalma listesi
|
||||
Made in VLC = VLC'de oluşturuldu
|
||||
Where = Konum
|
||||
1 item = 1 öge
|
||||
Removed from %s = %s listesinden çıkarıldı
|
||||
This playlist is empty = Bu çalma listesi boş
|
||||
Create = Oluştur
|
||||
Play all = Tümünü oynat
|
||||
Remove = Çıkar
|
||||
Move = Taşı
|
||||
Add to playlist = Çalma listesine ekle
|
||||
Rename playlist = Çalma listesini yeniden adlandır
|
||||
Delete playlist = Çalma listesini sil
|
||||
Name the playlist = Çalma listesine ad verin
|
||||
%s goes in first = İlk olarak %s eklenir
|
||||
Type a name = Bir ad yazın
|
||||
Made %s = %s oluşturuldu
|
||||
Added to %s = %s listesine eklendi
|
||||
Already in %s = Zaten %s içinde
|
||||
Save = Kaydet
|
||||
%d playlists = %d çalma listesi
|
||||
Saved in the media folder's Playlists, as a file VLC on a computer opens too = Medya klasörünün Playlists klasörüne, bilgisayardaki VLC'nin de açtığı bir dosya olarak kaydedilir
|
||||
A playlist with this name is already there, or the disk can't be written = Bu adda bir çalma listesi zaten var ya da diske yazılamıyor
|
||||
Then add videos and songs from anywhere with the Options menu = Sonra her yerden Seçenekler menüsüyle video ve şarkı ekleyin
|
||||
Open the Options menu on a video or song and choose Add to playlist = Bir video veya şarkıda Seçenekler menüsünü açıp Çalma listesine ekle'yi seçin
|
||||
stereo = stereo
|
||||
Chapter %d = Bölüm %d
|
||||
Audio %d = Ses %d
|
||||
Fonts: Selawik, Inter, Noto, DejaVu (OFL). TV lists: iptv-org. Radio: radio-browser.info. Subtitles: OpenSubtitles.com. = Yazı tipleri: Selawik, Inter, Noto, DejaVu (OFL). TV listeleri: iptv-org. Radyo: radio-browser.info. Altyazılar: OpenSubtitles.com.
|
||||
15 min = 15 dk
|
||||
30 min = 30 dk
|
||||
45 min = 45 dk
|
||||
60 min = 60 dk
|
||||
90 min = 90 dk
|
||||
Sign in to the share = Paylaşıma giriş yap
|
||||
%s needs a user name and password. = %s bir kullanıcı adı ve parola istiyor.
|
||||
A Windows PC takes its own account; a NAS, the user you made on it. = Windows PC kendi hesabını, NAS ise üzerinde oluşturduğunuz kullanıcıyı kabul eder.
|
||||
Track %d = Parça %d
|
||||
Track = Parça
|
||||
Disc menu = Disk menüsü
|
||||
Pop-up menu = Açılır menü
|
||||
Blu-ray region = Blu-ray bölgesi
|
||||
Region %s = Bölge %s
|
||||
Blu-ray region: from the next disc you open = Blu-ray bölgesi: açacağın bir sonraki diskten itibaren
|
||||
A: the Americas and East Asia. B: Europe, Africa and Oceania. C: China, Russia and India = A: Amerika ve Doğu Asya. B: Avrupa, Afrika ve Okyanusya. C: Çin, Rusya ve Hindistan
|
||||
Add a subtitle file = Altyazı dosyası ekle
|
||||
Pick a subtitle file = Bir altyazı dosyası seç
|
||||
Subtitles: %s = Altyazı: %s
|
||||
Couldn't load that subtitle file = Bu altyazı dosyası yüklenemedi
|
||||
That isn't a subtitle file (.srt, .ass, .vtt...) = Bu bir altyazı dosyası değil (.srt, .ass, .vtt...)
|
||||
Java Blu-ray discs (BD-J) aren't supported on the PS5 = Java Blu-ray diskleri (BD-J) PS5'te desteklenmiyor
|
||||
Hardware decoding = Donanımla kod çözme
|
||||
The console's video chip. Off: the processor decodes, slower for 4K = Konsolun video yongası. Kapalı: işlemci çözer, 4K'da daha yavaş
|
||||
Looking for channels and stations… = Kanallar ve istasyonlar aranıyor…
|
||||
Hardware decoding: from the next video = Donanımla kod çözme: sonraki videodan itibaren
|
||||
Match frame rate = Kare hızını eşle
|
||||
Films play at their own 24, 25 or 50 Hz: smoother pans. Some TVs go black a moment = Filmler kendi 24, 25 veya 50 Hz'lerinde oynar: daha akıcı kaydırmalar. Bazı TV'ler bir an kararır
|
||||
+67
-10
@@ -146,13 +146,11 @@ About VLC = 关于 VLC
|
||||
PS5 port = PS5 移植
|
||||
VideoLAN and the VLC contributors = VideoLAN 和 VLC 贡献者
|
||||
Built with = 使用的组件
|
||||
GPLv2+. An unofficial port, not affiliated with VideoLAN or Sony. = GPLv2+。非官方移植版,与 VideoLAN 和 Sony 无关。
|
||||
GPL-3.0. An unofficial port, not affiliated with VideoLAN or Sony. = GPL-3.0。非官方移植版,与 VideoLAN 和 Sony 无关。
|
||||
Resume = 继续
|
||||
Audio, subtitles and more = 音频、字幕等
|
||||
Phone remote = 手机遥控
|
||||
Settings = 设置
|
||||
Stop playback = 停止播放
|
||||
Send files from a phone = 从手机发送文件
|
||||
Rescan media = 重新扫描媒体
|
||||
Options = 选项
|
||||
Found %zu files = 找到 %zu 个文件
|
||||
@@ -188,7 +186,7 @@ Writes VLC's warnings and stats to vlc-ps5.log, for bug reports = 将 VLC 的警
|
||||
What VLC can read on this console = VLC 在本主机上可读取的内容
|
||||
Starts VLC again: it then sees drives plugged in since (when sandboxed) = 重新启动 VLC:之后能看到期间插入的驱动器(沙盒模式下)
|
||||
Version, credits and licences = 版本、致谢和许可证
|
||||
The page that sends files and works as a remote, on your home network = 在家庭网络中发送文件并充当遥控器的页面
|
||||
The page that sends files and takes your OpenSubtitles key, on your home network = 在家庭网络中发送文件并接收 OpenSubtitles 密钥的页面
|
||||
Classic: panels and folders like a desktop player. Modern: black, VLC 4 style. VLC restarts = 经典:像桌面播放器一样的面板和文件夹。现代:黑色,VLC 4 风格。VLC 将重新启动
|
||||
Your own free OpenSubtitles API key (and account), here or from the phone page = 你自己的免费 OpenSubtitles API 密钥(及账号),在此处或手机页面填写
|
||||
The language of VLC's menus = VLC 菜单的语言
|
||||
@@ -228,16 +226,13 @@ Back right = 后右
|
||||
Each speaker plays a tone in turn. If one comes from the wrong place, tell us which. = 每个扬声器依次发出提示音。如果有声音来自错误的位置,请告诉我们是哪一个。
|
||||
Stop going round = 停止轮询
|
||||
Go round = 开始轮询
|
||||
Send files from your phone = 从你的手机发送文件
|
||||
Phone access is off. Turn it on in Settings > System. = 手机访问已关闭。请在 设置 > 系统 中开启。
|
||||
The PS5 isn't connected to a network. Connect it, then come back. = PS5 未连接网络。连接后再回来。
|
||||
On a phone or computer on the same Wi-Fi, open this address in the browser: = 在同一 Wi-Fi 下的手机或电脑浏览器中打开此地址:
|
||||
Send videos, music and subtitles to the PS5 = 将视频、音乐和字幕发送到 PS5
|
||||
Use it as a remote while something plays = 播放时可当作遥控器使用
|
||||
Add your OpenSubtitles API key = 添加你的 OpenSubtitles API 密钥
|
||||
Receiving %s = 正在接收 %s
|
||||
Volume %d%% = 音量 %d%%
|
||||
OpenSubtitles key received from your phone = 已从手机收到 OpenSubtitles 密钥
|
||||
A file arrived from your phone = 收到来自手机的文件
|
||||
VLC media folder = VLC 媒体文件夹
|
||||
USB drive %d = USB 驱动器 %d
|
||||
USB drive (%s) = USB 驱动器(%s)
|
||||
@@ -387,12 +382,10 @@ The API key works = API 密钥有效
|
||||
Checking the key = 验证密钥
|
||||
The server didn't answer. = 服务器没有响应。
|
||||
Couldn't open this place. = 无法打开此位置。
|
||||
File = 文件
|
||||
Folder = 文件夹
|
||||
Bitrate = 码率
|
||||
Container = 封装格式
|
||||
Video = 视频
|
||||
Track = 轨道
|
||||
White = 白色
|
||||
Yellow = 黄色
|
||||
Cyan = 青色
|
||||
@@ -512,3 +505,67 @@ Skip = 跳过
|
||||
Start = 开始
|
||||
Run setup again = 重新进行设置
|
||||
Language, look and playback, chosen again = 重新选择语言、外观和播放
|
||||
Send files from a phone or PC = 从手机或电脑发送文件
|
||||
Send files from your phone or PC = 从你的手机或电脑发送文件
|
||||
OpenSubtitles key received from your phone or PC = 已从手机或电脑收到 OpenSubtitles 密钥
|
||||
A file arrived from your phone or PC = 收到来自手机或电脑的文件
|
||||
File = 文件
|
||||
%s file = %s 文件
|
||||
OpenSubtitles refused this API key = OpenSubtitles 拒绝了此 API 密钥
|
||||
New playlist = 新建播放列表
|
||||
Made in VLC = 在 VLC 中创建
|
||||
Where = 位置
|
||||
1 item = 1 项
|
||||
Removed from %s = 已从 %s 移除
|
||||
This playlist is empty = 这个播放列表是空的
|
||||
Create = 创建
|
||||
Play all = 全部播放
|
||||
Remove = 移除
|
||||
Move = 移动
|
||||
Add to playlist = 添加到播放列表
|
||||
Rename playlist = 重命名播放列表
|
||||
Delete playlist = 删除播放列表
|
||||
Name the playlist = 给播放列表命名
|
||||
%s goes in first = %s 会最先加入
|
||||
Type a name = 请输入名称
|
||||
Made %s = 已创建 %s
|
||||
Added to %s = 已添加到 %s
|
||||
Already in %s = 已在 %s 中
|
||||
Save = 保存
|
||||
%d playlists = %d 个播放列表
|
||||
Saved in the media folder's Playlists, as a file VLC on a computer opens too = 保存在媒体文件夹的 Playlists 中,电脑上的 VLC 也能打开
|
||||
A playlist with this name is already there, or the disk can't be written = 已有同名播放列表,或磁盘无法写入
|
||||
Then add videos and songs from anywhere with the Options menu = 之后在任何地方用选项菜单添加视频和歌曲
|
||||
Open the Options menu on a video or song and choose Add to playlist = 在视频或歌曲上打开选项菜单,然后选择添加到播放列表
|
||||
stereo = 立体声
|
||||
Chapter %d = 第 %d 章
|
||||
Audio %d = 音轨 %d
|
||||
Fonts: Selawik, Inter, Noto, DejaVu (OFL). TV lists: iptv-org. Radio: radio-browser.info. Subtitles: OpenSubtitles.com. = 字体:Selawik、Inter、Noto、DejaVu (OFL)。电视列表:iptv-org。电台:radio-browser.info。字幕:OpenSubtitles.com。
|
||||
15 min = 15 分钟
|
||||
30 min = 30 分钟
|
||||
45 min = 45 分钟
|
||||
60 min = 60 分钟
|
||||
90 min = 90 分钟
|
||||
Sign in to the share = 登录共享文件夹
|
||||
%s needs a user name and password. = %s 需要用户名和密码。
|
||||
A Windows PC takes its own account; a NAS, the user you made on it. = Windows 电脑用它自己的账户;NAS 用你在上面创建的用户。
|
||||
Track %d = 音轨 %d
|
||||
Track = 音轨
|
||||
Disc menu = 光盘菜单
|
||||
Pop-up menu = 弹出菜单
|
||||
Blu-ray region = 蓝光区域
|
||||
Region %s = 区域 %s
|
||||
Blu-ray region: from the next disc you open = 蓝光区域:从下一张打开的光盘起生效
|
||||
A: the Americas and East Asia. B: Europe, Africa and Oceania. C: China, Russia and India = A:美洲和东亚。B:欧洲、非洲和大洋洲。C:中国、俄罗斯和印度
|
||||
Add a subtitle file = 添加字幕文件
|
||||
Pick a subtitle file = 选择字幕文件
|
||||
Subtitles: %s = 字幕:%s
|
||||
Couldn't load that subtitle file = 无法加载该字幕文件
|
||||
That isn't a subtitle file (.srt, .ass, .vtt...) = 这不是字幕文件(.srt、.ass、.vtt…)
|
||||
Java Blu-ray discs (BD-J) aren't supported on the PS5 = PS5 不支持 Java 蓝光光盘 (BD-J)
|
||||
Hardware decoding = 硬件解码
|
||||
The console's video chip. Off: the processor decodes, slower for 4K = 主机的视频芯片。关闭:由处理器解码,4K 较慢
|
||||
Looking for channels and stations… = 正在查找频道和电台…
|
||||
Hardware decoding: from the next video = 硬件解码:从下一个视频开始
|
||||
Match frame rate = 匹配帧率
|
||||
Films play at their own 24, 25 or 50 Hz: smoother pans. Some TVs go black a moment = 电影以其本身的 24、25 或 50 Hz 播放:平移更流畅。部分电视会黑屏片刻
|
||||
+67
-10
@@ -146,13 +146,11 @@ About VLC = 關於 VLC
|
||||
PS5 port = PS5 移植
|
||||
VideoLAN and the VLC contributors = VideoLAN 與 VLC 貢獻者
|
||||
Built with = 使用的元件
|
||||
GPLv2+. An unofficial port, not affiliated with VideoLAN or Sony. = GPLv2+。非官方移植版,與 VideoLAN 及 Sony 無關。
|
||||
GPL-3.0. An unofficial port, not affiliated with VideoLAN or Sony. = GPL-3.0。非官方移植版,與 VideoLAN 及 Sony 無關。
|
||||
Resume = 繼續
|
||||
Audio, subtitles and more = 音訊、字幕等
|
||||
Phone remote = 手機遙控
|
||||
Settings = 設定
|
||||
Stop playback = 停止播放
|
||||
Send files from a phone = 從手機傳送檔案
|
||||
Rescan media = 重新掃描媒體
|
||||
Options = 選項
|
||||
Found %zu files = 找到 %zu 個檔案
|
||||
@@ -188,7 +186,7 @@ Writes VLC's warnings and stats to vlc-ps5.log, for bug reports = 將 VLC 的警
|
||||
What VLC can read on this console = VLC 在本主機上可讀取的內容
|
||||
Starts VLC again: it then sees drives plugged in since (when sandboxed) = 重新啟動 VLC:之後能看到期間插入的磁碟(沙箱模式下)
|
||||
Version, credits and licences = 版本、致謝與授權
|
||||
The page that sends files and works as a remote, on your home network = 在家用網路中傳送檔案並當作遙控器的頁面
|
||||
The page that sends files and takes your OpenSubtitles key, on your home network = 在家用網路中傳送檔案並接收 OpenSubtitles 金鑰的頁面
|
||||
Classic: panels and folders like a desktop player. Modern: black, VLC 4 style. VLC restarts = 經典:像桌面播放器的面板與資料夾。現代:黑色,VLC 4 風格。VLC 將重新啟動
|
||||
Your own free OpenSubtitles API key (and account), here or from the phone page = 你自己的免費 OpenSubtitles API 金鑰(及帳號),可在此或手機頁面填寫
|
||||
The language of VLC's menus = VLC 選單的語言
|
||||
@@ -228,16 +226,13 @@ Back right = 後右
|
||||
Each speaker plays a tone in turn. If one comes from the wrong place, tell us which. = 每個喇叭依序發出提示音。如果有聲音來自錯誤的位置,請告訴我們是哪一個。
|
||||
Stop going round = 停止輪播
|
||||
Go round = 開始輪播
|
||||
Send files from your phone = 從你的手機傳送檔案
|
||||
Phone access is off. Turn it on in Settings > System. = 手機存取已關閉。請在 設定 > 系統 中開啟。
|
||||
The PS5 isn't connected to a network. Connect it, then come back. = PS5 未連上網路。連線後再回來。
|
||||
On a phone or computer on the same Wi-Fi, open this address in the browser: = 在同一 Wi-Fi 的手機或電腦瀏覽器中開啟此位址:
|
||||
Send videos, music and subtitles to the PS5 = 將影片、音樂與字幕傳送到 PS5
|
||||
Use it as a remote while something plays = 播放時可當作遙控器
|
||||
Add your OpenSubtitles API key = 新增你的 OpenSubtitles API 金鑰
|
||||
Receiving %s = 正在接收 %s
|
||||
Volume %d%% = 音量 %d%%
|
||||
OpenSubtitles key received from your phone = 已從手機收到 OpenSubtitles 金鑰
|
||||
A file arrived from your phone = 收到來自手機的檔案
|
||||
VLC media folder = VLC 媒體資料夾
|
||||
USB drive %d = USB 隨身碟 %d
|
||||
USB drive (%s) = USB 隨身碟(%s)
|
||||
@@ -387,12 +382,10 @@ The API key works = API 金鑰有效
|
||||
Checking the key = 驗證金鑰
|
||||
The server didn't answer. = 伺服器沒有回應。
|
||||
Couldn't open this place. = 無法開啟此位置。
|
||||
File = 檔案
|
||||
Folder = 資料夾
|
||||
Bitrate = 位元率
|
||||
Container = 封裝格式
|
||||
Video = 影片
|
||||
Track = 軌道
|
||||
White = 白色
|
||||
Yellow = 黃色
|
||||
Cyan = 青色
|
||||
@@ -512,3 +505,67 @@ Skip = 略過
|
||||
Start = 開始
|
||||
Run setup again = 重新進行設定
|
||||
Language, look and playback, chosen again = 重新選擇語言、外觀與播放
|
||||
Send files from a phone or PC = 從手機或電腦傳送檔案
|
||||
Send files from your phone or PC = 從你的手機或電腦傳送檔案
|
||||
OpenSubtitles key received from your phone or PC = 已從手機或電腦收到 OpenSubtitles 金鑰
|
||||
A file arrived from your phone or PC = 收到來自手機或電腦的檔案
|
||||
File = 檔案
|
||||
%s file = %s 檔案
|
||||
OpenSubtitles refused this API key = OpenSubtitles 拒絕了此 API 金鑰
|
||||
New playlist = 新增播放清單
|
||||
Made in VLC = 在 VLC 中建立
|
||||
Where = 位置
|
||||
1 item = 1 項
|
||||
Removed from %s = 已從 %s 移除
|
||||
This playlist is empty = 這個播放清單是空的
|
||||
Create = 建立
|
||||
Play all = 全部播放
|
||||
Remove = 移除
|
||||
Move = 移動
|
||||
Add to playlist = 加入播放清單
|
||||
Rename playlist = 重新命名播放清單
|
||||
Delete playlist = 刪除播放清單
|
||||
Name the playlist = 為播放清單命名
|
||||
%s goes in first = %s 會最先加入
|
||||
Type a name = 請輸入名稱
|
||||
Made %s = 已建立 %s
|
||||
Added to %s = 已加入 %s
|
||||
Already in %s = 已在 %s 中
|
||||
Save = 儲存
|
||||
%d playlists = %d 個播放清單
|
||||
Saved in the media folder's Playlists, as a file VLC on a computer opens too = 儲存在媒體資料夾的 Playlists 中,電腦上的 VLC 也能開啟
|
||||
A playlist with this name is already there, or the disk can't be written = 已有同名的播放清單,或磁碟無法寫入
|
||||
Then add videos and songs from anywhere with the Options menu = 之後在任何地方用選項選單加入影片和歌曲
|
||||
Open the Options menu on a video or song and choose Add to playlist = 在影片或歌曲上開啟選項選單,然後選擇加入播放清單
|
||||
stereo = 立體聲
|
||||
Chapter %d = 第 %d 章
|
||||
Audio %d = 音軌 %d
|
||||
Fonts: Selawik, Inter, Noto, DejaVu (OFL). TV lists: iptv-org. Radio: radio-browser.info. Subtitles: OpenSubtitles.com. = 字型:Selawik、Inter、Noto、DejaVu (OFL)。電視清單:iptv-org。電台:radio-browser.info。字幕:OpenSubtitles.com。
|
||||
15 min = 15 分鐘
|
||||
30 min = 30 分鐘
|
||||
45 min = 45 分鐘
|
||||
60 min = 60 分鐘
|
||||
90 min = 90 分鐘
|
||||
Sign in to the share = 登入共用資料夾
|
||||
%s needs a user name and password. = %s 需要使用者名稱和密碼。
|
||||
A Windows PC takes its own account; a NAS, the user you made on it. = Windows 電腦用它自己的帳戶;NAS 用你在上面建立的使用者。
|
||||
Track %d = 音軌 %d
|
||||
Track = 音軌
|
||||
Disc menu = 光碟選單
|
||||
Pop-up menu = 彈出式選單
|
||||
Blu-ray region = 藍光區碼
|
||||
Region %s = 區碼 %s
|
||||
Blu-ray region: from the next disc you open = 藍光區碼:從下一張開啟的光碟起生效
|
||||
A: the Americas and East Asia. B: Europe, Africa and Oceania. C: China, Russia and India = A:美洲與東亞。B:歐洲、非洲與大洋洲。C:中國、俄羅斯與印度
|
||||
Add a subtitle file = 加入字幕檔
|
||||
Pick a subtitle file = 選擇字幕檔
|
||||
Subtitles: %s = 字幕:%s
|
||||
Couldn't load that subtitle file = 無法載入該字幕檔
|
||||
That isn't a subtitle file (.srt, .ass, .vtt...) = 這不是字幕檔(.srt、.ass、.vtt…)
|
||||
Java Blu-ray discs (BD-J) aren't supported on the PS5 = PS5 不支援 Java 藍光光碟 (BD-J)
|
||||
Hardware decoding = 硬體解碼
|
||||
The console's video chip. Off: the processor decodes, slower for 4K = 主機的視訊晶片。關閉:由處理器解碼,4K 較慢
|
||||
Looking for channels and stations… = 正在尋找頻道和電台…
|
||||
Hardware decoding: from the next video = 硬體解碼:從下一個影片開始
|
||||
Match frame rate = 配合影格率
|
||||
Films play at their own 24, 25 or 50 Hz: smoother pans. Some TVs go black a moment = 電影以其原本的 24、25 或 50 Hz 播放:平移更流暢。部分電視會黑屏片刻
|
||||
+17
-5
@@ -1,6 +1,8 @@
|
||||
#!/usr/bin/env bash
|
||||
# Build the VLC-PS5 app for Linux (the test build: offscreen Vulkan, scripted pad).
|
||||
# bash host/build-app.sh -> $VLC_PS5_WORK/out/vlc-ps5-host
|
||||
# VLCPS5_ASAN=1 bash host/build-app.sh -> out/vlc-ps5-host-asan (AddressSanitizer +
|
||||
# UndefinedBehaviorSanitizer on our code, for stress tests)
|
||||
set -euo pipefail
|
||||
here=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)
|
||||
repo=$(dirname "$here")
|
||||
@@ -10,6 +12,13 @@ static=$work/static-host
|
||||
prefix=$work/prefix-host
|
||||
obj=$work/obj-host
|
||||
out=$work/out
|
||||
name=vlc-ps5-host
|
||||
san=()
|
||||
if [[ ${VLCPS5_ASAN:-0} == 1 ]]; then
|
||||
obj=$work/obj-host-asan
|
||||
name=vlc-ps5-host-asan
|
||||
san=(-fsanitize=address,undefined -fno-omit-frame-pointer -fno-sanitize-recover=undefined)
|
||||
fi
|
||||
mkdir -p "$obj" "$out"
|
||||
|
||||
bash "$repo/ps5/compile-shaders.sh"
|
||||
@@ -18,14 +27,17 @@ TARGET=host bash "$repo/ps5/gen-static-modules.sh" "$static" >/dev/null
|
||||
inc=(-I"$repo/src" -I"$repo/third_party/imgui" -I"$repo/third_party/volk" -I"$repo/third_party/stb"
|
||||
-I"$vk/.deps/native/radv-release/include" -I"$work/src/vlc-3.0.24/include" -I"$prefix/include")
|
||||
defs=(-DVK_NO_PROTOTYPES -DIMGUI_IMPL_VULKAN_USE_VOLK -DVLCPS5_HOST)
|
||||
cflags=(-O2 -g -Wall -Wno-unused-function "${defs[@]}" "${inc[@]}")
|
||||
cflags=(-O2 -g -Wall -Wno-unused-function "${san[@]}" "${defs[@]}" "${inc[@]}")
|
||||
# the newest of our headers: a file is built again when one changed (a struct
|
||||
# that grew, a default argument) not only when the file itself did
|
||||
newest_h=$(ls -t "$repo"/src/*.h "$repo"/src/gen/*.h | head -1)
|
||||
|
||||
objs=()
|
||||
compile() { # source compiler [flags...]
|
||||
local src=$1 cc=$2
|
||||
shift 2
|
||||
local o=$obj/$(basename "${src%.*}").o
|
||||
if [[ ! -f $o || $src -nt $o || $repo/src/gen/video_frag.h -nt $o ]]; then
|
||||
if [[ ! -f $o || $src -nt $o || $repo/src/gen/video_frag.h -nt $o || $newest_h -nt $o ]]; then
|
||||
"$cc" "${cflags[@]}" "$@" -c "$src" -o "$o"
|
||||
fi
|
||||
objs+=("$o")
|
||||
@@ -36,7 +48,7 @@ done
|
||||
compile "$repo/third_party/imgui/backends/imgui_impl_vulkan.cpp" g++ -std=c++17
|
||||
compile "$repo/third_party/volk/volk.c" gcc -std=c11
|
||||
compile "$repo/src/platform_host.c" gcc -std=gnu11
|
||||
for f in gfx image prefs player library network osub lang web ui main; do
|
||||
for f in gfx image prefs player subconv library network osub lang web ui main; do
|
||||
compile "$repo/src/$f.cc" g++ -std=c++17 -Wno-missing-field-initializers
|
||||
done
|
||||
gcc -O2 -c "$static/static_modules.c" -o "$obj/static_modules.o"
|
||||
@@ -55,5 +67,5 @@ if [[ ${VLCPS5_OWN_IO:-0} == 1 ]]; then
|
||||
objs+=("$obj/libc_missing.o")
|
||||
io_flags=(-Wl,--defsym=readv=xemu_ps5_readv -Wl,--defsym=writev=xemu_ps5_writev)
|
||||
fi
|
||||
g++ -o "$out/vlc-ps5-host" "${objs[@]}" @"$static/link.rsp" -lpthread -ldl "${io_flags[@]}"
|
||||
echo "built $out/vlc-ps5-host"
|
||||
g++ "${san[@]}" -o "$out/$name" "${objs[@]}" @"$static/link.rsp" "$prefix/lib/libiconv.a" -lpthread -ldl "${io_flags[@]}"
|
||||
echo "built $out/$name"
|
||||
@@ -0,0 +1,17 @@
|
||||
diff -ru a/modules/access/dvdnav.c b/modules/access/dvdnav.c
|
||||
--- a/modules/access/dvdnav.c
|
||||
+++ b/modules/access/dvdnav.c
|
||||
@@ -89,6 +89,13 @@
|
||||
static int AccessDemuxOpen ( vlc_object_t * );
|
||||
static void Close( vlc_object_t * );
|
||||
|
||||
+/* VLC-PS5: configure looks for dvdnav_stream_cb with the plain preprocessor,
|
||||
+ * without the cross prefix's include path, so it never finds it. libdvdnav
|
||||
+ * 6.1 has it: DVD ISOs on a share or a link need this demux. */
|
||||
+#ifndef HAVE_STREAM_CB_IN_DVDNAV_H
|
||||
+# define HAVE_STREAM_CB_IN_DVDNAV_H 1
|
||||
+#endif
|
||||
+
|
||||
#if DVDREAD_VERSION >= 50300 && defined( HAVE_STREAM_CB_IN_DVDNAV_H )
|
||||
#define HAVE_DVDNAV_DEMUX
|
||||
static int DemuxOpen ( vlc_object_t * );
|
||||
@@ -0,0 +1,35 @@
|
||||
--- a/modules/access/bluray.c 2026-10-09 16:18:09.281680898 +0000
|
||||
+++ b/modules/access/bluray.c 2026-10-09 16:18:09.281979298 +0000
|
||||
@@ -807,6 +807,11 @@
|
||||
var_SetBool( p_demux, "ts-pcr-offsetfix", false );
|
||||
|
||||
var_AddCallback( p_demux->p_input, "intf-event", onIntfEvent, p_demux );
|
||||
+ /* VLC-PS5: whether a menu (HDMV IG or pop-up) is on screen, and whether
|
||||
+ * the film has a pop-up menu, for the app: the d-pad presses its buttons
|
||||
+ * only then (a menu can show in any title, not only "Top Menu"). */
|
||||
+ var_Create( p_demux->p_input, "bluray-menu-open", VLC_VAR_BOOL );
|
||||
+ var_Create( p_demux->p_input, "bluray-popup", VLC_VAR_BOOL );
|
||||
|
||||
/* Open BluRay */
|
||||
#ifdef BLURAY_DEMUX
|
||||
@@ -1012,6 +1017,8 @@
|
||||
demux_sys_t *p_sys = p_demux->p_sys;
|
||||
|
||||
var_DelCallback( p_demux->p_input, "intf-event", onIntfEvent, p_demux );
|
||||
+ var_Destroy( p_demux->p_input, "bluray-menu-open" );
|
||||
+ var_Destroy( p_demux->p_input, "bluray-popup" );
|
||||
|
||||
setTitleInfo(p_sys, NULL);
|
||||
|
||||
@@ -2809,9 +2816,11 @@
|
||||
#endif
|
||||
case BD_EVENT_MENU:
|
||||
p_sys->b_menu_open = e->param;
|
||||
+ var_SetBool( p_demux->p_input, "bluray-menu-open", e->param != 0 );
|
||||
break;
|
||||
case BD_EVENT_POPUP:
|
||||
p_sys->b_popup_available = e->param;
|
||||
+ var_SetBool( p_demux->p_input, "bluray-popup", e->param != 0 );
|
||||
/* TODO: show / hide pop-up menu button in gui ? */
|
||||
break;
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
--- a/modules/text_renderer/freetype/freetype.c 2026-10-09 16:41:20.491780240 +0000
|
||||
+++ b/modules/text_renderer/freetype/freetype.c 2026-10-09 16:41:20.492100340 +0000
|
||||
@@ -1081,6 +1081,33 @@
|
||||
|
||||
return psz_ucs4;
|
||||
}
|
||||
+#elif !defined( HAVE_ICONV )
|
||||
+/* VLC-PS5: no iconv on the console (ToCharset gave nothing back, so plain-text
|
||||
+ * subtitles drew nothing): the UTF-8 is read here, to native-endian UCS-4 as
|
||||
+ * FREETYPE_TO_UCS asks; a bad byte becomes U+FFFD. */
|
||||
+static void *ToUCS4( const char *in, size_t *outsize )
|
||||
+{
|
||||
+ size_t i_len = strlen( in );
|
||||
+ uint32_t *p_out = vlc_alloc( i_len + 1, sizeof( *p_out ) );
|
||||
+ if( unlikely( !p_out ) )
|
||||
+ return NULL;
|
||||
+ size_t i = 0;
|
||||
+ while( *in )
|
||||
+ {
|
||||
+ uint32_t cp;
|
||||
+ size_t i_bytes = vlc_towc( in, &cp );
|
||||
+ if( i_bytes == 0 || i_bytes == (size_t)-1 )
|
||||
+ {
|
||||
+ cp = 0xFFFD;
|
||||
+ i_bytes = 1;
|
||||
+ }
|
||||
+ p_out[i++] = cp;
|
||||
+ in += i_bytes;
|
||||
+ }
|
||||
+ p_out[i] = 0;
|
||||
+ *outsize = i * sizeof( *p_out );
|
||||
+ return p_out;
|
||||
+}
|
||||
#else
|
||||
# define ToUCS4( in, outsize ) ToCharset( FREETYPE_TO_UCS, ( in ), ( outsize ))
|
||||
#endif
|
||||
@@ -0,0 +1,23 @@
|
||||
--- a/modules/demux/adaptive/http/HTTPConnection.cpp 2026-10-10 04:56:06.924021837 +0000
|
||||
+++ b/modules/demux/adaptive/http/HTTPConnection.cpp 2026-10-10 04:56:06.924582937 +0000
|
||||
@@ -195,14 +195,18 @@
|
||||
int create(const char *uri,const std::string &ua,
|
||||
const std::string &ref, const BytesRange &range)
|
||||
{
|
||||
- struct restuple *tpl = new struct restuple;
|
||||
+ /* VLC-PS5: malloc, as vlc_http_res_destroy() frees it with
|
||||
+ * free(); `new` here was a new/free mismatch (ASan) */
|
||||
+ struct restuple *tpl = (struct restuple *) malloc(sizeof(*tpl));
|
||||
+ if (tpl == nullptr)
|
||||
+ return -1;
|
||||
tpl->source = this;
|
||||
this->range = range;
|
||||
if (vlc_http_res_init(&tpl->resource, &this->callbacks, http_mgr, uri,
|
||||
ua.empty() ? nullptr : ua.c_str(),
|
||||
ref.empty() ? nullptr : ref.c_str()))
|
||||
{
|
||||
- delete tpl;
|
||||
+ free(tpl);
|
||||
return -1;
|
||||
}
|
||||
http_res = &tpl->resource;
|
||||
@@ -0,0 +1,35 @@
|
||||
--- a/modules/codec/avcodec/audio.c
|
||||
+++ b/modules/codec/avcodec/audio.c
|
||||
@@ -37,6 +37,7 @@
|
||||
#include <vlc_avcodec.h>
|
||||
|
||||
#include "avcodec.h"
|
||||
+#include "../../demux/xiph.h"
|
||||
|
||||
#include <libavcodec/avcodec.h>
|
||||
#include <libavutil/mem.h>
|
||||
@@ -103,6 +104,24 @@
|
||||
i_size = 0;
|
||||
}
|
||||
|
||||
+ /* VLC-PS5: VLC's demuxers hand Opus over as packed Xiph headers
|
||||
+ * (OpusHead, OpusTags) for its own opus module; FFmpeg's decoder
|
||||
+ * wants the OpusHead alone, else it reads no channels and fails */
|
||||
+ if( p_dec->fmt_in.i_codec == VLC_CODEC_OPUS &&
|
||||
+ ( i_size < 8 || memcmp( p_src, "OpusHead", 8 ) ) )
|
||||
+ {
|
||||
+ unsigned sizes[XIPH_MAX_HEADER_COUNT];
|
||||
+ const void *headers[XIPH_MAX_HEADER_COUNT];
|
||||
+ unsigned count;
|
||||
+ if( !xiph_SplitHeaders( sizes, headers, &count, i_size, p_src ) &&
|
||||
+ count > 0 && sizes[0] >= 19 &&
|
||||
+ !memcmp( headers[0], "OpusHead", 8 ) )
|
||||
+ {
|
||||
+ i_offset = (const uint8_t *)headers[0] - p_src;
|
||||
+ i_size = sizes[0];
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
if( i_size > 0 )
|
||||
{
|
||||
p_context->extradata =
|
||||
@@ -0,0 +1,16 @@
|
||||
--- a/modules/video_output/vmem.c
|
||||
+++ b/modules/video_output/vmem.c
|
||||
@@ -139,6 +139,13 @@
|
||||
video_format_t fmt;
|
||||
video_format_ApplyRotation(&fmt, &vd->fmt);
|
||||
|
||||
+ /* VLC-PS5: the picture's colours (HDR transfer, primaries, matrix,
|
||||
+ * light levels), which the setup callback doesn't carry */
|
||||
+ void (*colour)(void *, const video_format_t *) =
|
||||
+ var_InheritAddress(vd, "vmem-colour");
|
||||
+ if (colour != NULL)
|
||||
+ colour(sys->opaque, &fmt);
|
||||
+
|
||||
if (setup != NULL) {
|
||||
char chroma[5];
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
--- a/src/misc/picture.c
|
||||
+++ b/src/misc/picture.c
|
||||
@@ -62,9 +62,17 @@
|
||||
/**
|
||||
* Destroys a picture allocated with picture_NewFromFormat().
|
||||
*/
|
||||
+/* VLC-PS5: a 4K picture is 25 MiB and a video keeps 20 to 30 of them,
|
||||
+ * more than the console's heap holds; the title puts big ones in its
|
||||
+ * direct memory. Weak: without them, the heap as before. */
|
||||
+extern void *vlc_ps5_big_alloc( size_t ) __attribute__((weak));
|
||||
+extern int vlc_ps5_big_free( void * ) __attribute__((weak));
|
||||
+#define VLC_PS5_BIG_PICTURE (4 << 20)
|
||||
+
|
||||
static void picture_Destroy( picture_t *p_picture )
|
||||
{
|
||||
- aligned_free( p_picture->p[0].p_pixels );
|
||||
+ if( vlc_ps5_big_free == NULL || !vlc_ps5_big_free( p_picture->p[0].p_pixels ) )
|
||||
+ aligned_free( p_picture->p[0].p_pixels );
|
||||
free( p_picture );
|
||||
}
|
||||
|
||||
@@ -274,7 +282,11 @@
|
||||
goto error;
|
||||
|
||||
pic_size = (pic_size + 63) & ~63; /* must be a multiple of 64 */
|
||||
- uint8_t *buf = aligned_alloc(64, pic_size);
|
||||
+ uint8_t *buf = NULL;
|
||||
+ if (vlc_ps5_big_alloc != NULL && pic_size >= VLC_PS5_BIG_PICTURE)
|
||||
+ buf = vlc_ps5_big_alloc(pic_size);
|
||||
+ if (buf == NULL)
|
||||
+ buf = aligned_alloc(64, pic_size);
|
||||
if (buf == NULL)
|
||||
goto error;
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
--- a/modules/video_output/vmem.c
|
||||
+++ b/modules/video_output/vmem.c
|
||||
@@ -249,6 +249,10 @@
|
||||
return sys->pool;
|
||||
}
|
||||
|
||||
+/* VLC-PS5: the app's picture copy, when it has one */
|
||||
+extern void vlc_ps5_copy_plane(uint8_t *, size_t, const uint8_t *, size_t, size_t,
|
||||
+ unsigned) __attribute__((weak));
|
||||
+
|
||||
static void Prepare(vout_display_t *vd, picture_t *pic, subpicture_t *subpic)
|
||||
{
|
||||
vout_display_sys_t *sys = vd->sys;
|
||||
@@ -265,7 +269,19 @@
|
||||
|
||||
picture_t *locked = picture_NewFromResource(&vd->fmt, &rsc);
|
||||
if (likely(locked != NULL)) {
|
||||
- picture_CopyPixels(locked, pic);
|
||||
+ if (vlc_ps5_copy_plane != NULL) {
|
||||
+ /* VLC-PS5: split over a few threads (a 4K picture is 25 MiB) */
|
||||
+ for (int i = 0; i < locked->i_planes && i < pic->i_planes; i++) {
|
||||
+ const plane_t *d = &locked->p[i], *s = &pic->p[i];
|
||||
+ int lines = __MIN(d->i_visible_lines, s->i_visible_lines);
|
||||
+ int bytes = __MIN(d->i_visible_pitch, s->i_visible_pitch);
|
||||
+ if (lines > 0 && bytes > 0)
|
||||
+ vlc_ps5_copy_plane(d->p_pixels, d->i_pitch, s->p_pixels, s->i_pitch,
|
||||
+ bytes, lines);
|
||||
+ }
|
||||
+ } else {
|
||||
+ picture_CopyPixels(locked, pic);
|
||||
+ }
|
||||
picture_Release(locked);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
--- a/modules/access/smb2.c
|
||||
+++ b/modules/access/smb2.c
|
||||
@@ -123,6 +123,7 @@
|
||||
struct srvsvc_netshareenumall_rep *share_enum;
|
||||
#endif
|
||||
uint64_t smb2_size;
|
||||
+ uint64_t pos; /* VLC-PS5: where the next read starts */
|
||||
vlc_url_t encoded_url;
|
||||
bool eof;
|
||||
bool smb2_connected;
|
||||
@@ -320,8 +321,20 @@
|
||||
/* Limit the read size since smb2_read_async() will complete only after
|
||||
* reading the whole requested data and not when whatever data is available
|
||||
* (high read size means a faster I/O but a higher latency). */
|
||||
- if (len > 262144)
|
||||
- len = 262144;
|
||||
+ /* VLC-PS5: 2 MiB, fewer requests each waiting a network round trip
|
||||
+ * (a 4K film needs 9 MB/s; 256 KiB at a time over Wi-Fi didn't make it),
|
||||
+ * and never past the end of the file: a read crossing it failed, and with
|
||||
+ * it the last metadata of a 13 GB Blu-ray image (console run 14) */
|
||||
+ if (len > 2097152)
|
||||
+ len = 2097152;
|
||||
+ if (sys->smb2_size > 0) {
|
||||
+ if (sys->pos >= sys->smb2_size) {
|
||||
+ sys->eof = true;
|
||||
+ return 0;
|
||||
+ }
|
||||
+ if (len > sys->smb2_size - sys->pos)
|
||||
+ len = sys->smb2_size - sys->pos;
|
||||
+ }
|
||||
|
||||
struct vlc_smb2_op op = VLC_SMB2_OP(access, &sys->smb2);
|
||||
op.res.read.len = 0;
|
||||
@@ -339,6 +352,7 @@
|
||||
|
||||
if (op.res.read.len == 0)
|
||||
sys->eof = true;
|
||||
+ sys->pos += op.res.read.len;
|
||||
|
||||
return op.res.read.len;
|
||||
}
|
||||
@@ -366,6 +380,7 @@
|
||||
VLC_SMB2_SET_ERROR(&op, "smb2_lseek", err);
|
||||
return err;
|
||||
}
|
||||
+ sys->pos = i_pos;
|
||||
sys->eof = false;
|
||||
|
||||
return VLC_SUCCESS;
|
||||
@@ -0,0 +1,38 @@
|
||||
--- a/modules/video_output/vmem.c
|
||||
+++ b/modules/video_output/vmem.c
|
||||
@@ -145,6 +145,8 @@
|
||||
var_InheritAddress(vd, "vmem-colour");
|
||||
if (colour != NULL)
|
||||
colour(sys->opaque, &fmt);
|
||||
+ /* VLC-PS5: the decoder's own format, for its visible part below */
|
||||
+ const video_format_t source = fmt;
|
||||
|
||||
if (setup != NULL) {
|
||||
char chroma[5];
|
||||
@@ -178,9 +180,23 @@
|
||||
}
|
||||
sys->cleanup = NULL;
|
||||
}
|
||||
- fmt.i_x_offset = fmt.i_y_offset = 0;
|
||||
- fmt.i_visible_width = fmt.i_width;
|
||||
- fmt.i_visible_height = fmt.i_height;
|
||||
+ /* VLC-PS5: a buffer at the decoder's own size keeps the decoder's
|
||||
+ * visible part (1280x720 in 1280x736; 3840x2160 in 3840x2176): called
|
||||
+ * all visible, it made VLC scale every picture on the CPU to fill it
|
||||
+ * (swscale, a whole 4K picture per frame in software decoding). The
|
||||
+ * app crops it when drawing. */
|
||||
+ if (fmt.i_width == source.i_width && fmt.i_height == source.i_height &&
|
||||
+ source.i_x_offset == 0 && source.i_y_offset == 0 &&
|
||||
+ source.i_visible_width > 0 && source.i_visible_height > 0 &&
|
||||
+ source.i_visible_width <= fmt.i_width && source.i_visible_height <= fmt.i_height) {
|
||||
+ fmt.i_x_offset = fmt.i_y_offset = 0;
|
||||
+ fmt.i_visible_width = source.i_visible_width;
|
||||
+ fmt.i_visible_height = source.i_visible_height;
|
||||
+ } else {
|
||||
+ fmt.i_x_offset = fmt.i_y_offset = 0;
|
||||
+ fmt.i_visible_width = fmt.i_width;
|
||||
+ fmt.i_visible_height = fmt.i_height;
|
||||
+ }
|
||||
|
||||
if (!fmt.i_chroma) {
|
||||
msg_Err(vd, "vmem-chroma should be 4 characters long");
|
||||
@@ -0,0 +1,41 @@
|
||||
--- a/modules/codec/avcodec/video.c
|
||||
+++ b/modules/codec/avcodec/video.c
|
||||
@@ -84,6 +84,9 @@
|
||||
/* Hack to force display of still pictures */
|
||||
bool b_first_frame;
|
||||
|
||||
+ /* VLC-PS5: pictures refused in a row (see DecodeBlock) */
|
||||
+ int ps5_refused;
|
||||
+
|
||||
bool b_draining;
|
||||
|
||||
/* */
|
||||
@@ -1244,6 +1247,19 @@
|
||||
}
|
||||
|
||||
ret = avcodec_send_packet(p_context, pkt);
|
||||
+ if( ret == AVERROR(ENOMEM) && p_sys->ps5_refused < 200 )
|
||||
+ {
|
||||
+ /* VLC-PS5: no picture for a moment (the pictures are cancelled
|
||||
+ * at a live stream's break, while the decoder's threads still
|
||||
+ * ask for one): that packet is lost, and the video goes on
|
||||
+ * from the next keyframe instead of ending (BBC America's
|
||||
+ * picture stopped for good at a segment break, 2026-10-13) */
|
||||
+ if (p_sys->ps5_refused++ == 0)
|
||||
+ msg_Warn(p_dec, "avcodec_send_packet: no picture for now, going on from the next keyframe");
|
||||
+ avcodec_flush_buffers(p_context);
|
||||
+ av_packet_free( &pkt );
|
||||
+ break;
|
||||
+ }
|
||||
if( ret != 0 && ret != AVERROR(EAGAIN) )
|
||||
{
|
||||
if (ret == AVERROR(ENOMEM) || ret == AVERROR(EINVAL))
|
||||
@@ -1283,6 +1299,8 @@
|
||||
break;
|
||||
}
|
||||
bool not_received_frame = ret;
|
||||
+ if (!not_received_frame)
|
||||
+ p_sys->ps5_refused = 0;
|
||||
|
||||
wait_mt( p_sys );
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
--- a/modules/demux/adaptive/PlaylistManager.cpp
|
||||
+++ b/modules/demux/adaptive/PlaylistManager.cpp
|
||||
@@ -685,8 +685,14 @@
|
||||
}
|
||||
|
||||
case DEMUX_GET_PTS_DELAY:
|
||||
- *va_arg (args, int64_t *) = 1000 * INT64_C(1000);
|
||||
+ {
|
||||
+ /* VLC-PS5: the player's network caching, not always 1 s: a
|
||||
+ * channel whose server sends barely in real time stalled and
|
||||
+ * rebuffered each time (BBC America, 2026-10-18) */
|
||||
+ int64_t ms = var_InheritInteger(p_demux, "network-caching");
|
||||
+ *va_arg (args, int64_t *) = (ms > 1000 ? ms : 1000) * INT64_C(1000);
|
||||
break;
|
||||
+ }
|
||||
|
||||
default:
|
||||
return VLC_EGENERIC;
|
||||
@@ -0,0 +1,58 @@
|
||||
--- a/modules/demux/adaptive/http/HTTPConnection.cpp
|
||||
+++ b/modules/demux/adaptive/http/HTTPConnection.cpp
|
||||
@@ -42,6 +42,19 @@
|
||||
|
||||
using namespace adaptive::http;
|
||||
|
||||
+/* VLC-PS5: the player stopped this video (src/player.cc). Without this,
|
||||
+ * after a stop the next segment was still fetched, by VLC's own http once
|
||||
+ * the console's refused it, and leaving a slow channel took 10 s; the next
|
||||
+ * video waited for it (2026-10-18). */
|
||||
+extern "C" int vlc_ps5_stream_cancelled(long) __attribute__((weak));
|
||||
+static bool ps5_cancelled(vlc_object_t *obj)
|
||||
+{
|
||||
+ if (vlc_ps5_stream_cancelled == nullptr)
|
||||
+ return false;
|
||||
+ long serial = (long)var_InheritInteger(obj, "ps5http-serial");
|
||||
+ return serial > 0 && vlc_ps5_stream_cancelled(serial);
|
||||
+}
|
||||
+
|
||||
AbstractConnection::AbstractConnection(vlc_object_t *p_object_)
|
||||
{
|
||||
p_object = p_object_;
|
||||
@@ -295,7 +308,7 @@
|
||||
RequestStatus LibVLCHTTPConnection::request(const std::string &path,
|
||||
const BytesRange &range)
|
||||
{
|
||||
- if(source->http_mgr == nullptr)
|
||||
+ if(source->http_mgr == nullptr || ps5_cancelled(p_object))
|
||||
return RequestStatus::GenericError;
|
||||
|
||||
reset();
|
||||
@@ -414,6 +427,8 @@
|
||||
|
||||
ssize_t LibVLCHTTPConnection::read(void *p_buffer, size_t len)
|
||||
{
|
||||
+ if (ps5_cancelled(p_object))
|
||||
+ return 0;
|
||||
ssize_t read = vlc_stream_Read(stream, p_buffer, len);
|
||||
bytesRead = source->totalRead;
|
||||
return read;
|
||||
@@ -462,6 +477,8 @@
|
||||
RequestStatus StreamUrlConnection::request(const std::string &path,
|
||||
const BytesRange &range)
|
||||
{
|
||||
+ if (ps5_cancelled(p_object))
|
||||
+ return RequestStatus::GenericError;
|
||||
reset();
|
||||
|
||||
/* Set new path for this query */
|
||||
@@ -509,6 +526,8 @@
|
||||
{
|
||||
if( !p_streamurl )
|
||||
return VLC_EGENERIC;
|
||||
+ if (ps5_cancelled(p_object))
|
||||
+ return 0;
|
||||
|
||||
if(len == 0)
|
||||
return VLC_SUCCESS;
|
||||
@@ -0,0 +1,16 @@
|
||||
--- a/src/input/clock.c
|
||||
+++ b/src/input/clock.c
|
||||
@@ -80,7 +80,12 @@
|
||||
*****************************************************************************/
|
||||
|
||||
/* Maximum gap allowed between two CRs. */
|
||||
-#define CR_MAX_GAP (60 * CLOCK_FREQ)
|
||||
+/* VLC-PS5: 10 s, not 60. Between two clock references of one stream
|
||||
+ * (sent every 100 ms or so) a jump over 10 s is a new start; at 60 s a free
|
||||
+ * TV channel's ad break that moved its times by 35 s was taken as playing
|
||||
+ * on, every picture and sound counted 35 s late and thrown away, and the
|
||||
+ * picture froze (a Pluto channel, 2026-10-18). */
|
||||
+#define CR_MAX_GAP (10 * CLOCK_FREQ)
|
||||
|
||||
/* Latency introduced on DVDs with CR == 0 on chapter change - this is from
|
||||
* my dice --Meuuh */
|
||||
@@ -0,0 +1,15 @@
|
||||
--- a/modules/demux/adaptive/logic/BufferingLogic.cpp
|
||||
+++ b/modules/demux/adaptive/logic/BufferingLogic.cpp
|
||||
@@ -38,7 +38,11 @@
|
||||
using namespace adaptive::logic;
|
||||
|
||||
const vlc_tick_t AbstractBufferingLogic::BUFFERING_LOWEST_LIMIT = CLOCK_FREQ * 2;
|
||||
-const vlc_tick_t AbstractBufferingLogic::DEFAULT_MIN_BUFFERING = CLOCK_FREQ * 6;
|
||||
+/* VLC-PS5: 3 s before a live channel starts, not 6: on the console's Wi-Fi
|
||||
+ * (about 700 KiB/s to far servers) 6 s of an 8 Mbit/s channel took 4-5 s to
|
||||
+ * come in, and channels were slow to show (2026-10-18). It still fills up
|
||||
+ * to its live delay while it plays. */
|
||||
+const vlc_tick_t AbstractBufferingLogic::DEFAULT_MIN_BUFFERING = CLOCK_FREQ * 3;
|
||||
const vlc_tick_t AbstractBufferingLogic::DEFAULT_MAX_BUFFERING = CLOCK_FREQ * 30;
|
||||
const vlc_tick_t AbstractBufferingLogic::DEFAULT_LIVE_BUFFERING = CLOCK_FREQ * 15;
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
--- a/src/dvd_input.c
|
||||
+++ b/src/dvd_input.c
|
||||
@@ -103,6 +103,10 @@
|
||||
|
||||
/* dummy file input */
|
||||
int fd;
|
||||
+
|
||||
+ /* VLC-PS5: a stream (DVDOpenStream) without libdvdcss */
|
||||
+ dvd_reader_stream_cb *stream_cb;
|
||||
+ uint64_t pos;
|
||||
};
|
||||
|
||||
static dvd_input_t dvd_input_New(void *priv, dvd_logger_cb *logcb)
|
||||
@@ -199,12 +203,26 @@
|
||||
*/
|
||||
static dvd_input_t file_open(void *priv, dvd_logger_cb *logcb,
|
||||
const char *target,
|
||||
- dvd_reader_stream_cb *stream_cb UNUSED)
|
||||
+ dvd_reader_stream_cb *stream_cb)
|
||||
{
|
||||
dvd_input_t dev;
|
||||
|
||||
- if(target == NULL)
|
||||
- return NULL;
|
||||
+ if(target == NULL) {
|
||||
+ /* VLC-PS5: no libdvdcss, so the plain input reads the stream itself
|
||||
+ * (a DVD image on a network share). Unencrypted discs only. */
|
||||
+ if(priv == NULL || stream_cb == NULL || !stream_cb->pf_seek || !stream_cb->pf_read)
|
||||
+ return NULL;
|
||||
+ dev = dvd_input_New(priv, logcb);
|
||||
+ if(dev == NULL)
|
||||
+ return NULL;
|
||||
+ dev->fd = -1;
|
||||
+ dev->stream_cb = stream_cb;
|
||||
+ if(stream_cb->pf_seek(priv, 0) != 0) {
|
||||
+ free(dev);
|
||||
+ return NULL;
|
||||
+ }
|
||||
+ return dev;
|
||||
+ }
|
||||
/* Allocate the library structure */
|
||||
dev = dvd_input_New(priv, logcb);
|
||||
if(dev == NULL) {
|
||||
@@ -256,6 +274,14 @@
|
||||
{
|
||||
off_t pos;
|
||||
|
||||
+ if(dev->stream_cb) {
|
||||
+ uint64_t to = (uint64_t)blocks * DVD_VIDEO_LB_LEN;
|
||||
+ if(dev->stream_cb->pf_seek(dev->priv, to) != 0)
|
||||
+ return -1;
|
||||
+ dev->pos = to;
|
||||
+ return blocks;
|
||||
+ }
|
||||
+
|
||||
pos = lseek(dev->fd, (off_t)blocks * (off_t)DVD_VIDEO_LB_LEN, SEEK_SET);
|
||||
if(pos < 0) {
|
||||
return pos;
|
||||
@@ -283,6 +309,26 @@
|
||||
len = (size_t)blocks * DVD_VIDEO_LB_LEN;
|
||||
bytes = 0;
|
||||
|
||||
+ if(dev->stream_cb) {
|
||||
+ while(len > 0) {
|
||||
+ int chunk = len > (1 << 30) ? (1 << 30) : (int)len;
|
||||
+ int ret = dev->stream_cb->pf_read(dev->priv, ((char*)buffer) + bytes, chunk);
|
||||
+ if(ret < 0)
|
||||
+ return ret;
|
||||
+ if(ret == 0)
|
||||
+ break;
|
||||
+ len -= ret;
|
||||
+ bytes += ret;
|
||||
+ dev->pos += ret;
|
||||
+ }
|
||||
+ if(bytes % DVD_VIDEO_LB_LEN) {
|
||||
+ /* back to the last whole block, as the file input does */
|
||||
+ dev->pos -= bytes % DVD_VIDEO_LB_LEN;
|
||||
+ dev->stream_cb->pf_seek(dev->priv, dev->pos);
|
||||
+ }
|
||||
+ return (int) (bytes / DVD_VIDEO_LB_LEN);
|
||||
+ }
|
||||
+
|
||||
while(len > 0) {
|
||||
ssize_t ret = read(dev->fd, ((char*)buffer) + bytes, len);
|
||||
|
||||
@@ -318,7 +364,7 @@
|
||||
{
|
||||
int ret;
|
||||
|
||||
- ret = close(dev->fd);
|
||||
+ ret = dev->stream_cb ? 0 : close(dev->fd);
|
||||
|
||||
free(dev);
|
||||
|
||||
@@ -0,0 +1,139 @@
|
||||
--- a/src/vulkan/wsi/wsi_common_videoout.c
|
||||
+++ b/src/vulkan/wsi/wsi_common_videoout.c
|
||||
@@ -146,8 +146,46 @@
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
+
|
||||
+static int
|
||||
+sceVideoOutSubmitChangeBufferAttribute2(int32_t handle, int32_t set, const void *attribute, const void *option)
|
||||
+{
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+struct ps5_video_out_output_status {
|
||||
+ uint32_t resolution;
|
||||
+ uint32_t dynamic_range;
|
||||
+ uint64_t refresh_rate;
|
||||
+ uint64_t flags;
|
||||
+ uint64_t reserved[3];
|
||||
+};
|
||||
+
|
||||
+static int
|
||||
+sceVideoOutGetOutputStatus(int32_t handle, struct ps5_video_out_output_status *status)
|
||||
+{
|
||||
+ memset(status, 0, sizeof(*status));
|
||||
+ status->dynamic_range = 1;
|
||||
+ return 0;
|
||||
+}
|
||||
+#else
|
||||
+/* VLC-PS5: VideoOut calls ps5platform/videoout.h doesn't declare. */
|
||||
+struct ps5_video_out_output_status {
|
||||
+ uint32_t resolution;
|
||||
+ uint32_t dynamic_range; /* 0 unknown, 1 SDR, 2 HDR */
|
||||
+ uint64_t refresh_rate;
|
||||
+ uint64_t flags; /* bit 0: HDR output active */
|
||||
+ uint64_t reserved[3];
|
||||
+};
|
||||
+int sceVideoOutSubmitChangeBufferAttribute2(int32_t handle, int32_t set, const void *attribute,
|
||||
+ const void *option);
|
||||
+int sceVideoOutGetOutputStatus(int32_t handle, struct ps5_video_out_output_status *status);
|
||||
#endif
|
||||
|
||||
+/* VLC-PS5: HDR10 scanout, 10:10:10:2 in the framebuffers' B,G,R order with
|
||||
+ * BT.2020 primaries and the PQ curve. */
|
||||
+#define VLCPS5_VIDEO_OUT_PIXEL_FORMAT_HDR10 UINT64_C(0x8100070400000000)
|
||||
+
|
||||
/* The display and its modes: one each per process, as VideoOut is. */
|
||||
struct wsi_videoout_mode {
|
||||
uint32_t refresh_millihertz;
|
||||
@@ -399,6 +437,89 @@
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
+/*
|
||||
+ * VLC-PS5: HDR10 output. The framebuffers stay registered and are retyped in
|
||||
+ * place (registering them again isn't possible while one is on screen); the
|
||||
+ * new type applies from the next flip. The app waits for its GPU work to end
|
||||
+ * first and from then on writes 10:10:10:2 PQ pixels into the same 32-bit
|
||||
+ * buffers. 0 when VideoOut took it.
|
||||
+ */
|
||||
+int vlcps5_wsi_videoout_set_hdr(int enable);
|
||||
+int vlcps5_wsi_videoout_dynamic_range(void);
|
||||
+
|
||||
+int
|
||||
+vlcps5_wsi_videoout_set_hdr(int enable)
|
||||
+{
|
||||
+ struct wsi_videoout_output *out = &videoout_output;
|
||||
+ mtx_lock(&out->lock);
|
||||
+ int result = -1;
|
||||
+ if (out->buffers) {
|
||||
+ uint8_t attribute[PS5_VIDEO_OUT_ATTRIBUTE_BYTES] = {0};
|
||||
+ sceVideoOutSetBufferAttribute2(attribute,
|
||||
+ enable ? VLCPS5_VIDEO_OUT_PIXEL_FORMAT_HDR10
|
||||
+ : PS5_VIDEO_OUT_PIXEL_FORMAT_B8G8R8A8_SDR,
|
||||
+ PS5_VIDEO_OUT_TILING_64KB_R_X, VIDEOOUT_WIDTH, VIDEOOUT_HEIGHT, 0, 0, 0);
|
||||
+ result = sceVideoOutSubmitChangeBufferAttribute2(out->handle, 0, attribute, NULL);
|
||||
+ }
|
||||
+ mtx_unlock(&out->lock);
|
||||
+ fprintf(stderr, "wsi/videoout: framebuffers %s: 0x%08x\n", enable ? "HDR10" : "SDR", (unsigned)result);
|
||||
+ return result;
|
||||
+}
|
||||
+
|
||||
+/* VLC-PS5: what the output carries: 1 SDR, 2 HDR, 0 unknown, negative: no answer. */
|
||||
+int
|
||||
+vlcps5_wsi_videoout_dynamic_range(void)
|
||||
+{
|
||||
+ struct wsi_videoout_output *out = &videoout_output;
|
||||
+ mtx_lock(&out->lock);
|
||||
+ int result = -1;
|
||||
+ if (videoout_open_locked()) {
|
||||
+ struct ps5_video_out_output_status status;
|
||||
+ memset(&status, 0, sizeof(status));
|
||||
+ int rc = sceVideoOutGetOutputStatus(out->handle, &status);
|
||||
+ result = rc == 0 ? (int)status.dynamic_range : -1;
|
||||
+ fprintf(stderr, "wsi/videoout: output status 0x%08x: range %u, flags 0x%" PRIx64 "\n", (unsigned)rc,
|
||||
+ status.dynamic_range, status.flags);
|
||||
+ }
|
||||
+ mtx_unlock(&out->lock);
|
||||
+ return result;
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
+ * VLC-PS5: the output's refresh for films, as VideoOut's output modes number
|
||||
+ * it: 2 (23.976 Hz), 3 (24 Hz), 9 (50 Hz), 1 (back to the default). Asked
|
||||
+ * first whether the output takes it; then the vblank period measured, in
|
||||
+ * microseconds, into *period_us (0 if not changed). 0 when VideoOut took it.
|
||||
+ */
|
||||
+int vlcps5_wsi_videoout_set_refresh(int mode, int *period_us);
|
||||
+
|
||||
+int
|
||||
+vlcps5_wsi_videoout_set_refresh(int mode, int *period_us)
|
||||
+{
|
||||
+ struct wsi_videoout_output *out = &videoout_output;
|
||||
+ int result = -1;
|
||||
+ if (period_us)
|
||||
+ *period_us = 0;
|
||||
+ mtx_lock(&out->lock);
|
||||
+ if (videoout_open_locked()) {
|
||||
+ const int supported = mode == (int)PS5_VIDEO_OUT_MODE_RESTORE
|
||||
+ ? 1
|
||||
+ : sceVideoOutIsOutputSupported(out->handle, (uint32_t)mode, NULL, NULL, NULL);
|
||||
+ result = supported > 0 ? sceVideoOutConfigureOutput(out->handle, (uint32_t)mode, NULL, NULL, NULL)
|
||||
+ : (supported < 0 ? supported : -2);
|
||||
+ int measured = 0;
|
||||
+ if (result == 0)
|
||||
+ measured = (int)(videoout_vblank_period_ns(out->handle) / 1000);
|
||||
+ if (period_us)
|
||||
+ *period_us = measured;
|
||||
+ fprintf(stderr, "wsi/videoout: output mode %d: %s (0x%08x), a vblank every %.3f ms\n", mode,
|
||||
+ result == 0 ? "taken" : supported > 0 ? "refused" : "not supported", (unsigned)result,
|
||||
+ measured / 1000.0);
|
||||
+ }
|
||||
+ mtx_unlock(&out->lock);
|
||||
+ return result;
|
||||
+}
|
||||
+
|
||||
static int64_t
|
||||
videoout_shown_argument_locked(void)
|
||||
{
|
||||
@@ -0,0 +1,18 @@
|
||||
--- a/lib/socket.c 2026-10-10 18:59:32.030473620 +0000
|
||||
+++ b/lib/socket.c 2026-10-10 18:59:32.038975423 +0000
|
||||
@@ -1072,6 +1072,15 @@
|
||||
|
||||
set_nonblocking(fd);
|
||||
set_tcp_sockopt(fd, TCP_NODELAY, 1);
|
||||
+ /* VLC-PS5: big buffers, set before connect so the TCP window is
|
||||
+ * agreed on with them. The console's default (64 KiB) let one window
|
||||
+ * through per round trip: ~33 Mbit/s over Wi-Fi, under a 4K film's
|
||||
+ * 70 and a 16 MiB prefetch taking seconds to start a video. */
|
||||
+ {
|
||||
+ int rcv = 4 * 1024 * 1024, snd = 1024 * 1024;
|
||||
+ setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (const void *)&rcv, sizeof rcv);
|
||||
+ setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (const void *)&snd, sizeof snd);
|
||||
+ }
|
||||
#if 0 == CONFIGURE_OPTION_TCP_LINGER
|
||||
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const void*)&yes, sizeof yes);
|
||||
setsockopt(fd, SOL_SOCKET, SO_LINGER, (const void*)&lin, sizeof lin);
|
||||
@@ -0,0 +1,55 @@
|
||||
--- a/upnp/src/ssdp/ssdp_server.c 2026-10-09 20:35:17.057957885 +0000
|
||||
+++ b/upnp/src/ssdp/ssdp_server.c 2026-10-09 20:35:17.058290985 +0000
|
||||
@@ -981,6 +981,7 @@
|
||||
INADDR_ANY,
|
||||
SSDP_PORT,
|
||||
errorBuffer);
|
||||
+ fprintf(stderr, "upnp: bind UDP %d: %s\n", SSDP_PORT, errorBuffer);
|
||||
ret = UPNP_E_SOCKET_BIND;
|
||||
goto error_handler;
|
||||
}
|
||||
@@ -1509,10 +1510,23 @@
|
||||
retVal = create_ssdp_sock_v4(&out->ssdpSock4);
|
||||
if (retVal != UPNP_E_SUCCESS) {
|
||||
#ifdef INCLUDE_CLIENT_APIS
|
||||
- UpnpCloseSocket(out->ssdpReqSock4);
|
||||
- UpnpCloseSocket(out->ssdpReqSock6);
|
||||
- #endif /* INCLUDE_CLIENT_APIS */
|
||||
+ /* VLC-PS5: port 1900 taken (the console's own SSDP,
|
||||
+ * another user: no SO_REUSEPORT sharing when sandboxed).
|
||||
+ * A control point searches without it. */
|
||||
+ if (out->ssdpReqSock4 != INVALID_SOCKET) {
|
||||
+ fprintf(stderr,
|
||||
+ "upnp: no SSDP listener on port 1900 (%d): "
|
||||
+ "searching only\n",
|
||||
+ retVal);
|
||||
+ out->ssdpSock4 = INVALID_SOCKET;
|
||||
+ } else {
|
||||
+ UpnpCloseSocket(out->ssdpReqSock4);
|
||||
+ UpnpCloseSocket(out->ssdpReqSock6);
|
||||
+ return retVal;
|
||||
+ }
|
||||
+ #else
|
||||
return retVal;
|
||||
+ #endif /* INCLUDE_CLIENT_APIS */
|
||||
}
|
||||
} else
|
||||
out->ssdpSock4 = INVALID_SOCKET;
|
||||
--- a/upnp/src/genlib/miniserver/miniserver.c 2026-10-09 20:35:17.061594185 +0000
|
||||
+++ b/upnp/src/genlib/miniserver/miniserver.c 2026-10-09 20:35:17.061755185 +0000
|
||||
@@ -1046,6 +1046,7 @@
|
||||
"Error in IPv%d bind(): %s\n",
|
||||
s->ip_version,
|
||||
errorBuffer);
|
||||
+ fprintf(stderr, "upnp: miniserver IPv%d bind: %s\n", s->ip_version, errorBuffer);
|
||||
/* Bind failed. */
|
||||
ret_val = UPNP_E_SOCKET_BIND;
|
||||
goto error;
|
||||
@@ -1298,6 +1299,7 @@
|
||||
__FILE__,
|
||||
__LINE__,
|
||||
"Error in binding localhost!!!\n");
|
||||
+ fprintf(stderr, "upnp: stop socket bind 127.0.0.1: errno %d\n", errno);
|
||||
sock_close(miniServerStopSock);
|
||||
return UPNP_E_SOCKET_BIND;
|
||||
}
|
||||
+21
-6
@@ -38,7 +38,8 @@ mkdir -p "$work/obj" "$work/stubs"
|
||||
|
||||
# 1. The plugin table and the library list, read with the PS5 toolchain's nm.
|
||||
# Plus our own plugins (ps5/modules): ps5http, http(s) through the console.
|
||||
TARGET=ps5 NM="$sdk/bin/prospero-nm" APP_MODULES="vlc_entry__ps5http" bash "$here/gen-static-modules.sh" "$static"
|
||||
TARGET=ps5 NM="$sdk/bin/prospero-nm" APP_MODULES="vlc_entry__ps5http vlc_entry__ps5vdec" \
|
||||
bash "$here/gen-static-modules.sh" "$static"
|
||||
|
||||
# 2. Our objects, in an archive so --exclude-libs=ALL keeps them out of the
|
||||
# title's exports (the converter refuses application exports).
|
||||
@@ -52,12 +53,13 @@ cc "${cflags[@]}" -c "$static/static_modules.c" -o "$work/obj/static_modules.o"
|
||||
cc "${cflags[@]}" -std=c11 -c "$repo/third_party/volk/volk.c" -o "$work/obj/volk.o"
|
||||
cc "${cflags[@]}" -std=gnu11 -c "$repo/src/platform_ps5.c" -o "$work/obj/platform_ps5.o"
|
||||
cc "${cflags[@]}" -std=gnu11 -c "$here/modules/ps5http.c" -o "$work/obj/ps5http.o"
|
||||
cc "${cflags[@]}" -std=gnu11 -c "$here/modules/ps5vdec.c" -o "$work/obj/ps5vdec.o"
|
||||
for f in imgui imgui_draw imgui_tables imgui_widgets; do
|
||||
cc "${cflags[@]}" "${cxxflags[@]}" -c "$repo/third_party/imgui/$f.cpp" -o "$work/obj/$f.o"
|
||||
done
|
||||
cc "${cflags[@]}" "${cxxflags[@]}" -c "$repo/third_party/imgui/backends/imgui_impl_vulkan.cpp" \
|
||||
-o "$work/obj/imgui_impl_vulkan.o"
|
||||
for f in gfx image prefs player library network osub lang web ui main; do
|
||||
for f in gfx image prefs player subconv library network osub lang web ui main; do
|
||||
cc "${cflags[@]}" "${cxxflags[@]}" -c "$repo/src/$f.cc" -o "$work/obj/$f.o"
|
||||
done
|
||||
"$sdk/bin/prospero-ar" rcs "$work/libprobe.a" "$work"/obj/*.o
|
||||
@@ -73,6 +75,10 @@ stub() {
|
||||
}
|
||||
stub libSceAgc vendor/ps5/sdk/stubs/agc_canary_link_stub.c
|
||||
stub libSceAgcDriver vendor/ps5/sdk/stubs/agc_driver_canary_link_stub.c
|
||||
# The console's video decoder (ps5/modules/ps5vdec.c): our own stub.
|
||||
cc -std=c11 -O2 -fPIC -c "$here/stubs/videodec2_link_stub.c" -o "$work/libSceVideodec2_stub.o"
|
||||
"$sdk/bin/prospero-lld" --shared -soname libSceVideodec2.prx \
|
||||
-o "$work/stubs/libSceVideodec2.so" "$work/libSceVideodec2_stub.o"
|
||||
|
||||
# 3. VLC's archives for lld: -lfoo becomes our prefix's libfoo.a; the system
|
||||
# libraries (pthread, dl, atomic, ...) are the SDK's .so stubs, linked below.
|
||||
@@ -90,6 +96,8 @@ while read -r item; do
|
||||
esac
|
||||
done < "$static/link.rsp"
|
||||
vlc_inputs+=("$prefix/lib/libps5compat.a")
|
||||
# GNU libiconv: subtitle files that aren't UTF-8 (src/subconv.cc)
|
||||
vlc_inputs+=("$prefix/lib/libiconv.a")
|
||||
|
||||
# 4. Link.
|
||||
# shellcheck source=/dev/null
|
||||
@@ -140,7 +148,7 @@ fi
|
||||
-u vlc_static_modules \
|
||||
"$work/app_crt.o" "$work/app_cpp_runtime.o" \
|
||||
--start-group "$work/libprobe.a" "${vlc_inputs[@]}" --end-group \
|
||||
"$work/stubs/libSceAgc.so" "$work/stubs/libSceAgcDriver.so" \
|
||||
"$work/stubs/libSceAgc.so" "$work/stubs/libSceAgcDriver.so" "$work/stubs/libSceVideodec2.so" \
|
||||
"${radv_link_inputs[@]}" \
|
||||
--as-needed "$sdk"/target/lib/*.so 2>&1 | tee "$work/link.log" | grep -E "error|warning" | head -60
|
||||
[[ ${PIPESTATUS[0]} -eq 0 && -f $work/llvm-pie.elf ]] || { echo "link failed: $work/link.log" >&2; exit 1; }
|
||||
@@ -150,7 +158,8 @@ grep -aq "Video memory output" "$work/llvm-pie.elf" ||
|
||||
|
||||
"$tool" link --in "$work/llvm-pie.elf" --out "$work/eboot.elf" \
|
||||
--stub-dir "$sdk/target/lib" --stub "$work/stubs/libSceAgc.so" \
|
||||
--stub "$work/stubs/libSceAgcDriver.so" --module-sdk 0x02000009 \
|
||||
--stub "$work/stubs/libSceAgcDriver.so" --stub "$work/stubs/libSceVideodec2.so" \
|
||||
--module-sdk 0x02000009 \
|
||||
--companion-sdk 0x08050001 --file-name eboot.elf
|
||||
|
||||
# 5. The title folder.
|
||||
@@ -189,8 +198,11 @@ cp "$repo/assets/fonts/Inter-SemiBold.ttf" "$app/fonts/subtitle.ttf"
|
||||
cp "$repo/assets/fonts/Inter-Regular.ttf" "$app/fonts/mono.ttf"
|
||||
# Noto fonts for the scripts Inter lacks (Arabic, Hebrew, CJK, Thai, ...):
|
||||
# subtitles (patches/0005) and file names in the interface.
|
||||
mkdir -p "$app/fonts/fallback"
|
||||
cp "$repo/assets/fonts/fallback/"* "$app/fonts/fallback/"
|
||||
mkdir -p "$app/fonts/fallback" "$app/fonts/licenses"
|
||||
# only fonts in fallback/: libass loads every file there (the OFL texts were
|
||||
# "Error opening memory font" in every log); their licences beside them
|
||||
cp "$repo/assets/fonts/fallback/"*.tt[fc] "$app/fonts/fallback/"
|
||||
cp "$repo/assets/fonts/fallback/"*.txt "$app/fonts/licenses/"
|
||||
# HTTPS: Mozilla's CA list (curl.se/ca), where GnuTLS looks for it (/app0/certs).
|
||||
mkdir -p "$app/certs"
|
||||
cp "$repo/assets/certs/cacert.pem" "$app/certs/"
|
||||
@@ -204,5 +216,8 @@ fi
|
||||
sha=$(sha256sum "$app/eboot.bin" | cut -c1-12)
|
||||
mkdir -p "$repo/builds"
|
||||
cp "$work/llvm-pie.elf" "$repo/builds/llvm-pie-$sha.elf"
|
||||
# Only the newest three are kept (~140 MB each): enough to read a crash from
|
||||
# the build on the console and the two before it.
|
||||
ls -t "$repo"/builds/llvm-pie-*.elf | tail -n +4 | xargs -r rm -f --
|
||||
printf '==> %s: %s (eboot.bin %s bytes, %s; %s imports)\n' "$title_id" "$app" \
|
||||
"$(stat -c %s "$app/eboot.bin")" "$sha" "$(wc -l < "$app/imports.txt")"
|
||||
+97
-2
@@ -150,6 +150,97 @@ static bool unmap_direct(void *addr, size_t len)
|
||||
return found;
|
||||
}
|
||||
|
||||
/*
|
||||
* VLC's big pictures (patches/0015). A 4K 10-bit picture is 25 MiB and VLC
|
||||
* keeps 20 to 30 of them, more than the heap (flexible memory) holds: the
|
||||
* video then failed to start, a black screen (issue #9). Direct memory has
|
||||
* room for them.
|
||||
*/
|
||||
#define BIG_MAX 128
|
||||
static struct {
|
||||
void *addr;
|
||||
size_t len;
|
||||
int64_t start;
|
||||
} big_maps[BIG_MAX];
|
||||
|
||||
void *vlc_ps5_big_alloc(size_t len)
|
||||
{
|
||||
len = (len + DIRECT_ALIGNMENT - 1) & ~(DIRECT_ALIGNMENT - 1);
|
||||
void *result = NULL;
|
||||
pthread_mutex_lock(&direct_lock);
|
||||
int slot = -1;
|
||||
for (int i = 0; i < BIG_MAX && slot < 0; i++) {
|
||||
if (!big_maps[i].addr) {
|
||||
slot = i;
|
||||
}
|
||||
}
|
||||
int64_t start = -1;
|
||||
int rc = slot < 0 ? -1 :
|
||||
sceKernelAllocateDirectMemory(0, sceKernelGetDirectMemorySize(), len,
|
||||
DIRECT_ALIGNMENT, DIRECT_TYPE_CPU, &start);
|
||||
if (rc == 0) {
|
||||
result = ADDRESS_HINT;
|
||||
rc = sceKernelMapDirectMemory(&result, len, KERNEL_PROT_READ | KERNEL_PROT_WRITE,
|
||||
0, start, DIRECT_ALIGNMENT);
|
||||
if (rc != 0) {
|
||||
result = NULL;
|
||||
rc = sceKernelMapDirectMemory(&result, len, KERNEL_PROT_READ | KERNEL_PROT_WRITE,
|
||||
0, start, DIRECT_ALIGNMENT);
|
||||
}
|
||||
if (rc != 0) {
|
||||
sceKernelReleaseDirectMemory(start, len);
|
||||
result = NULL;
|
||||
}
|
||||
}
|
||||
if (!result && slot >= 0) {
|
||||
/* Direct memory full (the console's video decoder takes much of it
|
||||
* for 4K, console run 7): flexible memory, of which there was 1.6 GiB
|
||||
* left; start -1 marks it. */
|
||||
start = -1;
|
||||
result = ADDRESS_HINT;
|
||||
rc = sceKernelMapFlexibleMemory(&result, len, KERNEL_PROT_READ | KERNEL_PROT_WRITE, 0);
|
||||
if (rc != 0) {
|
||||
result = NULL;
|
||||
rc = sceKernelMapFlexibleMemory(&result, len, KERNEL_PROT_READ | KERNEL_PROT_WRITE, 0);
|
||||
}
|
||||
if (rc != 0)
|
||||
result = NULL;
|
||||
}
|
||||
if (result) {
|
||||
big_maps[slot].addr = result;
|
||||
big_maps[slot].len = len;
|
||||
big_maps[slot].start = start;
|
||||
}
|
||||
pthread_mutex_unlock(&direct_lock);
|
||||
if (!result) {
|
||||
report(slot < 0 ? "big picture (table full)" : "big picture", NULL, len, rc);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/* 1 if addr was vlc_ps5_big_alloc's (now freed), 0 if not. */
|
||||
int vlc_ps5_big_free(void *addr)
|
||||
{
|
||||
int found = 0;
|
||||
pthread_mutex_lock(&direct_lock);
|
||||
for (int i = 0; i < BIG_MAX && !found; i++) {
|
||||
if (big_maps[i].addr && big_maps[i].addr == addr) {
|
||||
if (big_maps[i].start < 0) {
|
||||
sceKernelMunmap(addr, big_maps[i].len); /* (released, it never came back) */
|
||||
big_maps[i].addr = NULL;
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
sceKernelMunmap(addr, big_maps[i].len);
|
||||
sceKernelReleaseDirectMemory(big_maps[i].start, big_maps[i].len);
|
||||
big_maps[i].addr = NULL;
|
||||
found = 1;
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&direct_lock);
|
||||
return found;
|
||||
}
|
||||
|
||||
void *__wrap_mmap(void *addr, size_t len, int prot, int flags, int fd,
|
||||
off_t offset)
|
||||
{
|
||||
@@ -248,7 +339,7 @@ void *__wrap_mmap(void *addr, size_t len, int prot, int flags, int fd,
|
||||
return MAP_FAILED;
|
||||
}
|
||||
if ((flags & MAP_FIXED) && result != addr) {
|
||||
sceKernelReleaseFlexibleMemory(result, len);
|
||||
sceKernelMunmap(result, len);
|
||||
errno = EINVAL;
|
||||
return MAP_FAILED;
|
||||
}
|
||||
@@ -261,7 +352,11 @@ int __wrap_munmap(void *addr, size_t len)
|
||||
if (unmap_direct(addr, len)) {
|
||||
return 0;
|
||||
}
|
||||
if (sceKernelReleaseFlexibleMemory(addr, len) == 0) {
|
||||
/* Flexible memory comes back with munmap, not with
|
||||
* sceKernelReleaseFlexibleMemory: released, it stayed taken (the app's
|
||||
* self-test on the console, 2026-10-13: 32 MiB released, 0 back; 32 MiB
|
||||
* unmapped, all back). Every big free VLC and FFmpeg made leaked so. */
|
||||
if (sceKernelMunmap(addr, len) == 0) {
|
||||
return 0;
|
||||
}
|
||||
/* A reserved range, or a file mapping. */
|
||||
|
||||
+29
-1
@@ -264,6 +264,10 @@ build_smb2() {
|
||||
fetch "https://github.com/sahlberg/libsmb2/archive/refs/tags/libsmb2-$v.tar.gz" "libsmb2-$v.tar.gz"
|
||||
unpack "libsmb2-$v.tar.gz" "$d"
|
||||
patch -d "$src/$d" -p1 -s < "$src/vlc-3.0.24/contrib/src/smb2/0001-cmake-add-ENABLE_LIBKRB5-and-ENABLE_GSSAPI-options.patch"
|
||||
# VLC-PS5's own (patches/smb2/): big socket buffers (the TCP window)
|
||||
for p in "$(dirname "$(dirname "$here")")"/patches/smb2/*.patch; do
|
||||
patch -d "$src/$d" -p1 -s < "$p"
|
||||
done
|
||||
cmake -S "$src/$d" -B "$src/build-smb2-$target" -G Ninja ${cmake_cross:-} \
|
||||
-DCMAKE_INSTALL_PREFIX="$prefix" -DCMAKE_INSTALL_LIBDIR=lib -DCMAKE_BUILD_TYPE=Release \
|
||||
-DBUILD_SHARED_LIBS=OFF -DCMAKE_POSITION_INDEPENDENT_CODE=ON \
|
||||
@@ -281,6 +285,11 @@ build_upnp() {
|
||||
for p in libtool-nostdlib-workaround miniserver; do
|
||||
patch -d "$src/$d" -p1 -s < "$src/vlc-3.0.24/contrib/src/upnp/$p.patch"
|
||||
done
|
||||
# Ours: discovery without the SSDP listener when port 1900 can't be had
|
||||
# (sandboxed on the console: UPNP_E_SOCKET_BIND).
|
||||
for p in "$(dirname "$(dirname "$here")")"/patches/upnp/*.patch; do
|
||||
patch -d "$src/$d" -p1 -s < "$p"
|
||||
done
|
||||
cmake -S "$src/$d" -B "$src/build-upnp-$target" -G Ninja ${cmake_cross:-} \
|
||||
-DCMAKE_INSTALL_PREFIX="$prefix" -DCMAKE_INSTALL_LIBDIR=lib -DCMAKE_BUILD_TYPE=Release \
|
||||
-DCMAKE_POSITION_INDEPENDENT_CODE=ON -DUPNP_BUILD_SHARED=OFF -DUPNP_BUILD_STATIC=ON \
|
||||
@@ -320,6 +329,11 @@ build_dvdread() {
|
||||
local v=6.1.3
|
||||
fetch "https://download.videolan.org/pub/videolan/libdvdread/$v/libdvdread-$v.tar.bz2"
|
||||
unpack "libdvdread-$v.tar.bz2" "libdvdread-$v"
|
||||
# VLC-PS5's own (patches/dvdread/): DVD images read from a stream (a network
|
||||
# share) without libdvdcss, which the PS5 build doesn't have.
|
||||
for p in "$(dirname "$(dirname "$here")")"/patches/dvdread/*.patch; do
|
||||
patch -d "$src/libdvdread-$v" -p1 -s < "$p"
|
||||
done
|
||||
(cd "$src/libdvdread-$v" && ./configure --prefix="$prefix" --libdir="$prefix/lib" \
|
||||
${host_triple:+--host=$host_triple --build=x86_64-pc-linux-gnu} \
|
||||
--enable-static --disable-shared --with-pic --disable-apidoc &&
|
||||
@@ -365,7 +379,21 @@ build_libarchive() {
|
||||
cmake --build "$src/build-libarchive-$target" && cmake --install "$src/build-libarchive-$target"
|
||||
}
|
||||
|
||||
all=(nasm compat zlib ffmpeg dav1d ebml matroska dvbpsi freetype fribidi harfbuzz gmp nettle gnutls smb2 upnp libxml2 ass dvdread dvdnav bluray libarchive)
|
||||
# Character sets for subtitle files that aren't UTF-8 (Windows-1252, GBK,
|
||||
# Big5, Shift JIS, Windows-1256...): the console's libc has no iconv. The app
|
||||
# converts such a file to UTF-8 before VLC reads it (src/subconv.cc).
|
||||
build_iconv() {
|
||||
local v=1.18
|
||||
fetch "https://ftp.gnu.org/gnu/libiconv/libiconv-$v.tar.gz"
|
||||
unpack "libiconv-$v.tar.gz" "libiconv-$v"
|
||||
(cd "$src/libiconv-$v" && ./configure --prefix="$prefix" --libdir="$prefix/lib" \
|
||||
${host_triple:+--host=$host_triple --build=x86_64-pc-linux-gnu} \
|
||||
--enable-static --disable-shared --disable-nls --with-pic &&
|
||||
make lib/localcharset.h && make -j"$jobs" -C lib && make -C lib install &&
|
||||
install -m 644 include/iconv.h.inst "$prefix/include/iconv.h")
|
||||
}
|
||||
|
||||
all=(nasm compat zlib ffmpeg dav1d ebml matroska dvbpsi freetype fribidi harfbuzz gmp nettle gnutls smb2 upnp libxml2 ass dvdread dvdnav bluray libarchive iconv)
|
||||
recipes=("$@")
|
||||
[[ ${#recipes[@]} -gt 0 ]] || recipes=("${all[@]}")
|
||||
for r in "${recipes[@]}"; do
|
||||
|
||||
+514
-10
@@ -17,7 +17,12 @@
|
||||
|
||||
#include <errno.h>
|
||||
#include <inttypes.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
#include <netinet/in.h>
|
||||
#include <pthread.h>
|
||||
#include <sys/socket.h>
|
||||
#include <time.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@@ -27,6 +32,7 @@
|
||||
#include <vlc_common.h>
|
||||
#include <vlc_access.h>
|
||||
#include <vlc_interrupt.h>
|
||||
#include <stdatomic.h>
|
||||
#include <vlc_plugin.h>
|
||||
#include <vlc_url.h>
|
||||
|
||||
@@ -69,13 +75,76 @@ static int http_template = -1;
|
||||
/* The console refused a request outright (run 15: 0x8095f00c on every https
|
||||
* request): VLC's own http module does the rest of the session's. */
|
||||
static bool service_refused;
|
||||
/* failures in a row that no answer came between: the service itself only
|
||||
* after a few (one cancelled search turned it off for the whole session and
|
||||
* the next channel went to VLC's own http, 2026-10-18) */
|
||||
static atomic_int service_failures;
|
||||
static atomic_int https_name_refusals;
|
||||
|
||||
/* Servers the console's SSL turned down: straight to VLC's own http next
|
||||
* time (every segment of a channel paid a refused attempt first). After
|
||||
* several different ones it refuses https as a whole this session (a log of
|
||||
* 2026-10-13: every https server refused, GitHub too). */
|
||||
#define REFUSED_MAX 64
|
||||
static vlc_mutex_t refused_lock = VLC_STATIC_MUTEX;
|
||||
static char *refused_hosts[REFUSED_MAX];
|
||||
static unsigned refused_count;
|
||||
static bool https_refused;
|
||||
|
||||
static char *url_host(const char *url)
|
||||
{
|
||||
const char *p = strstr(url, "://");
|
||||
if (!p)
|
||||
return NULL;
|
||||
p += 3;
|
||||
size_t n = strcspn(p, "/?#");
|
||||
return strndup(p, n);
|
||||
}
|
||||
|
||||
static bool host_refused(const char *url)
|
||||
{
|
||||
if (strncasecmp(url, "https:", 6))
|
||||
return false;
|
||||
char *host = url_host(url);
|
||||
bool refused = false;
|
||||
vlc_mutex_lock(&refused_lock);
|
||||
refused = https_refused;
|
||||
for (unsigned i = 0; host && !refused && i < refused_count; i++)
|
||||
refused = !strcasecmp(refused_hosts[i], host);
|
||||
vlc_mutex_unlock(&refused_lock);
|
||||
free(host);
|
||||
return refused;
|
||||
}
|
||||
|
||||
static unsigned ssl_refused_count;
|
||||
|
||||
static void refuse_host(const char *url, bool ssl)
|
||||
{
|
||||
char *host = url_host(url);
|
||||
if (!host)
|
||||
return;
|
||||
vlc_mutex_lock(&refused_lock);
|
||||
bool known = false;
|
||||
for (unsigned i = 0; i < refused_count; i++)
|
||||
known = known || !strcasecmp(refused_hosts[i], host);
|
||||
if (!known && refused_count < REFUSED_MAX) {
|
||||
refused_hosts[refused_count++] = host;
|
||||
host = NULL;
|
||||
if (ssl && ++ssl_refused_count == 4) {
|
||||
https_refused = true;
|
||||
fprintf(stderr, "ps5http: SSL refused 4 different servers: VLC's own http takes every https link\n");
|
||||
}
|
||||
}
|
||||
vlc_mutex_unlock(&refused_lock);
|
||||
free(host);
|
||||
}
|
||||
|
||||
static void start_service(void)
|
||||
{
|
||||
sceNetInit();
|
||||
int pool = sceNetPoolCreate("vlcps5_http", 1024 * 1024, 0);
|
||||
int pool = sceNetPoolCreate("vlcps5_http", 4 * 1024 * 1024, 0); /* room for parallel pieces */
|
||||
int ssl = sceSslInit(320 * 1024);
|
||||
int http = pool >= 0 && ssl >= 0 ? sceHttpInit(pool, ssl, 4 * 1024 * 1024) : -1;
|
||||
int http = pool >= 0 && ssl >= 0 ? sceHttpInit(pool, ssl, 8 * 1024 * 1024) : -1;
|
||||
if (http < 0) {
|
||||
fprintf(stderr, "ps5http: the console's HTTP service didn't start (net %d, ssl %d, http %d)\n",
|
||||
pool, ssl, http);
|
||||
@@ -106,8 +175,24 @@ typedef struct ps5http_sys {
|
||||
char *content_type;
|
||||
char *redirect; /* Location of a 3xx */
|
||||
int status;
|
||||
long serial; /* the player's open this belongs to (0: none) */
|
||||
bool logged_direct;
|
||||
mtime_t opened_at; /* for the speed in the log */
|
||||
uint64_t read_bytes;
|
||||
mtime_t read_wait; /* time spent inside the console's read */
|
||||
bool cancel_logged;
|
||||
struct parallel *par; /* a segment fetched over several connections, or NULL */
|
||||
} ps5http_sys;
|
||||
|
||||
/* The player (src/player.cc): its open number was stopped */
|
||||
extern int vlc_ps5_stream_cancelled(long serial) __attribute__((weak));
|
||||
extern int vlc_ps5_log_details(void) __attribute__((weak));
|
||||
|
||||
static bool cancelled(ps5http_sys *sys)
|
||||
{
|
||||
return sys->serial && vlc_ps5_stream_cancelled && vlc_ps5_stream_cancelled(sys->serial);
|
||||
}
|
||||
|
||||
static void drop_request(ps5http_sys *sys)
|
||||
{
|
||||
if (sys->req >= 0)
|
||||
@@ -147,6 +232,303 @@ static void abort_on_interrupt(void *data)
|
||||
sceHttpAbortRequest(*req);
|
||||
}
|
||||
|
||||
/* The app's own name lookup (ps5/compat/vlc_resolver.c): the console's
|
||||
* DNS can be one that blocks (a PS5 set up to keep away from updates sends
|
||||
* names to an address that refuses): every named server failed with
|
||||
* 0x8041013d while bare addresses worked (2026-10-18). */
|
||||
extern int vlcps5_getaddrinfo(const char *node, const char *service, const struct addrinfo *hints,
|
||||
struct addrinfo **res);
|
||||
extern void vlcps5_freeaddrinfo(struct addrinfo *ai);
|
||||
static atomic_bool direct_broken; /* a server answered an address-only request wrongly */
|
||||
|
||||
/* An http:// link with a name: the same link with the address our lookup
|
||||
* gives, and the name for the Host header ("name" or "name:port"). NULL: as
|
||||
* it is (https: the secure connection needs the name; an address already). */
|
||||
static char *direct_url(const char *url, char **host_header)
|
||||
{
|
||||
*host_header = NULL;
|
||||
if (atomic_load(&direct_broken) || strncasecmp(url, "http://", 7))
|
||||
return NULL;
|
||||
const char *h = url + 7;
|
||||
size_t hlen = strcspn(h, "/?#");
|
||||
if (!hlen || h[0] == '[' || memchr(h, '@', hlen))
|
||||
return NULL;
|
||||
char *hostport = strndup(h, hlen);
|
||||
if (!hostport)
|
||||
return NULL;
|
||||
char *colon = strchr(hostport, ':');
|
||||
char name[256];
|
||||
snprintf(name, sizeof(name), "%.*s", colon ? (int)(colon - hostport) : (int)hlen, hostport);
|
||||
struct in_addr ip;
|
||||
if (inet_pton(AF_INET, name, &ip) == 1) {
|
||||
free(hostport);
|
||||
return NULL;
|
||||
}
|
||||
struct addrinfo hints = { .ai_family = AF_INET, .ai_socktype = SOCK_STREAM }, *res = NULL;
|
||||
if (vlcps5_getaddrinfo(name, NULL, &hints, &res) != 0 || !res) {
|
||||
free(hostport);
|
||||
return NULL;
|
||||
}
|
||||
char addr[INET_ADDRSTRLEN];
|
||||
inet_ntop(AF_INET, &((struct sockaddr_in *)res->ai_addr)->sin_addr, addr, sizeof(addr));
|
||||
vlcps5_freeaddrinfo(res);
|
||||
char *out = NULL;
|
||||
if (asprintf(&out, "http://%s%s%s", addr, colon ? colon : "", h + hlen) < 0) {
|
||||
free(hostport);
|
||||
return NULL;
|
||||
}
|
||||
*host_header = hostport;
|
||||
return out;
|
||||
}
|
||||
|
||||
/* ---- a whole segment over several connections ------------------------------
|
||||
*
|
||||
* One connection to a far server is often slower than the line: the console
|
||||
* read BBC America at a steady 700 KiB/s, a 4 s segment in 5 s, and the
|
||||
* channel froze while the same server played on a PC (2026-10-18). A file of
|
||||
* a few MiB served with byte ranges (a live channel's segment) is fetched by
|
||||
* PAR_WORKERS connections at once, PAR_CHUNK at a time, into memory; VLC
|
||||
* reads it in order as the pieces come. */
|
||||
#define PAR_CHUNK ((uint64_t)512 << 10)
|
||||
#define PAR_WORKERS 4
|
||||
#define PAR_MIN ((uint64_t)1 << 20) /* smaller: one connection is enough */
|
||||
#define PAR_MAX ((uint64_t)24 << 20) /* bigger (films): one connection, as before */
|
||||
|
||||
typedef struct parallel {
|
||||
char *url, *ua, *ref;
|
||||
long serial;
|
||||
uint8_t *buf;
|
||||
uint64_t size;
|
||||
unsigned chunks, next;
|
||||
uint32_t *filled; /* bytes in so far, per chunk */
|
||||
bool *failed;
|
||||
bool stop;
|
||||
int reqs[PAR_WORKERS]; /* each worker's request, for an abort */
|
||||
pthread_t threads[PAR_WORKERS];
|
||||
int nthreads;
|
||||
uint64_t fetched;
|
||||
pthread_mutex_t lock;
|
||||
pthread_cond_t cond;
|
||||
} parallel;
|
||||
|
||||
static void add_headers(int req, const char *host_header, const char *ua, const char *ref)
|
||||
{
|
||||
if (host_header)
|
||||
sceHttpAddRequestHeader(req, "Host", host_header, HEADER_OVERWRITE);
|
||||
if (ua && *ua)
|
||||
sceHttpAddRequestHeader(req, "User-Agent", ua, HEADER_OVERWRITE);
|
||||
if (ref && *ref)
|
||||
sceHttpAddRequestHeader(req, "Referer", ref, HEADER_OVERWRITE);
|
||||
sceHttpAddRequestHeader(req, "Accept", "*/*", HEADER_OVERWRITE);
|
||||
sceHttpAddRequestHeader(req, "Cache-Control", "no-cache", HEADER_OVERWRITE);
|
||||
sceHttpAddRequestHeader(req, "Pragma", "no-cache", HEADER_OVERWRITE);
|
||||
}
|
||||
|
||||
static bool par_cancelled(parallel *p)
|
||||
{
|
||||
return p->serial && vlc_ps5_stream_cancelled && vlc_ps5_stream_cancelled(p->serial);
|
||||
}
|
||||
|
||||
/* One piece, from where it got to: true when it's all in. */
|
||||
static bool par_fetch(parallel *p, int w, unsigned idx)
|
||||
{
|
||||
uint64_t start = idx * PAR_CHUNK, end = start + PAR_CHUNK;
|
||||
if (end > p->size)
|
||||
end = p->size;
|
||||
pthread_mutex_lock(&p->lock);
|
||||
uint64_t from = start + p->filled[idx];
|
||||
pthread_mutex_unlock(&p->lock);
|
||||
if (from >= end)
|
||||
return true;
|
||||
char *host_header = NULL;
|
||||
char *direct = direct_url(p->url, &host_header);
|
||||
const char *url = direct ? direct : p->url;
|
||||
int conn = sceHttpCreateConnectionWithURL(http_template, url, 1);
|
||||
int req = conn >= 0 ? sceHttpCreateRequestWithURL(conn, METHOD_GET, url, 0) : -1;
|
||||
free(direct);
|
||||
bool ok = false;
|
||||
if (req >= 0) {
|
||||
add_headers(req, host_header, p->ua, p->ref);
|
||||
char range[64];
|
||||
snprintf(range, sizeof(range), "bytes=%" PRIu64 "-%" PRIu64, from, end - 1);
|
||||
sceHttpAddRequestHeader(req, "Range", range, HEADER_OVERWRITE);
|
||||
pthread_mutex_lock(&p->lock);
|
||||
p->reqs[w] = p->stop ? -1 : req;
|
||||
bool stop = p->stop;
|
||||
pthread_mutex_unlock(&p->lock);
|
||||
int status = 0;
|
||||
if (!stop && sceHttpSendRequest(req, NULL, 0) >= 0 && sceHttpGetStatusCode(req, &status) >= 0 &&
|
||||
(status == 206 || (status == 200 && from == 0))) {
|
||||
ok = true;
|
||||
while (from < end) {
|
||||
size_t want = end - from > (64u << 10) ? (64u << 10) : (size_t)(end - from);
|
||||
int n = sceHttpReadData(req, p->buf + from, want);
|
||||
if (n <= 0) {
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
from += (uint64_t)n;
|
||||
pthread_mutex_lock(&p->lock);
|
||||
p->filled[idx] += (uint32_t)n;
|
||||
p->fetched += (uint64_t)n;
|
||||
stop = p->stop;
|
||||
pthread_cond_broadcast(&p->cond);
|
||||
pthread_mutex_unlock(&p->lock);
|
||||
if (stop || par_cancelled(p)) {
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
pthread_mutex_lock(&p->lock);
|
||||
p->reqs[w] = -1;
|
||||
pthread_mutex_unlock(&p->lock);
|
||||
sceHttpDeleteRequest(req);
|
||||
}
|
||||
if (conn >= 0)
|
||||
sceHttpDeleteConnection(conn);
|
||||
free(host_header);
|
||||
return ok;
|
||||
}
|
||||
|
||||
struct par_worker {
|
||||
parallel *p;
|
||||
int w;
|
||||
};
|
||||
|
||||
static void *par_run(void *arg)
|
||||
{
|
||||
struct par_worker *pw = arg;
|
||||
parallel *p = pw->p;
|
||||
int w = pw->w;
|
||||
free(pw);
|
||||
for (;;) {
|
||||
pthread_mutex_lock(&p->lock);
|
||||
if (p->stop || p->next >= p->chunks) {
|
||||
pthread_mutex_unlock(&p->lock);
|
||||
break;
|
||||
}
|
||||
unsigned idx = p->next++;
|
||||
pthread_mutex_unlock(&p->lock);
|
||||
bool ok = false;
|
||||
for (int tries = 0; tries < 3 && !ok && !p->stop && !par_cancelled(p); tries++)
|
||||
ok = par_fetch(p, w, idx);
|
||||
if (!ok) {
|
||||
pthread_mutex_lock(&p->lock);
|
||||
p->failed[idx] = true;
|
||||
pthread_cond_broadcast(&p->cond);
|
||||
pthread_mutex_unlock(&p->lock);
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void par_free(parallel *p)
|
||||
{
|
||||
if (!p)
|
||||
return;
|
||||
pthread_mutex_lock(&p->lock);
|
||||
p->stop = true;
|
||||
for (int w = 0; w < PAR_WORKERS; w++)
|
||||
if (p->reqs[w] >= 0)
|
||||
sceHttpAbortRequest(p->reqs[w]);
|
||||
pthread_cond_broadcast(&p->cond);
|
||||
pthread_mutex_unlock(&p->lock);
|
||||
for (int i = 0; i < p->nthreads; i++)
|
||||
pthread_join(p->threads[i], NULL);
|
||||
pthread_mutex_destroy(&p->lock);
|
||||
pthread_cond_destroy(&p->cond);
|
||||
free(p->buf);
|
||||
free(p->filled);
|
||||
free(p->failed);
|
||||
free(p->url);
|
||||
free(p->ua);
|
||||
free(p->ref);
|
||||
free(p);
|
||||
}
|
||||
|
||||
static parallel *par_start(stream_t *access, uint64_t size, long serial)
|
||||
{
|
||||
parallel *p = calloc(1, sizeof(*p));
|
||||
if (!p)
|
||||
return NULL;
|
||||
p->size = size;
|
||||
p->chunks = (unsigned)((size + PAR_CHUNK - 1) / PAR_CHUNK);
|
||||
p->buf = malloc(size);
|
||||
p->filled = calloc(p->chunks, sizeof(*p->filled));
|
||||
p->failed = calloc(p->chunks, sizeof(*p->failed));
|
||||
p->url = strdup(access->psz_url);
|
||||
p->ua = var_InheritString(access, "http-user-agent");
|
||||
p->ref = var_InheritString(access, "http-referrer");
|
||||
p->serial = serial;
|
||||
for (int w = 0; w < PAR_WORKERS; w++)
|
||||
p->reqs[w] = -1;
|
||||
pthread_mutex_init(&p->lock, NULL);
|
||||
pthread_cond_init(&p->cond, NULL);
|
||||
if (!p->buf || !p->filled || !p->failed || !p->url) {
|
||||
par_free(p);
|
||||
return NULL;
|
||||
}
|
||||
int workers = p->chunks < PAR_WORKERS ? (int)p->chunks : PAR_WORKERS;
|
||||
for (int w = 0; w < workers; w++) {
|
||||
struct par_worker *pw = malloc(sizeof(*pw));
|
||||
if (!pw)
|
||||
break;
|
||||
pw->p = p;
|
||||
pw->w = w;
|
||||
if (pthread_create(&p->threads[p->nthreads], NULL, par_run, pw) != 0) {
|
||||
free(pw);
|
||||
break;
|
||||
}
|
||||
p->nthreads++;
|
||||
}
|
||||
if (!p->nthreads) {
|
||||
par_free(p);
|
||||
return NULL;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
/* VLC's read from the pieces: what's in at `pos`, waiting for it if needed. */
|
||||
static ssize_t par_read(stream_t *access, ps5http_sys *sys, void *buf, size_t len)
|
||||
{
|
||||
parallel *p = sys->par;
|
||||
if (sys->pos >= p->size)
|
||||
return 0;
|
||||
unsigned idx = (unsigned)(sys->pos / PAR_CHUNK);
|
||||
uint64_t within = sys->pos % PAR_CHUNK;
|
||||
pthread_mutex_lock(&p->lock);
|
||||
while (p->filled[idx] <= within && !p->failed[idx] && !p->stop) {
|
||||
pthread_mutex_unlock(&p->lock);
|
||||
if (vlc_killed() || cancelled(sys))
|
||||
return 0;
|
||||
pthread_mutex_lock(&p->lock);
|
||||
struct timespec ts;
|
||||
clock_gettime(CLOCK_REALTIME, &ts);
|
||||
ts.tv_nsec += 50 * 1000000;
|
||||
if (ts.tv_nsec >= 1000000000) {
|
||||
ts.tv_sec++;
|
||||
ts.tv_nsec -= 1000000000;
|
||||
}
|
||||
if (p->filled[idx] <= within && !p->failed[idx])
|
||||
pthread_cond_timedwait(&p->cond, &p->lock, &ts);
|
||||
}
|
||||
size_t have = p->filled[idx] > within ? (size_t)(p->filled[idx] - within) : 0;
|
||||
bool failed = !have && p->failed[idx];
|
||||
pthread_mutex_unlock(&p->lock);
|
||||
if (failed) {
|
||||
PLOG("a piece at %" PRIu64 " couldn't be fetched", sys->pos);
|
||||
return 0;
|
||||
}
|
||||
if (len > have)
|
||||
len = have;
|
||||
memcpy(buf, p->buf + sys->pos, len);
|
||||
sys->pos += len;
|
||||
sys->read_bytes += len;
|
||||
(void)access;
|
||||
return (ssize_t)len;
|
||||
}
|
||||
|
||||
/* Sends a GET from `offset`; fills status, size, type, redirect. */
|
||||
static int send_request(stream_t *access, uint64_t offset)
|
||||
{
|
||||
@@ -156,17 +538,26 @@ static int send_request(stream_t *access, uint64_t offset)
|
||||
sys->redirect = NULL;
|
||||
sys->eof = false;
|
||||
|
||||
sys->conn = sceHttpCreateConnectionWithURL(http_template, access->psz_url, 1);
|
||||
char *host_header = NULL;
|
||||
char *direct = direct_url(access->psz_url, &host_header);
|
||||
const char *url = direct ? direct : access->psz_url;
|
||||
sys->conn = sceHttpCreateConnectionWithURL(http_template, url, 1);
|
||||
if (sys->conn < 0) {
|
||||
PLOG("connection failed (%#x)", (unsigned)sys->conn);
|
||||
free(direct);
|
||||
free(host_header);
|
||||
return VLC_EGENERIC;
|
||||
}
|
||||
sys->req = sceHttpCreateRequestWithURL(sys->conn, METHOD_GET, access->psz_url, 0);
|
||||
sys->req = sceHttpCreateRequestWithURL(sys->conn, METHOD_GET, url, 0);
|
||||
free(direct);
|
||||
if (sys->req < 0) {
|
||||
PLOG("request failed (%#x)", (unsigned)sys->req);
|
||||
free(host_header);
|
||||
drop_request(sys);
|
||||
return VLC_EGENERIC;
|
||||
}
|
||||
if (host_header)
|
||||
sceHttpAddRequestHeader(sys->req, "Host", host_header, HEADER_OVERWRITE);
|
||||
char *ua = var_InheritString(access, "http-user-agent");
|
||||
char *ref = var_InheritString(access, "http-referrer");
|
||||
if (ua && *ua)
|
||||
@@ -176,6 +567,11 @@ static int send_request(stream_t *access, uint64_t offset)
|
||||
free(ua);
|
||||
free(ref);
|
||||
sceHttpAddRequestHeader(sys->req, "Accept", "*/*", HEADER_OVERWRITE);
|
||||
/* never a cached copy: a live playlist read again came back the same
|
||||
* (BBC, 2026-10-13: 20 s on, the same ten segments), VLC ran out of
|
||||
* segments and the channel stopped */
|
||||
sceHttpAddRequestHeader(sys->req, "Cache-Control", "no-cache", HEADER_OVERWRITE);
|
||||
sceHttpAddRequestHeader(sys->req, "Pragma", "no-cache", HEADER_OVERWRITE);
|
||||
if (offset > 0) {
|
||||
char range[48];
|
||||
snprintf(range, sizeof(range), "bytes=%" PRIu64 "-", offset);
|
||||
@@ -186,14 +582,61 @@ static int send_request(stream_t *access, uint64_t offset)
|
||||
int r = sceHttpSendRequest(sys->req, NULL, 0);
|
||||
vlc_interrupt_unregister();
|
||||
if (r < 0) {
|
||||
PLOG("sending failed (%#x): VLC's own http is used from now on", (unsigned)r);
|
||||
service_refused = true;
|
||||
/* 0x8095xxxx: the console's SSL turned this one server down (its
|
||||
* certificate, its ciphers). VLC's own http takes this link; the
|
||||
* service stays for the others. Anything else: the service itself. */
|
||||
bool ssl = ((unsigned)r & 0xFFFF0000u) == 0x80950000u;
|
||||
/* 0x8043xxxx: this server's connection (down, refused, timed out):
|
||||
* this link only too. Taken as the service's, one dead channel sent
|
||||
* every stream after it to VLC's own http (2026-10-13). */
|
||||
bool net = ((unsigned)r & 0xFFFF0000u) == 0x80430000u ||
|
||||
((unsigned)r & 0xFFFF0000u) == 0x80410000u; /* 0x8041: the network's errno */
|
||||
/* stopped on purpose (the player left, a search was typed over):
|
||||
* nothing wrong with anything */
|
||||
bool stopped = vlc_killed() || cancelled(sys);
|
||||
int in_row = stopped || ssl || net ? 0 : atomic_fetch_add(&service_failures, 1) + 1;
|
||||
PLOG("sending failed (%#x): %s", (unsigned)r,
|
||||
stopped ? "stopped"
|
||||
: ssl ? "SSL refused this server, VLC's own http takes this link"
|
||||
: net ? "connection failed, VLC's own http tries this link"
|
||||
: in_row >= 3 ? "third time in a row: VLC's own http is used from now on"
|
||||
: "VLC's own http takes this link");
|
||||
if (in_row >= 3)
|
||||
service_refused = true;
|
||||
if (ssl)
|
||||
refuse_host(access->psz_url, true);
|
||||
/* https by name refused (the console's DNS): this one's https links
|
||||
* straight to VLC's own http from now on, no failed try first */
|
||||
if (net && !strncasecmp(access->psz_url, "https://", 8) &&
|
||||
((unsigned)r & 0xFFFF0000u) == 0x80410000u && atomic_fetch_add(&https_name_refusals, 1) + 1 == 3) {
|
||||
vlc_mutex_lock(&refused_lock);
|
||||
https_refused = true;
|
||||
vlc_mutex_unlock(&refused_lock);
|
||||
PLOG("https refused 3 times by name (the console's DNS?): VLC's own http takes every https link");
|
||||
}
|
||||
free(host_header);
|
||||
drop_request(sys);
|
||||
return VLC_EGENERIC;
|
||||
}
|
||||
atomic_store(&service_failures, 0);
|
||||
int status = 0;
|
||||
sceHttpGetStatusCode(sys->req, &status);
|
||||
sys->status = status;
|
||||
if (host_header && (status == 400 || status == 403 || status == 404 || status == 421)) {
|
||||
/* the server wanted its name, not just its address (the Host header
|
||||
* didn't get through): no more address-only requests this session */
|
||||
PLOG("HTTP %d to %s by address: VLC's own http takes it, no more by address", status, host_header);
|
||||
atomic_store(&direct_broken, true);
|
||||
free(host_header);
|
||||
drop_request(sys);
|
||||
return VLC_EGENERIC;
|
||||
}
|
||||
if (host_header && !sys->logged_direct) {
|
||||
sys->logged_direct = true;
|
||||
PLOG("%s by the app's own name lookup", host_header);
|
||||
}
|
||||
free(host_header);
|
||||
host_header = NULL;
|
||||
|
||||
char *headers = NULL;
|
||||
size_t hlen = 0;
|
||||
@@ -220,11 +663,32 @@ static int send_request(stream_t *access, uint64_t offset)
|
||||
static ssize_t Read(stream_t *access, void *buf, size_t len)
|
||||
{
|
||||
ps5http_sys *sys = access->p_sys;
|
||||
if (sys->par)
|
||||
return par_read(access, sys, buf, len);
|
||||
if (sys->eof || sys->req < 0)
|
||||
return 0;
|
||||
if (cancelled(sys)) {
|
||||
/* the player left this video: no waiting for the rest of a slow
|
||||
* server's segment (the next video waited 10 s, 2026-10-18) */
|
||||
if (!sys->cancel_logged)
|
||||
PLOG("stopped by the player: connection ended");
|
||||
sys->cancel_logged = true;
|
||||
sys->eof = true;
|
||||
return 0;
|
||||
}
|
||||
/* A little at a time: VLC's prefetch asks for 16 MiB at the start, and a
|
||||
* live channel (no size, 4-8 Mbit/s) took 15-33 s to fill that before the
|
||||
* first picture (issue #11's log). */
|
||||
size_t most = sys->size && sys->can_seek ? ((size_t)1 << 20) : ((size_t)64 << 10);
|
||||
if (len > most)
|
||||
len = most;
|
||||
vlc_interrupt_register(abort_on_interrupt, &sys->req);
|
||||
mtime_t t0 = mdate();
|
||||
int n = sceHttpReadData(sys->req, buf, len);
|
||||
sys->read_wait += mdate() - t0;
|
||||
vlc_interrupt_unregister();
|
||||
if (n > 0)
|
||||
sys->read_bytes += (uint64_t)n;
|
||||
if (n <= 0) {
|
||||
if (n < 0)
|
||||
PLOG("read failed (%#x)", (unsigned)n);
|
||||
@@ -238,6 +702,10 @@ static ssize_t Read(stream_t *access, void *buf, size_t len)
|
||||
static int Seek(stream_t *access, uint64_t offset)
|
||||
{
|
||||
ps5http_sys *sys = access->p_sys;
|
||||
if (sys->par) {
|
||||
sys->pos = offset < sys->size ? offset : sys->size;
|
||||
return VLC_SUCCESS;
|
||||
}
|
||||
if (!sys->can_seek)
|
||||
return VLC_EGENERIC;
|
||||
if (sys->size && offset >= sys->size) {
|
||||
@@ -294,6 +762,19 @@ static void Close(vlc_object_t *obj)
|
||||
{
|
||||
stream_t *access = (stream_t *)obj;
|
||||
ps5http_sys *sys = access->p_sys;
|
||||
/* each download's speed: a live channel's segments must come faster than
|
||||
* they play (a 4 s piece in under 4 s), or it freezes */
|
||||
if (sys->read_bytes >= (256u << 10) && vlc_ps5_log_details && vlc_ps5_log_details()) {
|
||||
double secs = (mdate() - sys->opened_at) / 1e6, wait = sys->read_wait / 1e6;
|
||||
if (sys->par)
|
||||
PLOG("read %" PRIu64 " KiB in %.2f s (%.0f KiB/s; %d connections)", sys->read_bytes >> 10, secs,
|
||||
secs > 0 ? (sys->read_bytes >> 10) / secs : 0.0, sys->par->nthreads);
|
||||
else
|
||||
PLOG("read %" PRIu64 " KiB in %.2f s (%.0f KiB/s; %.2f s waiting for the network)",
|
||||
sys->read_bytes >> 10, secs, secs > 0 ? (sys->read_bytes >> 10) / secs : 0.0, wait);
|
||||
}
|
||||
par_free(sys->par);
|
||||
sys->par = NULL;
|
||||
drop_request(sys);
|
||||
free(sys->content_type);
|
||||
free(sys->redirect);
|
||||
@@ -304,7 +785,7 @@ static int Open(vlc_object_t *obj)
|
||||
{
|
||||
stream_t *access = (stream_t *)obj;
|
||||
pthread_once(&service_once, start_service);
|
||||
if (http_template < 0 || service_refused)
|
||||
if (http_template < 0 || service_refused || host_refused(access->psz_url))
|
||||
return VLC_EGENERIC; /* VLC's own http module takes over */
|
||||
|
||||
ps5http_sys *sys = calloc(1, sizeof(*sys));
|
||||
@@ -312,6 +793,13 @@ static int Open(vlc_object_t *obj)
|
||||
return VLC_ENOMEM;
|
||||
sys->conn = sys->req = -1;
|
||||
access->p_sys = sys;
|
||||
sys->serial = (long)var_InheritInteger(access, "ps5http-serial");
|
||||
sys->opened_at = mdate();
|
||||
if (cancelled(sys)) {
|
||||
free(sys);
|
||||
access->p_sys = NULL;
|
||||
return VLC_EGENERIC; /* a segment for a video already stopped */
|
||||
}
|
||||
PLOG("open %s", access->psz_url);
|
||||
|
||||
if (send_request(access, 0) != VLC_SUCCESS)
|
||||
@@ -319,10 +807,16 @@ static int Open(vlc_object_t *obj)
|
||||
if (sys->redirect) {
|
||||
/* VLC opens the new address (and probes the modules again). */
|
||||
char *to = vlc_uri_resolve(access->psz_url, sys->redirect);
|
||||
PLOG("redirected (%d) to %s", sys->status, to ? to : sys->redirect);
|
||||
free(access->psz_url);
|
||||
access->psz_url = to ? to : strdup(sys->redirect);
|
||||
if (!to)
|
||||
to = strdup(sys->redirect);
|
||||
if (!to)
|
||||
goto error;
|
||||
PLOG("redirected (%d) to %s", sys->status, to);
|
||||
/* Not freed here: access_New() keeps the old address (to spot a
|
||||
* loop) and frees it itself. Freeing it too was a double free. */
|
||||
access->psz_url = to;
|
||||
Close(obj);
|
||||
access->p_sys = NULL;
|
||||
return VLC_ACCESS_REDIRECT;
|
||||
}
|
||||
if (sys->status == 401 || sys->status == 407) {
|
||||
@@ -334,6 +828,11 @@ static int Open(vlc_object_t *obj)
|
||||
PLOG("HTTP %d", sys->status);
|
||||
goto error;
|
||||
}
|
||||
if (sys->status == 200 && sys->can_seek && sys->size >= PAR_MIN && sys->size <= PAR_MAX) {
|
||||
sys->par = par_start(access, sys->size, sys->serial);
|
||||
if (sys->par)
|
||||
drop_request(sys); /* the pieces have their own connections */
|
||||
}
|
||||
access->pf_read = Read;
|
||||
access->pf_block = NULL;
|
||||
access->pf_seek = Seek;
|
||||
@@ -342,6 +841,7 @@ static int Open(vlc_object_t *obj)
|
||||
|
||||
error:
|
||||
Close(obj);
|
||||
access->p_sys = NULL; /* the next module (VLC's own http) starts clean */
|
||||
return VLC_EGENERIC;
|
||||
}
|
||||
|
||||
@@ -352,5 +852,9 @@ vlc_module_begin()
|
||||
set_subcategory(SUBCAT_INPUT_ACCESS)
|
||||
set_capability("access", 300)
|
||||
add_shortcut("http", "https")
|
||||
/* the player's number for the open (see vlc_ps5_stream_cancelled) */
|
||||
add_integer("ps5http-serial", 0, "Player open", NULL, true)
|
||||
change_private()
|
||||
change_safe()
|
||||
set_callbacks(Open, Close)
|
||||
vlc_module_end()
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,36 @@
|
||||
#!/usr/bin/env bash
|
||||
# VLC-PS5's changes to the console's Vulkan driver (patches/mesa/): applied to
|
||||
# the RADV source tree PS5_Vulkan's tools/build-radv.sh made, built, and
|
||||
# installed where ps5/build-title.sh links it from. Run after build-radv.sh
|
||||
# (which puts back the fork's own files when its revision changes).
|
||||
#
|
||||
# bash ps5/radv-patches.sh
|
||||
#
|
||||
# patches/mesa/0001: HDR10 output (the framebuffers switched in place, the
|
||||
# output's dynamic range read back) for src/player.cc, and the output's
|
||||
# refresh for films (23.976 / 24 / 50 Hz) for src/main.cc. One patch per file:
|
||||
# each run starts the file again from the fork's original.
|
||||
set -euo pipefail
|
||||
here=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)
|
||||
repo=$(dirname "$here")
|
||||
vk=${PS5_VULKAN:-$HOME/ps5/PS5_Vulkan}
|
||||
src=$vk/.deps/work/radv-src
|
||||
build=$vk/.deps/work/radv-build-ps5-release
|
||||
install=$vk/.deps/native/radv-release
|
||||
ninja=${NINJA:-$(command -v ninja || echo "$HOME/.local/bin/ninja")}
|
||||
|
||||
[[ -d $src && -f $build/build.ninja ]] || { echo "build RADV first: $vk/tools/build-radv.sh release" >&2; exit 2; }
|
||||
for p in "$repo"/patches/mesa/*.patch; do
|
||||
# each file keeps its fork original beside it, so a patch goes on once
|
||||
target=$(sed -n 's/^+++ b\///p' "$p" | head -1)
|
||||
[[ -f $src/$target.orig-vlcps5 ]] || cp "$src/$target" "$src/$target.orig-vlcps5"
|
||||
cp "$src/$target.orig-vlcps5" "$src/$target"
|
||||
patch -d "$src" -p1 -s < "$p"
|
||||
echo "applied $(basename "$p")"
|
||||
done
|
||||
export PATH="$vk/.deps/work/radv-clc-bin:$PATH"
|
||||
"$ninja" -C "$build" src/amd/vulkan/libvulkan_radeon.a > "$build.vlcps5.log" 2>&1 ||
|
||||
{ grep -E "error|FAILED" "$build.vlcps5.log" | head -20 >&2; exit 1; }
|
||||
cp "$build/src/amd/vulkan/libvulkan_radeon.a" "$install/lib/libvulkan_radeon.ps5.a"
|
||||
printf 'VLC-PS5 patches: %s\n' "$(cd "$repo/patches/mesa" && ls *.patch | tr '\n' ' ')" >> "$install/PROVENANCE.txt"
|
||||
echo "==> RADV with VLC-PS5's patches in $install"
|
||||
@@ -0,0 +1,38 @@
|
||||
{
|
||||
"ageLevel": {
|
||||
"default": 0
|
||||
},
|
||||
"applicationCategoryType": 0,
|
||||
"applicationDrmType": "free",
|
||||
"attribute": 0,
|
||||
"attribute2": 0,
|
||||
"attribute3": 524352,
|
||||
"conceptId": "85300",
|
||||
"contentBadgeType": 1,
|
||||
"contentId": "UP9000-PPSA85300_00-VLCFORPS50000001",
|
||||
"contentVersion": "01.000.006",
|
||||
"downloadDataSize": 256,
|
||||
"gameIntent": {
|
||||
"permittedIntents": [
|
||||
{
|
||||
"intentType": "launchActivity"
|
||||
}
|
||||
]
|
||||
},
|
||||
"localizedParameters": {
|
||||
"defaultLanguage": "en-US",
|
||||
"en-US": {
|
||||
"titleName": "VLC"
|
||||
}
|
||||
},
|
||||
"masterVersion": "01.00",
|
||||
"pubtools": {
|
||||
"creationDate": "2026-10-06 00:00:00",
|
||||
"loudnessSnd0": "-28.00",
|
||||
"toolVersion": "2.00"
|
||||
},
|
||||
"requiredSystemSoftwareVersion": "0x0000000000000000",
|
||||
"sdkVersion": "0x0000000000000000",
|
||||
"titleId": "PPSA85300",
|
||||
"versionFileUri": ""
|
||||
}
|
||||
+4
-11
@@ -2,23 +2,16 @@
|
||||
"ageLevel": {
|
||||
"default": 0
|
||||
},
|
||||
"applicationCategoryType": 0,
|
||||
"applicationCategoryType": 65536,
|
||||
"applicationDrmType": "free",
|
||||
"attribute": 0,
|
||||
"attribute": 1644167168,
|
||||
"attribute2": 0,
|
||||
"attribute3": 524352,
|
||||
"conceptId": "85300",
|
||||
"contentBadgeType": 1,
|
||||
"contentBadgeType": 2,
|
||||
"contentId": "UP9000-PPSA85300_00-VLCFORPS50000001",
|
||||
"contentVersion": "01.000.000",
|
||||
"contentVersion": "01.000.006",
|
||||
"downloadDataSize": 256,
|
||||
"gameIntent": {
|
||||
"permittedIntents": [
|
||||
{
|
||||
"intentType": "launchActivity"
|
||||
}
|
||||
]
|
||||
},
|
||||
"localizedParameters": {
|
||||
"defaultLanguage": "en-US",
|
||||
"en-US": {
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* Link stub for the console's libSceVideodec2: the names the title imports
|
||||
* (ps5/modules/ps5vdec.c). Only linked against, never run: the console's own
|
||||
* library answers these calls.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
int sceVideodec2QueryComputeMemoryInfo(void *info) { (void)info; return -1; }
|
||||
int sceVideodec2AllocateComputeQueue(const void *config, const void *memory, void **queue) { (void)config; (void)memory; (void)queue; return -1; }
|
||||
int sceVideodec2ReleaseComputeQueue(void *queue) { (void)queue; return -1; }
|
||||
int sceVideodec2QueryDecoderMemoryInfo(const void *config, void *memory) { (void)config; (void)memory; return -1; }
|
||||
int sceVideodec2CreateDecoder(const void *config, const void *memory, void **decoder) { (void)config; (void)memory; (void)decoder; return -1; }
|
||||
int sceVideodec2DeleteDecoder(void *decoder) { (void)decoder; return -1; }
|
||||
int sceVideodec2Decode(void *decoder, const void *input, void *frame, void *output) { (void)decoder; (void)input; (void)frame; (void)output; return -1; }
|
||||
int sceVideodec2Flush(void *decoder, void *frame, void *output) { (void)decoder; (void)frame; (void)output; return -1; }
|
||||
int sceVideodec2Reset(void *decoder) { (void)decoder; return -1; }
|
||||
int sceVideodec2GetPictureInfo(const void *output, void *first, void *second) { (void)output; (void)first; (void)second; return -1; }
|
||||
@@ -0,0 +1,10 @@
|
||||
#version 450
|
||||
// One triangle over the whole target (the UI layer composited in HDR mode).
|
||||
layout(location = 0) out vec2 uv;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec2 p = vec2((gl_VertexIndex << 1) & 2, gl_VertexIndex & 2);
|
||||
uv = p;
|
||||
gl_Position = vec4(p * 2.0 - 1.0, 0.0, 1.0);
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
#version 450
|
||||
// HDR output: the UI layer (8-bit, premultiplied, the TV's gamma) over the
|
||||
// PQ picture. Its colours become light at a graphics white of pc.nits
|
||||
// (BT.2408's 203), BT.709 -> BT.2020, then PQ; premultiplied again so it
|
||||
// blends with ONE, ONE_MINUS_SRC_ALPHA as on an SDR screen.
|
||||
layout(location = 0) in vec2 uv;
|
||||
layout(location = 0) out vec4 color;
|
||||
|
||||
layout(set = 0, binding = 0) uniform sampler2D ui;
|
||||
|
||||
layout(push_constant) uniform Push {
|
||||
float nits;
|
||||
} pc;
|
||||
|
||||
const float PQ_M1 = 0.1593017578125, PQ_M2 = 78.84375;
|
||||
const float PQ_C1 = 0.8359375, PQ_C2 = 18.8515625, PQ_C3 = 18.6875;
|
||||
|
||||
vec3 nits_to_pq(vec3 nits)
|
||||
{
|
||||
vec3 y = pow(clamp(nits / 10000.0, 0.0, 1.0), vec3(PQ_M1));
|
||||
return pow((PQ_C1 + PQ_C2 * y) / (1.0 + PQ_C3 * y), vec3(PQ_M2));
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 c = texture(ui, uv);
|
||||
if (c.a <= 0.0) {
|
||||
color = vec4(0.0);
|
||||
return;
|
||||
}
|
||||
vec3 straight = clamp(c.rgb / c.a, 0.0, 1.0);
|
||||
vec3 lin = pow(straight, vec3(2.2)) * pc.nits;
|
||||
/* BT.709 -> BT.2020 primaries (GLSL matrices are by column) */
|
||||
lin = mat3(0.6274, 0.0691, 0.0164,
|
||||
0.3293, 0.9195, 0.0880,
|
||||
0.0433, 0.0114, 0.8956) * lin;
|
||||
/* The blend happens on PQ codes: half-transparent black over the picture
|
||||
* halved the code, which darkened it far more than on an SDR screen.
|
||||
* There the blend is on gamma codes, leaving (1 - a)^2.2 of the light;
|
||||
* the coverage that leaves that much of a 100-nit picture is used. */
|
||||
const float ref = 100.0;
|
||||
float left = pow(1.0 - c.a, 2.2);
|
||||
float a = c.a < 1.0 ? 1.0 - nits_to_pq(vec3(ref * left)).x / nits_to_pq(vec3(ref)).x : 1.0;
|
||||
color = vec4(nits_to_pq(lin) * a, a);
|
||||
}
|
||||
+103
-4
@@ -1,8 +1,10 @@
|
||||
#version 450
|
||||
// Planar YCbCr (VLC's I420 / J420 / I0AL) to RGB. Same constants as
|
||||
// Planar YCbCr (VLC's I420 / J420 / I0AL, or NV12 / P010) to RGB. Same constants as
|
||||
// host/vlc_probe.c, which checked them against real frames in World 1.
|
||||
// Then the picture controls: brightness and contrast on luma, hue and
|
||||
// saturation on chroma, gamma on the result.
|
||||
// saturation on chroma, gamma on the result. HDR (PQ, HLG) is tone mapped
|
||||
// to SDR between the two; with HDR10 output on (outp.x), the picture goes
|
||||
// out as PQ, BT.2020 instead.
|
||||
layout(location = 0) in vec2 uv;
|
||||
layout(location = 0) out vec4 color;
|
||||
|
||||
@@ -19,8 +21,96 @@ layout(push_constant) uniform Push {
|
||||
vec4 adjust; // brightness, contrast, saturation, gamma exponent
|
||||
vec4 view; // 360: yaw, pitch, tan(fov / 2), screen aspect
|
||||
vec4 xform; // quarter turns clockwise, mirror, upside down, sharpen amount
|
||||
vec4 hdr; // transfer (0 SDR, 1 PQ, 2 HLG), peak (nits), BT.2020 primaries (1), NV12/P010 (1)
|
||||
vec4 outp; // HDR10 output (1): PQ, BT.2020; -, -, -
|
||||
} pc;
|
||||
|
||||
/* HDR to SDR, the same sums as hdr_to_sdr() in player.cc (screenshots). */
|
||||
const float SDR_WHITE = 203.0; // HDR's reference white (BT.2408) = the TV's white
|
||||
const float PQ_M1 = 0.1593017578125, PQ_M2 = 78.84375;
|
||||
const float PQ_C1 = 0.8359375, PQ_C2 = 18.8515625, PQ_C3 = 18.6875;
|
||||
|
||||
vec3 pq_to_nits(vec3 e)
|
||||
{
|
||||
vec3 p = pow(clamp(e, 0.0, 1.0), vec3(1.0 / PQ_M2));
|
||||
return 10000.0 * pow(max(p - PQ_C1, 0.0) / (PQ_C2 - PQ_C3 * p), vec3(1.0 / PQ_M1));
|
||||
}
|
||||
|
||||
float nits_to_pq(float nits)
|
||||
{
|
||||
float y = pow(clamp(nits / 10000.0, 0.0, 1.0), PQ_M1);
|
||||
return pow((PQ_C1 + PQ_C2 * y) / (1.0 + PQ_C3 * y), PQ_M2);
|
||||
}
|
||||
|
||||
/* HLG: scene light, then the system gamma of a 1000-nit TV (BT.2100) */
|
||||
vec3 hlg_to_nits(vec3 e)
|
||||
{
|
||||
const float a = 0.17883277, b = 0.28466892, c = 0.55991073;
|
||||
e = clamp(e, 0.0, 1.0);
|
||||
vec3 s = mix(e * e / 3.0, (exp((e - c) / a) + b) / 12.0, step(vec3(0.5), e));
|
||||
float ys = max(dot(s, vec3(0.2627, 0.6780, 0.0593)), 1e-6);
|
||||
return 1000.0 * pow(ys, 0.2) * s;
|
||||
}
|
||||
|
||||
vec3 nits_to_pq3(vec3 nits)
|
||||
{
|
||||
vec3 y = pow(clamp(nits / 10000.0, 0.0, 1.0), vec3(PQ_M1));
|
||||
return pow((PQ_C1 + PQ_C2 * y) / (1.0 + PQ_C3 * y), vec3(PQ_M2));
|
||||
}
|
||||
|
||||
/* HDR10 output: the picture as PQ with BT.2020 primaries. HDR10 is that
|
||||
* already and goes through untouched; HLG and SDR become light (SDR white
|
||||
* at 203 nits), then BT.2020, then PQ. */
|
||||
vec3 to_pq_output(vec3 e)
|
||||
{
|
||||
if (pc.hdr.x > 0.5 && pc.hdr.x < 1.5 && pc.hdr.z > 0.5)
|
||||
return e;
|
||||
vec3 nits;
|
||||
if (pc.hdr.x > 0.5)
|
||||
nits = pc.hdr.x < 1.5 ? pq_to_nits(e) : hlg_to_nits(e);
|
||||
else
|
||||
nits = pow(clamp(e, 0.0, 1.0), vec3(2.4)) * SDR_WHITE;
|
||||
if (pc.hdr.z < 0.5) {
|
||||
/* BT.709 -> BT.2020 primaries */
|
||||
nits = mat3(0.6274, 0.0691, 0.0164,
|
||||
0.3293, 0.9195, 0.0880,
|
||||
0.0433, 0.0114, 0.8956) * nits;
|
||||
}
|
||||
return nits_to_pq3(nits);
|
||||
}
|
||||
|
||||
vec3 hdr_to_sdr(vec3 e)
|
||||
{
|
||||
vec3 nits = pc.hdr.x < 1.5 ? pq_to_nits(e) : hlg_to_nits(e);
|
||||
/* BT.2390's roll-off on the brightest channel (keeps the hue): up to
|
||||
* about half of SDR white nothing changes, above it the highlights bend
|
||||
* down to fit under white. */
|
||||
float peak = pc.hdr.y;
|
||||
float sig = max(nits.r, max(nits.g, nits.b));
|
||||
if (sig > 0.0 && peak > SDR_WHITE) {
|
||||
float src = nits_to_pq(peak);
|
||||
float e1 = min(nits_to_pq(sig) / src, 1.0);
|
||||
float maxl = nits_to_pq(SDR_WHITE) / src;
|
||||
float ks = 1.5 * maxl - 0.5;
|
||||
float e2 = e1;
|
||||
if (e1 > ks) {
|
||||
float t = (e1 - ks) / (1.0 - ks), t2 = t * t, t3 = t2 * t;
|
||||
e2 = (2.0 * t3 - 3.0 * t2 + 1.0) * ks + (t3 - 2.0 * t2 + t) * (1.0 - ks) +
|
||||
(-2.0 * t3 + 3.0 * t2) * maxl;
|
||||
}
|
||||
nits *= pq_to_nits(vec3(e2 * src)).r / sig;
|
||||
}
|
||||
vec3 lin = nits / SDR_WHITE;
|
||||
if (pc.hdr.z > 0.5) {
|
||||
/* BT.2020 -> BT.709 primaries (linear light; GLSL matrices are by column) */
|
||||
lin = mat3(1.6605, -0.1246, -0.0182,
|
||||
-0.5876, 1.1329, -0.1006,
|
||||
-0.0728, -0.0083, 1.1187) * lin;
|
||||
}
|
||||
/* back to a TV's signal (BT.1886, gamma 2.4) */
|
||||
return pow(clamp(lin, 0.0, 1.0), vec3(1.0 / 2.4));
|
||||
}
|
||||
|
||||
/* Rotate and flip: the point of the picture this pixel shows. */
|
||||
vec2 turned_uv()
|
||||
{
|
||||
@@ -69,8 +159,11 @@ void main()
|
||||
around += texture(tex_y, at + vec2(float(dx), float(dy)) * t).r;
|
||||
y = clamp(y + (y - around * 0.125 * s) * pc.xform.w, 0.0, 1.0);
|
||||
}
|
||||
float u = texture(tex_u, at).r * s - 0.5;
|
||||
float v = texture(tex_v, at).r * s - 0.5;
|
||||
/* NV12 / P010: U and V side by side in the second plane */
|
||||
vec2 chroma = pc.hdr.w > 0.5 ? texture(tex_u, at).rg
|
||||
: vec2(texture(tex_u, at).r, texture(tex_v, at).r);
|
||||
float u = chroma.x * s - 0.5;
|
||||
float v = chroma.y * s - 0.5;
|
||||
if (pc.params.y > 0.5) {
|
||||
y = (y - 16.0 / 255.0) * (255.0 / 219.0);
|
||||
u *= 255.0 / 224.0;
|
||||
@@ -82,5 +175,11 @@ void main()
|
||||
vec3 yuv = vec3(y, uv2);
|
||||
vec3 rgb = clamp(vec3(dot(pc.row0.xyz, yuv), dot(pc.row1.xyz, yuv), dot(pc.row2.xyz, yuv)),
|
||||
0.0, 1.0);
|
||||
if (pc.outp.x > 0.5) {
|
||||
color = vec4(to_pq_output(rgb), 1.0);
|
||||
return;
|
||||
}
|
||||
if (pc.hdr.x > 0.5)
|
||||
rgb = hdr_to_sdr(rgb);
|
||||
color = vec4(pow(rgb, vec3(pc.adjust.w)), 1.0);
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
// 1116.2.0
|
||||
#pragma once
|
||||
const uint32_t spv_fullscreen_vert[] = {
|
||||
0x07230203,0x00010300,0x0008000b,0x0000002e,0x00000000,0x00020011,0x00000001,0x0006000b,
|
||||
0x00000001,0x4c534c47,0x6474732e,0x3035342e,0x00000000,0x0003000e,0x00000000,0x00000001,
|
||||
0x0008000f,0x00000000,0x00000004,0x6e69616d,0x00000000,0x0000000c,0x00000018,0x00000020,
|
||||
0x00030003,0x00000002,0x000001c2,0x00040005,0x00000004,0x6e69616d,0x00000000,0x00030005,
|
||||
0x00000009,0x00000070,0x00060005,0x0000000c,0x565f6c67,0x65747265,0x646e4978,0x00007865,
|
||||
0x00030005,0x00000018,0x00007675,0x00060005,0x0000001e,0x505f6c67,0x65567265,0x78657472,
|
||||
0x00000000,0x00060006,0x0000001e,0x00000000,0x505f6c67,0x7469736f,0x006e6f69,0x00070006,
|
||||
0x0000001e,0x00000001,0x505f6c67,0x746e696f,0x657a6953,0x00000000,0x00070006,0x0000001e,
|
||||
0x00000002,0x435f6c67,0x4470696c,0x61747369,0x0065636e,0x00070006,0x0000001e,0x00000003,
|
||||
0x435f6c67,0x446c6c75,0x61747369,0x0065636e,0x00030005,0x00000020,0x00000000,0x00040047,
|
||||
0x0000000c,0x0000000b,0x0000002a,0x00040047,0x00000018,0x0000001e,0x00000000,0x00030047,
|
||||
0x0000001e,0x00000002,0x00050048,0x0000001e,0x00000000,0x0000000b,0x00000000,0x00050048,
|
||||
0x0000001e,0x00000001,0x0000000b,0x00000001,0x00050048,0x0000001e,0x00000002,0x0000000b,
|
||||
0x00000003,0x00050048,0x0000001e,0x00000003,0x0000000b,0x00000004,0x00020013,0x00000002,
|
||||
0x00030021,0x00000003,0x00000002,0x00030016,0x00000006,0x00000020,0x00040017,0x00000007,
|
||||
0x00000006,0x00000002,0x00040020,0x00000008,0x00000007,0x00000007,0x00040015,0x0000000a,
|
||||
0x00000020,0x00000001,0x00040020,0x0000000b,0x00000001,0x0000000a,0x0004003b,0x0000000b,
|
||||
0x0000000c,0x00000001,0x0004002b,0x0000000a,0x0000000e,0x00000001,0x0004002b,0x0000000a,
|
||||
0x00000010,0x00000002,0x00040020,0x00000017,0x00000003,0x00000007,0x0004003b,0x00000017,
|
||||
0x00000018,0x00000003,0x00040017,0x0000001a,0x00000006,0x00000004,0x00040015,0x0000001b,
|
||||
0x00000020,0x00000000,0x0004002b,0x0000001b,0x0000001c,0x00000001,0x0004001c,0x0000001d,
|
||||
0x00000006,0x0000001c,0x0006001e,0x0000001e,0x0000001a,0x00000006,0x0000001d,0x0000001d,
|
||||
0x00040020,0x0000001f,0x00000003,0x0000001e,0x0004003b,0x0000001f,0x00000020,0x00000003,
|
||||
0x0004002b,0x0000000a,0x00000021,0x00000000,0x0004002b,0x00000006,0x00000023,0x40000000,
|
||||
0x0004002b,0x00000006,0x00000025,0x3f800000,0x0004002b,0x00000006,0x00000028,0x00000000,
|
||||
0x00040020,0x0000002c,0x00000003,0x0000001a,0x00050036,0x00000002,0x00000004,0x00000000,
|
||||
0x00000003,0x000200f8,0x00000005,0x0004003b,0x00000008,0x00000009,0x00000007,0x0004003d,
|
||||
0x0000000a,0x0000000d,0x0000000c,0x000500c4,0x0000000a,0x0000000f,0x0000000d,0x0000000e,
|
||||
0x000500c7,0x0000000a,0x00000011,0x0000000f,0x00000010,0x0004006f,0x00000006,0x00000012,
|
||||
0x00000011,0x0004003d,0x0000000a,0x00000013,0x0000000c,0x000500c7,0x0000000a,0x00000014,
|
||||
0x00000013,0x00000010,0x0004006f,0x00000006,0x00000015,0x00000014,0x00050050,0x00000007,
|
||||
0x00000016,0x00000012,0x00000015,0x0003003e,0x00000009,0x00000016,0x0004003d,0x00000007,
|
||||
0x00000019,0x00000009,0x0003003e,0x00000018,0x00000019,0x0004003d,0x00000007,0x00000022,
|
||||
0x00000009,0x0005008e,0x00000007,0x00000024,0x00000022,0x00000023,0x00050050,0x00000007,
|
||||
0x00000026,0x00000025,0x00000025,0x00050083,0x00000007,0x00000027,0x00000024,0x00000026,
|
||||
0x00050051,0x00000006,0x00000029,0x00000027,0x00000000,0x00050051,0x00000006,0x0000002a,
|
||||
0x00000027,0x00000001,0x00070050,0x0000001a,0x0000002b,0x00000029,0x0000002a,0x00000028,
|
||||
0x00000025,0x00050041,0x0000002c,0x0000002d,0x00000020,0x00000021,0x0003003e,0x0000002d,
|
||||
0x0000002b,0x000100fd,0x00010038
|
||||
};
|
||||
@@ -0,0 +1,109 @@
|
||||
// 1116.2.0
|
||||
#pragma once
|
||||
const uint32_t spv_ui_pq_frag[] = {
|
||||
0x07230203,0x00010300,0x0008000b,0x00000093,0x00000000,0x00020011,0x00000001,0x0006000b,
|
||||
0x00000001,0x4c534c47,0x6474732e,0x3035342e,0x00000000,0x0003000e,0x00000000,0x00000001,
|
||||
0x0007000f,0x00000004,0x00000004,0x6e69616d,0x00000000,0x00000035,0x00000042,0x00030010,
|
||||
0x00000004,0x00000007,0x00030003,0x00000002,0x000001c2,0x00040005,0x00000004,0x6e69616d,
|
||||
0x00000000,0x00060005,0x0000000b,0x7374696e,0x5f6f745f,0x76287170,0x003b3366,0x00040005,
|
||||
0x0000000a,0x7374696e,0x00000000,0x00030005,0x0000000d,0x00000079,0x00030005,0x0000002d,
|
||||
0x00000063,0x00030005,0x00000031,0x00006975,0x00030005,0x00000035,0x00007675,0x00040005,
|
||||
0x00000042,0x6f6c6f63,0x00000072,0x00050005,0x00000045,0x61727473,0x74686769,0x00000000,
|
||||
0x00030005,0x0000004f,0x006e696c,0x00040005,0x00000054,0x68737550,0x00000000,0x00050006,
|
||||
0x00000054,0x00000000,0x7374696e,0x00000000,0x00030005,0x00000056,0x00006370,0x00040005,
|
||||
0x0000006d,0x7466656c,0x00000000,0x00030005,0x00000072,0x00000061,0x00040005,0x0000007d,
|
||||
0x61726170,0x0000006d,0x00040005,0x00000082,0x61726170,0x0000006d,0x00040005,0x00000089,
|
||||
0x61726170,0x0000006d,0x00040047,0x00000031,0x00000021,0x00000000,0x00040047,0x00000031,
|
||||
0x00000022,0x00000000,0x00040047,0x00000035,0x0000001e,0x00000000,0x00040047,0x00000042,
|
||||
0x0000001e,0x00000000,0x00030047,0x00000054,0x00000002,0x00050048,0x00000054,0x00000000,
|
||||
0x00000023,0x00000000,0x00020013,0x00000002,0x00030021,0x00000003,0x00000002,0x00030016,
|
||||
0x00000006,0x00000020,0x00040017,0x00000007,0x00000006,0x00000003,0x00040020,0x00000008,
|
||||
0x00000007,0x00000007,0x00040021,0x00000009,0x00000007,0x00000008,0x0004002b,0x00000006,
|
||||
0x0000000f,0x461c4000,0x0004002b,0x00000006,0x00000012,0x00000000,0x0004002b,0x00000006,
|
||||
0x00000013,0x3f800000,0x0004002b,0x00000006,0x00000017,0x3e232000,0x0006002c,0x00000007,
|
||||
0x00000018,0x00000017,0x00000017,0x00000017,0x0004002b,0x00000006,0x0000001a,0x3f560000,
|
||||
0x0004002b,0x00000006,0x0000001b,0x4196d000,0x0004002b,0x00000006,0x00000020,0x41958000,
|
||||
0x0004002b,0x00000006,0x00000026,0x429db000,0x0006002c,0x00000007,0x00000027,0x00000026,
|
||||
0x00000026,0x00000026,0x00040017,0x0000002b,0x00000006,0x00000004,0x00040020,0x0000002c,
|
||||
0x00000007,0x0000002b,0x00090019,0x0000002e,0x00000006,0x00000001,0x00000000,0x00000000,
|
||||
0x00000000,0x00000001,0x00000000,0x0003001b,0x0000002f,0x0000002e,0x00040020,0x00000030,
|
||||
0x00000000,0x0000002f,0x0004003b,0x00000030,0x00000031,0x00000000,0x00040017,0x00000033,
|
||||
0x00000006,0x00000002,0x00040020,0x00000034,0x00000001,0x00000033,0x0004003b,0x00000034,
|
||||
0x00000035,0x00000001,0x00040015,0x00000038,0x00000020,0x00000000,0x0004002b,0x00000038,
|
||||
0x00000039,0x00000003,0x00040020,0x0000003a,0x00000007,0x00000006,0x00020014,0x0000003d,
|
||||
0x00040020,0x00000041,0x00000003,0x0000002b,0x0004003b,0x00000041,0x00000042,0x00000003,
|
||||
0x0007002c,0x0000002b,0x00000043,0x00000012,0x00000012,0x00000012,0x00000012,0x0004002b,
|
||||
0x00000006,0x00000051,0x400ccccd,0x0006002c,0x00000007,0x00000052,0x00000051,0x00000051,
|
||||
0x00000051,0x0003001e,0x00000054,0x00000006,0x00040020,0x00000055,0x00000009,0x00000054,
|
||||
0x0004003b,0x00000055,0x00000056,0x00000009,0x00040015,0x00000057,0x00000020,0x00000001,
|
||||
0x0004002b,0x00000057,0x00000058,0x00000000,0x00040020,0x00000059,0x00000009,0x00000006,
|
||||
0x00040018,0x0000005d,0x00000007,0x00000003,0x0004002b,0x00000006,0x0000005e,0x3f209d49,
|
||||
0x0004002b,0x00000006,0x0000005f,0x3d8d844d,0x0004002b,0x00000006,0x00000060,0x3c86594b,
|
||||
0x0006002c,0x00000007,0x00000061,0x0000005e,0x0000005f,0x00000060,0x0004002b,0x00000006,
|
||||
0x00000062,0x3ea89a02,0x0004002b,0x00000006,0x00000063,0x3f6b645a,0x0004002b,0x00000006,
|
||||
0x00000064,0x3db43958,0x0006002c,0x00000007,0x00000065,0x00000062,0x00000063,0x00000064,
|
||||
0x0004002b,0x00000006,0x00000066,0x3d315b57,0x0004002b,0x00000006,0x00000067,0x3c3ac711,
|
||||
0x0004002b,0x00000006,0x00000068,0x3f65460b,0x0006002c,0x00000007,0x00000069,0x00000066,
|
||||
0x00000067,0x00000068,0x0006002c,0x0000005d,0x0000006a,0x00000061,0x00000065,0x00000069,
|
||||
0x0004002b,0x00000006,0x00000079,0x42c80000,0x0004002b,0x00000038,0x0000007f,0x00000000,
|
||||
0x0006002c,0x00000007,0x00000081,0x00000079,0x00000079,0x00000079,0x00050036,0x00000002,
|
||||
0x00000004,0x00000000,0x00000003,0x000200f8,0x00000005,0x0004003b,0x0000002c,0x0000002d,
|
||||
0x00000007,0x0004003b,0x00000008,0x00000045,0x00000007,0x0004003b,0x00000008,0x0000004f,
|
||||
0x00000007,0x0004003b,0x0000003a,0x0000006d,0x00000007,0x0004003b,0x0000003a,0x00000072,
|
||||
0x00000007,0x0004003b,0x0000003a,0x00000076,0x00000007,0x0004003b,0x00000008,0x0000007d,
|
||||
0x00000007,0x0004003b,0x00000008,0x00000082,0x00000007,0x0004003b,0x00000008,0x00000089,
|
||||
0x00000007,0x0004003d,0x0000002f,0x00000032,0x00000031,0x0004003d,0x00000033,0x00000036,
|
||||
0x00000035,0x00050057,0x0000002b,0x00000037,0x00000032,0x00000036,0x0003003e,0x0000002d,
|
||||
0x00000037,0x00050041,0x0000003a,0x0000003b,0x0000002d,0x00000039,0x0004003d,0x00000006,
|
||||
0x0000003c,0x0000003b,0x000500bc,0x0000003d,0x0000003e,0x0000003c,0x00000012,0x000300f7,
|
||||
0x00000040,0x00000000,0x000400fa,0x0000003e,0x0000003f,0x00000040,0x000200f8,0x0000003f,
|
||||
0x0003003e,0x00000042,0x00000043,0x000100fd,0x000200f8,0x00000040,0x0004003d,0x0000002b,
|
||||
0x00000046,0x0000002d,0x0008004f,0x00000007,0x00000047,0x00000046,0x00000046,0x00000000,
|
||||
0x00000001,0x00000002,0x00050041,0x0000003a,0x00000048,0x0000002d,0x00000039,0x0004003d,
|
||||
0x00000006,0x00000049,0x00000048,0x00060050,0x00000007,0x0000004a,0x00000049,0x00000049,
|
||||
0x00000049,0x00050088,0x00000007,0x0000004b,0x00000047,0x0000004a,0x00060050,0x00000007,
|
||||
0x0000004c,0x00000012,0x00000012,0x00000012,0x00060050,0x00000007,0x0000004d,0x00000013,
|
||||
0x00000013,0x00000013,0x0008000c,0x00000007,0x0000004e,0x00000001,0x0000002b,0x0000004b,
|
||||
0x0000004c,0x0000004d,0x0003003e,0x00000045,0x0000004e,0x0004003d,0x00000007,0x00000050,
|
||||
0x00000045,0x0007000c,0x00000007,0x00000053,0x00000001,0x0000001a,0x00000050,0x00000052,
|
||||
0x00050041,0x00000059,0x0000005a,0x00000056,0x00000058,0x0004003d,0x00000006,0x0000005b,
|
||||
0x0000005a,0x0005008e,0x00000007,0x0000005c,0x00000053,0x0000005b,0x0003003e,0x0000004f,
|
||||
0x0000005c,0x0004003d,0x00000007,0x0000006b,0x0000004f,0x00050091,0x00000007,0x0000006c,
|
||||
0x0000006a,0x0000006b,0x0003003e,0x0000004f,0x0000006c,0x00050041,0x0000003a,0x0000006e,
|
||||
0x0000002d,0x00000039,0x0004003d,0x00000006,0x0000006f,0x0000006e,0x00050083,0x00000006,
|
||||
0x00000070,0x00000013,0x0000006f,0x0007000c,0x00000006,0x00000071,0x00000001,0x0000001a,
|
||||
0x00000070,0x00000051,0x0003003e,0x0000006d,0x00000071,0x00050041,0x0000003a,0x00000073,
|
||||
0x0000002d,0x00000039,0x0004003d,0x00000006,0x00000074,0x00000073,0x000500b8,0x0000003d,
|
||||
0x00000075,0x00000074,0x00000013,0x000300f7,0x00000078,0x00000000,0x000400fa,0x00000075,
|
||||
0x00000077,0x00000087,0x000200f8,0x00000077,0x0004003d,0x00000006,0x0000007a,0x0000006d,
|
||||
0x00050085,0x00000006,0x0000007b,0x00000079,0x0000007a,0x00060050,0x00000007,0x0000007c,
|
||||
0x0000007b,0x0000007b,0x0000007b,0x0003003e,0x0000007d,0x0000007c,0x00050039,0x00000007,
|
||||
0x0000007e,0x0000000b,0x0000007d,0x00050051,0x00000006,0x00000080,0x0000007e,0x00000000,
|
||||
0x0003003e,0x00000082,0x00000081,0x00050039,0x00000007,0x00000083,0x0000000b,0x00000082,
|
||||
0x00050051,0x00000006,0x00000084,0x00000083,0x00000000,0x00050088,0x00000006,0x00000085,
|
||||
0x00000080,0x00000084,0x00050083,0x00000006,0x00000086,0x00000013,0x00000085,0x0003003e,
|
||||
0x00000076,0x00000086,0x000200f9,0x00000078,0x000200f8,0x00000087,0x0003003e,0x00000076,
|
||||
0x00000013,0x000200f9,0x00000078,0x000200f8,0x00000078,0x0004003d,0x00000006,0x00000088,
|
||||
0x00000076,0x0003003e,0x00000072,0x00000088,0x0004003d,0x00000007,0x0000008a,0x0000004f,
|
||||
0x0003003e,0x00000089,0x0000008a,0x00050039,0x00000007,0x0000008b,0x0000000b,0x00000089,
|
||||
0x0004003d,0x00000006,0x0000008c,0x00000072,0x0005008e,0x00000007,0x0000008d,0x0000008b,
|
||||
0x0000008c,0x0004003d,0x00000006,0x0000008e,0x00000072,0x00050051,0x00000006,0x0000008f,
|
||||
0x0000008d,0x00000000,0x00050051,0x00000006,0x00000090,0x0000008d,0x00000001,0x00050051,
|
||||
0x00000006,0x00000091,0x0000008d,0x00000002,0x00070050,0x0000002b,0x00000092,0x0000008f,
|
||||
0x00000090,0x00000091,0x0000008e,0x0003003e,0x00000042,0x00000092,0x000100fd,0x00010038,
|
||||
0x00050036,0x00000007,0x0000000b,0x00000000,0x00000009,0x00030037,0x00000008,0x0000000a,
|
||||
0x000200f8,0x0000000c,0x0004003b,0x00000008,0x0000000d,0x00000007,0x0004003d,0x00000007,
|
||||
0x0000000e,0x0000000a,0x00060050,0x00000007,0x00000010,0x0000000f,0x0000000f,0x0000000f,
|
||||
0x00050088,0x00000007,0x00000011,0x0000000e,0x00000010,0x00060050,0x00000007,0x00000014,
|
||||
0x00000012,0x00000012,0x00000012,0x00060050,0x00000007,0x00000015,0x00000013,0x00000013,
|
||||
0x00000013,0x0008000c,0x00000007,0x00000016,0x00000001,0x0000002b,0x00000011,0x00000014,
|
||||
0x00000015,0x0007000c,0x00000007,0x00000019,0x00000001,0x0000001a,0x00000016,0x00000018,
|
||||
0x0003003e,0x0000000d,0x00000019,0x0004003d,0x00000007,0x0000001c,0x0000000d,0x0005008e,
|
||||
0x00000007,0x0000001d,0x0000001c,0x0000001b,0x00060050,0x00000007,0x0000001e,0x0000001a,
|
||||
0x0000001a,0x0000001a,0x00050081,0x00000007,0x0000001f,0x0000001e,0x0000001d,0x0004003d,
|
||||
0x00000007,0x00000021,0x0000000d,0x0005008e,0x00000007,0x00000022,0x00000021,0x00000020,
|
||||
0x00060050,0x00000007,0x00000023,0x00000013,0x00000013,0x00000013,0x00050081,0x00000007,
|
||||
0x00000024,0x00000023,0x00000022,0x00050088,0x00000007,0x00000025,0x0000001f,0x00000024,
|
||||
0x0007000c,0x00000007,0x00000028,0x00000001,0x0000001a,0x00000025,0x00000027,0x000200fe,
|
||||
0x00000028,0x00010038
|
||||
};
|
||||
+570
-294
@@ -1,300 +1,576 @@
|
||||
// 1116.2.0
|
||||
#pragma once
|
||||
const uint32_t spv_video_frag[] = {
|
||||
0x07230203,0x00010300,0x0008000b,0x000001a8,0x00000000,0x00020011,0x00000001,0x00020011,
|
||||
0x07230203,0x00010300,0x0008000b,0x00000336,0x00000000,0x00020011,0x00000001,0x00020011,
|
||||
0x00000032,0x0006000b,0x00000001,0x4c534c47,0x6474732e,0x3035342e,0x00000000,0x0003000e,
|
||||
0x00000000,0x00000001,0x0007000f,0x00000004,0x00000004,0x6e69616d,0x00000000,0x00000010,
|
||||
0x0000019e,0x00030010,0x00000004,0x00000007,0x00030003,0x00000002,0x000001c2,0x00040005,
|
||||
0x00000004,0x6e69616d,0x00000000,0x00050005,0x00000009,0x6e727574,0x755f6465,0x00002876,
|
||||
0x00060005,0x0000000b,0x65687073,0x61636972,0x76755f6c,0x00000028,0x00030005,0x0000000e,
|
||||
0x0000006e,0x00030005,0x00000010,0x00007675,0x00040005,0x00000013,0x68737550,0x00000000,
|
||||
0x00050006,0x00000013,0x00000000,0x30776f72,0x00000000,0x00050006,0x00000013,0x00000001,
|
||||
0x31776f72,0x00000000,0x00050006,0x00000013,0x00000002,0x32776f72,0x00000000,0x00050006,
|
||||
0x00000013,0x00000003,0x61726170,0x0000736d,0x00060006,0x00000013,0x00000004,0x735f7675,
|
||||
0x656c6163,0x00000000,0x00050006,0x00000013,0x00000005,0x756a6461,0x00007473,0x00050006,
|
||||
0x00000013,0x00000006,0x77656976,0x00000000,0x00050006,0x00000013,0x00000007,0x726f6678,
|
||||
0x0000006d,0x00030005,0x00000015,0x00006370,0x00030005,0x00000039,0x00000071,0x00030005,
|
||||
0x00000068,0x0063646e,0x00030005,0x00000073,0x00000064,0x00030005,0x00000086,0x00007063,
|
||||
0x00030005,0x0000008a,0x00007073,0x00030005,0x000000a4,0x00007963,0x00030005,0x000000a8,
|
||||
0x00007973,0x00030005,0x000000c2,0x006e6f6c,0x00030005,0x000000c8,0x0074616c,0x00030005,
|
||||
0x000000dc,0x00000073,0x00030005,0x000000df,0x00007461,0x00030005,0x000000ea,0x00000079,
|
||||
0x00040005,0x000000ee,0x5f786574,0x00000079,0x00030005,0x000000fb,0x00000074,0x00040005,
|
||||
0x00000104,0x756f7261,0x0000646e,0x00030005,0x00000105,0x00007964,0x00030005,0x0000010e,
|
||||
0x00007864,0x00030005,0x0000013c,0x00000075,0x00040005,0x0000013d,0x5f786574,0x00000075,
|
||||
0x00030005,0x00000145,0x00000076,0x00040005,0x00000146,0x5f786574,0x00000076,0x00030005,
|
||||
0x00000167,0x00000063,0x00030005,0x0000016b,0x00006e73,0x00030005,0x0000016f,0x00327675,
|
||||
0x00030005,0x00000182,0x00767579,0x00030005,0x00000188,0x00626772,0x00040005,0x0000019e,
|
||||
0x6f6c6f63,0x00000072,0x00040047,0x00000010,0x0000001e,0x00000000,0x00030047,0x00000013,
|
||||
0x00000002,0x00050048,0x00000013,0x00000000,0x00000023,0x00000000,0x00050048,0x00000013,
|
||||
0x00000001,0x00000023,0x00000010,0x00050048,0x00000013,0x00000002,0x00000023,0x00000020,
|
||||
0x00050048,0x00000013,0x00000003,0x00000023,0x00000030,0x00050048,0x00000013,0x00000004,
|
||||
0x00000023,0x00000040,0x00050048,0x00000013,0x00000005,0x00000023,0x00000050,0x00050048,
|
||||
0x00000013,0x00000006,0x00000023,0x00000060,0x00050048,0x00000013,0x00000007,0x00000023,
|
||||
0x00000070,0x00040047,0x000000ee,0x00000021,0x00000000,0x00040047,0x000000ee,0x00000022,
|
||||
0x00000000,0x00040047,0x0000013d,0x00000021,0x00000001,0x00040047,0x0000013d,0x00000022,
|
||||
0x00000000,0x00040047,0x00000146,0x00000021,0x00000002,0x00040047,0x00000146,0x00000022,
|
||||
0x00000000,0x00040047,0x0000019e,0x0000001e,0x00000000,0x00020013,0x00000002,0x00030021,
|
||||
0x00000000,0x00000001,0x0007000f,0x00000004,0x00000004,0x6e69616d,0x00000000,0x00000188,
|
||||
0x0000031c,0x00030010,0x00000004,0x00000007,0x00030003,0x00000002,0x000001c2,0x00040005,
|
||||
0x00000004,0x6e69616d,0x00000000,0x00060005,0x0000000b,0x745f7170,0x696e5f6f,0x76287374,
|
||||
0x003b3366,0x00030005,0x0000000a,0x00000065,0x00060005,0x00000010,0x7374696e,0x5f6f745f,
|
||||
0x66287170,0x00003b31,0x00040005,0x0000000f,0x7374696e,0x00000000,0x00070005,0x00000013,
|
||||
0x5f676c68,0x6e5f6f74,0x28737469,0x3b336676,0x00000000,0x00030005,0x00000012,0x00000065,
|
||||
0x00070005,0x00000016,0x7374696e,0x5f6f745f,0x28337170,0x3b336676,0x00000000,0x00040005,
|
||||
0x00000015,0x7374696e,0x00000000,0x00070005,0x00000019,0x705f6f74,0x756f5f71,0x74757074,
|
||||
0x33667628,0x0000003b,0x00030005,0x00000018,0x00000065,0x00060005,0x0000001c,0x5f726468,
|
||||
0x735f6f74,0x76287264,0x003b3366,0x00030005,0x0000001b,0x00000065,0x00050005,0x00000020,
|
||||
0x6e727574,0x755f6465,0x00002876,0x00060005,0x00000022,0x65687073,0x61636972,0x76755f6c,
|
||||
0x00000028,0x00030005,0x00000024,0x00000070,0x00030005,0x00000042,0x00000079,0x00030005,
|
||||
0x00000057,0x00000073,0x00030005,0x00000071,0x00007379,0x00030005,0x00000083,0x00000079,
|
||||
0x00040005,0x0000009b,0x68737550,0x00000000,0x00050006,0x0000009b,0x00000000,0x30776f72,
|
||||
0x00000000,0x00050006,0x0000009b,0x00000001,0x31776f72,0x00000000,0x00050006,0x0000009b,
|
||||
0x00000002,0x32776f72,0x00000000,0x00050006,0x0000009b,0x00000003,0x61726170,0x0000736d,
|
||||
0x00060006,0x0000009b,0x00000004,0x735f7675,0x656c6163,0x00000000,0x00050006,0x0000009b,
|
||||
0x00000005,0x756a6461,0x00007473,0x00050006,0x0000009b,0x00000006,0x77656976,0x00000000,
|
||||
0x00050006,0x0000009b,0x00000007,0x726f6678,0x0000006d,0x00040006,0x0000009b,0x00000008,
|
||||
0x00726468,0x00050006,0x0000009b,0x00000009,0x7074756f,0x00000000,0x00030005,0x0000009d,
|
||||
0x00006370,0x00040005,0x000000bd,0x7374696e,0x00000000,0x00040005,0x000000c4,0x61726170,
|
||||
0x0000006d,0x00040005,0x000000c8,0x61726170,0x0000006d,0x00040005,0x000000eb,0x61726170,
|
||||
0x0000006d,0x00040005,0x000000f0,0x7374696e,0x00000000,0x00040005,0x000000f7,0x61726170,
|
||||
0x0000006d,0x00040005,0x000000fb,0x61726170,0x0000006d,0x00040005,0x000000ff,0x6b616570,
|
||||
0x00000000,0x00030005,0x00000103,0x00676973,0x00030005,0x00000113,0x00637273,0x00040005,
|
||||
0x00000114,0x61726170,0x0000006d,0x00030005,0x00000117,0x00003165,0x00040005,0x00000118,
|
||||
0x61726170,0x0000006d,0x00040005,0x0000011e,0x6c78616d,0x00000000,0x00040005,0x0000011f,
|
||||
0x61726170,0x0000006d,0x00030005,0x00000123,0x0000736b,0x00030005,0x00000127,0x00003265,
|
||||
0x00030005,0x0000012e,0x00000074,0x00030005,0x00000135,0x00003274,0x00030005,0x00000139,
|
||||
0x00003374,0x00040005,0x0000015d,0x61726170,0x0000006d,0x00030005,0x00000164,0x006e696c,
|
||||
0x00030005,0x00000186,0x0000006e,0x00030005,0x00000188,0x00007675,0x00030005,0x000001a3,
|
||||
0x00000071,0x00030005,0x000001d2,0x0063646e,0x00030005,0x000001da,0x00000064,0x00030005,
|
||||
0x000001ed,0x00007063,0x00030005,0x000001f1,0x00007073,0x00030005,0x0000020b,0x00007963,
|
||||
0x00030005,0x0000020f,0x00007973,0x00030005,0x00000229,0x006e6f6c,0x00030005,0x0000022f,
|
||||
0x0074616c,0x00030005,0x00000243,0x00000073,0x00030005,0x00000246,0x00007461,0x00030005,
|
||||
0x00000251,0x00000079,0x00040005,0x00000255,0x5f786574,0x00000079,0x00030005,0x00000261,
|
||||
0x00000074,0x00040005,0x0000026a,0x756f7261,0x0000646e,0x00030005,0x0000026b,0x00007964,
|
||||
0x00030005,0x00000274,0x00007864,0x00040005,0x000002a2,0x6f726863,0x0000616d,0x00040005,
|
||||
0x000002a9,0x5f786574,0x00000075,0x00040005,0x000002b3,0x5f786574,0x00000076,0x00030005,
|
||||
0x000002ba,0x00000075,0x00030005,0x000002c0,0x00000076,0x00030005,0x000002df,0x00000063,
|
||||
0x00030005,0x000002e3,0x00006e73,0x00030005,0x000002e7,0x00327675,0x00030005,0x000002fa,
|
||||
0x00767579,0x00030005,0x00000300,0x00626772,0x00040005,0x0000031c,0x6f6c6f63,0x00000072,
|
||||
0x00040005,0x0000031d,0x61726170,0x0000006d,0x00040005,0x0000032a,0x61726170,0x0000006d,
|
||||
0x00030047,0x0000009b,0x00000002,0x00050048,0x0000009b,0x00000000,0x00000023,0x00000000,
|
||||
0x00050048,0x0000009b,0x00000001,0x00000023,0x00000010,0x00050048,0x0000009b,0x00000002,
|
||||
0x00000023,0x00000020,0x00050048,0x0000009b,0x00000003,0x00000023,0x00000030,0x00050048,
|
||||
0x0000009b,0x00000004,0x00000023,0x00000040,0x00050048,0x0000009b,0x00000005,0x00000023,
|
||||
0x00000050,0x00050048,0x0000009b,0x00000006,0x00000023,0x00000060,0x00050048,0x0000009b,
|
||||
0x00000007,0x00000023,0x00000070,0x00050048,0x0000009b,0x00000008,0x00000023,0x00000080,
|
||||
0x00050048,0x0000009b,0x00000009,0x00000023,0x00000090,0x00040047,0x00000188,0x0000001e,
|
||||
0x00000000,0x00040047,0x00000255,0x00000021,0x00000000,0x00040047,0x00000255,0x00000022,
|
||||
0x00000000,0x00040047,0x000002a9,0x00000021,0x00000001,0x00040047,0x000002a9,0x00000022,
|
||||
0x00000000,0x00040047,0x000002b3,0x00000021,0x00000002,0x00040047,0x000002b3,0x00000022,
|
||||
0x00000000,0x00040047,0x0000031c,0x0000001e,0x00000000,0x00020013,0x00000002,0x00030021,
|
||||
0x00000003,0x00000002,0x00030016,0x00000006,0x00000020,0x00040017,0x00000007,0x00000006,
|
||||
0x00000002,0x00030021,0x00000008,0x00000007,0x00040020,0x0000000d,0x00000007,0x00000007,
|
||||
0x00040020,0x0000000f,0x00000001,0x00000007,0x0004003b,0x0000000f,0x00000010,0x00000001,
|
||||
0x00040017,0x00000012,0x00000006,0x00000004,0x000a001e,0x00000013,0x00000012,0x00000012,
|
||||
0x00000012,0x00000012,0x00000007,0x00000012,0x00000012,0x00000012,0x00040020,0x00000014,
|
||||
0x00000009,0x00000013,0x0004003b,0x00000014,0x00000015,0x00000009,0x00040015,0x00000016,
|
||||
0x00000020,0x00000001,0x0004002b,0x00000016,0x00000017,0x00000004,0x00040020,0x00000018,
|
||||
0x00000009,0x00000007,0x0004002b,0x00000016,0x0000001c,0x00000007,0x00040015,0x0000001d,
|
||||
0x00000020,0x00000000,0x0004002b,0x0000001d,0x0000001e,0x00000001,0x00040020,0x0000001f,
|
||||
0x00000009,0x00000006,0x0004002b,0x00000006,0x00000022,0x3f000000,0x00020014,0x00000023,
|
||||
0x0004002b,0x00000006,0x00000027,0x3f800000,0x0004002b,0x0000001d,0x00000028,0x00000000,
|
||||
0x00040020,0x00000029,0x00000007,0x00000006,0x0004002b,0x0000001d,0x0000002e,0x00000002,
|
||||
0x00040020,0x00000038,0x00000007,0x00000016,0x0004002b,0x00000016,0x0000003f,0x00000001,
|
||||
0x0004002b,0x00000016,0x0000004b,0x00000002,0x0004002b,0x00000016,0x00000058,0x00000003,
|
||||
0x0004002b,0x00000006,0x0000006d,0x40000000,0x00040017,0x00000071,0x00000006,0x00000003,
|
||||
0x00040020,0x00000072,0x00000007,0x00000071,0x0004002b,0x00000016,0x00000076,0x00000006,
|
||||
0x0004002b,0x0000001d,0x0000007a,0x00000003,0x0004002b,0x00000006,0x000000cb,0xbf800000,
|
||||
0x0004002b,0x00000006,0x000000cf,0x40c90fdb,0x0004002b,0x00000006,0x000000d3,0x40490fdb,
|
||||
0x00090019,0x000000eb,0x00000006,0x00000001,0x00000000,0x00000000,0x00000000,0x00000001,
|
||||
0x00000000,0x0003001b,0x000000ec,0x000000eb,0x00040020,0x000000ed,0x00000000,0x000000ec,
|
||||
0x0004003b,0x000000ed,0x000000ee,0x00000000,0x0004002b,0x00000006,0x000000f7,0x00000000,
|
||||
0x0004002b,0x00000016,0x000000fd,0x00000000,0x00040017,0x000000ff,0x00000016,0x00000002,
|
||||
0x0004002b,0x00000016,0x00000106,0xffffffff,0x0004002b,0x00000006,0x00000132,0x3e000000,
|
||||
0x0004003b,0x000000ed,0x0000013d,0x00000000,0x0004003b,0x000000ed,0x00000146,0x00000000,
|
||||
0x0004002b,0x00000006,0x00000154,0x3d808081,0x0004002b,0x00000006,0x00000156,0x3f950a85,
|
||||
0x0004002b,0x00000006,0x00000158,0x3f91b6db,0x0004002b,0x00000016,0x0000015f,0x00000005,
|
||||
0x00040020,0x00000189,0x00000009,0x00000012,0x00040020,0x0000019d,0x00000003,0x00000012,
|
||||
0x0004003b,0x0000019d,0x0000019e,0x00000003,0x00050036,0x00000002,0x00000004,0x00000000,
|
||||
0x00000003,0x000200f8,0x00000005,0x0004003b,0x00000029,0x000000dc,0x00000007,0x0004003b,
|
||||
0x0000000d,0x000000df,0x00000007,0x0004003b,0x0000000d,0x000000e3,0x00000007,0x0004003b,
|
||||
0x00000029,0x000000ea,0x00000007,0x0004003b,0x0000000d,0x000000fb,0x00000007,0x0004003b,
|
||||
0x00000029,0x00000104,0x00000007,0x0004003b,0x00000038,0x00000105,0x00000007,0x0004003b,
|
||||
0x00000038,0x0000010e,0x00000007,0x0004003b,0x00000029,0x0000013c,0x00000007,0x0004003b,
|
||||
0x00000029,0x00000145,0x00000007,0x0004003b,0x00000029,0x00000167,0x00000007,0x0004003b,
|
||||
0x00000029,0x0000016b,0x00000007,0x0004003b,0x0000000d,0x0000016f,0x00000007,0x0004003b,
|
||||
0x00000072,0x00000182,0x00000007,0x0004003b,0x00000072,0x00000188,0x00000007,0x00060041,
|
||||
0x0000001f,0x000000dd,0x00000015,0x00000058,0x00000028,0x0004003d,0x00000006,0x000000de,
|
||||
0x000000dd,0x0003003e,0x000000dc,0x000000de,0x00060041,0x0000001f,0x000000e0,0x00000015,
|
||||
0x00000058,0x0000007a,0x0004003d,0x00000006,0x000000e1,0x000000e0,0x000500ba,0x00000023,
|
||||
0x000000e2,0x000000e1,0x00000022,0x000300f7,0x000000e5,0x00000000,0x000400fa,0x000000e2,
|
||||
0x000000e4,0x000000e7,0x000200f8,0x000000e4,0x00040039,0x00000007,0x000000e6,0x0000000b,
|
||||
0x0003003e,0x000000e3,0x000000e6,0x000200f9,0x000000e5,0x000200f8,0x000000e7,0x00040039,
|
||||
0x00000007,0x000000e8,0x00000009,0x0003003e,0x000000e3,0x000000e8,0x000200f9,0x000000e5,
|
||||
0x000200f8,0x000000e5,0x0004003d,0x00000007,0x000000e9,0x000000e3,0x0003003e,0x000000df,
|
||||
0x000000e9,0x0004003d,0x000000ec,0x000000ef,0x000000ee,0x0004003d,0x00000007,0x000000f0,
|
||||
0x000000df,0x00050057,0x00000012,0x000000f1,0x000000ef,0x000000f0,0x00050051,0x00000006,
|
||||
0x000000f2,0x000000f1,0x00000000,0x0004003d,0x00000006,0x000000f3,0x000000dc,0x00050085,
|
||||
0x00000006,0x000000f4,0x000000f2,0x000000f3,0x0003003e,0x000000ea,0x000000f4,0x00060041,
|
||||
0x0000001f,0x000000f5,0x00000015,0x0000001c,0x0000007a,0x0004003d,0x00000006,0x000000f6,
|
||||
0x000000f5,0x000500ba,0x00000023,0x000000f8,0x000000f6,0x000000f7,0x000300f7,0x000000fa,
|
||||
0x00000000,0x000400fa,0x000000f8,0x000000f9,0x000000fa,0x000200f8,0x000000f9,0x0004003d,
|
||||
0x000000ec,0x000000fc,0x000000ee,0x00040064,0x000000eb,0x000000fe,0x000000fc,0x00050067,
|
||||
0x000000ff,0x00000100,0x000000fe,0x000000fd,0x0004006f,0x00000007,0x00000101,0x00000100,
|
||||
0x00050050,0x00000007,0x00000102,0x00000027,0x00000027,0x00050088,0x00000007,0x00000103,
|
||||
0x00000102,0x00000101,0x0003003e,0x000000fb,0x00000103,0x0003003e,0x00000104,0x000000f7,
|
||||
0x0003003e,0x00000105,0x00000106,0x000200f9,0x00000107,0x000200f8,0x00000107,0x000400f6,
|
||||
0x00000109,0x0000010a,0x00000000,0x000200f9,0x0000010b,0x000200f8,0x0000010b,0x0004003d,
|
||||
0x00000016,0x0000010c,0x00000105,0x000500b3,0x00000023,0x0000010d,0x0000010c,0x0000003f,
|
||||
0x000400fa,0x0000010d,0x00000108,0x00000109,0x000200f8,0x00000108,0x0003003e,0x0000010e,
|
||||
0x00000106,0x000200f9,0x0000010f,0x000200f8,0x0000010f,0x000400f6,0x00000111,0x00000112,
|
||||
0x00000000,0x000200f9,0x00000113,0x000200f8,0x00000113,0x0004003d,0x00000016,0x00000114,
|
||||
0x0000010e,0x000500b3,0x00000023,0x00000115,0x00000114,0x0000003f,0x000400fa,0x00000115,
|
||||
0x00000110,0x00000111,0x000200f8,0x00000110,0x0004003d,0x00000016,0x00000116,0x0000010e,
|
||||
0x000500ab,0x00000023,0x00000117,0x00000116,0x000000fd,0x0004003d,0x00000016,0x00000118,
|
||||
0x00000105,0x000500ab,0x00000023,0x00000119,0x00000118,0x000000fd,0x000500a6,0x00000023,
|
||||
0x0000011a,0x00000117,0x00000119,0x000300f7,0x0000011c,0x00000000,0x000400fa,0x0000011a,
|
||||
0x0000011b,0x0000011c,0x000200f8,0x0000011b,0x0004003d,0x000000ec,0x0000011d,0x000000ee,
|
||||
0x0004003d,0x00000007,0x0000011e,0x000000df,0x0004003d,0x00000016,0x0000011f,0x0000010e,
|
||||
0x0004006f,0x00000006,0x00000120,0x0000011f,0x0004003d,0x00000016,0x00000121,0x00000105,
|
||||
0x0004006f,0x00000006,0x00000122,0x00000121,0x00050050,0x00000007,0x00000123,0x00000120,
|
||||
0x00000122,0x0004003d,0x00000007,0x00000124,0x000000fb,0x00050085,0x00000007,0x00000125,
|
||||
0x00000123,0x00000124,0x00050081,0x00000007,0x00000126,0x0000011e,0x00000125,0x00050057,
|
||||
0x00000012,0x00000127,0x0000011d,0x00000126,0x00050051,0x00000006,0x00000128,0x00000127,
|
||||
0x00000000,0x0004003d,0x00000006,0x00000129,0x00000104,0x00050081,0x00000006,0x0000012a,
|
||||
0x00000129,0x00000128,0x0003003e,0x00000104,0x0000012a,0x000200f9,0x0000011c,0x000200f8,
|
||||
0x0000011c,0x000200f9,0x00000112,0x000200f8,0x00000112,0x0004003d,0x00000016,0x0000012b,
|
||||
0x0000010e,0x00050080,0x00000016,0x0000012c,0x0000012b,0x0000003f,0x0003003e,0x0000010e,
|
||||
0x0000012c,0x000200f9,0x0000010f,0x000200f8,0x00000111,0x000200f9,0x0000010a,0x000200f8,
|
||||
0x0000010a,0x0004003d,0x00000016,0x0000012d,0x00000105,0x00050080,0x00000016,0x0000012e,
|
||||
0x0000012d,0x0000003f,0x0003003e,0x00000105,0x0000012e,0x000200f9,0x00000107,0x000200f8,
|
||||
0x00000109,0x0004003d,0x00000006,0x0000012f,0x000000ea,0x0004003d,0x00000006,0x00000130,
|
||||
0x000000ea,0x0004003d,0x00000006,0x00000131,0x00000104,0x00050085,0x00000006,0x00000133,
|
||||
0x00000131,0x00000132,0x0004003d,0x00000006,0x00000134,0x000000dc,0x00050085,0x00000006,
|
||||
0x00000135,0x00000133,0x00000134,0x00050083,0x00000006,0x00000136,0x00000130,0x00000135,
|
||||
0x00060041,0x0000001f,0x00000137,0x00000015,0x0000001c,0x0000007a,0x0004003d,0x00000006,
|
||||
0x00000138,0x00000137,0x00050085,0x00000006,0x00000139,0x00000136,0x00000138,0x00050081,
|
||||
0x00000006,0x0000013a,0x0000012f,0x00000139,0x0008000c,0x00000006,0x0000013b,0x00000001,
|
||||
0x0000002b,0x0000013a,0x000000f7,0x00000027,0x0003003e,0x000000ea,0x0000013b,0x000200f9,
|
||||
0x000000fa,0x000200f8,0x000000fa,0x0004003d,0x000000ec,0x0000013e,0x0000013d,0x0004003d,
|
||||
0x00000007,0x0000013f,0x000000df,0x00050057,0x00000012,0x00000140,0x0000013e,0x0000013f,
|
||||
0x00050051,0x00000006,0x00000141,0x00000140,0x00000000,0x0004003d,0x00000006,0x00000142,
|
||||
0x000000dc,0x00050085,0x00000006,0x00000143,0x00000141,0x00000142,0x00050083,0x00000006,
|
||||
0x00000144,0x00000143,0x00000022,0x0003003e,0x0000013c,0x00000144,0x0004003d,0x000000ec,
|
||||
0x00000147,0x00000146,0x0004003d,0x00000007,0x00000148,0x000000df,0x00050057,0x00000012,
|
||||
0x00000149,0x00000147,0x00000148,0x00050051,0x00000006,0x0000014a,0x00000149,0x00000000,
|
||||
0x0004003d,0x00000006,0x0000014b,0x000000dc,0x00050085,0x00000006,0x0000014c,0x0000014a,
|
||||
0x0000014b,0x00050083,0x00000006,0x0000014d,0x0000014c,0x00000022,0x0003003e,0x00000145,
|
||||
0x0000014d,0x00060041,0x0000001f,0x0000014e,0x00000015,0x00000058,0x0000001e,0x0004003d,
|
||||
0x00000006,0x0000014f,0x0000014e,0x000500ba,0x00000023,0x00000150,0x0000014f,0x00000022,
|
||||
0x000300f7,0x00000152,0x00000000,0x000400fa,0x00000150,0x00000151,0x00000152,0x000200f8,
|
||||
0x00000151,0x0004003d,0x00000006,0x00000153,0x000000ea,0x00050083,0x00000006,0x00000155,
|
||||
0x00000153,0x00000154,0x00050085,0x00000006,0x00000157,0x00000155,0x00000156,0x0003003e,
|
||||
0x000000ea,0x00000157,0x0004003d,0x00000006,0x00000159,0x0000013c,0x00050085,0x00000006,
|
||||
0x0000015a,0x00000159,0x00000158,0x0003003e,0x0000013c,0x0000015a,0x0004003d,0x00000006,
|
||||
0x0000015b,0x00000145,0x00050085,0x00000006,0x0000015c,0x0000015b,0x00000158,0x0003003e,
|
||||
0x00000145,0x0000015c,0x000200f9,0x00000152,0x000200f8,0x00000152,0x0004003d,0x00000006,
|
||||
0x0000015d,0x000000ea,0x00050083,0x00000006,0x0000015e,0x0000015d,0x00000022,0x00060041,
|
||||
0x0000001f,0x00000160,0x00000015,0x0000015f,0x0000001e,0x0004003d,0x00000006,0x00000161,
|
||||
0x00000160,0x00050085,0x00000006,0x00000162,0x0000015e,0x00000161,0x00050081,0x00000006,
|
||||
0x00000163,0x00000162,0x00000022,0x00060041,0x0000001f,0x00000164,0x00000015,0x0000015f,
|
||||
0x00000028,0x0004003d,0x00000006,0x00000165,0x00000164,0x00050081,0x00000006,0x00000166,
|
||||
0x00000163,0x00000165,0x0003003e,0x000000ea,0x00000166,0x00060041,0x0000001f,0x00000168,
|
||||
0x00000015,0x00000058,0x0000002e,0x0004003d,0x00000006,0x00000169,0x00000168,0x0006000c,
|
||||
0x00000006,0x0000016a,0x00000001,0x0000000e,0x00000169,0x0003003e,0x00000167,0x0000016a,
|
||||
0x00060041,0x0000001f,0x0000016c,0x00000015,0x00000058,0x0000002e,0x0004003d,0x00000006,
|
||||
0x0000016d,0x0000016c,0x0006000c,0x00000006,0x0000016e,0x00000001,0x0000000d,0x0000016d,
|
||||
0x0003003e,0x0000016b,0x0000016e,0x0004003d,0x00000006,0x00000170,0x0000013c,0x0004003d,
|
||||
0x00000006,0x00000171,0x00000167,0x00050085,0x00000006,0x00000172,0x00000170,0x00000171,
|
||||
0x0004003d,0x00000006,0x00000173,0x00000145,0x0004003d,0x00000006,0x00000174,0x0000016b,
|
||||
0x00050085,0x00000006,0x00000175,0x00000173,0x00000174,0x00050083,0x00000006,0x00000176,
|
||||
0x00000172,0x00000175,0x0004003d,0x00000006,0x00000177,0x0000013c,0x0004003d,0x00000006,
|
||||
0x00000178,0x0000016b,0x00050085,0x00000006,0x00000179,0x00000177,0x00000178,0x0004003d,
|
||||
0x00000006,0x0000017a,0x00000145,0x0004003d,0x00000006,0x0000017b,0x00000167,0x00050085,
|
||||
0x00000006,0x0000017c,0x0000017a,0x0000017b,0x00050081,0x00000006,0x0000017d,0x00000179,
|
||||
0x0000017c,0x00050050,0x00000007,0x0000017e,0x00000176,0x0000017d,0x00060041,0x0000001f,
|
||||
0x0000017f,0x00000015,0x0000015f,0x0000002e,0x0004003d,0x00000006,0x00000180,0x0000017f,
|
||||
0x0005008e,0x00000007,0x00000181,0x0000017e,0x00000180,0x0003003e,0x0000016f,0x00000181,
|
||||
0x0004003d,0x00000006,0x00000183,0x000000ea,0x0004003d,0x00000007,0x00000184,0x0000016f,
|
||||
0x00050051,0x00000006,0x00000185,0x00000184,0x00000000,0x00050051,0x00000006,0x00000186,
|
||||
0x00000184,0x00000001,0x00060050,0x00000071,0x00000187,0x00000183,0x00000185,0x00000186,
|
||||
0x0003003e,0x00000182,0x00000187,0x00050041,0x00000189,0x0000018a,0x00000015,0x000000fd,
|
||||
0x0004003d,0x00000012,0x0000018b,0x0000018a,0x0008004f,0x00000071,0x0000018c,0x0000018b,
|
||||
0x0000018b,0x00000000,0x00000001,0x00000002,0x0004003d,0x00000071,0x0000018d,0x00000182,
|
||||
0x00050094,0x00000006,0x0000018e,0x0000018c,0x0000018d,0x00050041,0x00000189,0x0000018f,
|
||||
0x00000015,0x0000003f,0x0004003d,0x00000012,0x00000190,0x0000018f,0x0008004f,0x00000071,
|
||||
0x00000191,0x00000190,0x00000190,0x00000000,0x00000001,0x00000002,0x0004003d,0x00000071,
|
||||
0x00000192,0x00000182,0x00050094,0x00000006,0x00000193,0x00000191,0x00000192,0x00050041,
|
||||
0x00000189,0x00000194,0x00000015,0x0000004b,0x0004003d,0x00000012,0x00000195,0x00000194,
|
||||
0x0008004f,0x00000071,0x00000196,0x00000195,0x00000195,0x00000000,0x00000001,0x00000002,
|
||||
0x0004003d,0x00000071,0x00000197,0x00000182,0x00050094,0x00000006,0x00000198,0x00000196,
|
||||
0x00000197,0x00060050,0x00000071,0x00000199,0x0000018e,0x00000193,0x00000198,0x00060050,
|
||||
0x00000071,0x0000019a,0x000000f7,0x000000f7,0x000000f7,0x00060050,0x00000071,0x0000019b,
|
||||
0x00000027,0x00000027,0x00000027,0x0008000c,0x00000071,0x0000019c,0x00000001,0x0000002b,
|
||||
0x00000199,0x0000019a,0x0000019b,0x0003003e,0x00000188,0x0000019c,0x0004003d,0x00000071,
|
||||
0x0000019f,0x00000188,0x00060041,0x0000001f,0x000001a0,0x00000015,0x0000015f,0x0000007a,
|
||||
0x0004003d,0x00000006,0x000001a1,0x000001a0,0x00060050,0x00000071,0x000001a2,0x000001a1,
|
||||
0x000001a1,0x000001a1,0x0007000c,0x00000071,0x000001a3,0x00000001,0x0000001a,0x0000019f,
|
||||
0x000001a2,0x00050051,0x00000006,0x000001a4,0x000001a3,0x00000000,0x00050051,0x00000006,
|
||||
0x000001a5,0x000001a3,0x00000001,0x00050051,0x00000006,0x000001a6,0x000001a3,0x00000002,
|
||||
0x00070050,0x00000012,0x000001a7,0x000001a4,0x000001a5,0x000001a6,0x00000027,0x0003003e,
|
||||
0x0000019e,0x000001a7,0x000100fd,0x00010038,0x00050036,0x00000007,0x00000009,0x00000000,
|
||||
0x00000008,0x000200f8,0x0000000a,0x0004003b,0x0000000d,0x0000000e,0x00000007,0x0004003b,
|
||||
0x00000038,0x00000039,0x00000007,0x0004003d,0x00000007,0x00000011,0x00000010,0x00050041,
|
||||
0x00000018,0x00000019,0x00000015,0x00000017,0x0004003d,0x00000007,0x0000001a,0x00000019,
|
||||
0x00050088,0x00000007,0x0000001b,0x00000011,0x0000001a,0x0003003e,0x0000000e,0x0000001b,
|
||||
0x00060041,0x0000001f,0x00000020,0x00000015,0x0000001c,0x0000001e,0x0004003d,0x00000006,
|
||||
0x00000021,0x00000020,0x000500ba,0x00000023,0x00000024,0x00000021,0x00000022,0x000300f7,
|
||||
0x00000026,0x00000000,0x000400fa,0x00000024,0x00000025,0x00000026,0x000200f8,0x00000025,
|
||||
0x00050041,0x00000029,0x0000002a,0x0000000e,0x00000028,0x0004003d,0x00000006,0x0000002b,
|
||||
0x0000002a,0x00050083,0x00000006,0x0000002c,0x00000027,0x0000002b,0x00050041,0x00000029,
|
||||
0x0000002d,0x0000000e,0x00000028,0x0003003e,0x0000002d,0x0000002c,0x000200f9,0x00000026,
|
||||
0x000200f8,0x00000026,0x00060041,0x0000001f,0x0000002f,0x00000015,0x0000001c,0x0000002e,
|
||||
0x0004003d,0x00000006,0x00000030,0x0000002f,0x000500ba,0x00000023,0x00000031,0x00000030,
|
||||
0x00000022,0x000300f7,0x00000033,0x00000000,0x000400fa,0x00000031,0x00000032,0x00000033,
|
||||
0x000200f8,0x00000032,0x00050041,0x00000029,0x00000034,0x0000000e,0x0000001e,0x0004003d,
|
||||
0x00000006,0x00000035,0x00000034,0x00050083,0x00000006,0x00000036,0x00000027,0x00000035,
|
||||
0x00050041,0x00000029,0x00000037,0x0000000e,0x0000001e,0x0003003e,0x00000037,0x00000036,
|
||||
0x000200f9,0x00000033,0x000200f8,0x00000033,0x00060041,0x0000001f,0x0000003a,0x00000015,
|
||||
0x0000001c,0x00000028,0x0004003d,0x00000006,0x0000003b,0x0000003a,0x00050081,0x00000006,
|
||||
0x0000003c,0x0000003b,0x00000022,0x0004006e,0x00000016,0x0000003d,0x0000003c,0x0003003e,
|
||||
0x00000039,0x0000003d,0x0004003d,0x00000016,0x0000003e,0x00000039,0x000500aa,0x00000023,
|
||||
0x00000040,0x0000003e,0x0000003f,0x000300f7,0x00000042,0x00000000,0x000400fa,0x00000040,
|
||||
0x00000041,0x00000049,0x000200f8,0x00000041,0x00050041,0x00000029,0x00000043,0x0000000e,
|
||||
0x0000001e,0x0004003d,0x00000006,0x00000044,0x00000043,0x00050041,0x00000029,0x00000045,
|
||||
0x0000000e,0x00000028,0x0004003d,0x00000006,0x00000046,0x00000045,0x00050083,0x00000006,
|
||||
0x00000047,0x00000027,0x00000046,0x00050050,0x00000007,0x00000048,0x00000044,0x00000047,
|
||||
0x0003003e,0x0000000e,0x00000048,0x000200f9,0x00000042,0x000200f8,0x00000049,0x0004003d,
|
||||
0x00000016,0x0000004a,0x00000039,0x000500aa,0x00000023,0x0000004c,0x0000004a,0x0000004b,
|
||||
0x000300f7,0x0000004e,0x00000000,0x000400fa,0x0000004c,0x0000004d,0x00000056,0x000200f8,
|
||||
0x0000004d,0x00050041,0x00000029,0x0000004f,0x0000000e,0x00000028,0x0004003d,0x00000006,
|
||||
0x00000050,0x0000004f,0x00050083,0x00000006,0x00000051,0x00000027,0x00000050,0x00050041,
|
||||
0x00000029,0x00000052,0x0000000e,0x0000001e,0x0004003d,0x00000006,0x00000053,0x00000052,
|
||||
0x00050083,0x00000006,0x00000054,0x00000027,0x00000053,0x00050050,0x00000007,0x00000055,
|
||||
0x00000051,0x00000054,0x0003003e,0x0000000e,0x00000055,0x000200f9,0x0000004e,0x000200f8,
|
||||
0x00000056,0x0004003d,0x00000016,0x00000057,0x00000039,0x000500aa,0x00000023,0x00000059,
|
||||
0x00000057,0x00000058,0x000300f7,0x0000005b,0x00000000,0x000400fa,0x00000059,0x0000005a,
|
||||
0x0000005b,0x000200f8,0x0000005a,0x00050041,0x00000029,0x0000005c,0x0000000e,0x0000001e,
|
||||
0x0004003d,0x00000006,0x0000005d,0x0000005c,0x00050083,0x00000006,0x0000005e,0x00000027,
|
||||
0x0000005d,0x00050041,0x00000029,0x0000005f,0x0000000e,0x00000028,0x0004003d,0x00000006,
|
||||
0x00000060,0x0000005f,0x00050050,0x00000007,0x00000061,0x0000005e,0x00000060,0x0003003e,
|
||||
0x0000000e,0x00000061,0x000200f9,0x0000005b,0x000200f8,0x0000005b,0x000200f9,0x0000004e,
|
||||
0x000200f8,0x0000004e,0x000200f9,0x00000042,0x000200f8,0x00000042,0x0004003d,0x00000007,
|
||||
0x00000062,0x0000000e,0x00050041,0x00000018,0x00000063,0x00000015,0x00000017,0x0004003d,
|
||||
0x00000007,0x00000064,0x00000063,0x00050085,0x00000007,0x00000065,0x00000062,0x00000064,
|
||||
0x000200fe,0x00000065,0x00010038,0x00050036,0x00000007,0x0000000b,0x00000000,0x00000008,
|
||||
0x000200f8,0x0000000c,0x0004003b,0x0000000d,0x00000068,0x00000007,0x0004003b,0x00000072,
|
||||
0x00000073,0x00000007,0x0004003b,0x00000029,0x00000086,0x00000007,0x0004003b,0x00000029,
|
||||
0x0000008a,0x00000007,0x0004003b,0x00000029,0x000000a4,0x00000007,0x0004003b,0x00000029,
|
||||
0x000000a8,0x00000007,0x0004003b,0x00000029,0x000000c2,0x00000007,0x0004003b,0x00000029,
|
||||
0x000000c8,0x00000007,0x0004003d,0x00000007,0x00000069,0x00000010,0x00050041,0x00000018,
|
||||
0x0000006a,0x00000015,0x00000017,0x0004003d,0x00000007,0x0000006b,0x0000006a,0x00050088,
|
||||
0x00000007,0x0000006c,0x00000069,0x0000006b,0x0005008e,0x00000007,0x0000006e,0x0000006c,
|
||||
0x0000006d,0x00050050,0x00000007,0x0000006f,0x00000027,0x00000027,0x00050083,0x00000007,
|
||||
0x00000070,0x0000006e,0x0000006f,0x0003003e,0x00000068,0x00000070,0x00050041,0x00000029,
|
||||
0x00000074,0x00000068,0x00000028,0x0004003d,0x00000006,0x00000075,0x00000074,0x00060041,
|
||||
0x0000001f,0x00000077,0x00000015,0x00000076,0x0000002e,0x0004003d,0x00000006,0x00000078,
|
||||
0x00000077,0x00050085,0x00000006,0x00000079,0x00000075,0x00000078,0x00060041,0x0000001f,
|
||||
0x0000007b,0x00000015,0x00000076,0x0000007a,0x0004003d,0x00000006,0x0000007c,0x0000007b,
|
||||
0x00050085,0x00000006,0x0000007d,0x00000079,0x0000007c,0x00050041,0x00000029,0x0000007e,
|
||||
0x00000068,0x0000001e,0x0004003d,0x00000006,0x0000007f,0x0000007e,0x0004007f,0x00000006,
|
||||
0x00000080,0x0000007f,0x00060041,0x0000001f,0x00000081,0x00000015,0x00000076,0x0000002e,
|
||||
0x0004003d,0x00000006,0x00000082,0x00000081,0x00050085,0x00000006,0x00000083,0x00000080,
|
||||
0x00000082,0x00060050,0x00000071,0x00000084,0x0000007d,0x00000083,0x00000027,0x0006000c,
|
||||
0x00000071,0x00000085,0x00000001,0x00000045,0x00000084,0x0003003e,0x00000073,0x00000085,
|
||||
0x00060041,0x0000001f,0x00000087,0x00000015,0x00000076,0x0000001e,0x0004003d,0x00000006,
|
||||
0x00000088,0x00000087,0x0006000c,0x00000006,0x00000089,0x00000001,0x0000000e,0x00000088,
|
||||
0x0003003e,0x00000086,0x00000089,0x00060041,0x0000001f,0x0000008b,0x00000015,0x00000076,
|
||||
0x0000001e,0x0004003d,0x00000006,0x0000008c,0x0000008b,0x0006000c,0x00000006,0x0000008d,
|
||||
0x00000001,0x0000000d,0x0000008c,0x0003003e,0x0000008a,0x0000008d,0x00050041,0x00000029,
|
||||
0x0000008e,0x00000073,0x00000028,0x0004003d,0x00000006,0x0000008f,0x0000008e,0x00050041,
|
||||
0x00000029,0x00000090,0x00000073,0x0000001e,0x0004003d,0x00000006,0x00000091,0x00000090,
|
||||
0x0004003d,0x00000006,0x00000092,0x00000086,0x00050085,0x00000006,0x00000093,0x00000091,
|
||||
0x00000092,0x00050041,0x00000029,0x00000094,0x00000073,0x0000002e,0x0004003d,0x00000006,
|
||||
0x00000095,0x00000094,0x0004003d,0x00000006,0x00000096,0x0000008a,0x00050085,0x00000006,
|
||||
0x00000097,0x00000095,0x00000096,0x00050081,0x00000006,0x00000098,0x00000093,0x00000097,
|
||||
0x00050041,0x00000029,0x00000099,0x00000073,0x0000001e,0x0004003d,0x00000006,0x0000009a,
|
||||
0x00000099,0x0004007f,0x00000006,0x0000009b,0x0000009a,0x0004003d,0x00000006,0x0000009c,
|
||||
0x0000008a,0x00050085,0x00000006,0x0000009d,0x0000009b,0x0000009c,0x00050041,0x00000029,
|
||||
0x0000009e,0x00000073,0x0000002e,0x0004003d,0x00000006,0x0000009f,0x0000009e,0x0004003d,
|
||||
0x00000006,0x000000a0,0x00000086,0x00050085,0x00000006,0x000000a1,0x0000009f,0x000000a0,
|
||||
0x00050081,0x00000006,0x000000a2,0x0000009d,0x000000a1,0x00060050,0x00000071,0x000000a3,
|
||||
0x0000008f,0x00000098,0x000000a2,0x0003003e,0x00000073,0x000000a3,0x00060041,0x0000001f,
|
||||
0x000000a5,0x00000015,0x00000076,0x00000028,0x0004003d,0x00000006,0x000000a6,0x000000a5,
|
||||
0x0006000c,0x00000006,0x000000a7,0x00000001,0x0000000e,0x000000a6,0x0003003e,0x000000a4,
|
||||
0x000000a7,0x00060041,0x0000001f,0x000000a9,0x00000015,0x00000076,0x00000028,0x0004003d,
|
||||
0x00000006,0x000000aa,0x000000a9,0x0006000c,0x00000006,0x000000ab,0x00000001,0x0000000d,
|
||||
0x000000aa,0x0003003e,0x000000a8,0x000000ab,0x00050041,0x00000029,0x000000ac,0x00000073,
|
||||
0x00000028,0x0004003d,0x00000006,0x000000ad,0x000000ac,0x0004003d,0x00000006,0x000000ae,
|
||||
0x000000a4,0x00050085,0x00000006,0x000000af,0x000000ad,0x000000ae,0x00050041,0x00000029,
|
||||
0x000000b0,0x00000073,0x0000002e,0x0004003d,0x00000006,0x000000b1,0x000000b0,0x0004003d,
|
||||
0x00000006,0x000000b2,0x000000a8,0x00050085,0x00000006,0x000000b3,0x000000b1,0x000000b2,
|
||||
0x00050081,0x00000006,0x000000b4,0x000000af,0x000000b3,0x00050041,0x00000029,0x000000b5,
|
||||
0x00000073,0x0000001e,0x0004003d,0x00000006,0x000000b6,0x000000b5,0x00050041,0x00000029,
|
||||
0x000000b7,0x00000073,0x00000028,0x0004003d,0x00000006,0x000000b8,0x000000b7,0x0004007f,
|
||||
0x00000006,0x000000b9,0x000000b8,0x0004003d,0x00000006,0x000000ba,0x000000a8,0x00050085,
|
||||
0x00000006,0x000000bb,0x000000b9,0x000000ba,0x00050041,0x00000029,0x000000bc,0x00000073,
|
||||
0x0000002e,0x0004003d,0x00000006,0x000000bd,0x000000bc,0x0004003d,0x00000006,0x000000be,
|
||||
0x000000a4,0x00050085,0x00000006,0x000000bf,0x000000bd,0x000000be,0x00050081,0x00000006,
|
||||
0x000000c0,0x000000bb,0x000000bf,0x00060050,0x00000071,0x000000c1,0x000000b4,0x000000b6,
|
||||
0x000000c0,0x0003003e,0x00000073,0x000000c1,0x00050041,0x00000029,0x000000c3,0x00000073,
|
||||
0x00000028,0x0004003d,0x00000006,0x000000c4,0x000000c3,0x00050041,0x00000029,0x000000c5,
|
||||
0x00000073,0x0000002e,0x0004003d,0x00000006,0x000000c6,0x000000c5,0x0007000c,0x00000006,
|
||||
0x000000c7,0x00000001,0x00000019,0x000000c4,0x000000c6,0x0003003e,0x000000c2,0x000000c7,
|
||||
0x00050041,0x00000029,0x000000c9,0x00000073,0x0000001e,0x0004003d,0x00000006,0x000000ca,
|
||||
0x000000c9,0x0008000c,0x00000006,0x000000cc,0x00000001,0x0000002b,0x000000ca,0x000000cb,
|
||||
0x00000027,0x0006000c,0x00000006,0x000000cd,0x00000001,0x00000010,0x000000cc,0x0003003e,
|
||||
0x000000c8,0x000000cd,0x0004003d,0x00000006,0x000000ce,0x000000c2,0x00050088,0x00000006,
|
||||
0x000000d0,0x000000ce,0x000000cf,0x00050081,0x00000006,0x000000d1,0x000000d0,0x00000022,
|
||||
0x0004003d,0x00000006,0x000000d2,0x000000c8,0x00050088,0x00000006,0x000000d4,0x000000d2,
|
||||
0x000000d3,0x00050083,0x00000006,0x000000d5,0x00000022,0x000000d4,0x00050050,0x00000007,
|
||||
0x000000d6,0x000000d1,0x000000d5,0x00050041,0x00000018,0x000000d7,0x00000015,0x00000017,
|
||||
0x0004003d,0x00000007,0x000000d8,0x000000d7,0x00050085,0x00000007,0x000000d9,0x000000d6,
|
||||
0x000000d8,0x000200fe,0x000000d9,0x00010038
|
||||
0x00000003,0x00040020,0x00000008,0x00000007,0x00000007,0x00040021,0x00000009,0x00000007,
|
||||
0x00000008,0x00040020,0x0000000d,0x00000007,0x00000006,0x00040021,0x0000000e,0x00000006,
|
||||
0x0000000d,0x00040017,0x0000001e,0x00000006,0x00000002,0x00030021,0x0000001f,0x0000001e,
|
||||
0x0004002b,0x00000006,0x00000026,0x00000000,0x0004002b,0x00000006,0x00000027,0x3f800000,
|
||||
0x0004002b,0x00000006,0x0000002b,0x3c4fcdac,0x0006002c,0x00000007,0x0000002c,0x0000002b,
|
||||
0x0000002b,0x0000002b,0x0004002b,0x00000006,0x0000002e,0x461c4000,0x0004002b,0x00000006,
|
||||
0x00000030,0x3f560000,0x0004002b,0x00000006,0x00000035,0x4196d000,0x0004002b,0x00000006,
|
||||
0x00000036,0x41958000,0x0004002b,0x00000006,0x0000003c,0x40c8e06b,0x0006002c,0x00000007,
|
||||
0x0000003d,0x0000003c,0x0000003c,0x0000003c,0x0004002b,0x00000006,0x00000046,0x3e232000,
|
||||
0x0004002b,0x00000006,0x0000004f,0x429db000,0x0004002b,0x00000006,0x0000005b,0x40400000,
|
||||
0x0004002b,0x00000006,0x0000005f,0x3f0f564f,0x0004002b,0x00000006,0x00000062,0x3e371ff0,
|
||||
0x0004002b,0x00000006,0x00000066,0x3e91c020,0x0004002b,0x00000006,0x00000069,0x41400000,
|
||||
0x0004002b,0x00000006,0x0000006c,0x3f000000,0x0006002c,0x00000007,0x0000006d,0x0000006c,
|
||||
0x0000006c,0x0000006c,0x0004002b,0x00000006,0x00000073,0x3e86809d,0x0004002b,0x00000006,
|
||||
0x00000074,0x3f2d9168,0x0004002b,0x00000006,0x00000075,0x3d72e48f,0x0006002c,0x00000007,
|
||||
0x00000076,0x00000073,0x00000074,0x00000075,0x0004002b,0x00000006,0x00000078,0x358637bd,
|
||||
0x0004002b,0x00000006,0x0000007a,0x447a0000,0x0004002b,0x00000006,0x0000007c,0x3e4ccccd,
|
||||
0x0006002c,0x00000007,0x0000008a,0x00000046,0x00000046,0x00000046,0x0006002c,0x00000007,
|
||||
0x00000095,0x0000004f,0x0000004f,0x0000004f,0x00020014,0x00000099,0x00040017,0x0000009a,
|
||||
0x00000006,0x00000004,0x000c001e,0x0000009b,0x0000009a,0x0000009a,0x0000009a,0x0000009a,
|
||||
0x0000001e,0x0000009a,0x0000009a,0x0000009a,0x0000009a,0x0000009a,0x00040020,0x0000009c,
|
||||
0x00000009,0x0000009b,0x0004003b,0x0000009c,0x0000009d,0x00000009,0x00040015,0x0000009e,
|
||||
0x00000020,0x00000001,0x0004002b,0x0000009e,0x0000009f,0x00000008,0x00040015,0x000000a0,
|
||||
0x00000020,0x00000000,0x0004002b,0x000000a0,0x000000a1,0x00000000,0x00040020,0x000000a2,
|
||||
0x00000009,0x00000006,0x0004002b,0x00000006,0x000000aa,0x3fc00000,0x0004002b,0x000000a0,
|
||||
0x000000af,0x00000002,0x0004002b,0x00000006,0x000000d1,0x4019999a,0x0006002c,0x00000007,
|
||||
0x000000d2,0x000000d1,0x000000d1,0x000000d1,0x0004002b,0x00000006,0x000000d4,0x434b0000,
|
||||
0x00040018,0x000000db,0x00000007,0x00000003,0x0004002b,0x00000006,0x000000dc,0x3f209d49,
|
||||
0x0004002b,0x00000006,0x000000dd,0x3d8d844d,0x0004002b,0x00000006,0x000000de,0x3c86594b,
|
||||
0x0006002c,0x00000007,0x000000df,0x000000dc,0x000000dd,0x000000de,0x0004002b,0x00000006,
|
||||
0x000000e0,0x3ea89a02,0x0004002b,0x00000006,0x000000e1,0x3f6b645a,0x0004002b,0x00000006,
|
||||
0x000000e2,0x3db43958,0x0006002c,0x00000007,0x000000e3,0x000000e0,0x000000e1,0x000000e2,
|
||||
0x0004002b,0x00000006,0x000000e4,0x3d315b57,0x0004002b,0x00000006,0x000000e5,0x3c3ac711,
|
||||
0x0004002b,0x00000006,0x000000e6,0x3f65460b,0x0006002c,0x00000007,0x000000e7,0x000000e4,
|
||||
0x000000e5,0x000000e6,0x0006002c,0x000000db,0x000000e8,0x000000df,0x000000e3,0x000000e7,
|
||||
0x0004002b,0x000000a0,0x00000100,0x00000001,0x0004002b,0x00000006,0x0000013d,0x40000000,
|
||||
0x0004002b,0x00000006,0x00000150,0xc0000000,0x0004002b,0x00000006,0x0000016d,0x3fd48b44,
|
||||
0x0004002b,0x00000006,0x0000016e,0xbdff2e49,0x0004002b,0x00000006,0x0000016f,0xbc95182b,
|
||||
0x0006002c,0x00000007,0x00000170,0x0000016d,0x0000016e,0x0000016f,0x0004002b,0x00000006,
|
||||
0x00000171,0xbf166cf4,0x0004002b,0x00000006,0x00000172,0x3f9102de,0x0004002b,0x00000006,
|
||||
0x00000173,0xbdce075f,0x0006002c,0x00000007,0x00000174,0x00000171,0x00000172,0x00000173,
|
||||
0x0004002b,0x00000006,0x00000175,0xbd95182b,0x0004002b,0x00000006,0x00000176,0xbc07fcb9,
|
||||
0x0004002b,0x00000006,0x00000177,0x3f8f3190,0x0006002c,0x00000007,0x00000178,0x00000175,
|
||||
0x00000176,0x00000177,0x0006002c,0x000000db,0x00000179,0x00000170,0x00000174,0x00000178,
|
||||
0x0004002b,0x00000006,0x00000180,0x3ed55555,0x0006002c,0x00000007,0x00000181,0x00000180,
|
||||
0x00000180,0x00000180,0x00040020,0x00000185,0x00000007,0x0000001e,0x00040020,0x00000187,
|
||||
0x00000001,0x0000001e,0x0004003b,0x00000187,0x00000188,0x00000001,0x0004002b,0x0000009e,
|
||||
0x0000018a,0x00000004,0x00040020,0x0000018b,0x00000009,0x0000001e,0x0004002b,0x0000009e,
|
||||
0x0000018f,0x00000007,0x00040020,0x000001a2,0x00000007,0x0000009e,0x0004002b,0x0000009e,
|
||||
0x000001a9,0x00000001,0x0004002b,0x0000009e,0x000001b5,0x00000002,0x0004002b,0x0000009e,
|
||||
0x000001c2,0x00000003,0x0004002b,0x0000009e,0x000001dd,0x00000006,0x0004002b,0x000000a0,
|
||||
0x000001e1,0x00000003,0x0004002b,0x00000006,0x00000232,0xbf800000,0x0004002b,0x00000006,
|
||||
0x00000236,0x40c90fdb,0x0004002b,0x00000006,0x0000023a,0x40490fdb,0x00090019,0x00000252,
|
||||
0x00000006,0x00000001,0x00000000,0x00000000,0x00000000,0x00000001,0x00000000,0x0003001b,
|
||||
0x00000253,0x00000252,0x00040020,0x00000254,0x00000000,0x00000253,0x0004003b,0x00000254,
|
||||
0x00000255,0x00000000,0x0004002b,0x0000009e,0x00000263,0x00000000,0x00040017,0x00000265,
|
||||
0x0000009e,0x00000002,0x0004002b,0x0000009e,0x0000026c,0xffffffff,0x0004002b,0x00000006,
|
||||
0x00000298,0x3e000000,0x0004003b,0x00000254,0x000002a9,0x00000000,0x0004003b,0x00000254,
|
||||
0x000002b3,0x00000000,0x0004002b,0x00000006,0x000002cc,0x3d808081,0x0004002b,0x00000006,
|
||||
0x000002ce,0x3f950a85,0x0004002b,0x00000006,0x000002d0,0x3f91b6db,0x0004002b,0x0000009e,
|
||||
0x000002d7,0x00000005,0x00040020,0x00000301,0x00000009,0x0000009a,0x0004002b,0x0000009e,
|
||||
0x00000315,0x00000009,0x00040020,0x0000031b,0x00000003,0x0000009a,0x0004003b,0x0000031b,
|
||||
0x0000031c,0x00000003,0x00050036,0x00000002,0x00000004,0x00000000,0x00000003,0x000200f8,
|
||||
0x00000005,0x0004003b,0x0000000d,0x00000243,0x00000007,0x0004003b,0x00000185,0x00000246,
|
||||
0x00000007,0x0004003b,0x00000185,0x0000024a,0x00000007,0x0004003b,0x0000000d,0x00000251,
|
||||
0x00000007,0x0004003b,0x00000185,0x00000261,0x00000007,0x0004003b,0x0000000d,0x0000026a,
|
||||
0x00000007,0x0004003b,0x000001a2,0x0000026b,0x00000007,0x0004003b,0x000001a2,0x00000274,
|
||||
0x00000007,0x0004003b,0x00000185,0x000002a2,0x00000007,0x0004003b,0x00000185,0x000002a6,
|
||||
0x00000007,0x0004003b,0x0000000d,0x000002ba,0x00000007,0x0004003b,0x0000000d,0x000002c0,
|
||||
0x00000007,0x0004003b,0x0000000d,0x000002df,0x00000007,0x0004003b,0x0000000d,0x000002e3,
|
||||
0x00000007,0x0004003b,0x00000185,0x000002e7,0x00000007,0x0004003b,0x00000008,0x000002fa,
|
||||
0x00000007,0x0004003b,0x00000008,0x00000300,0x00000007,0x0004003b,0x00000008,0x0000031d,
|
||||
0x00000007,0x0004003b,0x00000008,0x0000032a,0x00000007,0x00060041,0x000000a2,0x00000244,
|
||||
0x0000009d,0x000001c2,0x000000a1,0x0004003d,0x00000006,0x00000245,0x00000244,0x0003003e,
|
||||
0x00000243,0x00000245,0x00060041,0x000000a2,0x00000247,0x0000009d,0x000001c2,0x000001e1,
|
||||
0x0004003d,0x00000006,0x00000248,0x00000247,0x000500ba,0x00000099,0x00000249,0x00000248,
|
||||
0x0000006c,0x000300f7,0x0000024c,0x00000000,0x000400fa,0x00000249,0x0000024b,0x0000024e,
|
||||
0x000200f8,0x0000024b,0x00040039,0x0000001e,0x0000024d,0x00000022,0x0003003e,0x0000024a,
|
||||
0x0000024d,0x000200f9,0x0000024c,0x000200f8,0x0000024e,0x00040039,0x0000001e,0x0000024f,
|
||||
0x00000020,0x0003003e,0x0000024a,0x0000024f,0x000200f9,0x0000024c,0x000200f8,0x0000024c,
|
||||
0x0004003d,0x0000001e,0x00000250,0x0000024a,0x0003003e,0x00000246,0x00000250,0x0004003d,
|
||||
0x00000253,0x00000256,0x00000255,0x0004003d,0x0000001e,0x00000257,0x00000246,0x00050057,
|
||||
0x0000009a,0x00000258,0x00000256,0x00000257,0x00050051,0x00000006,0x00000259,0x00000258,
|
||||
0x00000000,0x0004003d,0x00000006,0x0000025a,0x00000243,0x00050085,0x00000006,0x0000025b,
|
||||
0x00000259,0x0000025a,0x0003003e,0x00000251,0x0000025b,0x00060041,0x000000a2,0x0000025c,
|
||||
0x0000009d,0x0000018f,0x000001e1,0x0004003d,0x00000006,0x0000025d,0x0000025c,0x000500ba,
|
||||
0x00000099,0x0000025e,0x0000025d,0x00000026,0x000300f7,0x00000260,0x00000000,0x000400fa,
|
||||
0x0000025e,0x0000025f,0x00000260,0x000200f8,0x0000025f,0x0004003d,0x00000253,0x00000262,
|
||||
0x00000255,0x00040064,0x00000252,0x00000264,0x00000262,0x00050067,0x00000265,0x00000266,
|
||||
0x00000264,0x00000263,0x0004006f,0x0000001e,0x00000267,0x00000266,0x00050050,0x0000001e,
|
||||
0x00000268,0x00000027,0x00000027,0x00050088,0x0000001e,0x00000269,0x00000268,0x00000267,
|
||||
0x0003003e,0x00000261,0x00000269,0x0003003e,0x0000026a,0x00000026,0x0003003e,0x0000026b,
|
||||
0x0000026c,0x000200f9,0x0000026d,0x000200f8,0x0000026d,0x000400f6,0x0000026f,0x00000270,
|
||||
0x00000000,0x000200f9,0x00000271,0x000200f8,0x00000271,0x0004003d,0x0000009e,0x00000272,
|
||||
0x0000026b,0x000500b3,0x00000099,0x00000273,0x00000272,0x000001a9,0x000400fa,0x00000273,
|
||||
0x0000026e,0x0000026f,0x000200f8,0x0000026e,0x0003003e,0x00000274,0x0000026c,0x000200f9,
|
||||
0x00000275,0x000200f8,0x00000275,0x000400f6,0x00000277,0x00000278,0x00000000,0x000200f9,
|
||||
0x00000279,0x000200f8,0x00000279,0x0004003d,0x0000009e,0x0000027a,0x00000274,0x000500b3,
|
||||
0x00000099,0x0000027b,0x0000027a,0x000001a9,0x000400fa,0x0000027b,0x00000276,0x00000277,
|
||||
0x000200f8,0x00000276,0x0004003d,0x0000009e,0x0000027c,0x00000274,0x000500ab,0x00000099,
|
||||
0x0000027d,0x0000027c,0x00000263,0x0004003d,0x0000009e,0x0000027e,0x0000026b,0x000500ab,
|
||||
0x00000099,0x0000027f,0x0000027e,0x00000263,0x000500a6,0x00000099,0x00000280,0x0000027d,
|
||||
0x0000027f,0x000300f7,0x00000282,0x00000000,0x000400fa,0x00000280,0x00000281,0x00000282,
|
||||
0x000200f8,0x00000281,0x0004003d,0x00000253,0x00000283,0x00000255,0x0004003d,0x0000001e,
|
||||
0x00000284,0x00000246,0x0004003d,0x0000009e,0x00000285,0x00000274,0x0004006f,0x00000006,
|
||||
0x00000286,0x00000285,0x0004003d,0x0000009e,0x00000287,0x0000026b,0x0004006f,0x00000006,
|
||||
0x00000288,0x00000287,0x00050050,0x0000001e,0x00000289,0x00000286,0x00000288,0x0004003d,
|
||||
0x0000001e,0x0000028a,0x00000261,0x00050085,0x0000001e,0x0000028b,0x00000289,0x0000028a,
|
||||
0x00050081,0x0000001e,0x0000028c,0x00000284,0x0000028b,0x00050057,0x0000009a,0x0000028d,
|
||||
0x00000283,0x0000028c,0x00050051,0x00000006,0x0000028e,0x0000028d,0x00000000,0x0004003d,
|
||||
0x00000006,0x0000028f,0x0000026a,0x00050081,0x00000006,0x00000290,0x0000028f,0x0000028e,
|
||||
0x0003003e,0x0000026a,0x00000290,0x000200f9,0x00000282,0x000200f8,0x00000282,0x000200f9,
|
||||
0x00000278,0x000200f8,0x00000278,0x0004003d,0x0000009e,0x00000291,0x00000274,0x00050080,
|
||||
0x0000009e,0x00000292,0x00000291,0x000001a9,0x0003003e,0x00000274,0x00000292,0x000200f9,
|
||||
0x00000275,0x000200f8,0x00000277,0x000200f9,0x00000270,0x000200f8,0x00000270,0x0004003d,
|
||||
0x0000009e,0x00000293,0x0000026b,0x00050080,0x0000009e,0x00000294,0x00000293,0x000001a9,
|
||||
0x0003003e,0x0000026b,0x00000294,0x000200f9,0x0000026d,0x000200f8,0x0000026f,0x0004003d,
|
||||
0x00000006,0x00000295,0x00000251,0x0004003d,0x00000006,0x00000296,0x00000251,0x0004003d,
|
||||
0x00000006,0x00000297,0x0000026a,0x00050085,0x00000006,0x00000299,0x00000297,0x00000298,
|
||||
0x0004003d,0x00000006,0x0000029a,0x00000243,0x00050085,0x00000006,0x0000029b,0x00000299,
|
||||
0x0000029a,0x00050083,0x00000006,0x0000029c,0x00000296,0x0000029b,0x00060041,0x000000a2,
|
||||
0x0000029d,0x0000009d,0x0000018f,0x000001e1,0x0004003d,0x00000006,0x0000029e,0x0000029d,
|
||||
0x00050085,0x00000006,0x0000029f,0x0000029c,0x0000029e,0x00050081,0x00000006,0x000002a0,
|
||||
0x00000295,0x0000029f,0x0008000c,0x00000006,0x000002a1,0x00000001,0x0000002b,0x000002a0,
|
||||
0x00000026,0x00000027,0x0003003e,0x00000251,0x000002a1,0x000200f9,0x00000260,0x000200f8,
|
||||
0x00000260,0x00060041,0x000000a2,0x000002a3,0x0000009d,0x0000009f,0x000001e1,0x0004003d,
|
||||
0x00000006,0x000002a4,0x000002a3,0x000500ba,0x00000099,0x000002a5,0x000002a4,0x0000006c,
|
||||
0x000300f7,0x000002a8,0x00000000,0x000400fa,0x000002a5,0x000002a7,0x000002ae,0x000200f8,
|
||||
0x000002a7,0x0004003d,0x00000253,0x000002aa,0x000002a9,0x0004003d,0x0000001e,0x000002ab,
|
||||
0x00000246,0x00050057,0x0000009a,0x000002ac,0x000002aa,0x000002ab,0x0007004f,0x0000001e,
|
||||
0x000002ad,0x000002ac,0x000002ac,0x00000000,0x00000001,0x0003003e,0x000002a6,0x000002ad,
|
||||
0x000200f9,0x000002a8,0x000200f8,0x000002ae,0x0004003d,0x00000253,0x000002af,0x000002a9,
|
||||
0x0004003d,0x0000001e,0x000002b0,0x00000246,0x00050057,0x0000009a,0x000002b1,0x000002af,
|
||||
0x000002b0,0x00050051,0x00000006,0x000002b2,0x000002b1,0x00000000,0x0004003d,0x00000253,
|
||||
0x000002b4,0x000002b3,0x0004003d,0x0000001e,0x000002b5,0x00000246,0x00050057,0x0000009a,
|
||||
0x000002b6,0x000002b4,0x000002b5,0x00050051,0x00000006,0x000002b7,0x000002b6,0x00000000,
|
||||
0x00050050,0x0000001e,0x000002b8,0x000002b2,0x000002b7,0x0003003e,0x000002a6,0x000002b8,
|
||||
0x000200f9,0x000002a8,0x000200f8,0x000002a8,0x0004003d,0x0000001e,0x000002b9,0x000002a6,
|
||||
0x0003003e,0x000002a2,0x000002b9,0x00050041,0x0000000d,0x000002bb,0x000002a2,0x000000a1,
|
||||
0x0004003d,0x00000006,0x000002bc,0x000002bb,0x0004003d,0x00000006,0x000002bd,0x00000243,
|
||||
0x00050085,0x00000006,0x000002be,0x000002bc,0x000002bd,0x00050083,0x00000006,0x000002bf,
|
||||
0x000002be,0x0000006c,0x0003003e,0x000002ba,0x000002bf,0x00050041,0x0000000d,0x000002c1,
|
||||
0x000002a2,0x00000100,0x0004003d,0x00000006,0x000002c2,0x000002c1,0x0004003d,0x00000006,
|
||||
0x000002c3,0x00000243,0x00050085,0x00000006,0x000002c4,0x000002c2,0x000002c3,0x00050083,
|
||||
0x00000006,0x000002c5,0x000002c4,0x0000006c,0x0003003e,0x000002c0,0x000002c5,0x00060041,
|
||||
0x000000a2,0x000002c6,0x0000009d,0x000001c2,0x00000100,0x0004003d,0x00000006,0x000002c7,
|
||||
0x000002c6,0x000500ba,0x00000099,0x000002c8,0x000002c7,0x0000006c,0x000300f7,0x000002ca,
|
||||
0x00000000,0x000400fa,0x000002c8,0x000002c9,0x000002ca,0x000200f8,0x000002c9,0x0004003d,
|
||||
0x00000006,0x000002cb,0x00000251,0x00050083,0x00000006,0x000002cd,0x000002cb,0x000002cc,
|
||||
0x00050085,0x00000006,0x000002cf,0x000002cd,0x000002ce,0x0003003e,0x00000251,0x000002cf,
|
||||
0x0004003d,0x00000006,0x000002d1,0x000002ba,0x00050085,0x00000006,0x000002d2,0x000002d1,
|
||||
0x000002d0,0x0003003e,0x000002ba,0x000002d2,0x0004003d,0x00000006,0x000002d3,0x000002c0,
|
||||
0x00050085,0x00000006,0x000002d4,0x000002d3,0x000002d0,0x0003003e,0x000002c0,0x000002d4,
|
||||
0x000200f9,0x000002ca,0x000200f8,0x000002ca,0x0004003d,0x00000006,0x000002d5,0x00000251,
|
||||
0x00050083,0x00000006,0x000002d6,0x000002d5,0x0000006c,0x00060041,0x000000a2,0x000002d8,
|
||||
0x0000009d,0x000002d7,0x00000100,0x0004003d,0x00000006,0x000002d9,0x000002d8,0x00050085,
|
||||
0x00000006,0x000002da,0x000002d6,0x000002d9,0x00050081,0x00000006,0x000002db,0x000002da,
|
||||
0x0000006c,0x00060041,0x000000a2,0x000002dc,0x0000009d,0x000002d7,0x000000a1,0x0004003d,
|
||||
0x00000006,0x000002dd,0x000002dc,0x00050081,0x00000006,0x000002de,0x000002db,0x000002dd,
|
||||
0x0003003e,0x00000251,0x000002de,0x00060041,0x000000a2,0x000002e0,0x0000009d,0x000001c2,
|
||||
0x000000af,0x0004003d,0x00000006,0x000002e1,0x000002e0,0x0006000c,0x00000006,0x000002e2,
|
||||
0x00000001,0x0000000e,0x000002e1,0x0003003e,0x000002df,0x000002e2,0x00060041,0x000000a2,
|
||||
0x000002e4,0x0000009d,0x000001c2,0x000000af,0x0004003d,0x00000006,0x000002e5,0x000002e4,
|
||||
0x0006000c,0x00000006,0x000002e6,0x00000001,0x0000000d,0x000002e5,0x0003003e,0x000002e3,
|
||||
0x000002e6,0x0004003d,0x00000006,0x000002e8,0x000002ba,0x0004003d,0x00000006,0x000002e9,
|
||||
0x000002df,0x00050085,0x00000006,0x000002ea,0x000002e8,0x000002e9,0x0004003d,0x00000006,
|
||||
0x000002eb,0x000002c0,0x0004003d,0x00000006,0x000002ec,0x000002e3,0x00050085,0x00000006,
|
||||
0x000002ed,0x000002eb,0x000002ec,0x00050083,0x00000006,0x000002ee,0x000002ea,0x000002ed,
|
||||
0x0004003d,0x00000006,0x000002ef,0x000002ba,0x0004003d,0x00000006,0x000002f0,0x000002e3,
|
||||
0x00050085,0x00000006,0x000002f1,0x000002ef,0x000002f0,0x0004003d,0x00000006,0x000002f2,
|
||||
0x000002c0,0x0004003d,0x00000006,0x000002f3,0x000002df,0x00050085,0x00000006,0x000002f4,
|
||||
0x000002f2,0x000002f3,0x00050081,0x00000006,0x000002f5,0x000002f1,0x000002f4,0x00050050,
|
||||
0x0000001e,0x000002f6,0x000002ee,0x000002f5,0x00060041,0x000000a2,0x000002f7,0x0000009d,
|
||||
0x000002d7,0x000000af,0x0004003d,0x00000006,0x000002f8,0x000002f7,0x0005008e,0x0000001e,
|
||||
0x000002f9,0x000002f6,0x000002f8,0x0003003e,0x000002e7,0x000002f9,0x0004003d,0x00000006,
|
||||
0x000002fb,0x00000251,0x0004003d,0x0000001e,0x000002fc,0x000002e7,0x00050051,0x00000006,
|
||||
0x000002fd,0x000002fc,0x00000000,0x00050051,0x00000006,0x000002fe,0x000002fc,0x00000001,
|
||||
0x00060050,0x00000007,0x000002ff,0x000002fb,0x000002fd,0x000002fe,0x0003003e,0x000002fa,
|
||||
0x000002ff,0x00050041,0x00000301,0x00000302,0x0000009d,0x00000263,0x0004003d,0x0000009a,
|
||||
0x00000303,0x00000302,0x0008004f,0x00000007,0x00000304,0x00000303,0x00000303,0x00000000,
|
||||
0x00000001,0x00000002,0x0004003d,0x00000007,0x00000305,0x000002fa,0x00050094,0x00000006,
|
||||
0x00000306,0x00000304,0x00000305,0x00050041,0x00000301,0x00000307,0x0000009d,0x000001a9,
|
||||
0x0004003d,0x0000009a,0x00000308,0x00000307,0x0008004f,0x00000007,0x00000309,0x00000308,
|
||||
0x00000308,0x00000000,0x00000001,0x00000002,0x0004003d,0x00000007,0x0000030a,0x000002fa,
|
||||
0x00050094,0x00000006,0x0000030b,0x00000309,0x0000030a,0x00050041,0x00000301,0x0000030c,
|
||||
0x0000009d,0x000001b5,0x0004003d,0x0000009a,0x0000030d,0x0000030c,0x0008004f,0x00000007,
|
||||
0x0000030e,0x0000030d,0x0000030d,0x00000000,0x00000001,0x00000002,0x0004003d,0x00000007,
|
||||
0x0000030f,0x000002fa,0x00050094,0x00000006,0x00000310,0x0000030e,0x0000030f,0x00060050,
|
||||
0x00000007,0x00000311,0x00000306,0x0000030b,0x00000310,0x00060050,0x00000007,0x00000312,
|
||||
0x00000026,0x00000026,0x00000026,0x00060050,0x00000007,0x00000313,0x00000027,0x00000027,
|
||||
0x00000027,0x0008000c,0x00000007,0x00000314,0x00000001,0x0000002b,0x00000311,0x00000312,
|
||||
0x00000313,0x0003003e,0x00000300,0x00000314,0x00060041,0x000000a2,0x00000316,0x0000009d,
|
||||
0x00000315,0x000000a1,0x0004003d,0x00000006,0x00000317,0x00000316,0x000500ba,0x00000099,
|
||||
0x00000318,0x00000317,0x0000006c,0x000300f7,0x0000031a,0x00000000,0x000400fa,0x00000318,
|
||||
0x00000319,0x0000031a,0x000200f8,0x00000319,0x0004003d,0x00000007,0x0000031e,0x00000300,
|
||||
0x0003003e,0x0000031d,0x0000031e,0x00050039,0x00000007,0x0000031f,0x00000019,0x0000031d,
|
||||
0x00050051,0x00000006,0x00000320,0x0000031f,0x00000000,0x00050051,0x00000006,0x00000321,
|
||||
0x0000031f,0x00000001,0x00050051,0x00000006,0x00000322,0x0000031f,0x00000002,0x00070050,
|
||||
0x0000009a,0x00000323,0x00000320,0x00000321,0x00000322,0x00000027,0x0003003e,0x0000031c,
|
||||
0x00000323,0x000100fd,0x000200f8,0x0000031a,0x00060041,0x000000a2,0x00000325,0x0000009d,
|
||||
0x0000009f,0x000000a1,0x0004003d,0x00000006,0x00000326,0x00000325,0x000500ba,0x00000099,
|
||||
0x00000327,0x00000326,0x0000006c,0x000300f7,0x00000329,0x00000000,0x000400fa,0x00000327,
|
||||
0x00000328,0x00000329,0x000200f8,0x00000328,0x0004003d,0x00000007,0x0000032b,0x00000300,
|
||||
0x0003003e,0x0000032a,0x0000032b,0x00050039,0x00000007,0x0000032c,0x0000001c,0x0000032a,
|
||||
0x0003003e,0x00000300,0x0000032c,0x000200f9,0x00000329,0x000200f8,0x00000329,0x0004003d,
|
||||
0x00000007,0x0000032d,0x00000300,0x00060041,0x000000a2,0x0000032e,0x0000009d,0x000002d7,
|
||||
0x000001e1,0x0004003d,0x00000006,0x0000032f,0x0000032e,0x00060050,0x00000007,0x00000330,
|
||||
0x0000032f,0x0000032f,0x0000032f,0x0007000c,0x00000007,0x00000331,0x00000001,0x0000001a,
|
||||
0x0000032d,0x00000330,0x00050051,0x00000006,0x00000332,0x00000331,0x00000000,0x00050051,
|
||||
0x00000006,0x00000333,0x00000331,0x00000001,0x00050051,0x00000006,0x00000334,0x00000331,
|
||||
0x00000002,0x00070050,0x0000009a,0x00000335,0x00000332,0x00000333,0x00000334,0x00000027,
|
||||
0x0003003e,0x0000031c,0x00000335,0x000100fd,0x00010038,0x00050036,0x00000007,0x0000000b,
|
||||
0x00000000,0x00000009,0x00030037,0x00000008,0x0000000a,0x000200f8,0x0000000c,0x0004003b,
|
||||
0x00000008,0x00000024,0x00000007,0x0004003d,0x00000007,0x00000025,0x0000000a,0x00060050,
|
||||
0x00000007,0x00000028,0x00000026,0x00000026,0x00000026,0x00060050,0x00000007,0x00000029,
|
||||
0x00000027,0x00000027,0x00000027,0x0008000c,0x00000007,0x0000002a,0x00000001,0x0000002b,
|
||||
0x00000025,0x00000028,0x00000029,0x0007000c,0x00000007,0x0000002d,0x00000001,0x0000001a,
|
||||
0x0000002a,0x0000002c,0x0003003e,0x00000024,0x0000002d,0x0004003d,0x00000007,0x0000002f,
|
||||
0x00000024,0x00060050,0x00000007,0x00000031,0x00000030,0x00000030,0x00000030,0x00050083,
|
||||
0x00000007,0x00000032,0x0000002f,0x00000031,0x00060050,0x00000007,0x00000033,0x00000026,
|
||||
0x00000026,0x00000026,0x0007000c,0x00000007,0x00000034,0x00000001,0x00000028,0x00000032,
|
||||
0x00000033,0x0004003d,0x00000007,0x00000037,0x00000024,0x0005008e,0x00000007,0x00000038,
|
||||
0x00000037,0x00000036,0x00060050,0x00000007,0x00000039,0x00000035,0x00000035,0x00000035,
|
||||
0x00050083,0x00000007,0x0000003a,0x00000039,0x00000038,0x00050088,0x00000007,0x0000003b,
|
||||
0x00000034,0x0000003a,0x0007000c,0x00000007,0x0000003e,0x00000001,0x0000001a,0x0000003b,
|
||||
0x0000003d,0x0005008e,0x00000007,0x0000003f,0x0000003e,0x0000002e,0x000200fe,0x0000003f,
|
||||
0x00010038,0x00050036,0x00000006,0x00000010,0x00000000,0x0000000e,0x00030037,0x0000000d,
|
||||
0x0000000f,0x000200f8,0x00000011,0x0004003b,0x0000000d,0x00000042,0x00000007,0x0004003d,
|
||||
0x00000006,0x00000043,0x0000000f,0x00050088,0x00000006,0x00000044,0x00000043,0x0000002e,
|
||||
0x0008000c,0x00000006,0x00000045,0x00000001,0x0000002b,0x00000044,0x00000026,0x00000027,
|
||||
0x0007000c,0x00000006,0x00000047,0x00000001,0x0000001a,0x00000045,0x00000046,0x0003003e,
|
||||
0x00000042,0x00000047,0x0004003d,0x00000006,0x00000048,0x00000042,0x00050085,0x00000006,
|
||||
0x00000049,0x00000035,0x00000048,0x00050081,0x00000006,0x0000004a,0x00000030,0x00000049,
|
||||
0x0004003d,0x00000006,0x0000004b,0x00000042,0x00050085,0x00000006,0x0000004c,0x00000036,
|
||||
0x0000004b,0x00050081,0x00000006,0x0000004d,0x00000027,0x0000004c,0x00050088,0x00000006,
|
||||
0x0000004e,0x0000004a,0x0000004d,0x0007000c,0x00000006,0x00000050,0x00000001,0x0000001a,
|
||||
0x0000004e,0x0000004f,0x000200fe,0x00000050,0x00010038,0x00050036,0x00000007,0x00000013,
|
||||
0x00000000,0x00000009,0x00030037,0x00000008,0x00000012,0x000200f8,0x00000014,0x0004003b,
|
||||
0x00000008,0x00000057,0x00000007,0x0004003b,0x0000000d,0x00000071,0x00000007,0x0004003d,
|
||||
0x00000007,0x00000053,0x00000012,0x00060050,0x00000007,0x00000054,0x00000026,0x00000026,
|
||||
0x00000026,0x00060050,0x00000007,0x00000055,0x00000027,0x00000027,0x00000027,0x0008000c,
|
||||
0x00000007,0x00000056,0x00000001,0x0000002b,0x00000053,0x00000054,0x00000055,0x0003003e,
|
||||
0x00000012,0x00000056,0x0004003d,0x00000007,0x00000058,0x00000012,0x0004003d,0x00000007,
|
||||
0x00000059,0x00000012,0x00050085,0x00000007,0x0000005a,0x00000058,0x00000059,0x00060050,
|
||||
0x00000007,0x0000005c,0x0000005b,0x0000005b,0x0000005b,0x00050088,0x00000007,0x0000005d,
|
||||
0x0000005a,0x0000005c,0x0004003d,0x00000007,0x0000005e,0x00000012,0x00060050,0x00000007,
|
||||
0x00000060,0x0000005f,0x0000005f,0x0000005f,0x00050083,0x00000007,0x00000061,0x0000005e,
|
||||
0x00000060,0x00060050,0x00000007,0x00000063,0x00000062,0x00000062,0x00000062,0x00050088,
|
||||
0x00000007,0x00000064,0x00000061,0x00000063,0x0006000c,0x00000007,0x00000065,0x00000001,
|
||||
0x0000001b,0x00000064,0x00060050,0x00000007,0x00000067,0x00000066,0x00000066,0x00000066,
|
||||
0x00050081,0x00000007,0x00000068,0x00000065,0x00000067,0x00060050,0x00000007,0x0000006a,
|
||||
0x00000069,0x00000069,0x00000069,0x00050088,0x00000007,0x0000006b,0x00000068,0x0000006a,
|
||||
0x0004003d,0x00000007,0x0000006e,0x00000012,0x0007000c,0x00000007,0x0000006f,0x00000001,
|
||||
0x00000030,0x0000006d,0x0000006e,0x0008000c,0x00000007,0x00000070,0x00000001,0x0000002e,
|
||||
0x0000005d,0x0000006b,0x0000006f,0x0003003e,0x00000057,0x00000070,0x0004003d,0x00000007,
|
||||
0x00000072,0x00000057,0x00050094,0x00000006,0x00000077,0x00000072,0x00000076,0x0007000c,
|
||||
0x00000006,0x00000079,0x00000001,0x00000028,0x00000077,0x00000078,0x0003003e,0x00000071,
|
||||
0x00000079,0x0004003d,0x00000006,0x0000007b,0x00000071,0x0007000c,0x00000006,0x0000007d,
|
||||
0x00000001,0x0000001a,0x0000007b,0x0000007c,0x00050085,0x00000006,0x0000007e,0x0000007a,
|
||||
0x0000007d,0x0004003d,0x00000007,0x0000007f,0x00000057,0x0005008e,0x00000007,0x00000080,
|
||||
0x0000007f,0x0000007e,0x000200fe,0x00000080,0x00010038,0x00050036,0x00000007,0x00000016,
|
||||
0x00000000,0x00000009,0x00030037,0x00000008,0x00000015,0x000200f8,0x00000017,0x0004003b,
|
||||
0x00000008,0x00000083,0x00000007,0x0004003d,0x00000007,0x00000084,0x00000015,0x00060050,
|
||||
0x00000007,0x00000085,0x0000002e,0x0000002e,0x0000002e,0x00050088,0x00000007,0x00000086,
|
||||
0x00000084,0x00000085,0x00060050,0x00000007,0x00000087,0x00000026,0x00000026,0x00000026,
|
||||
0x00060050,0x00000007,0x00000088,0x00000027,0x00000027,0x00000027,0x0008000c,0x00000007,
|
||||
0x00000089,0x00000001,0x0000002b,0x00000086,0x00000087,0x00000088,0x0007000c,0x00000007,
|
||||
0x0000008b,0x00000001,0x0000001a,0x00000089,0x0000008a,0x0003003e,0x00000083,0x0000008b,
|
||||
0x0004003d,0x00000007,0x0000008c,0x00000083,0x0005008e,0x00000007,0x0000008d,0x0000008c,
|
||||
0x00000035,0x00060050,0x00000007,0x0000008e,0x00000030,0x00000030,0x00000030,0x00050081,
|
||||
0x00000007,0x0000008f,0x0000008e,0x0000008d,0x0004003d,0x00000007,0x00000090,0x00000083,
|
||||
0x0005008e,0x00000007,0x00000091,0x00000090,0x00000036,0x00060050,0x00000007,0x00000092,
|
||||
0x00000027,0x00000027,0x00000027,0x00050081,0x00000007,0x00000093,0x00000092,0x00000091,
|
||||
0x00050088,0x00000007,0x00000094,0x0000008f,0x00000093,0x0007000c,0x00000007,0x00000096,
|
||||
0x00000001,0x0000001a,0x00000094,0x00000095,0x000200fe,0x00000096,0x00010038,0x00050036,
|
||||
0x00000007,0x00000019,0x00000000,0x00000009,0x00030037,0x00000008,0x00000018,0x000200f8,
|
||||
0x0000001a,0x0004003b,0x00000008,0x000000bd,0x00000007,0x0004003b,0x00000008,0x000000c1,
|
||||
0x00000007,0x0004003b,0x00000008,0x000000c4,0x00000007,0x0004003b,0x00000008,0x000000c8,
|
||||
0x00000007,0x0004003b,0x00000008,0x000000eb,0x00000007,0x00060041,0x000000a2,0x000000a3,
|
||||
0x0000009d,0x0000009f,0x000000a1,0x0004003d,0x00000006,0x000000a4,0x000000a3,0x000500ba,
|
||||
0x00000099,0x000000a5,0x000000a4,0x0000006c,0x000300f7,0x000000a7,0x00000000,0x000400fa,
|
||||
0x000000a5,0x000000a6,0x000000a7,0x000200f8,0x000000a6,0x00060041,0x000000a2,0x000000a8,
|
||||
0x0000009d,0x0000009f,0x000000a1,0x0004003d,0x00000006,0x000000a9,0x000000a8,0x000500b8,
|
||||
0x00000099,0x000000ab,0x000000a9,0x000000aa,0x000200f9,0x000000a7,0x000200f8,0x000000a7,
|
||||
0x000700f5,0x00000099,0x000000ac,0x000000a5,0x0000001a,0x000000ab,0x000000a6,0x000300f7,
|
||||
0x000000ae,0x00000000,0x000400fa,0x000000ac,0x000000ad,0x000000ae,0x000200f8,0x000000ad,
|
||||
0x00060041,0x000000a2,0x000000b0,0x0000009d,0x0000009f,0x000000af,0x0004003d,0x00000006,
|
||||
0x000000b1,0x000000b0,0x000500ba,0x00000099,0x000000b2,0x000000b1,0x0000006c,0x000200f9,
|
||||
0x000000ae,0x000200f8,0x000000ae,0x000700f5,0x00000099,0x000000b3,0x000000ac,0x000000a7,
|
||||
0x000000b2,0x000000ad,0x000300f7,0x000000b5,0x00000000,0x000400fa,0x000000b3,0x000000b4,
|
||||
0x000000b5,0x000200f8,0x000000b4,0x0004003d,0x00000007,0x000000b6,0x00000018,0x000200fe,
|
||||
0x000000b6,0x000200f8,0x000000b5,0x00060041,0x000000a2,0x000000b8,0x0000009d,0x0000009f,
|
||||
0x000000a1,0x0004003d,0x00000006,0x000000b9,0x000000b8,0x000500ba,0x00000099,0x000000ba,
|
||||
0x000000b9,0x0000006c,0x000300f7,0x000000bc,0x00000000,0x000400fa,0x000000ba,0x000000bb,
|
||||
0x000000cc,0x000200f8,0x000000bb,0x00060041,0x000000a2,0x000000be,0x0000009d,0x0000009f,
|
||||
0x000000a1,0x0004003d,0x00000006,0x000000bf,0x000000be,0x000500b8,0x00000099,0x000000c0,
|
||||
0x000000bf,0x000000aa,0x000300f7,0x000000c3,0x00000000,0x000400fa,0x000000c0,0x000000c2,
|
||||
0x000000c7,0x000200f8,0x000000c2,0x0004003d,0x00000007,0x000000c5,0x00000018,0x0003003e,
|
||||
0x000000c4,0x000000c5,0x00050039,0x00000007,0x000000c6,0x0000000b,0x000000c4,0x0003003e,
|
||||
0x000000c1,0x000000c6,0x000200f9,0x000000c3,0x000200f8,0x000000c7,0x0004003d,0x00000007,
|
||||
0x000000c9,0x00000018,0x0003003e,0x000000c8,0x000000c9,0x00050039,0x00000007,0x000000ca,
|
||||
0x00000013,0x000000c8,0x0003003e,0x000000c1,0x000000ca,0x000200f9,0x000000c3,0x000200f8,
|
||||
0x000000c3,0x0004003d,0x00000007,0x000000cb,0x000000c1,0x0003003e,0x000000bd,0x000000cb,
|
||||
0x000200f9,0x000000bc,0x000200f8,0x000000cc,0x0004003d,0x00000007,0x000000cd,0x00000018,
|
||||
0x00060050,0x00000007,0x000000ce,0x00000026,0x00000026,0x00000026,0x00060050,0x00000007,
|
||||
0x000000cf,0x00000027,0x00000027,0x00000027,0x0008000c,0x00000007,0x000000d0,0x00000001,
|
||||
0x0000002b,0x000000cd,0x000000ce,0x000000cf,0x0007000c,0x00000007,0x000000d3,0x00000001,
|
||||
0x0000001a,0x000000d0,0x000000d2,0x0005008e,0x00000007,0x000000d5,0x000000d3,0x000000d4,
|
||||
0x0003003e,0x000000bd,0x000000d5,0x000200f9,0x000000bc,0x000200f8,0x000000bc,0x00060041,
|
||||
0x000000a2,0x000000d6,0x0000009d,0x0000009f,0x000000af,0x0004003d,0x00000006,0x000000d7,
|
||||
0x000000d6,0x000500b8,0x00000099,0x000000d8,0x000000d7,0x0000006c,0x000300f7,0x000000da,
|
||||
0x00000000,0x000400fa,0x000000d8,0x000000d9,0x000000da,0x000200f8,0x000000d9,0x0004003d,
|
||||
0x00000007,0x000000e9,0x000000bd,0x00050091,0x00000007,0x000000ea,0x000000e8,0x000000e9,
|
||||
0x0003003e,0x000000bd,0x000000ea,0x000200f9,0x000000da,0x000200f8,0x000000da,0x0004003d,
|
||||
0x00000007,0x000000ec,0x000000bd,0x0003003e,0x000000eb,0x000000ec,0x00050039,0x00000007,
|
||||
0x000000ed,0x00000016,0x000000eb,0x000200fe,0x000000ed,0x00010038,0x00050036,0x00000007,
|
||||
0x0000001c,0x00000000,0x00000009,0x00030037,0x00000008,0x0000001b,0x000200f8,0x0000001d,
|
||||
0x0004003b,0x00000008,0x000000f0,0x00000007,0x0004003b,0x00000008,0x000000f4,0x00000007,
|
||||
0x0004003b,0x00000008,0x000000f7,0x00000007,0x0004003b,0x00000008,0x000000fb,0x00000007,
|
||||
0x0004003b,0x0000000d,0x000000ff,0x00000007,0x0004003b,0x0000000d,0x00000103,0x00000007,
|
||||
0x0004003b,0x0000000d,0x00000113,0x00000007,0x0004003b,0x0000000d,0x00000114,0x00000007,
|
||||
0x0004003b,0x0000000d,0x00000117,0x00000007,0x0004003b,0x0000000d,0x00000118,0x00000007,
|
||||
0x0004003b,0x0000000d,0x0000011e,0x00000007,0x0004003b,0x0000000d,0x0000011f,0x00000007,
|
||||
0x0004003b,0x0000000d,0x00000123,0x00000007,0x0004003b,0x0000000d,0x00000127,0x00000007,
|
||||
0x0004003b,0x0000000d,0x0000012e,0x00000007,0x0004003b,0x0000000d,0x00000135,0x00000007,
|
||||
0x0004003b,0x0000000d,0x00000139,0x00000007,0x0004003b,0x00000008,0x0000015d,0x00000007,
|
||||
0x0004003b,0x00000008,0x00000164,0x00000007,0x00060041,0x000000a2,0x000000f1,0x0000009d,
|
||||
0x0000009f,0x000000a1,0x0004003d,0x00000006,0x000000f2,0x000000f1,0x000500b8,0x00000099,
|
||||
0x000000f3,0x000000f2,0x000000aa,0x000300f7,0x000000f6,0x00000000,0x000400fa,0x000000f3,
|
||||
0x000000f5,0x000000fa,0x000200f8,0x000000f5,0x0004003d,0x00000007,0x000000f8,0x0000001b,
|
||||
0x0003003e,0x000000f7,0x000000f8,0x00050039,0x00000007,0x000000f9,0x0000000b,0x000000f7,
|
||||
0x0003003e,0x000000f4,0x000000f9,0x000200f9,0x000000f6,0x000200f8,0x000000fa,0x0004003d,
|
||||
0x00000007,0x000000fc,0x0000001b,0x0003003e,0x000000fb,0x000000fc,0x00050039,0x00000007,
|
||||
0x000000fd,0x00000013,0x000000fb,0x0003003e,0x000000f4,0x000000fd,0x000200f9,0x000000f6,
|
||||
0x000200f8,0x000000f6,0x0004003d,0x00000007,0x000000fe,0x000000f4,0x0003003e,0x000000f0,
|
||||
0x000000fe,0x00060041,0x000000a2,0x00000101,0x0000009d,0x0000009f,0x00000100,0x0004003d,
|
||||
0x00000006,0x00000102,0x00000101,0x0003003e,0x000000ff,0x00000102,0x00050041,0x0000000d,
|
||||
0x00000104,0x000000f0,0x000000a1,0x0004003d,0x00000006,0x00000105,0x00000104,0x00050041,
|
||||
0x0000000d,0x00000106,0x000000f0,0x00000100,0x0004003d,0x00000006,0x00000107,0x00000106,
|
||||
0x00050041,0x0000000d,0x00000108,0x000000f0,0x000000af,0x0004003d,0x00000006,0x00000109,
|
||||
0x00000108,0x0007000c,0x00000006,0x0000010a,0x00000001,0x00000028,0x00000107,0x00000109,
|
||||
0x0007000c,0x00000006,0x0000010b,0x00000001,0x00000028,0x00000105,0x0000010a,0x0003003e,
|
||||
0x00000103,0x0000010b,0x0004003d,0x00000006,0x0000010c,0x00000103,0x000500ba,0x00000099,
|
||||
0x0000010d,0x0000010c,0x00000026,0x0004003d,0x00000006,0x0000010e,0x000000ff,0x000500ba,
|
||||
0x00000099,0x0000010f,0x0000010e,0x000000d4,0x000500a7,0x00000099,0x00000110,0x0000010d,
|
||||
0x0000010f,0x000300f7,0x00000112,0x00000000,0x000400fa,0x00000110,0x00000111,0x00000112,
|
||||
0x000200f8,0x00000111,0x0004003d,0x00000006,0x00000115,0x000000ff,0x0003003e,0x00000114,
|
||||
0x00000115,0x00050039,0x00000006,0x00000116,0x00000010,0x00000114,0x0003003e,0x00000113,
|
||||
0x00000116,0x0004003d,0x00000006,0x00000119,0x00000103,0x0003003e,0x00000118,0x00000119,
|
||||
0x00050039,0x00000006,0x0000011a,0x00000010,0x00000118,0x0004003d,0x00000006,0x0000011b,
|
||||
0x00000113,0x00050088,0x00000006,0x0000011c,0x0000011a,0x0000011b,0x0007000c,0x00000006,
|
||||
0x0000011d,0x00000001,0x00000025,0x0000011c,0x00000027,0x0003003e,0x00000117,0x0000011d,
|
||||
0x0003003e,0x0000011f,0x000000d4,0x00050039,0x00000006,0x00000120,0x00000010,0x0000011f,
|
||||
0x0004003d,0x00000006,0x00000121,0x00000113,0x00050088,0x00000006,0x00000122,0x00000120,
|
||||
0x00000121,0x0003003e,0x0000011e,0x00000122,0x0004003d,0x00000006,0x00000124,0x0000011e,
|
||||
0x00050085,0x00000006,0x00000125,0x000000aa,0x00000124,0x00050083,0x00000006,0x00000126,
|
||||
0x00000125,0x0000006c,0x0003003e,0x00000123,0x00000126,0x0004003d,0x00000006,0x00000128,
|
||||
0x00000117,0x0003003e,0x00000127,0x00000128,0x0004003d,0x00000006,0x00000129,0x00000117,
|
||||
0x0004003d,0x00000006,0x0000012a,0x00000123,0x000500ba,0x00000099,0x0000012b,0x00000129,
|
||||
0x0000012a,0x000300f7,0x0000012d,0x00000000,0x000400fa,0x0000012b,0x0000012c,0x0000012d,
|
||||
0x000200f8,0x0000012c,0x0004003d,0x00000006,0x0000012f,0x00000117,0x0004003d,0x00000006,
|
||||
0x00000130,0x00000123,0x00050083,0x00000006,0x00000131,0x0000012f,0x00000130,0x0004003d,
|
||||
0x00000006,0x00000132,0x00000123,0x00050083,0x00000006,0x00000133,0x00000027,0x00000132,
|
||||
0x00050088,0x00000006,0x00000134,0x00000131,0x00000133,0x0003003e,0x0000012e,0x00000134,
|
||||
0x0004003d,0x00000006,0x00000136,0x0000012e,0x0004003d,0x00000006,0x00000137,0x0000012e,
|
||||
0x00050085,0x00000006,0x00000138,0x00000136,0x00000137,0x0003003e,0x00000135,0x00000138,
|
||||
0x0004003d,0x00000006,0x0000013a,0x00000135,0x0004003d,0x00000006,0x0000013b,0x0000012e,
|
||||
0x00050085,0x00000006,0x0000013c,0x0000013a,0x0000013b,0x0003003e,0x00000139,0x0000013c,
|
||||
0x0004003d,0x00000006,0x0000013e,0x00000139,0x00050085,0x00000006,0x0000013f,0x0000013d,
|
||||
0x0000013e,0x0004003d,0x00000006,0x00000140,0x00000135,0x00050085,0x00000006,0x00000141,
|
||||
0x0000005b,0x00000140,0x00050083,0x00000006,0x00000142,0x0000013f,0x00000141,0x00050081,
|
||||
0x00000006,0x00000143,0x00000142,0x00000027,0x0004003d,0x00000006,0x00000144,0x00000123,
|
||||
0x00050085,0x00000006,0x00000145,0x00000143,0x00000144,0x0004003d,0x00000006,0x00000146,
|
||||
0x00000139,0x0004003d,0x00000006,0x00000147,0x00000135,0x00050085,0x00000006,0x00000148,
|
||||
0x0000013d,0x00000147,0x00050083,0x00000006,0x00000149,0x00000146,0x00000148,0x0004003d,
|
||||
0x00000006,0x0000014a,0x0000012e,0x00050081,0x00000006,0x0000014b,0x00000149,0x0000014a,
|
||||
0x0004003d,0x00000006,0x0000014c,0x00000123,0x00050083,0x00000006,0x0000014d,0x00000027,
|
||||
0x0000014c,0x00050085,0x00000006,0x0000014e,0x0000014b,0x0000014d,0x00050081,0x00000006,
|
||||
0x0000014f,0x00000145,0x0000014e,0x0004003d,0x00000006,0x00000151,0x00000139,0x00050085,
|
||||
0x00000006,0x00000152,0x00000150,0x00000151,0x0004003d,0x00000006,0x00000153,0x00000135,
|
||||
0x00050085,0x00000006,0x00000154,0x0000005b,0x00000153,0x00050081,0x00000006,0x00000155,
|
||||
0x00000152,0x00000154,0x0004003d,0x00000006,0x00000156,0x0000011e,0x00050085,0x00000006,
|
||||
0x00000157,0x00000155,0x00000156,0x00050081,0x00000006,0x00000158,0x0000014f,0x00000157,
|
||||
0x0003003e,0x00000127,0x00000158,0x000200f9,0x0000012d,0x000200f8,0x0000012d,0x0004003d,
|
||||
0x00000006,0x00000159,0x00000127,0x0004003d,0x00000006,0x0000015a,0x00000113,0x00050085,
|
||||
0x00000006,0x0000015b,0x00000159,0x0000015a,0x00060050,0x00000007,0x0000015c,0x0000015b,
|
||||
0x0000015b,0x0000015b,0x0003003e,0x0000015d,0x0000015c,0x00050039,0x00000007,0x0000015e,
|
||||
0x0000000b,0x0000015d,0x00050051,0x00000006,0x0000015f,0x0000015e,0x00000000,0x0004003d,
|
||||
0x00000006,0x00000160,0x00000103,0x00050088,0x00000006,0x00000161,0x0000015f,0x00000160,
|
||||
0x0004003d,0x00000007,0x00000162,0x000000f0,0x0005008e,0x00000007,0x00000163,0x00000162,
|
||||
0x00000161,0x0003003e,0x000000f0,0x00000163,0x000200f9,0x00000112,0x000200f8,0x00000112,
|
||||
0x0004003d,0x00000007,0x00000165,0x000000f0,0x00060050,0x00000007,0x00000166,0x000000d4,
|
||||
0x000000d4,0x000000d4,0x00050088,0x00000007,0x00000167,0x00000165,0x00000166,0x0003003e,
|
||||
0x00000164,0x00000167,0x00060041,0x000000a2,0x00000168,0x0000009d,0x0000009f,0x000000af,
|
||||
0x0004003d,0x00000006,0x00000169,0x00000168,0x000500ba,0x00000099,0x0000016a,0x00000169,
|
||||
0x0000006c,0x000300f7,0x0000016c,0x00000000,0x000400fa,0x0000016a,0x0000016b,0x0000016c,
|
||||
0x000200f8,0x0000016b,0x0004003d,0x00000007,0x0000017a,0x00000164,0x00050091,0x00000007,
|
||||
0x0000017b,0x00000179,0x0000017a,0x0003003e,0x00000164,0x0000017b,0x000200f9,0x0000016c,
|
||||
0x000200f8,0x0000016c,0x0004003d,0x00000007,0x0000017c,0x00000164,0x00060050,0x00000007,
|
||||
0x0000017d,0x00000026,0x00000026,0x00000026,0x00060050,0x00000007,0x0000017e,0x00000027,
|
||||
0x00000027,0x00000027,0x0008000c,0x00000007,0x0000017f,0x00000001,0x0000002b,0x0000017c,
|
||||
0x0000017d,0x0000017e,0x0007000c,0x00000007,0x00000182,0x00000001,0x0000001a,0x0000017f,
|
||||
0x00000181,0x000200fe,0x00000182,0x00010038,0x00050036,0x0000001e,0x00000020,0x00000000,
|
||||
0x0000001f,0x000200f8,0x00000021,0x0004003b,0x00000185,0x00000186,0x00000007,0x0004003b,
|
||||
0x000001a2,0x000001a3,0x00000007,0x0004003d,0x0000001e,0x00000189,0x00000188,0x00050041,
|
||||
0x0000018b,0x0000018c,0x0000009d,0x0000018a,0x0004003d,0x0000001e,0x0000018d,0x0000018c,
|
||||
0x00050088,0x0000001e,0x0000018e,0x00000189,0x0000018d,0x0003003e,0x00000186,0x0000018e,
|
||||
0x00060041,0x000000a2,0x00000190,0x0000009d,0x0000018f,0x00000100,0x0004003d,0x00000006,
|
||||
0x00000191,0x00000190,0x000500ba,0x00000099,0x00000192,0x00000191,0x0000006c,0x000300f7,
|
||||
0x00000194,0x00000000,0x000400fa,0x00000192,0x00000193,0x00000194,0x000200f8,0x00000193,
|
||||
0x00050041,0x0000000d,0x00000195,0x00000186,0x000000a1,0x0004003d,0x00000006,0x00000196,
|
||||
0x00000195,0x00050083,0x00000006,0x00000197,0x00000027,0x00000196,0x00050041,0x0000000d,
|
||||
0x00000198,0x00000186,0x000000a1,0x0003003e,0x00000198,0x00000197,0x000200f9,0x00000194,
|
||||
0x000200f8,0x00000194,0x00060041,0x000000a2,0x00000199,0x0000009d,0x0000018f,0x000000af,
|
||||
0x0004003d,0x00000006,0x0000019a,0x00000199,0x000500ba,0x00000099,0x0000019b,0x0000019a,
|
||||
0x0000006c,0x000300f7,0x0000019d,0x00000000,0x000400fa,0x0000019b,0x0000019c,0x0000019d,
|
||||
0x000200f8,0x0000019c,0x00050041,0x0000000d,0x0000019e,0x00000186,0x00000100,0x0004003d,
|
||||
0x00000006,0x0000019f,0x0000019e,0x00050083,0x00000006,0x000001a0,0x00000027,0x0000019f,
|
||||
0x00050041,0x0000000d,0x000001a1,0x00000186,0x00000100,0x0003003e,0x000001a1,0x000001a0,
|
||||
0x000200f9,0x0000019d,0x000200f8,0x0000019d,0x00060041,0x000000a2,0x000001a4,0x0000009d,
|
||||
0x0000018f,0x000000a1,0x0004003d,0x00000006,0x000001a5,0x000001a4,0x00050081,0x00000006,
|
||||
0x000001a6,0x000001a5,0x0000006c,0x0004006e,0x0000009e,0x000001a7,0x000001a6,0x0003003e,
|
||||
0x000001a3,0x000001a7,0x0004003d,0x0000009e,0x000001a8,0x000001a3,0x000500aa,0x00000099,
|
||||
0x000001aa,0x000001a8,0x000001a9,0x000300f7,0x000001ac,0x00000000,0x000400fa,0x000001aa,
|
||||
0x000001ab,0x000001b3,0x000200f8,0x000001ab,0x00050041,0x0000000d,0x000001ad,0x00000186,
|
||||
0x00000100,0x0004003d,0x00000006,0x000001ae,0x000001ad,0x00050041,0x0000000d,0x000001af,
|
||||
0x00000186,0x000000a1,0x0004003d,0x00000006,0x000001b0,0x000001af,0x00050083,0x00000006,
|
||||
0x000001b1,0x00000027,0x000001b0,0x00050050,0x0000001e,0x000001b2,0x000001ae,0x000001b1,
|
||||
0x0003003e,0x00000186,0x000001b2,0x000200f9,0x000001ac,0x000200f8,0x000001b3,0x0004003d,
|
||||
0x0000009e,0x000001b4,0x000001a3,0x000500aa,0x00000099,0x000001b6,0x000001b4,0x000001b5,
|
||||
0x000300f7,0x000001b8,0x00000000,0x000400fa,0x000001b6,0x000001b7,0x000001c0,0x000200f8,
|
||||
0x000001b7,0x00050041,0x0000000d,0x000001b9,0x00000186,0x000000a1,0x0004003d,0x00000006,
|
||||
0x000001ba,0x000001b9,0x00050083,0x00000006,0x000001bb,0x00000027,0x000001ba,0x00050041,
|
||||
0x0000000d,0x000001bc,0x00000186,0x00000100,0x0004003d,0x00000006,0x000001bd,0x000001bc,
|
||||
0x00050083,0x00000006,0x000001be,0x00000027,0x000001bd,0x00050050,0x0000001e,0x000001bf,
|
||||
0x000001bb,0x000001be,0x0003003e,0x00000186,0x000001bf,0x000200f9,0x000001b8,0x000200f8,
|
||||
0x000001c0,0x0004003d,0x0000009e,0x000001c1,0x000001a3,0x000500aa,0x00000099,0x000001c3,
|
||||
0x000001c1,0x000001c2,0x000300f7,0x000001c5,0x00000000,0x000400fa,0x000001c3,0x000001c4,
|
||||
0x000001c5,0x000200f8,0x000001c4,0x00050041,0x0000000d,0x000001c6,0x00000186,0x00000100,
|
||||
0x0004003d,0x00000006,0x000001c7,0x000001c6,0x00050083,0x00000006,0x000001c8,0x00000027,
|
||||
0x000001c7,0x00050041,0x0000000d,0x000001c9,0x00000186,0x000000a1,0x0004003d,0x00000006,
|
||||
0x000001ca,0x000001c9,0x00050050,0x0000001e,0x000001cb,0x000001c8,0x000001ca,0x0003003e,
|
||||
0x00000186,0x000001cb,0x000200f9,0x000001c5,0x000200f8,0x000001c5,0x000200f9,0x000001b8,
|
||||
0x000200f8,0x000001b8,0x000200f9,0x000001ac,0x000200f8,0x000001ac,0x0004003d,0x0000001e,
|
||||
0x000001cc,0x00000186,0x00050041,0x0000018b,0x000001cd,0x0000009d,0x0000018a,0x0004003d,
|
||||
0x0000001e,0x000001ce,0x000001cd,0x00050085,0x0000001e,0x000001cf,0x000001cc,0x000001ce,
|
||||
0x000200fe,0x000001cf,0x00010038,0x00050036,0x0000001e,0x00000022,0x00000000,0x0000001f,
|
||||
0x000200f8,0x00000023,0x0004003b,0x00000185,0x000001d2,0x00000007,0x0004003b,0x00000008,
|
||||
0x000001da,0x00000007,0x0004003b,0x0000000d,0x000001ed,0x00000007,0x0004003b,0x0000000d,
|
||||
0x000001f1,0x00000007,0x0004003b,0x0000000d,0x0000020b,0x00000007,0x0004003b,0x0000000d,
|
||||
0x0000020f,0x00000007,0x0004003b,0x0000000d,0x00000229,0x00000007,0x0004003b,0x0000000d,
|
||||
0x0000022f,0x00000007,0x0004003d,0x0000001e,0x000001d3,0x00000188,0x00050041,0x0000018b,
|
||||
0x000001d4,0x0000009d,0x0000018a,0x0004003d,0x0000001e,0x000001d5,0x000001d4,0x00050088,
|
||||
0x0000001e,0x000001d6,0x000001d3,0x000001d5,0x0005008e,0x0000001e,0x000001d7,0x000001d6,
|
||||
0x0000013d,0x00050050,0x0000001e,0x000001d8,0x00000027,0x00000027,0x00050083,0x0000001e,
|
||||
0x000001d9,0x000001d7,0x000001d8,0x0003003e,0x000001d2,0x000001d9,0x00050041,0x0000000d,
|
||||
0x000001db,0x000001d2,0x000000a1,0x0004003d,0x00000006,0x000001dc,0x000001db,0x00060041,
|
||||
0x000000a2,0x000001de,0x0000009d,0x000001dd,0x000000af,0x0004003d,0x00000006,0x000001df,
|
||||
0x000001de,0x00050085,0x00000006,0x000001e0,0x000001dc,0x000001df,0x00060041,0x000000a2,
|
||||
0x000001e2,0x0000009d,0x000001dd,0x000001e1,0x0004003d,0x00000006,0x000001e3,0x000001e2,
|
||||
0x00050085,0x00000006,0x000001e4,0x000001e0,0x000001e3,0x00050041,0x0000000d,0x000001e5,
|
||||
0x000001d2,0x00000100,0x0004003d,0x00000006,0x000001e6,0x000001e5,0x0004007f,0x00000006,
|
||||
0x000001e7,0x000001e6,0x00060041,0x000000a2,0x000001e8,0x0000009d,0x000001dd,0x000000af,
|
||||
0x0004003d,0x00000006,0x000001e9,0x000001e8,0x00050085,0x00000006,0x000001ea,0x000001e7,
|
||||
0x000001e9,0x00060050,0x00000007,0x000001eb,0x000001e4,0x000001ea,0x00000027,0x0006000c,
|
||||
0x00000007,0x000001ec,0x00000001,0x00000045,0x000001eb,0x0003003e,0x000001da,0x000001ec,
|
||||
0x00060041,0x000000a2,0x000001ee,0x0000009d,0x000001dd,0x00000100,0x0004003d,0x00000006,
|
||||
0x000001ef,0x000001ee,0x0006000c,0x00000006,0x000001f0,0x00000001,0x0000000e,0x000001ef,
|
||||
0x0003003e,0x000001ed,0x000001f0,0x00060041,0x000000a2,0x000001f2,0x0000009d,0x000001dd,
|
||||
0x00000100,0x0004003d,0x00000006,0x000001f3,0x000001f2,0x0006000c,0x00000006,0x000001f4,
|
||||
0x00000001,0x0000000d,0x000001f3,0x0003003e,0x000001f1,0x000001f4,0x00050041,0x0000000d,
|
||||
0x000001f5,0x000001da,0x000000a1,0x0004003d,0x00000006,0x000001f6,0x000001f5,0x00050041,
|
||||
0x0000000d,0x000001f7,0x000001da,0x00000100,0x0004003d,0x00000006,0x000001f8,0x000001f7,
|
||||
0x0004003d,0x00000006,0x000001f9,0x000001ed,0x00050085,0x00000006,0x000001fa,0x000001f8,
|
||||
0x000001f9,0x00050041,0x0000000d,0x000001fb,0x000001da,0x000000af,0x0004003d,0x00000006,
|
||||
0x000001fc,0x000001fb,0x0004003d,0x00000006,0x000001fd,0x000001f1,0x00050085,0x00000006,
|
||||
0x000001fe,0x000001fc,0x000001fd,0x00050081,0x00000006,0x000001ff,0x000001fa,0x000001fe,
|
||||
0x00050041,0x0000000d,0x00000200,0x000001da,0x00000100,0x0004003d,0x00000006,0x00000201,
|
||||
0x00000200,0x0004007f,0x00000006,0x00000202,0x00000201,0x0004003d,0x00000006,0x00000203,
|
||||
0x000001f1,0x00050085,0x00000006,0x00000204,0x00000202,0x00000203,0x00050041,0x0000000d,
|
||||
0x00000205,0x000001da,0x000000af,0x0004003d,0x00000006,0x00000206,0x00000205,0x0004003d,
|
||||
0x00000006,0x00000207,0x000001ed,0x00050085,0x00000006,0x00000208,0x00000206,0x00000207,
|
||||
0x00050081,0x00000006,0x00000209,0x00000204,0x00000208,0x00060050,0x00000007,0x0000020a,
|
||||
0x000001f6,0x000001ff,0x00000209,0x0003003e,0x000001da,0x0000020a,0x00060041,0x000000a2,
|
||||
0x0000020c,0x0000009d,0x000001dd,0x000000a1,0x0004003d,0x00000006,0x0000020d,0x0000020c,
|
||||
0x0006000c,0x00000006,0x0000020e,0x00000001,0x0000000e,0x0000020d,0x0003003e,0x0000020b,
|
||||
0x0000020e,0x00060041,0x000000a2,0x00000210,0x0000009d,0x000001dd,0x000000a1,0x0004003d,
|
||||
0x00000006,0x00000211,0x00000210,0x0006000c,0x00000006,0x00000212,0x00000001,0x0000000d,
|
||||
0x00000211,0x0003003e,0x0000020f,0x00000212,0x00050041,0x0000000d,0x00000213,0x000001da,
|
||||
0x000000a1,0x0004003d,0x00000006,0x00000214,0x00000213,0x0004003d,0x00000006,0x00000215,
|
||||
0x0000020b,0x00050085,0x00000006,0x00000216,0x00000214,0x00000215,0x00050041,0x0000000d,
|
||||
0x00000217,0x000001da,0x000000af,0x0004003d,0x00000006,0x00000218,0x00000217,0x0004003d,
|
||||
0x00000006,0x00000219,0x0000020f,0x00050085,0x00000006,0x0000021a,0x00000218,0x00000219,
|
||||
0x00050081,0x00000006,0x0000021b,0x00000216,0x0000021a,0x00050041,0x0000000d,0x0000021c,
|
||||
0x000001da,0x00000100,0x0004003d,0x00000006,0x0000021d,0x0000021c,0x00050041,0x0000000d,
|
||||
0x0000021e,0x000001da,0x000000a1,0x0004003d,0x00000006,0x0000021f,0x0000021e,0x0004007f,
|
||||
0x00000006,0x00000220,0x0000021f,0x0004003d,0x00000006,0x00000221,0x0000020f,0x00050085,
|
||||
0x00000006,0x00000222,0x00000220,0x00000221,0x00050041,0x0000000d,0x00000223,0x000001da,
|
||||
0x000000af,0x0004003d,0x00000006,0x00000224,0x00000223,0x0004003d,0x00000006,0x00000225,
|
||||
0x0000020b,0x00050085,0x00000006,0x00000226,0x00000224,0x00000225,0x00050081,0x00000006,
|
||||
0x00000227,0x00000222,0x00000226,0x00060050,0x00000007,0x00000228,0x0000021b,0x0000021d,
|
||||
0x00000227,0x0003003e,0x000001da,0x00000228,0x00050041,0x0000000d,0x0000022a,0x000001da,
|
||||
0x000000a1,0x0004003d,0x00000006,0x0000022b,0x0000022a,0x00050041,0x0000000d,0x0000022c,
|
||||
0x000001da,0x000000af,0x0004003d,0x00000006,0x0000022d,0x0000022c,0x0007000c,0x00000006,
|
||||
0x0000022e,0x00000001,0x00000019,0x0000022b,0x0000022d,0x0003003e,0x00000229,0x0000022e,
|
||||
0x00050041,0x0000000d,0x00000230,0x000001da,0x00000100,0x0004003d,0x00000006,0x00000231,
|
||||
0x00000230,0x0008000c,0x00000006,0x00000233,0x00000001,0x0000002b,0x00000231,0x00000232,
|
||||
0x00000027,0x0006000c,0x00000006,0x00000234,0x00000001,0x00000010,0x00000233,0x0003003e,
|
||||
0x0000022f,0x00000234,0x0004003d,0x00000006,0x00000235,0x00000229,0x00050088,0x00000006,
|
||||
0x00000237,0x00000235,0x00000236,0x00050081,0x00000006,0x00000238,0x00000237,0x0000006c,
|
||||
0x0004003d,0x00000006,0x00000239,0x0000022f,0x00050088,0x00000006,0x0000023b,0x00000239,
|
||||
0x0000023a,0x00050083,0x00000006,0x0000023c,0x0000006c,0x0000023b,0x00050050,0x0000001e,
|
||||
0x0000023d,0x00000238,0x0000023c,0x00050041,0x0000018b,0x0000023e,0x0000009d,0x0000018a,
|
||||
0x0004003d,0x0000001e,0x0000023f,0x0000023e,0x00050085,0x0000001e,0x00000240,0x0000023d,
|
||||
0x0000023f,0x000200fe,0x00000240,0x00010038
|
||||
};
|
||||
+375
-11
@@ -11,17 +11,25 @@
|
||||
#include "gfx.h"
|
||||
#include "image.h"
|
||||
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <vector>
|
||||
|
||||
#include "platform.h"
|
||||
#include "gen/fullscreen_vert.h"
|
||||
#include "gen/ui_pq_frag.h"
|
||||
|
||||
#ifdef VLCPS5_HOST
|
||||
#include <zlib.h>
|
||||
#endif
|
||||
|
||||
/* The console's Vulkan driver, with patches/mesa/0001 (absent elsewhere). */
|
||||
extern "C" int vlcps5_wsi_videoout_set_hdr(int enable) __attribute__((weak));
|
||||
extern "C" int vlcps5_wsi_videoout_dynamic_range(void) __attribute__((weak));
|
||||
extern "C" int vlcps5_wsi_videoout_set_refresh(int mode, int *period_us) __attribute__((weak));
|
||||
|
||||
Gfx gfx;
|
||||
|
||||
namespace {
|
||||
@@ -50,6 +58,26 @@ VkDeviceMemory offscreen_memory, readback_memory;
|
||||
VkBuffer readback;
|
||||
void *readback_mapped;
|
||||
|
||||
/* HDR10 output (gfx.h): the UI layer, the 10-bit frame and the pipeline that
|
||||
* puts the first over the second. 10:10:10:2 with blue in the low bits: the
|
||||
* framebuffers' B,G,R order (VideoOut's Bgr10A2), as their 8-bit SDR is. */
|
||||
const VkFormat HDR_FORMAT = VK_FORMAT_A2R10G10B10_UNORM_PACK32;
|
||||
const float UI_NITS = 203; /* BT.2408's graphics white */
|
||||
struct Hdr {
|
||||
VkImage ui_image, image;
|
||||
VkDeviceMemory ui_memory, memory;
|
||||
VkImageView ui_view, view;
|
||||
VkRenderPass ui_pass;
|
||||
VkFramebuffer ui_fb, fb;
|
||||
VkSampler sampler;
|
||||
VkDescriptorSetLayout set_layout;
|
||||
VkDescriptorPool pool;
|
||||
VkDescriptorSet set;
|
||||
VkPipelineLayout layout;
|
||||
VkPipeline pipeline;
|
||||
} hdr;
|
||||
enum PassNow { PASS_NONE, PASS_MAIN, PASS_UI, PASS_HDR } pass_now;
|
||||
|
||||
#define CHECK(expr) \
|
||||
do { \
|
||||
VkResult r_ = (expr); \
|
||||
@@ -168,7 +196,8 @@ bool create_swapchain()
|
||||
info.imageColorSpace = chosen.colorSpace;
|
||||
info.imageExtent = { gfx.width, gfx.height };
|
||||
info.imageArrayLayers = 1;
|
||||
info.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
|
||||
/* (copied into in HDR10 output: the 10-bit frame) */
|
||||
info.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
|
||||
info.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||
info.preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
|
||||
info.compositeAlpha = (caps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR)
|
||||
@@ -193,8 +222,9 @@ bool create_offscreen()
|
||||
VkImage image;
|
||||
VkImageView view;
|
||||
if (!gfx_image(gfx.width, gfx.height, gfx.format,
|
||||
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT, &image,
|
||||
&offscreen_memory, &view))
|
||||
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
|
||||
VK_IMAGE_USAGE_TRANSFER_DST_BIT,
|
||||
&image, &offscreen_memory, &view))
|
||||
return false;
|
||||
images.push_back(image);
|
||||
views.push_back(view);
|
||||
@@ -294,6 +324,223 @@ bool create_targets()
|
||||
return true;
|
||||
}
|
||||
|
||||
/* A pass over one colour attachment, cleared, ending in `final` and made
|
||||
* visible to `next_stage`/`next_access` (what reads it next). */
|
||||
bool make_pass(VkFormat format, VkImageLayout final, VkPipelineStageFlags next_stage,
|
||||
VkAccessFlags next_access, VkRenderPass *pass)
|
||||
{
|
||||
VkAttachmentDescription color = {};
|
||||
color.format = format;
|
||||
color.samples = VK_SAMPLE_COUNT_1_BIT;
|
||||
color.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
|
||||
color.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
|
||||
color.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
||||
color.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
|
||||
color.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
color.finalLayout = final;
|
||||
VkAttachmentReference ref = { 0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL };
|
||||
VkSubpassDescription subpass = {};
|
||||
subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
|
||||
subpass.colorAttachmentCount = 1;
|
||||
subpass.pColorAttachments = &ref;
|
||||
VkSubpassDependency deps[3] = {};
|
||||
deps[0].srcSubpass = VK_SUBPASS_EXTERNAL;
|
||||
deps[0].dstSubpass = 0;
|
||||
deps[0].srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
deps[0].srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
|
||||
deps[0].dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
||||
deps[0].dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
||||
deps[1].srcSubpass = VK_SUBPASS_EXTERNAL;
|
||||
deps[1].dstSubpass = 0;
|
||||
deps[1].srcStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT | VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
||||
deps[1].srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
||||
deps[1].dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
|
||||
deps[1].dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
||||
deps[2].srcSubpass = 0;
|
||||
deps[2].dstSubpass = VK_SUBPASS_EXTERNAL;
|
||||
deps[2].srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
||||
deps[2].srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
||||
deps[2].dstStageMask = next_stage;
|
||||
deps[2].dstAccessMask = next_access;
|
||||
VkRenderPassCreateInfo rp = { VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO };
|
||||
rp.attachmentCount = 1;
|
||||
rp.pAttachments = &color;
|
||||
rp.subpassCount = 1;
|
||||
rp.pSubpasses = &subpass;
|
||||
rp.dependencyCount = 3;
|
||||
rp.pDependencies = deps;
|
||||
CHECK(vkCreateRenderPass(gfx.device, &rp, nullptr, pass));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool make_framebuffer(VkRenderPass pass, VkImageView view, VkFramebuffer *fb)
|
||||
{
|
||||
VkFramebufferCreateInfo fi = { VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO };
|
||||
fi.renderPass = pass;
|
||||
fi.attachmentCount = 1;
|
||||
fi.pAttachments = &view;
|
||||
fi.width = gfx.width;
|
||||
fi.height = gfx.height;
|
||||
fi.layers = 1;
|
||||
CHECK(vkCreateFramebuffer(gfx.device, &fi, nullptr, fb));
|
||||
return true;
|
||||
}
|
||||
|
||||
/* HDR10 output's targets and the UI layer's pipeline. Optional: without
|
||||
* them the app stays SDR. */
|
||||
bool create_hdr()
|
||||
{
|
||||
/* the UI layer: the swapchain's format, so ImGui's pipeline (made for
|
||||
* gfx.render_pass) draws in its pass as well */
|
||||
if (!gfx_image(gfx.width, gfx.height, gfx.format,
|
||||
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, &hdr.ui_image,
|
||||
&hdr.ui_memory, &hdr.ui_view))
|
||||
return false;
|
||||
if (!gfx_image(gfx.width, gfx.height, HDR_FORMAT,
|
||||
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT, &hdr.image,
|
||||
&hdr.memory, &hdr.view))
|
||||
return false;
|
||||
if (!make_pass(gfx.format, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
|
||||
VK_ACCESS_SHADER_READ_BIT, &hdr.ui_pass) ||
|
||||
!make_pass(HDR_FORMAT, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
VK_ACCESS_TRANSFER_READ_BIT, &gfx.hdr_pass) ||
|
||||
!make_framebuffer(hdr.ui_pass, hdr.ui_view, &hdr.ui_fb) ||
|
||||
!make_framebuffer(gfx.hdr_pass, hdr.view, &hdr.fb))
|
||||
return false;
|
||||
|
||||
VkSamplerCreateInfo si = { VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO };
|
||||
si.magFilter = si.minFilter = VK_FILTER_NEAREST;
|
||||
si.addressModeU = si.addressModeV = si.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
||||
CHECK(vkCreateSampler(gfx.device, &si, nullptr, &hdr.sampler));
|
||||
VkDescriptorSetLayoutBinding b = {};
|
||||
b.binding = 0;
|
||||
b.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
||||
b.descriptorCount = 1;
|
||||
b.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||
VkDescriptorSetLayoutCreateInfo li = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO };
|
||||
li.bindingCount = 1;
|
||||
li.pBindings = &b;
|
||||
CHECK(vkCreateDescriptorSetLayout(gfx.device, &li, nullptr, &hdr.set_layout));
|
||||
VkDescriptorPoolSize ps = { VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1 };
|
||||
VkDescriptorPoolCreateInfo pi = { VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO };
|
||||
pi.maxSets = 1;
|
||||
pi.poolSizeCount = 1;
|
||||
pi.pPoolSizes = &ps;
|
||||
CHECK(vkCreateDescriptorPool(gfx.device, &pi, nullptr, &hdr.pool));
|
||||
VkDescriptorSetAllocateInfo ai = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO };
|
||||
ai.descriptorPool = hdr.pool;
|
||||
ai.descriptorSetCount = 1;
|
||||
ai.pSetLayouts = &hdr.set_layout;
|
||||
CHECK(vkAllocateDescriptorSets(gfx.device, &ai, &hdr.set));
|
||||
VkDescriptorImageInfo ii = { hdr.sampler, hdr.ui_view, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL };
|
||||
VkWriteDescriptorSet w = { VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET };
|
||||
w.dstSet = hdr.set;
|
||||
w.dstBinding = 0;
|
||||
w.descriptorCount = 1;
|
||||
w.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
||||
w.pImageInfo = ⅈ
|
||||
vkUpdateDescriptorSets(gfx.device, 1, &w, 0, nullptr);
|
||||
|
||||
VkPushConstantRange range = { VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(float) };
|
||||
VkPipelineLayoutCreateInfo pl = { VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO };
|
||||
pl.setLayoutCount = 1;
|
||||
pl.pSetLayouts = &hdr.set_layout;
|
||||
pl.pushConstantRangeCount = 1;
|
||||
pl.pPushConstantRanges = ⦥
|
||||
CHECK(vkCreatePipelineLayout(gfx.device, &pl, nullptr, &hdr.layout));
|
||||
VkShaderModule vs = gfx_shader(spv_fullscreen_vert, sizeof(spv_fullscreen_vert));
|
||||
VkShaderModule fs = gfx_shader(spv_ui_pq_frag, sizeof(spv_ui_pq_frag));
|
||||
VkPipelineShaderStageCreateInfo stages[2] = {};
|
||||
stages[0] = { VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO };
|
||||
stages[0].stage = VK_SHADER_STAGE_VERTEX_BIT;
|
||||
stages[0].module = vs;
|
||||
stages[0].pName = "main";
|
||||
stages[1] = { VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO };
|
||||
stages[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||
stages[1].module = fs;
|
||||
stages[1].pName = "main";
|
||||
VkPipelineVertexInputStateCreateInfo vi = { VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO };
|
||||
VkPipelineInputAssemblyStateCreateInfo ia = { VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO };
|
||||
ia.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
|
||||
VkPipelineViewportStateCreateInfo vp = { VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO };
|
||||
vp.viewportCount = 1;
|
||||
vp.scissorCount = 1;
|
||||
VkPipelineRasterizationStateCreateInfo rs = { VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO };
|
||||
rs.polygonMode = VK_POLYGON_MODE_FILL;
|
||||
rs.cullMode = VK_CULL_MODE_NONE;
|
||||
rs.lineWidth = 1.0f;
|
||||
VkPipelineMultisampleStateCreateInfo ms = { VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO };
|
||||
ms.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
|
||||
/* premultiplied over */
|
||||
VkPipelineColorBlendAttachmentState att = {};
|
||||
att.blendEnable = VK_TRUE;
|
||||
att.srcColorBlendFactor = VK_BLEND_FACTOR_ONE;
|
||||
att.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
|
||||
att.colorBlendOp = VK_BLEND_OP_ADD;
|
||||
att.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE;
|
||||
att.dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
|
||||
att.alphaBlendOp = VK_BLEND_OP_ADD;
|
||||
att.colorWriteMask = 0xf;
|
||||
VkPipelineColorBlendStateCreateInfo cb = { VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO };
|
||||
cb.attachmentCount = 1;
|
||||
cb.pAttachments = &att;
|
||||
VkDynamicState dyn[2] = { VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR };
|
||||
VkPipelineDynamicStateCreateInfo ds = { VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO };
|
||||
ds.dynamicStateCount = 2;
|
||||
ds.pDynamicStates = dyn;
|
||||
VkGraphicsPipelineCreateInfo gp = { VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO };
|
||||
gp.stageCount = 2;
|
||||
gp.pStages = stages;
|
||||
gp.pVertexInputState = &vi;
|
||||
gp.pInputAssemblyState = &ia;
|
||||
gp.pViewportState = &vp;
|
||||
gp.pRasterizationState = &rs;
|
||||
gp.pMultisampleState = &ms;
|
||||
gp.pColorBlendState = &cb;
|
||||
gp.pDynamicState = &ds;
|
||||
gp.layout = hdr.layout;
|
||||
gp.renderPass = gfx.hdr_pass;
|
||||
VkResult r = vkCreateGraphicsPipelines(gfx.device, VK_NULL_HANDLE, 1, &gp, nullptr, &hdr.pipeline);
|
||||
vkDestroyShaderModule(gfx.device, vs, nullptr);
|
||||
vkDestroyShaderModule(gfx.device, fs, nullptr);
|
||||
CHECK(r);
|
||||
return true;
|
||||
}
|
||||
|
||||
void begin(VkCommandBuffer cmd, VkRenderPass pass, VkFramebuffer fb, float alpha)
|
||||
{
|
||||
VkClearValue clear = {};
|
||||
clear.color = { { 0.0f, 0.0f, 0.0f, alpha } };
|
||||
VkRenderPassBeginInfo rb = { VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO };
|
||||
rb.renderPass = pass;
|
||||
rb.framebuffer = fb;
|
||||
rb.renderArea.extent = { gfx.width, gfx.height };
|
||||
rb.clearValueCount = 1;
|
||||
rb.pClearValues = &clear;
|
||||
vkCmdBeginRenderPass(cmd, &rb, VK_SUBPASS_CONTENTS_INLINE);
|
||||
}
|
||||
|
||||
#ifdef VLCPS5_HOST
|
||||
/* An HDR10 frame (10:10:10:2 PQ, BT.2020) in the offscreen image, made
|
||||
* viewable for the PNG: light, SDR white at 203 nits, BT.709, gamma 2.4. */
|
||||
void hdr_preview(std::vector<uint8_t> &rgb, const uint32_t *px, size_t n)
|
||||
{
|
||||
auto nits = [](float e) {
|
||||
float p = powf(e, 1 / 78.84375f);
|
||||
return 10000 * powf(fmaxf(p - 0.8359375f, 0) / (18.8515625f - 18.6875f * p), 1 / 0.1593017578125f);
|
||||
};
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
uint32_t v = px[i];
|
||||
float b = nits((v & 1023) / 1023.0f) / UI_NITS, g = nits(((v >> 10) & 1023) / 1023.0f) / UI_NITS,
|
||||
r = nits(((v >> 20) & 1023) / 1023.0f) / UI_NITS;
|
||||
float o[3] = { 1.6605f * r - 0.5876f * g - 0.0728f * b, -0.1246f * r + 1.1329f * g - 0.0083f * b,
|
||||
-0.0182f * r - 0.1006f * g + 1.1187f * b };
|
||||
for (int c = 0; c < 3; c++)
|
||||
rgb[i * 3 + c] = (uint8_t)(powf(fminf(fmaxf(o[c], 0), 1), 1 / 2.4f) * 255 + 0.5f);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef VLCPS5_HOST
|
||||
/* The offscreen image (BGRA) as an RGB PNG. */
|
||||
void save_png(const char *path)
|
||||
@@ -301,7 +548,9 @@ void save_png(const char *path)
|
||||
uint32_t w = gfx.width, h = gfx.height;
|
||||
std::vector<uint8_t> rgb((size_t)w * h * 3);
|
||||
const uint8_t *src = (const uint8_t *)readback_mapped;
|
||||
for (size_t i = 0; i < (size_t)w * h; i++) {
|
||||
if (gfx.hdr)
|
||||
hdr_preview(rgb, (const uint32_t *)src, (size_t)w * h);
|
||||
for (size_t i = 0; i < (size_t)w * h && !gfx.hdr; i++) {
|
||||
rgb[i * 3] = src[i * 4 + 2];
|
||||
rgb[i * 3 + 1] = src[i * 4 + 1];
|
||||
rgb[i * 3 + 2] = src[i * 4];
|
||||
@@ -334,7 +583,82 @@ bool gfx_init()
|
||||
return false;
|
||||
if (gfx.offscreen ? !create_offscreen() : !create_swapchain())
|
||||
return false;
|
||||
return create_targets();
|
||||
if (!create_targets())
|
||||
return false;
|
||||
if (!create_hdr()) {
|
||||
fprintf(stderr, "gfx: no HDR10 output (its targets couldn't be made)\n");
|
||||
gfx.hdr_pass = VK_NULL_HANDLE;
|
||||
}
|
||||
gfx.display_range = vlcps5_wsi_videoout_dynamic_range ? vlcps5_wsi_videoout_dynamic_range() : -1;
|
||||
fprintf(stderr, "gfx: output %s, HDR10 output %s\n",
|
||||
gfx.display_range == 2 ? "HDR" : gfx.display_range == 1 ? "SDR" : "unknown",
|
||||
gfx.hdr_pass && (vlcps5_wsi_videoout_set_hdr || gfx.offscreen) ? "possible" : "not possible");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool gfx_set_hdr(bool on)
|
||||
{
|
||||
if (on == gfx.hdr)
|
||||
return true;
|
||||
if (on && !gfx.hdr_pass)
|
||||
return false;
|
||||
/* nothing drawn in one format may land after the switch */
|
||||
vkDeviceWaitIdle(gfx.device);
|
||||
int rc;
|
||||
if (vlcps5_wsi_videoout_set_hdr)
|
||||
rc = vlcps5_wsi_videoout_set_hdr(on ? 1 : 0);
|
||||
else
|
||||
rc = gfx.offscreen && getenv("VLCPS5_HDR_TEST") ? 0 : -1; /* host: the preview */
|
||||
fprintf(stderr, "gfx: HDR10 output %s: %s (%#x)\n", on ? "on" : "off", rc == 0 ? "done" : "refused",
|
||||
(unsigned)rc);
|
||||
if (rc != 0 && on)
|
||||
return false;
|
||||
/* off even if refused: SDR pixels are what is drawn from here */
|
||||
gfx.hdr = on;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool gfx_set_refresh(int mode, int *period_us)
|
||||
{
|
||||
*period_us = 0;
|
||||
if (!vlcps5_wsi_videoout_set_refresh)
|
||||
return false;
|
||||
/* nothing in flight while the output changes */
|
||||
vkDeviceWaitIdle(gfx.device);
|
||||
return vlcps5_wsi_videoout_set_refresh(mode, period_us) == 0;
|
||||
}
|
||||
|
||||
int gfx_output_range()
|
||||
{
|
||||
if (vlcps5_wsi_videoout_dynamic_range)
|
||||
return vlcps5_wsi_videoout_dynamic_range();
|
||||
return gfx.offscreen && getenv("VLCPS5_HDR_TEST") ? atoi(getenv("VLCPS5_HDR_TEST")) : -1;
|
||||
}
|
||||
|
||||
void gfx_begin_ui_pass(VkCommandBuffer cmd)
|
||||
{
|
||||
begin(cmd, hdr.ui_pass, hdr.ui_fb, 0.0f); /* clear: transparent */
|
||||
pass_now = PASS_UI;
|
||||
}
|
||||
|
||||
void gfx_begin_hdr_pass(VkCommandBuffer cmd)
|
||||
{
|
||||
if (pass_now != PASS_NONE)
|
||||
vkCmdEndRenderPass(cmd);
|
||||
begin(cmd, gfx.hdr_pass, hdr.fb, 1.0f);
|
||||
pass_now = PASS_HDR;
|
||||
}
|
||||
|
||||
void gfx_draw_ui_layer(VkCommandBuffer cmd)
|
||||
{
|
||||
VkViewport vp = { 0, 0, (float)gfx.width, (float)gfx.height, 0, 1 };
|
||||
VkRect2D sc = { { 0, 0 }, { gfx.width, gfx.height } };
|
||||
vkCmdSetViewport(cmd, 0, 1, &vp);
|
||||
vkCmdSetScissor(cmd, 0, 1, &sc);
|
||||
vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, hdr.pipeline);
|
||||
vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, hdr.layout, 0, 1, &hdr.set, 0, nullptr);
|
||||
vkCmdPushConstants(cmd, hdr.layout, VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(float), &UI_NITS);
|
||||
vkCmdDraw(cmd, 3, 1, 0, 0);
|
||||
}
|
||||
|
||||
void gfx_shutdown()
|
||||
@@ -383,12 +707,32 @@ void gfx_begin_pass(VkCommandBuffer cmd)
|
||||
rb.clearValueCount = 1;
|
||||
rb.pClearValues = &clear;
|
||||
vkCmdBeginRenderPass(cmd, &rb, VK_SUBPASS_CONTENTS_INLINE);
|
||||
pass_now = PASS_MAIN;
|
||||
}
|
||||
|
||||
void gfx_end_frame(VkCommandBuffer cmd)
|
||||
{
|
||||
Frame &f = frames[gfx.frame_slot];
|
||||
vkCmdEndRenderPass(cmd);
|
||||
if (pass_now == PASS_HDR) {
|
||||
/* the 10-bit frame into the framebuffer: same 32-bit pixels and tiling */
|
||||
VkImage dst = images[image_index];
|
||||
gfx_barrier(cmd, dst, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT, 0, VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
VK_ACCESS_TRANSFER_WRITE_BIT);
|
||||
VkImageCopy region = {};
|
||||
region.srcSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 };
|
||||
region.dstSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 };
|
||||
region.extent = { gfx.width, gfx.height, 1 };
|
||||
vkCmdCopyImage(cmd, hdr.image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, dst,
|
||||
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion);
|
||||
gfx_barrier(cmd, dst, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||
gfx.offscreen ? VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL : VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT, VK_ACCESS_TRANSFER_WRITE_BIT,
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT | VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
|
||||
VK_ACCESS_TRANSFER_READ_BIT);
|
||||
}
|
||||
pass_now = PASS_NONE;
|
||||
#ifdef VLCPS5_HOST
|
||||
const char *shot = plat_screenshot_path(gfx.frame_number);
|
||||
if (shot) {
|
||||
@@ -400,7 +744,8 @@ void gfx_end_frame(VkCommandBuffer cmd)
|
||||
}
|
||||
#endif
|
||||
vkEndCommandBuffer(cmd);
|
||||
VkPipelineStageFlags wait_stage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
||||
/* (the HDR10 frame reaches the framebuffer by a copy) */
|
||||
VkPipelineStageFlags wait_stage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
VkSubmitInfo si = { VK_STRUCTURE_TYPE_SUBMIT_INFO };
|
||||
si.commandBufferCount = 1;
|
||||
si.pCommandBuffers = &cmd;
|
||||
@@ -469,13 +814,13 @@ bool gfx_buffer(VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFla
|
||||
}
|
||||
|
||||
bool gfx_image(uint32_t w, uint32_t h, VkFormat format, VkImageUsageFlags usage, VkImage *image,
|
||||
VkDeviceMemory *memory, VkImageView *view)
|
||||
VkDeviceMemory *memory, VkImageView *view, uint32_t mips)
|
||||
{
|
||||
VkImageCreateInfo ii = { VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO };
|
||||
ii.imageType = VK_IMAGE_TYPE_2D;
|
||||
ii.format = format;
|
||||
ii.extent = { w, h, 1 };
|
||||
ii.mipLevels = 1;
|
||||
ii.mipLevels = mips;
|
||||
ii.arrayLayers = 1;
|
||||
ii.samples = VK_SAMPLE_COUNT_1_BIT;
|
||||
ii.tiling = VK_IMAGE_TILING_OPTIMAL;
|
||||
@@ -490,13 +835,32 @@ bool gfx_image(uint32_t w, uint32_t h, VkFormat format, VkImageUsageFlags usage,
|
||||
ai.memoryTypeIndex = gfx_memory_type(req.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
|
||||
if (ai.memoryTypeIndex == UINT32_MAX)
|
||||
ai.memoryTypeIndex = gfx_memory_type(req.memoryTypeBits, 0);
|
||||
CHECK(vkAllocateMemory(gfx.device, &ai, nullptr, memory));
|
||||
VkResult r = vkAllocateMemory(gfx.device, &ai, nullptr, memory);
|
||||
/* The video memory full (a 4K HDR film's decoder holds 840 MiB of it):
|
||||
* any other kind the image can live in. Failing, a 4K video stayed
|
||||
* black for the whole of its first open (2026-10-18). */
|
||||
for (uint32_t t = 0; r != VK_SUCCESS && t < 32; t++) {
|
||||
if (!(req.memoryTypeBits & (1u << t)) || t == ai.memoryTypeIndex)
|
||||
continue;
|
||||
VkMemoryAllocateInfo other = ai;
|
||||
other.memoryTypeIndex = t;
|
||||
r = vkAllocateMemory(gfx.device, &other, nullptr, memory);
|
||||
if (r == VK_SUCCESS)
|
||||
fprintf(stderr, "gfx: %ux%u image: video memory full, memory type %u instead\n", w, h, t);
|
||||
}
|
||||
if (r != VK_SUCCESS) {
|
||||
fprintf(stderr, "gfx: no memory for a %ux%u image (%llu KiB): %d\n", w, h,
|
||||
(unsigned long long)(req.size >> 10), r);
|
||||
vkDestroyImage(gfx.device, *image, nullptr);
|
||||
*image = VK_NULL_HANDLE;
|
||||
return false;
|
||||
}
|
||||
CHECK(vkBindImageMemory(gfx.device, *image, *memory, 0));
|
||||
VkImageViewCreateInfo vi = { VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO };
|
||||
vi.image = *image;
|
||||
vi.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||
vi.format = format;
|
||||
vi.subresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 };
|
||||
vi.subresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT, 0, mips, 0, 1 };
|
||||
CHECK(vkCreateImageView(gfx.device, &vi, nullptr, view));
|
||||
return true;
|
||||
}
|
||||
@@ -549,6 +913,6 @@ void gfx_barrier(VkCommandBuffer cmd, VkImage image, VkImageLayout from, VkImage
|
||||
b.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
b.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
b.image = image;
|
||||
b.subresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 };
|
||||
b.subresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT, 0, VK_REMAINING_MIP_LEVELS, 0, 1 };
|
||||
vkCmdPipelineBarrier(cmd, src_stage, dst_stage, 0, 0, nullptr, 0, nullptr, 1, &b);
|
||||
}
|
||||
@@ -26,6 +26,12 @@ struct Gfx {
|
||||
bool offscreen; /* host test build */
|
||||
uint32_t frame_slot; /* 0..GFX_FRAMES-1, the frame being recorded */
|
||||
uint64_t frame_number; /* frames presented so far */
|
||||
/* HDR10 output: the frame is drawn in a 10-bit image (video as PQ,
|
||||
* BT.2020, the UI layer over it) and copied into the framebuffer, which
|
||||
* VideoOut then shows as HDR10. */
|
||||
VkRenderPass hdr_pass; /* the 10-bit frame's pass (null: no HDR output) */
|
||||
bool hdr; /* HDR10 output on now */
|
||||
int display_range; /* the output at start: 1 SDR, 2 HDR, other unknown */
|
||||
};
|
||||
extern Gfx gfx;
|
||||
|
||||
@@ -38,14 +44,27 @@ VkCommandBuffer gfx_begin_frame();
|
||||
void gfx_begin_pass(VkCommandBuffer cmd);
|
||||
/* Ends the pass, submits, presents (or saves the host screenshot). */
|
||||
void gfx_end_frame(VkCommandBuffer cmd);
|
||||
/* HDR10 output on or off (waits for the GPU); false if it couldn't change. */
|
||||
bool gfx_set_hdr(bool on);
|
||||
/* What the console sends to the TV now: 1 SDR, 2 HDR, other unknown. */
|
||||
int gfx_output_range();
|
||||
/* The output's refresh (VideoOut modes: 2 = 23.976 Hz, 3 = 24, 9 = 50,
|
||||
* 1 = the default); the vblank period measured after, in microseconds. */
|
||||
bool gfx_set_refresh(int mode, int *period_us);
|
||||
/* With HDR10 output on, a frame is: the UI pass (ImGui into its own layer),
|
||||
* then the HDR pass (the video, then gfx_draw_ui_layer), then gfx_end_frame. */
|
||||
void gfx_begin_ui_pass(VkCommandBuffer cmd);
|
||||
void gfx_begin_hdr_pass(VkCommandBuffer cmd); /* ends the UI pass */
|
||||
void gfx_draw_ui_layer(VkCommandBuffer cmd);
|
||||
/* The fence of the frame recorded in this slot has passed: its resources are free. */
|
||||
uint64_t gfx_completed_frame();
|
||||
|
||||
uint32_t gfx_memory_type(uint32_t type_bits, VkMemoryPropertyFlags flags);
|
||||
bool gfx_buffer(VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags flags,
|
||||
VkBuffer *buffer, VkDeviceMemory *memory, void **mapped);
|
||||
/* mips: levels made and seen by the view (the caller fills them). */
|
||||
bool gfx_image(uint32_t w, uint32_t h, VkFormat format, VkImageUsageFlags usage, VkImage *image,
|
||||
VkDeviceMemory *memory, VkImageView *view);
|
||||
VkDeviceMemory *memory, VkImageView *view, uint32_t mips = 1);
|
||||
VkShaderModule gfx_shader(const uint32_t *code, size_t size);
|
||||
/* Runs commands now and waits (set-up only). */
|
||||
VkCommandBuffer gfx_one_shot_begin();
|
||||
|
||||
+17
-1
@@ -6,10 +6,13 @@
|
||||
#include "lang.h"
|
||||
|
||||
#include <atomic>
|
||||
#include <mutex>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
#include <fribidi/fribidi.h>
|
||||
@@ -170,7 +173,20 @@ const char *tr(const char *english)
|
||||
if (!t)
|
||||
return english;
|
||||
auto it = t->find(english);
|
||||
return it == t->end() ? english : it->second.c_str();
|
||||
if (it == t->end()) {
|
||||
/* Test aid (the host build with VLCPS5_LANG_MISSES set): each string
|
||||
* drawn that this language lacks, once, so a tour finds them all. */
|
||||
static const bool log_misses = getenv("VLCPS5_LANG_MISSES") != nullptr;
|
||||
if (log_misses) {
|
||||
static std::mutex m;
|
||||
static std::unordered_set<std::string> said;
|
||||
std::lock_guard<std::mutex> g(m);
|
||||
if (said.insert(english).second)
|
||||
fprintf(stderr, "lang-miss: %s\n", english);
|
||||
}
|
||||
return english;
|
||||
}
|
||||
return it->second.c_str();
|
||||
}
|
||||
|
||||
std::string trf(const char *english_format, ...)
|
||||
|
||||
+294
-18
@@ -29,6 +29,7 @@
|
||||
|
||||
#include "backends/imgui_impl_vulkan.h"
|
||||
#include "gfx.h"
|
||||
#include "lang.h"
|
||||
#include "platform.h"
|
||||
#include "player.h"
|
||||
|
||||
@@ -129,6 +130,17 @@ bool has_file(const std::string &path)
|
||||
return stat(path.c_str(), &st) == 0;
|
||||
}
|
||||
|
||||
/* What a scan passed over, for the log: "(folder too deep) 1". */
|
||||
std::map<std::string, int> skipped;
|
||||
int archives_found, others_found;
|
||||
|
||||
/* Folders a drive keeps for the system, never media. */
|
||||
bool system_folder(const char *name)
|
||||
{
|
||||
return !strcmp(name, "System Volume Information") || !strcmp(name, "$RECYCLE.BIN") ||
|
||||
!strcmp(name, "lost+found") || !strcmp(name, "sce_sys") || !strcmp(name, "sce_module");
|
||||
}
|
||||
|
||||
void scan_dir(const std::string &dir, int depth)
|
||||
{
|
||||
/* A disc copied as a folder (VIDEO_TS, BDMV): one item, not its files. */
|
||||
@@ -156,23 +168,32 @@ void scan_dir(const std::string &dir, int depth)
|
||||
continue;
|
||||
std::string path = dir + "/" + e->d_name;
|
||||
struct stat st;
|
||||
if (stat(path.c_str(), &st) != 0)
|
||||
if (stat(path.c_str(), &st) != 0) {
|
||||
skipped["(can't read)"]++;
|
||||
continue;
|
||||
}
|
||||
if (S_ISDIR(st.st_mode)) {
|
||||
if (system_folder(e->d_name))
|
||||
continue;
|
||||
if (depth < 4)
|
||||
scan_dir(path, depth + 1);
|
||||
else
|
||||
skipped["(folder too deep)"]++;
|
||||
continue;
|
||||
}
|
||||
const char *dot = strrchr(e->d_name, '.');
|
||||
if (!dot)
|
||||
continue;
|
||||
if (has_ext(dot + 1, playlist_exts)) {
|
||||
dot = e->d_name + strlen(e->d_name); /* no extension: "" */
|
||||
if (!strcasecmp(dot, ".part"))
|
||||
continue; /* a file still arriving from the phone page */
|
||||
if (*dot && has_ext(dot + 1, playlist_exts)) {
|
||||
playlists.push_back({ path, tidy_name(e->d_name), dir });
|
||||
continue;
|
||||
}
|
||||
bool video = has_ext(dot + 1, video_exts), audio = has_ext(dot + 1, audio_exts);
|
||||
bool image = has_ext(dot + 1, image_exts), text = has_ext(dot + 1, text_exts);
|
||||
bool archive = has_ext(dot + 1, archive_exts), iso = !strcasecmp(dot + 1, "iso");
|
||||
const char *x = *dot ? dot + 1 : dot;
|
||||
bool video = has_ext(x, video_exts), audio = has_ext(x, audio_exts);
|
||||
bool image = has_ext(x, image_exts), text = has_ext(x, text_exts);
|
||||
bool archive = has_ext(x, archive_exts), iso = !strcasecmp(x, "iso") || !strcasecmp(x, "img"); /* a DVD image named .img */
|
||||
if (image) {
|
||||
/* an album's cover file isn't a photo of its own */
|
||||
std::string base = std::string(e->d_name, dot - e->d_name);
|
||||
@@ -181,12 +202,14 @@ void scan_dir(const std::string &dir, int depth)
|
||||
if (base == "cover" || base == "folder" || base == "front" || base.compare(0, 8, "albumart") == 0)
|
||||
continue;
|
||||
}
|
||||
if (!video && !audio && !image && !text && !archive && !iso)
|
||||
continue;
|
||||
/* Everything else shows in Browse too: what VLC can't play says so. */
|
||||
bool other = !video && !audio && !image && !text && !archive && !iso;
|
||||
archives_found += archive;
|
||||
others_found += other;
|
||||
MediaItem m = {};
|
||||
m.path = path;
|
||||
m.name = tidy_name(e->d_name);
|
||||
m.ext = dot + 1;
|
||||
m.name = *dot ? tidy_name(e->d_name) : tidy_name(std::string(e->d_name) + ".x");
|
||||
m.ext = x;
|
||||
for (char &c : m.ext)
|
||||
c = (char)toupper((unsigned char)c);
|
||||
m.folder = dir;
|
||||
@@ -194,6 +217,7 @@ void scan_dir(const std::string &dir, int depth)
|
||||
m.image = image;
|
||||
m.text = text;
|
||||
m.archive = archive;
|
||||
m.other = other;
|
||||
m.disc = iso;
|
||||
m.size = st.st_size;
|
||||
m.mtime = st.st_mtime;
|
||||
@@ -640,6 +664,8 @@ void look_at(const Job &job)
|
||||
libvlc_media_add_option(m, ":no-audio");
|
||||
libvlc_media_add_option(m, ":no-spu");
|
||||
libvlc_media_add_option(m, ":avcodec-threads=2");
|
||||
/* the console's video decoder stays for the video being watched */
|
||||
libvlc_media_add_option(m, ":no-ps5vdec");
|
||||
Grab g;
|
||||
g.frames = 0;
|
||||
g.got = false;
|
||||
@@ -822,7 +848,7 @@ void details_main(std::string path, int64_t size, std::string ext)
|
||||
if (!lang.empty())
|
||||
val += " (" + lang + ")";
|
||||
char label[32];
|
||||
snprintf(label, sizeof(label), "Audio %d", ++audio_no);
|
||||
snprintf(label, sizeof(label), tr("Audio %d"), ++audio_no);
|
||||
d.rows.push_back({ label, val });
|
||||
} else if (t[i]->i_type == libvlc_track_text) {
|
||||
sub_no++;
|
||||
@@ -856,35 +882,86 @@ void apply_resumes()
|
||||
|
||||
/* ---- textures ----------------------------------------------------------------------- */
|
||||
|
||||
/* The next smaller level of a BGRA picture: each pixel the mean of 2x2. */
|
||||
std::vector<uint8_t> half_size(const std::vector<uint8_t> &src, uint32_t w, uint32_t h, uint32_t *nw, uint32_t *nh)
|
||||
{
|
||||
*nw = std::max(1u, w / 2);
|
||||
*nh = std::max(1u, h / 2);
|
||||
std::vector<uint8_t> out((size_t)*nw * *nh * 4);
|
||||
for (uint32_t y = 0; y < *nh; y++) {
|
||||
const uint8_t *r0 = &src[(size_t)std::min(2 * y, h - 1) * w * 4];
|
||||
const uint8_t *r1 = &src[(size_t)std::min(2 * y + 1, h - 1) * w * 4];
|
||||
uint8_t *o = &out[(size_t)y * *nw * 4];
|
||||
for (uint32_t x = 0; x < *nw; x++) {
|
||||
uint32_t x0 = std::min(2 * x, w - 1) * 4, x1 = std::min(2 * x + 1, w - 1) * 4;
|
||||
for (int c = 0; c < 4; c++)
|
||||
o[x * 4 + c] = (uint8_t)((r0[x0 + c] + r0[x1 + c] + r1[x0 + c] + r1[x1 + c] + 2) / 4);
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
/* A picture as a texture. Thumbnails (and covers) get every smaller level
|
||||
* too: drawn small (a playlist row, a Music cover) a 480-wide picture
|
||||
* sampled once a pixel shimmered; the levels make it smooth at any size.
|
||||
* Big photos are drawn near their size and keep one level. */
|
||||
ImTextureID make_texture(const Finished &t)
|
||||
{
|
||||
if (!thumb_sampler) {
|
||||
VkSamplerCreateInfo si = { VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO };
|
||||
si.magFilter = si.minFilter = VK_FILTER_LINEAR;
|
||||
si.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
|
||||
si.minLod = 0;
|
||||
si.maxLod = VK_LOD_CLAMP_NONE;
|
||||
si.addressModeU = si.addressModeV = si.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
||||
vkCreateSampler(gfx.device, &si, nullptr, &thumb_sampler);
|
||||
}
|
||||
/* the levels, one after another in the staging buffer */
|
||||
std::vector<std::vector<uint8_t>> made;
|
||||
made.reserve(12);
|
||||
std::vector<VkBufferImageCopy> regions;
|
||||
VkDeviceSize total = t.bgra.size();
|
||||
regions.push_back({});
|
||||
regions[0].imageSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 };
|
||||
regions[0].imageExtent = { t.w, t.h, 1 };
|
||||
if (t.w <= 1024 && t.h <= 1024) {
|
||||
uint32_t w = t.w, h = t.h;
|
||||
const std::vector<uint8_t> *src = &t.bgra;
|
||||
while ((w > 1 || h > 1) && regions.size() < 12) {
|
||||
uint32_t nw, nh;
|
||||
made.push_back(half_size(*src, w, h, &nw, &nh));
|
||||
src = &made.back();
|
||||
w = nw;
|
||||
h = nh;
|
||||
VkBufferImageCopy r = {};
|
||||
r.bufferOffset = total;
|
||||
r.imageSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, (uint32_t)regions.size(), 0, 1 };
|
||||
r.imageExtent = { w, h, 1 };
|
||||
regions.push_back(r);
|
||||
total += made.back().size();
|
||||
}
|
||||
}
|
||||
Texture tex;
|
||||
if (!gfx_image(t.w, t.h, VK_FORMAT_B8G8R8A8_UNORM,
|
||||
VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT, &tex.image,
|
||||
&tex.memory, &tex.view))
|
||||
&tex.memory, &tex.view, (uint32_t)regions.size()))
|
||||
return 0;
|
||||
VkBuffer staging;
|
||||
VkDeviceMemory staging_mem;
|
||||
void *mapped;
|
||||
if (!gfx_buffer(t.bgra.size(), VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
|
||||
if (!gfx_buffer(total, VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
|
||||
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
|
||||
&staging, &staging_mem, &mapped))
|
||||
return 0;
|
||||
memcpy(mapped, t.bgra.data(), t.bgra.size());
|
||||
for (size_t i = 0; i < made.size(); i++)
|
||||
memcpy((uint8_t *)mapped + regions[i + 1].bufferOffset, made[i].data(), made[i].size());
|
||||
VkCommandBuffer cmd = gfx_one_shot_begin();
|
||||
gfx_barrier(cmd, tex.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, 0, VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
VK_ACCESS_TRANSFER_WRITE_BIT);
|
||||
VkBufferImageCopy region = {};
|
||||
region.imageSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 };
|
||||
region.imageExtent = { t.w, t.h, 1 };
|
||||
vkCmdCopyBufferToImage(cmd, staging, tex.image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion);
|
||||
vkCmdCopyBufferToImage(cmd, staging, tex.image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||
(uint32_t)regions.size(), regions.data());
|
||||
gfx_barrier(cmd, tex.image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
|
||||
@@ -984,6 +1061,8 @@ void scan()
|
||||
items.clear();
|
||||
playlists.clear();
|
||||
roots.clear();
|
||||
skipped.clear();
|
||||
archives_found = others_found = 0;
|
||||
roots.push_back(media_dir);
|
||||
scan_dir(media_dir, 0);
|
||||
for (const char *const *r = plat_media_roots(); *r; r++) {
|
||||
@@ -1012,7 +1091,7 @@ void scan()
|
||||
m.favourite = std::find(favourites.begin(), favourites.end(), m.path) != favourites.end();
|
||||
std::vector<Job> todo;
|
||||
for (MediaItem &m : items) {
|
||||
if (m.text || m.archive || m.disc)
|
||||
if (m.text || m.archive || m.disc || m.other)
|
||||
continue; /* no picture to make (a disc's menu is its picture) */
|
||||
auto k = known.find(thumb_file(m));
|
||||
if (k != known.end()) {
|
||||
@@ -1044,6 +1123,11 @@ void scan()
|
||||
last_signature = watch_signature();
|
||||
fprintf(stderr, "library: %zu files in %zu folders, %zu to look at\n", items.size(),
|
||||
roots.size(), todo.size());
|
||||
std::string passed;
|
||||
for (auto &k : skipped)
|
||||
passed += (passed.empty() ? "" : ", ") + k.first + " " + std::to_string(k.second);
|
||||
fprintf(stderr, "library: %d archives, %d other files; passed over: %s\n", archives_found,
|
||||
others_found, passed.empty() ? "nothing" : passed.c_str());
|
||||
}
|
||||
|
||||
} // namespace
|
||||
@@ -1356,6 +1440,198 @@ std::vector<int> library_playlist_items(const std::string &path)
|
||||
return out;
|
||||
}
|
||||
|
||||
int library_playlist_count(const std::string &path)
|
||||
{
|
||||
FILE *f = fopen(path.c_str(), "r");
|
||||
if (!f)
|
||||
return 0;
|
||||
bool pls = path.size() > 4 && strcasecmp(path.c_str() + path.size() - 4, ".pls") == 0;
|
||||
int n = 0;
|
||||
char line[4096];
|
||||
while (fgets(line, sizeof(line), f)) {
|
||||
const char *l = line;
|
||||
while (*l == ' ' || *l == '\t' || (unsigned char)*l == 0xEF || (unsigned char)*l == 0xBB || (unsigned char)*l == 0xBF)
|
||||
l++; /* indent, UTF-8 mark */
|
||||
if (pls ? (!strncasecmp(l, "File", 4) && strchr(l, '=')) : (*l && *l != '#' && *l != '\r' && *l != '\n'))
|
||||
n++;
|
||||
}
|
||||
fclose(f);
|
||||
return n;
|
||||
}
|
||||
|
||||
bool library_playlist_has_links(const std::string &path)
|
||||
{
|
||||
FILE *f = fopen(path.c_str(), "r");
|
||||
if (!f)
|
||||
return false;
|
||||
bool links = false;
|
||||
char line[4096];
|
||||
while (!links && fgets(line, sizeof(line), f)) {
|
||||
const char *l = line;
|
||||
if (*l == '#')
|
||||
continue;
|
||||
if (!strncasecmp(l, "File", 4) && strchr(l, '='))
|
||||
l = strchr(l, '=') + 1; /* .pls */
|
||||
const char *scheme = strstr(l, "://");
|
||||
links = scheme && scheme > l && strncasecmp(l, "file://", 7) != 0;
|
||||
}
|
||||
fclose(f);
|
||||
return links;
|
||||
}
|
||||
|
||||
/* ---- playlists made in VLC -------------------------------------------------------- */
|
||||
|
||||
namespace {
|
||||
|
||||
std::string playlist_dir()
|
||||
{
|
||||
return media_dir + "/Playlists";
|
||||
}
|
||||
|
||||
/* A name that can be a file name everywhere (FAT/exFAT drives, Windows). */
|
||||
std::string playlist_file_name(const std::string &name)
|
||||
{
|
||||
std::string n;
|
||||
for (char c : name)
|
||||
n += strchr("/\\:*?\"<>|", c) || (unsigned char)c < 32 ? '-' : c;
|
||||
while (!n.empty() && (n.back() == ' ' || n.back() == '.'))
|
||||
n.pop_back();
|
||||
while (!n.empty() && n[0] == ' ')
|
||||
n.erase(0, 1);
|
||||
return n.substr(0, 120);
|
||||
}
|
||||
|
||||
/* The files of one of ours, in order. */
|
||||
std::vector<std::string> playlist_read(const std::string &path)
|
||||
{
|
||||
std::vector<std::string> out;
|
||||
FILE *f = fopen(path.c_str(), "r");
|
||||
if (!f)
|
||||
return out;
|
||||
char line[4096];
|
||||
while (fgets(line, sizeof(line), f)) {
|
||||
std::string l = line;
|
||||
while (!l.empty() && (l.back() == '\n' || l.back() == '\r'))
|
||||
l.pop_back();
|
||||
if (l.size() >= 3 && (unsigned char)l[0] == 0xEF)
|
||||
l = l.substr(3);
|
||||
if (!l.empty() && l[0] != '#')
|
||||
out.push_back(l);
|
||||
}
|
||||
fclose(f);
|
||||
return out;
|
||||
}
|
||||
|
||||
/* Written whole to a temporary file, then put in place. */
|
||||
bool playlist_write(const std::string &path, const std::vector<std::string> &files)
|
||||
{
|
||||
std::string tmp = path + ".tmp";
|
||||
FILE *f = fopen(tmp.c_str(), "w");
|
||||
if (!f)
|
||||
return false;
|
||||
bool ok = fputs("#EXTM3U\n", f) >= 0;
|
||||
for (const std::string &p : files) {
|
||||
std::string name = p.substr(p.rfind('/') + 1);
|
||||
ok = ok && fprintf(f, "#EXTINF:-1,%s\n%s\n", tidy_name(name).c_str(), p.c_str()) > 0;
|
||||
}
|
||||
ok = fclose(f) == 0 && ok;
|
||||
if (ok)
|
||||
ok = rename(tmp.c_str(), path.c_str()) == 0;
|
||||
if (!ok)
|
||||
unlink(tmp.c_str());
|
||||
return ok;
|
||||
}
|
||||
|
||||
void playlists_sort()
|
||||
{
|
||||
std::sort(playlists.begin(), playlists.end(), [](const PlaylistFile &a, const PlaylistFile &b) {
|
||||
return strcasecmp(a.name.c_str(), b.name.c_str()) < 0;
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
bool library_playlist_ours(const std::string &path)
|
||||
{
|
||||
std::string d = playlist_dir() + "/";
|
||||
return path.compare(0, d.size(), d) == 0 && path.size() > 5 &&
|
||||
!strcasecmp(path.c_str() + path.size() - 5, ".m3u8");
|
||||
}
|
||||
|
||||
std::string library_playlist_create(const std::string &name)
|
||||
{
|
||||
std::string n = playlist_file_name(name);
|
||||
if (n.empty())
|
||||
return "";
|
||||
mkdir(playlist_dir().c_str(), 0777);
|
||||
std::string path = playlist_dir() + "/" + n + ".m3u8";
|
||||
struct stat st;
|
||||
if (stat(path.c_str(), &st) == 0 || !playlist_write(path, {}))
|
||||
return "";
|
||||
playlists.push_back({ path, tidy_name(n + ".m3u8"), playlist_dir() });
|
||||
playlists_sort();
|
||||
return path;
|
||||
}
|
||||
|
||||
bool library_playlist_add(const std::string &playlist, const std::string &file)
|
||||
{
|
||||
std::vector<std::string> files = playlist_read(playlist);
|
||||
if (std::find(files.begin(), files.end(), file) != files.end())
|
||||
return false;
|
||||
files.push_back(file);
|
||||
return playlist_write(playlist, files);
|
||||
}
|
||||
|
||||
bool library_playlist_remove(const std::string &playlist, const std::string &file)
|
||||
{
|
||||
std::vector<std::string> files = playlist_read(playlist);
|
||||
auto it = std::find(files.begin(), files.end(), file);
|
||||
if (it == files.end())
|
||||
return false;
|
||||
files.erase(it);
|
||||
return playlist_write(playlist, files);
|
||||
}
|
||||
|
||||
bool library_playlist_move(const std::string &playlist, const std::string &file, int step)
|
||||
{
|
||||
std::vector<std::string> files = playlist_read(playlist);
|
||||
auto it = std::find(files.begin(), files.end(), file);
|
||||
if (it == files.end())
|
||||
return false;
|
||||
/* to the next one the library has (a file on a drive that's out is
|
||||
* skipped over, so a move always shows) */
|
||||
long i = it - files.begin(), j = i;
|
||||
do
|
||||
j += step;
|
||||
while (j >= 0 && j < (long)files.size() && !library_find(files[j]));
|
||||
if (j < 0 || j >= (long)files.size())
|
||||
return false;
|
||||
std::string moved = files[i];
|
||||
files.erase(files.begin() + i);
|
||||
files.insert(files.begin() + j, moved);
|
||||
return playlist_write(playlist, files);
|
||||
}
|
||||
|
||||
std::string library_playlist_rename(const std::string &playlist, const std::string &name)
|
||||
{
|
||||
std::string n = playlist_file_name(name);
|
||||
if (n.empty())
|
||||
return "";
|
||||
std::string path = playlist_dir() + "/" + n + ".m3u8";
|
||||
struct stat st;
|
||||
if (path == playlist)
|
||||
return path;
|
||||
if (stat(path.c_str(), &st) == 0 || rename(playlist.c_str(), path.c_str()) != 0)
|
||||
return "";
|
||||
for (PlaylistFile &p : playlists)
|
||||
if (p.path == playlist) {
|
||||
p.path = path;
|
||||
p.name = tidy_name(n + ".m3u8");
|
||||
}
|
||||
playlists_sort();
|
||||
return path;
|
||||
}
|
||||
|
||||
std::vector<int64_t> library_bookmarks(const std::string &path)
|
||||
{
|
||||
std::vector<int64_t> out;
|
||||
|
||||
@@ -23,6 +23,7 @@ struct MediaItem {
|
||||
std::string artist, album; /* a song's tags, "" until read (or none) */
|
||||
bool disc; /* a DVD / Blu-ray: an .iso, or a folder with VIDEO_TS or BDMV */
|
||||
bool archive; /* .zip / .rar / .7z: opened like a folder in Browse */
|
||||
bool other; /* any other file: listed in Browse only; X hands it to VLC */
|
||||
int64_t size;
|
||||
int64_t mtime;
|
||||
int64_t length_ms; /* 0 until known */
|
||||
@@ -68,6 +69,23 @@ MediaItem *library_find(const std::string &path);
|
||||
std::vector<PlaylistFile> &library_playlists();
|
||||
/* The library files a playlist names, in its order (others are skipped). */
|
||||
std::vector<int> library_playlist_items(const std::string &path);
|
||||
/* Every entry it names, links and files alike. */
|
||||
int library_playlist_count(const std::string &path);
|
||||
/* It names links (http://, rtp://...): a channel list, opened in Browse. */
|
||||
bool library_playlist_has_links(const std::string &path);
|
||||
/* Playlists made in VLC: <media>/Playlists/<name>.m3u8, one absolute path a
|
||||
* line (with #EXTINF names), so VLC on a computer reads them too. Only these
|
||||
* are changed; ones found elsewhere just play. */
|
||||
bool library_playlist_ours(const std::string &path);
|
||||
/* A new empty one; its path, or "" (the name is taken, or no disk). */
|
||||
std::string library_playlist_create(const std::string &name);
|
||||
/* Adds a file at the end; false when it was already in or can't be written. */
|
||||
bool library_playlist_add(const std::string &playlist, const std::string &file);
|
||||
bool library_playlist_remove(const std::string &playlist, const std::string &file);
|
||||
/* Moves a file one place up (-1) or down (+1). */
|
||||
bool library_playlist_move(const std::string &playlist, const std::string &file, int step);
|
||||
/* A new name; the playlist's new path, or "". */
|
||||
std::string library_playlist_rename(const std::string &playlist, const std::string &name);
|
||||
/* Bookmarks inside a file (ms, sorted), remembered in cache/bookmarks.txt. */
|
||||
std::vector<int64_t> library_bookmarks(const std::string &path);
|
||||
void library_add_bookmark(const std::string &path, int64_t ms);
|
||||
|
||||
+84
-4
@@ -8,7 +8,9 @@
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <string>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "backends/imgui_impl_vulkan.h"
|
||||
@@ -78,6 +80,9 @@ int main(void)
|
||||
double t = plat_time();
|
||||
float dt = (float)(t - last);
|
||||
last = t;
|
||||
/* the interface stood still: always in the log (a freeze report) */
|
||||
if (dt > 0.5f && gfx.frame_number > 10)
|
||||
fprintf(stderr, "ui: a frame took %.0f ms (the interface froze)\n", dt * 1000);
|
||||
PadState pad;
|
||||
plat_pad_read(&pad);
|
||||
library_update();
|
||||
@@ -92,16 +97,91 @@ int main(void)
|
||||
ImGui::Render();
|
||||
double t_ui = plat_time();
|
||||
|
||||
/* HDR10 output while an HDR video shows (once a refusal, not again
|
||||
* until the wish changes) */
|
||||
/* The wish has to hold a moment first: while a video starts (its
|
||||
* picture set up, set up again) it came and went, and each switch
|
||||
* blanks the screen (on, off, on, off in a second: a 2026-10-13 log). */
|
||||
static bool hdr_refused;
|
||||
static double wish_since;
|
||||
static bool wish_last;
|
||||
bool want_hdr = video_wants_hdr_output();
|
||||
if (want_hdr != wish_last) {
|
||||
wish_last = want_hdr;
|
||||
wish_since = plat_time();
|
||||
}
|
||||
double hold = want_hdr ? 0.4 : 1.0;
|
||||
if (want_hdr != gfx.hdr && !(want_hdr && hdr_refused) && plat_time() - wish_since >= hold)
|
||||
hdr_refused = !gfx_set_hdr(want_hdr);
|
||||
if (!want_hdr)
|
||||
hdr_refused = false;
|
||||
|
||||
/* Match frame rate: the output's refresh follows the film playing
|
||||
* (23.976 / 24 / 50 Hz), and goes back to the default after. Asked
|
||||
* once a picture is up (the rate is known then); a mode the TV
|
||||
* doesn't really run at (the vblanks say) is put back and not asked
|
||||
* again for that video. */
|
||||
{
|
||||
static int mode_now = 1;
|
||||
static std::string refused_for;
|
||||
int want = 1;
|
||||
const VideoInfo &vi = player_video_info();
|
||||
if (player_match_rate() && player_active() && video_has_picture() && vi.fps > 0 &&
|
||||
refused_for != player_current_path()) {
|
||||
float f = vi.fps;
|
||||
if (fabsf(f - 23.976f) < 0.01f)
|
||||
want = 2;
|
||||
else if (fabsf(f - 24.0f) < 0.01f)
|
||||
want = 3;
|
||||
else if (fabsf(f - 25.0f) < 0.05f || fabsf(f - 50.0f) < 0.1f)
|
||||
want = 9;
|
||||
}
|
||||
if (want != mode_now) {
|
||||
int period = 0;
|
||||
bool ok = gfx_set_refresh(want, &period);
|
||||
static const struct { int mode, us; } expect[] = { { 1, 16683 }, { 2, 41708 }, { 3, 41667 }, { 9, 20000 } };
|
||||
int us = 0;
|
||||
for (const auto &e : expect)
|
||||
if (e.mode == want)
|
||||
us = e.us;
|
||||
if (ok && period > 0 && fabs(period - us) > us * 0.05) {
|
||||
fprintf(stderr, "main: output mode %d taken but a vblank every %d us (not %d): default again\n",
|
||||
want, period, us);
|
||||
gfx_set_refresh(1, &period);
|
||||
ok = false;
|
||||
}
|
||||
if (ok || want == 1) {
|
||||
mode_now = ok ? want : 1;
|
||||
} else {
|
||||
refused_for = player_current_path();
|
||||
if (mode_now != 1 && gfx_set_refresh(1, &period))
|
||||
mode_now = 1;
|
||||
}
|
||||
fprintf(stderr, "main: refresh %s for %.3f fps\n", ok ? "matched" : "not matched", vi.fps);
|
||||
}
|
||||
}
|
||||
|
||||
VkCommandBuffer cmd = gfx_begin_frame();
|
||||
if (!cmd)
|
||||
continue;
|
||||
double t_begin = plat_time();
|
||||
video_upload(cmd);
|
||||
gfx_begin_pass(cmd);
|
||||
float vx, vy, vw, vh;
|
||||
if (ui_video_rect(&vx, &vy, &vw, &vh))
|
||||
video_draw(cmd, vx, vy, vw, vh);
|
||||
ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmd);
|
||||
bool video = ui_video_rect(&vx, &vy, &vw, &vh);
|
||||
if (gfx.hdr) {
|
||||
/* the UI in its layer, then the video as PQ and the layer over it */
|
||||
gfx_begin_ui_pass(cmd);
|
||||
ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmd);
|
||||
gfx_begin_hdr_pass(cmd);
|
||||
if (video)
|
||||
video_draw(cmd, vx, vy, vw, vh);
|
||||
gfx_draw_ui_layer(cmd);
|
||||
} else {
|
||||
gfx_begin_pass(cmd);
|
||||
if (video)
|
||||
video_draw(cmd, vx, vy, vw, vh);
|
||||
ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmd);
|
||||
}
|
||||
gfx_end_frame(cmd);
|
||||
double t_end = plat_time();
|
||||
|
||||
|
||||
+257
-2
@@ -15,6 +15,7 @@
|
||||
|
||||
#include <vlc/vlc.h>
|
||||
|
||||
#include "osub.h"
|
||||
#include "platform.h"
|
||||
#include "player.h"
|
||||
|
||||
@@ -287,8 +288,14 @@ void finish_listing()
|
||||
libvlc_media_list_unlock(subs);
|
||||
libvlc_media_list_release(subs);
|
||||
}
|
||||
/* Folders A-Z; a playlist (TV channels, radio) keeps its own order. */
|
||||
bool playlist = list_url.compare(0, 4, "http") == 0;
|
||||
/* Folders A-Z; a playlist (TV channels, radio, an .m3u on a share)
|
||||
* keeps its own order. */
|
||||
std::string bare = list_url.substr(0, list_url.find('?'));
|
||||
size_t dot = bare.rfind('.');
|
||||
std::string ext = dot == std::string::npos ? "" : bare.substr(dot + 1);
|
||||
for (char &c : ext)
|
||||
c = (char)tolower((unsigned char)c);
|
||||
bool playlist = list_url.compare(0, 4, "http") == 0 || ext == "m3u" || ext == "m3u8" || ext == "pls";
|
||||
if (!playlist)
|
||||
std::stable_sort(entries.begin(), entries.end(), [](const NetEntry &a, const NetEntry &b) {
|
||||
if (a.dir != b.dir)
|
||||
@@ -385,6 +392,199 @@ bool list_menu(const std::string &url)
|
||||
return true;
|
||||
}
|
||||
|
||||
/* ---- search: every free TV channel and radio stations by name, fetched in
|
||||
* the background while Search is typed into (not through Browse) ---- */
|
||||
|
||||
struct Fetch {
|
||||
libvlc_media_t *m = nullptr;
|
||||
bool loading = false;
|
||||
std::string url;
|
||||
std::vector<NetEntry> got;
|
||||
};
|
||||
Fetch radio_found;
|
||||
int search_serial; /* changes when search results arrive */
|
||||
|
||||
/* Every free TV channel for Search: index.m3u downloaded and read here, as
|
||||
* names, addresses and options only. Kept as VLC media (11,000 of them, each
|
||||
* with its locks), it and the same list open in Browse ran the console out
|
||||
* of mutexes: VLC aborts when it can't make one (crash, 2026-10-13). */
|
||||
std::vector<NetEntry> tv_list; /* main thread */
|
||||
std::mutex tv_lock;
|
||||
std::vector<NetEntry> tv_arrived; /* from the download thread */
|
||||
bool tv_has_arrived, tv_loading, tv_started;
|
||||
std::thread tv_thread;
|
||||
|
||||
std::vector<NetEntry> parse_m3u(const std::string &text)
|
||||
{
|
||||
std::vector<NetEntry> out;
|
||||
std::string name;
|
||||
std::vector<std::string> opts;
|
||||
size_t at = 0;
|
||||
while (at < text.size()) {
|
||||
size_t eol = text.find('\n', at);
|
||||
if (eol == std::string::npos)
|
||||
eol = text.size();
|
||||
std::string line = text.substr(at, eol - at);
|
||||
at = eol + 1;
|
||||
while (!line.empty() && (line.back() == '\r' || line.back() == ' '))
|
||||
line.pop_back();
|
||||
if (line.empty())
|
||||
continue;
|
||||
if (line.compare(0, 8, "#EXTINF:") == 0) {
|
||||
/* the name: after the first comma outside the attributes' quotes */
|
||||
bool quoted = false;
|
||||
size_t comma = std::string::npos;
|
||||
for (size_t i = 8; i < line.size(); i++) {
|
||||
if (line[i] == '"')
|
||||
quoted = !quoted;
|
||||
else if (line[i] == ',' && !quoted) {
|
||||
comma = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
name = comma == std::string::npos ? "" : line.substr(comma + 1);
|
||||
while (!name.empty() && name[0] == ' ')
|
||||
name.erase(0, 1);
|
||||
} else if (line.compare(0, 11, "#EXTVLCOPT:") == 0) {
|
||||
opts.push_back(":" + line.substr(11));
|
||||
} else if (line[0] != '#') {
|
||||
NetEntry e;
|
||||
e.url = line;
|
||||
e.name = name.empty() ? line : name;
|
||||
e.dir = false;
|
||||
e.options.swap(opts);
|
||||
out.push_back(std::move(e));
|
||||
name.clear();
|
||||
opts.clear();
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
void tv_start_download()
|
||||
{
|
||||
if (tv_started)
|
||||
return;
|
||||
tv_started = true;
|
||||
tv_loading = true;
|
||||
search_serial++;
|
||||
std::string url = std::string(TV_LISTS) + "index.m3u";
|
||||
fprintf(stderr, "net: search fetching %s\n", url.c_str());
|
||||
tv_thread = std::thread([url] {
|
||||
std::string body, error;
|
||||
std::vector<NetEntry> got;
|
||||
if (web_https_get(url, body, error))
|
||||
got = parse_m3u(body);
|
||||
fprintf(stderr, "net: search got %zu channels (%zu bytes)%s%s\n", got.size(), body.size(),
|
||||
error.empty() ? "" : ": ", error.c_str());
|
||||
std::lock_guard<std::mutex> g(tv_lock);
|
||||
tv_arrived.swap(got);
|
||||
tv_has_arrived = true;
|
||||
});
|
||||
}
|
||||
std::string search_query, radio_query; /* typed; last asked of radio-browser */
|
||||
double search_typed_at;
|
||||
|
||||
void fetch_clear(Fetch &f)
|
||||
{
|
||||
if (f.m) {
|
||||
if (f.loading)
|
||||
libvlc_media_parse_stop(f.m);
|
||||
libvlc_media_release(f.m);
|
||||
f.m = nullptr;
|
||||
}
|
||||
f.loading = false;
|
||||
for (NetEntry &e : f.got)
|
||||
if (e.media)
|
||||
libvlc_media_release(e.media);
|
||||
f.got.clear();
|
||||
}
|
||||
|
||||
void fetch_start(Fetch &f, const std::string &url)
|
||||
{
|
||||
fetch_clear(f);
|
||||
libvlc_instance_t *vlc = player_vlc();
|
||||
f.url = url;
|
||||
f.m = vlc ? libvlc_media_new_location(vlc, url.c_str()) : nullptr;
|
||||
if (f.m && libvlc_media_parse_with_options(f.m, libvlc_media_parse_network, 20000) == 0) {
|
||||
f.loading = true;
|
||||
fprintf(stderr, "net: search fetching %s\n", url.c_str());
|
||||
}
|
||||
search_serial++;
|
||||
}
|
||||
|
||||
void fetch_poll(Fetch &f)
|
||||
{
|
||||
if (!f.loading || libvlc_media_get_parsed_status(f.m) == 0)
|
||||
return;
|
||||
f.loading = false;
|
||||
if (libvlc_media_list_t *subs = libvlc_media_subitems(f.m)) {
|
||||
libvlc_media_list_lock(subs);
|
||||
for (int i = 0; i < libvlc_media_list_count(subs); i++) {
|
||||
libvlc_media_t *m = libvlc_media_list_item_at_index(subs, i);
|
||||
if (!m)
|
||||
continue;
|
||||
char *mrl = libvlc_media_get_mrl(m), *title = libvlc_media_get_meta(m, libvlc_meta_Title);
|
||||
if (mrl && libvlc_media_get_type(m) != libvlc_media_type_directory) {
|
||||
NetEntry e;
|
||||
e.url = mrl;
|
||||
e.name = title ? title : e.url.substr(e.url.rfind('/') + 1);
|
||||
e.dir = false;
|
||||
e.media = m;
|
||||
libvlc_media_retain(m);
|
||||
f.got.push_back(e);
|
||||
}
|
||||
free(mrl);
|
||||
free(title);
|
||||
libvlc_media_release(m);
|
||||
}
|
||||
libvlc_media_list_unlock(subs);
|
||||
libvlc_media_list_release(subs);
|
||||
}
|
||||
fprintf(stderr, "net: search got %zu from %s\n", f.got.size(), f.url.c_str());
|
||||
search_serial++;
|
||||
}
|
||||
|
||||
std::string url_encode(const std::string &s)
|
||||
{
|
||||
std::string out;
|
||||
for (unsigned char c : s) {
|
||||
if (isalnum(c) || c == '-' || c == '.' || c == '_') {
|
||||
out += (char)c;
|
||||
} else {
|
||||
char h[4];
|
||||
snprintf(h, sizeof(h), "%%%02X", c);
|
||||
out += h;
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
void search_update()
|
||||
{
|
||||
{
|
||||
std::lock_guard<std::mutex> g(tv_lock);
|
||||
if (tv_has_arrived) {
|
||||
tv_has_arrived = false;
|
||||
tv_list.swap(tv_arrived);
|
||||
tv_loading = false;
|
||||
if (tv_list.empty())
|
||||
tv_started = false; /* failed: asked again the next time Search is used */
|
||||
search_serial++;
|
||||
}
|
||||
}
|
||||
if (!tv_loading && tv_thread.joinable())
|
||||
tv_thread.join();
|
||||
fetch_poll(radio_found);
|
||||
/* radio-browser is asked once the typing pauses */
|
||||
if (search_query.size() >= 2 && search_query != radio_query && plat_time() - search_typed_at > 0.6) {
|
||||
radio_query = search_query;
|
||||
fetch_start(radio_found, std::string(RADIO_LISTS) + "byname/" + url_encode(search_query) +
|
||||
"?limit=40&order=clickcount&reverse=true&hidebroken=true");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} // namespace
|
||||
|
||||
void net_init()
|
||||
@@ -424,6 +624,10 @@ void net_shutdown()
|
||||
upnp_starter.join();
|
||||
net_list_stop();
|
||||
clear_entries();
|
||||
if (tv_thread.joinable())
|
||||
tv_thread.join();
|
||||
tv_list.clear();
|
||||
fetch_clear(radio_found);
|
||||
if (upnp) {
|
||||
libvlc_media_discoverer_stop(upnp);
|
||||
libvlc_media_discoverer_release(upnp);
|
||||
@@ -449,6 +653,7 @@ void net_update()
|
||||
libvlc_dialog_dismiss(id);
|
||||
if (list_state == NET_LOADING && libvlc_media_get_parsed_status(listing) != 0)
|
||||
finish_listing();
|
||||
search_update();
|
||||
}
|
||||
|
||||
std::vector<NetServer> net_servers()
|
||||
@@ -491,6 +696,56 @@ void net_forget_server(const std::string &url)
|
||||
store_saved();
|
||||
}
|
||||
|
||||
|
||||
void net_search_typed(const std::string &query)
|
||||
{
|
||||
std::string q = query;
|
||||
while (!q.empty() && q.back() == ' ')
|
||||
q.pop_back();
|
||||
while (!q.empty() && q[0] == ' ')
|
||||
q.erase(0, 1);
|
||||
tv_start_download(); /* once a session (again if it failed) */
|
||||
if (q != search_query) {
|
||||
search_query = q;
|
||||
search_typed_at = plat_time();
|
||||
if (q.size() < 2) {
|
||||
fetch_clear(radio_found);
|
||||
radio_query.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool net_search_busy()
|
||||
{
|
||||
return tv_loading || radio_found.loading ||
|
||||
(search_query.size() >= 2 && search_query != radio_query);
|
||||
}
|
||||
|
||||
int net_search_serial()
|
||||
{
|
||||
return search_serial;
|
||||
}
|
||||
|
||||
const std::vector<NetEntry> &net_search_tv()
|
||||
{
|
||||
return tv_list;
|
||||
}
|
||||
|
||||
const std::vector<NetEntry> &net_search_radio()
|
||||
{
|
||||
return radio_found.got;
|
||||
}
|
||||
|
||||
libvlc_media_t *net_search_media(const std::string &url)
|
||||
{
|
||||
for (NetEntry &e : radio_found.got)
|
||||
if (e.url == url && e.media) {
|
||||
libvlc_media_retain(e.media);
|
||||
return e.media;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool net_is_saved_server(const std::string &url)
|
||||
{
|
||||
for (const Saved &s : saved)
|
||||
|
||||
@@ -23,6 +23,7 @@ struct NetEntry {
|
||||
std::string url; /* no login in it: net_login_options() gives it */
|
||||
bool dir;
|
||||
libvlc_media_t *media = nullptr; /* VLC's own item (keeps a list's #EXTVLCOPT) */
|
||||
std::vector<std::string> options; /* or a list's #EXTVLCOPT as media options (":http-referrer=...") */
|
||||
};
|
||||
|
||||
enum NetListState { NET_IDLE, NET_LOADING, NET_READY, NET_FAILED };
|
||||
@@ -60,6 +61,15 @@ libvlc_media_t *net_take_media(const std::string &url);
|
||||
/* The media options that log in to an address's saved share (":smb-user=..."). */
|
||||
std::vector<std::string> net_login_options(const std::string &url);
|
||||
|
||||
/* Search, as it's typed: every free TV channel (the whole list, fetched once a
|
||||
* session) and radio stations by name (asked once the typing pauses). */
|
||||
void net_search_typed(const std::string &query);
|
||||
bool net_search_busy();
|
||||
int net_search_serial(); /* changes when results arrive */
|
||||
const std::vector<NetEntry> &net_search_tv();
|
||||
const std::vector<NetEntry> &net_search_radio();
|
||||
libvlc_media_t *net_search_media(const std::string &url); /* with a reference, or null */
|
||||
|
||||
/* What VLC is asking (login / question), answered from the interface. */
|
||||
NetAsk net_ask();
|
||||
void net_answer_login(const std::string &user, const std::string &password, bool remember);
|
||||
|
||||
+26
-6
@@ -32,7 +32,7 @@
|
||||
namespace {
|
||||
|
||||
const char *API_HOST = "api.opensubtitles.com";
|
||||
const char *USER_AGENT = "VLC-PS5 v0.1";
|
||||
const char *USER_AGENT = "VLC-PS5 v" VLC_PS5_VERSION;
|
||||
|
||||
/* ---- what the interface sees ---- */
|
||||
|
||||
@@ -584,6 +584,22 @@ bool start()
|
||||
|
||||
} // namespace
|
||||
|
||||
/* A plain HTTPS download (redirects followed), for other parts of the app. */
|
||||
bool web_https_get(const std::string &url, std::string &body, std::string &error)
|
||||
{
|
||||
Reply r = https_get(url);
|
||||
if (!r.error.empty()) {
|
||||
error = r.error;
|
||||
return false;
|
||||
}
|
||||
if (r.status != 200) {
|
||||
error = "HTTP " + std::to_string(r.status);
|
||||
return false;
|
||||
}
|
||||
body.swap(r.body);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool osub_has_key()
|
||||
{
|
||||
return !pref_str("osub_key", "").empty();
|
||||
@@ -722,11 +738,15 @@ void osub_sign_in()
|
||||
}
|
||||
std::string msg, bearer, host;
|
||||
if (a.user.empty()) {
|
||||
/* no account: try the key alone with a small search (the
|
||||
* informational calls answer any key) */
|
||||
Reply r = https("GET", API_HOST, "/api/v1/subtitles?languages=en&query=vlc", api_headers(a, ""), "");
|
||||
finish(r.error.empty() && r.status == 200 ? OSUB_DONE : OSUB_FAILED,
|
||||
r.error.empty() && r.status == 200 ? "The API key works" : server_error(r, "Checking the key"));
|
||||
/* no account: try the key alone. Searches and the informational
|
||||
* calls answer any key, even none; "discover" refuses a bad one
|
||||
* (403, "You cannot consume this service"). */
|
||||
Reply r = https("GET", API_HOST, "/api/v1/discover/popular?languages=en", api_headers(a, ""), "");
|
||||
bool ok = r.error.empty() && r.status == 200;
|
||||
finish(ok ? OSUB_DONE : OSUB_FAILED,
|
||||
ok ? "The API key works"
|
||||
: r.error.empty() && (r.status == 401 || r.status == 403) ? "OpenSubtitles refused this API key"
|
||||
: server_error(r, "Checking the key"));
|
||||
return;
|
||||
}
|
||||
bool ok = sign_in(a, msg, bearer, host);
|
||||
|
||||
@@ -34,3 +34,6 @@ OsubState osub_state();
|
||||
std::vector<SubResult> osub_results();
|
||||
std::string osub_message(); /* what went wrong, or "12 downloads left today" */
|
||||
std::string osub_saved_path(); /* the file a download wrote, once */
|
||||
|
||||
/* A plain HTTPS GET (redirects followed; blocking: a background thread's). */
|
||||
bool web_https_get(const std::string &url, std::string &body, std::string &error);
|
||||
+1
-1
@@ -23,7 +23,7 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
#define VLC_PS5_TITLE_ID "PPSA85300"
|
||||
#define VLC_PS5_VERSION "0.1"
|
||||
#define VLC_PS5_VERSION "0.4.5"
|
||||
|
||||
/* DualSense buttons (scePadRead's layout, as QUICK3 and PS5_vkQuake use it),
|
||||
* plus the triggers past half as buttons. */
|
||||
|
||||
+21
-2
@@ -10,6 +10,7 @@
|
||||
* options touchpad)
|
||||
* <frame> hold <button> <frames>
|
||||
* <frame> shot <file.png> saves that frame
|
||||
* <frame> type <text> the on-screen keyboard gets it (_ for a space)
|
||||
* <frame> quit
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
@@ -23,11 +24,11 @@
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define MAX_STEPS 512
|
||||
#define MAX_STEPS 20000 /* a long stress tour has thousands */
|
||||
|
||||
typedef struct {
|
||||
uint64_t frame;
|
||||
enum { STEP_HOLD, STEP_SHOT, STEP_QUIT, STEP_STICK } kind;
|
||||
enum { STEP_HOLD, STEP_SHOT, STEP_QUIT, STEP_STICK, STEP_TYPE } kind;
|
||||
uint32_t button;
|
||||
float rx, ry; /* STEP_STICK: the right stick, held for frames */
|
||||
uint64_t frames;
|
||||
@@ -87,6 +88,11 @@ static void load_script(void)
|
||||
s->frames = frames;
|
||||
} else if (!strcmp(word, "shot") && sscanf(line, "%*u %*s %255s", s->path) == 1) {
|
||||
s->kind = STEP_SHOT;
|
||||
} else if (!strcmp(word, "type") && sscanf(line, "%*u %*s %255s", s->path) == 1) {
|
||||
s->kind = STEP_TYPE;
|
||||
for (char *c = s->path; *c; c++)
|
||||
if (*c == '_')
|
||||
*c = ' ';
|
||||
} else if (!strcmp(word, "quit")) {
|
||||
s->kind = STEP_QUIT;
|
||||
quit_frame = frame;
|
||||
@@ -255,3 +261,16 @@ bool plat_script_done(uint64_t frame)
|
||||
{
|
||||
return frame >= quit_frame;
|
||||
}
|
||||
|
||||
/* Script "type" steps due by now, once (the interface's keyboard reads it). */
|
||||
const char *plat_take_typed(void)
|
||||
{
|
||||
static int next;
|
||||
for (; next < nsteps; next++) {
|
||||
if (steps[next].frame > frame_now)
|
||||
break;
|
||||
if (steps[next].kind == STEP_TYPE)
|
||||
return steps[next++].path;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
+158
-5
@@ -124,6 +124,14 @@ static void crash_handler(int sig, siginfo_t *info, void *context)
|
||||
|
||||
/* " name " of each import left unresolved: optional calls check it first. */
|
||||
static char unresolved[2048] = " ";
|
||||
/* the video decoder's import slots (imports.txt), checked once its library
|
||||
* is loaded */
|
||||
#define VDEC_SLOTS 16
|
||||
static struct {
|
||||
unsigned long offset;
|
||||
char name[48];
|
||||
} vdec_slots[VDEC_SLOTS];
|
||||
static int vdec_slot_count;
|
||||
|
||||
static bool import_resolved(const char *name)
|
||||
{
|
||||
@@ -132,6 +140,69 @@ static bool import_resolved(const char *name)
|
||||
return strstr(unresolved, key) == NULL;
|
||||
}
|
||||
|
||||
/* settings.txt's "key=value" at start (read before full access: /app0 may
|
||||
* be gone after it). */
|
||||
static int boot_setting(const char *key, int fallback)
|
||||
{
|
||||
FILE *s = fopen(APP_DIR "/settings.txt", "r");
|
||||
if (!s)
|
||||
return fallback;
|
||||
char line[128];
|
||||
size_t n = strlen(key);
|
||||
int value = fallback;
|
||||
while (fgets(line, sizeof(line), s))
|
||||
if (!strncmp(line, key, n) && line[n] == '=')
|
||||
value = atoi(line + n + 1);
|
||||
fclose(s);
|
||||
return value;
|
||||
}
|
||||
|
||||
/* The console's video decoder (ps5/modules/ps5vdec.c). Its library (sysmodule
|
||||
* 207) and compute queue are made before the Helper's full access: after it
|
||||
* the library is refused (0x80020063, console run 11) and the queue too
|
||||
* (0x811D0111, run 12). Run 10's "no jailbreak daemon answered" with the
|
||||
* library loaded first was the Helper not running then (run 12: it answered
|
||||
* in 60 ms). settings.txt vdec_load=0 loads it after full access instead,
|
||||
* hw_decode=0 not at all. */
|
||||
int sceSysmoduleLoadModule(uint16_t id);
|
||||
void vlc_ps5_vdec_prepare(void) __attribute__((weak)); /* ps5/modules/ps5vdec.c */
|
||||
void vlc_ps5_vdec_probe(const char *when) __attribute__((weak));
|
||||
#define SYSMODULE_VIDEODEC2 207
|
||||
static bool vdec_ready;
|
||||
static double jb_wait = 2.5; /* seconds the Helper has to answer */
|
||||
|
||||
static void load_video_decoder(void)
|
||||
{
|
||||
/* (the decoder's own functions only get their addresses with the
|
||||
* library: they're checked after loading it, below) */
|
||||
if (!import_resolved("sceSysmoduleLoadModule")) {
|
||||
fprintf(stderr, "VLC-PS5: hardware decoding off: sceSysmoduleLoadModule unresolved\n");
|
||||
return;
|
||||
}
|
||||
int rc = sceSysmoduleLoadModule(SYSMODULE_VIDEODEC2);
|
||||
vdec_ready = rc == 0;
|
||||
/* now its functions must have their addresses (imports.txt known): an
|
||||
* empty one would be a jump to 0 */
|
||||
for (int i = 0; vdec_ready && i < vdec_slot_count; i++) {
|
||||
if (*(const uint64_t *)(EBOOT_BASE + vdec_slots[i].offset) == 0) {
|
||||
fprintf(stderr, "VLC-PS5: %s still unresolved after loading the library\n", vdec_slots[i].name);
|
||||
vdec_ready = false;
|
||||
}
|
||||
}
|
||||
fprintf(stderr, "VLC-PS5: video decoder library %#x: hardware decoding %s (%d functions checked)\n",
|
||||
(unsigned)rc, vdec_ready ? "on" : "off", vdec_slot_count);
|
||||
/* its compute queue now too, while still in the sandbox */
|
||||
if (vdec_ready && vlc_ps5_vdec_prepare)
|
||||
vlc_ps5_vdec_prepare();
|
||||
if (vdec_ready && vlc_ps5_vdec_probe)
|
||||
vlc_ps5_vdec_probe(plat_full_access() ? "after full access" : "before full access");
|
||||
}
|
||||
|
||||
int vlc_ps5_vdec_available(void)
|
||||
{
|
||||
return vdec_ready;
|
||||
}
|
||||
|
||||
/* Every import the console left unresolved (a call would jump to 0), in one
|
||||
* report: imports.txt lists each GOT slot's offset and symbol. */
|
||||
static void report_unresolved_imports(void)
|
||||
@@ -146,6 +217,16 @@ static void report_unresolved_imports(void)
|
||||
int checked = 0, missing = 0;
|
||||
while (fscanf(f, "%lx %127s", &offset, name) == 2) {
|
||||
checked++;
|
||||
/* the video decoder's are filled in when its library is loaded
|
||||
* (load_video_decoder), not at start: looked at after that */
|
||||
if (!strncmp(name, "sceVideodec2", 12)) {
|
||||
if (vdec_slot_count < VDEC_SLOTS) {
|
||||
vdec_slots[vdec_slot_count].offset = offset;
|
||||
snprintf(vdec_slots[vdec_slot_count].name, sizeof(vdec_slots[0].name), "%s", name);
|
||||
vdec_slot_count++;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (*(const uint64_t *)(EBOOT_BASE + offset) == 0) {
|
||||
fprintf(stderr, "VLC-PS5: unresolved import: %s\n", name);
|
||||
if (strlen(unresolved) + strlen(name) + 2 < sizeof(unresolved)) {
|
||||
@@ -176,11 +257,48 @@ static bool exists(const char *path)
|
||||
* resolve; otherwise the sandbox's own copy of it (/mnt/sandbox/<title>_NNN/app0,
|
||||
* the folder the daemon found our request in) or the folder
|
||||
* ShadowMountPlus launched us from. */
|
||||
/* Our folder is marked before full access (/app0 is gone after it), so the
|
||||
* search below finds this launch's folder and not another: the first
|
||||
* PPSA85300_ entry of /mnt/sandbox, as first done, could be an older launch's
|
||||
* or another copy of the app, whose prefs.txt then came up (the look
|
||||
* switching between Classic and Modern "by itself"). */
|
||||
#define INSTANCE_FILE "/cache/instance.txt"
|
||||
static char instance_mark[64];
|
||||
|
||||
static void mark_app_dir(void)
|
||||
{
|
||||
snprintf(instance_mark, sizeof(instance_mark), "%d-%.0f", (int)getpid(), plat_time() * 1000);
|
||||
mkdir(APP_DIR "/cache", 0777);
|
||||
FILE *f = fopen(APP_DIR INSTANCE_FILE, "w");
|
||||
if (!f) {
|
||||
instance_mark[0] = 0;
|
||||
return;
|
||||
}
|
||||
fputs(instance_mark, f);
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
static bool is_marked(const char *dir)
|
||||
{
|
||||
if (!instance_mark[0])
|
||||
return false;
|
||||
char path[300], got[64] = "";
|
||||
snprintf(path, sizeof(path), "%s" INSTANCE_FILE, dir);
|
||||
FILE *f = fopen(path, "r");
|
||||
if (!f)
|
||||
return false;
|
||||
if (!fgets(got, sizeof(got), f))
|
||||
got[0] = 0;
|
||||
fclose(f);
|
||||
return !strcmp(got, instance_mark);
|
||||
}
|
||||
|
||||
static void find_app_dir(void)
|
||||
{
|
||||
if (exists(APP_DIR "/eboot.bin"))
|
||||
return;
|
||||
char path[256];
|
||||
char path[256], first[256] = "";
|
||||
int candidates = 0;
|
||||
DIR *d = opendir("/mnt/sandbox");
|
||||
if (d) {
|
||||
struct dirent *e;
|
||||
@@ -188,13 +306,27 @@ static void find_app_dir(void)
|
||||
if (strncmp(e->d_name, VLC_PS5_TITLE_ID "_", sizeof(VLC_PS5_TITLE_ID)))
|
||||
continue;
|
||||
snprintf(path, sizeof(path), "/mnt/sandbox/%s/app0/eboot.bin", e->d_name);
|
||||
if (exists(path)) {
|
||||
snprintf(app_dir, sizeof(app_dir), "/mnt/sandbox/%s/app0", e->d_name);
|
||||
if (!exists(path))
|
||||
continue;
|
||||
candidates++;
|
||||
snprintf(path, sizeof(path), "/mnt/sandbox/%s/app0", e->d_name);
|
||||
fprintf(stderr, "VLC-PS5: candidate folder %s%s\n", path, is_marked(path) ? " (ours)" : "");
|
||||
if (!first[0])
|
||||
snprintf(first, sizeof(first), "%s", path);
|
||||
if (is_marked(path)) {
|
||||
snprintf(app_dir, sizeof(app_dir), "%s", path);
|
||||
break;
|
||||
}
|
||||
}
|
||||
closedir(d);
|
||||
}
|
||||
/* no mark found: the first one, as before */
|
||||
if (!strcmp(app_dir, APP_DIR) && first[0] && !(instance_mark[0] && candidates > 1))
|
||||
snprintf(app_dir, sizeof(app_dir), "%s", first);
|
||||
if (!strcmp(app_dir, APP_DIR) && is_marked("/data/homebrew/" VLC_PS5_TITLE_ID))
|
||||
snprintf(app_dir, sizeof(app_dir), "/data/homebrew/" VLC_PS5_TITLE_ID);
|
||||
if (!strcmp(app_dir, APP_DIR) && first[0])
|
||||
snprintf(app_dir, sizeof(app_dir), "%s", first);
|
||||
if (!strcmp(app_dir, APP_DIR) && exists("/data/homebrew/" VLC_PS5_TITLE_ID "/eboot.bin"))
|
||||
snprintf(app_dir, sizeof(app_dir), "/data/homebrew/" VLC_PS5_TITLE_ID);
|
||||
if (!strcmp(app_dir, APP_DIR))
|
||||
@@ -224,6 +356,7 @@ static bool lifted(void)
|
||||
|
||||
static void request_full_access(void)
|
||||
{
|
||||
mark_app_dir();
|
||||
if (lifted()) {
|
||||
full_access = true;
|
||||
fprintf(stderr, "VLC-PS5: full access already (euid %d)\n", (int)__real_geteuid());
|
||||
@@ -268,12 +401,14 @@ static void request_full_access(void)
|
||||
unlink(JB_STAGED);
|
||||
return;
|
||||
}
|
||||
/* (2.5 s: a busy daemon took longer than the 1 s first allowed) */
|
||||
double start = plat_time();
|
||||
while (exists(JB_REQUEST) && plat_time() - start < 1.0)
|
||||
while (exists(JB_REQUEST) && plat_time() - start < jb_wait)
|
||||
usleep(20000);
|
||||
if (exists(JB_REQUEST)) {
|
||||
unlink(JB_REQUEST); /* nobody listening: don't leave it for a daemon started later */
|
||||
fprintf(stderr, "VLC-PS5: sandboxed (no jailbreak daemon answered in 1 s)\n");
|
||||
fprintf(stderr, "VLC-PS5: sandboxed (no jailbreak daemon answered in %.1f s): no phone/PC page, "
|
||||
"no DLNA server; is etaHEN or the Helper running, PPSA85300 whitelisted?\n", jb_wait);
|
||||
return;
|
||||
}
|
||||
/* Taken. Daemons set the effective uid (the real one can stay as it was)
|
||||
@@ -310,6 +445,10 @@ static void use_app_dir(void)
|
||||
snprintf(path, sizeof(path), "%s/cache/mesa", app_dir);
|
||||
mkdir(path, 0777);
|
||||
setenv("MESA_SHADER_CACHE_DIR", path, 1);
|
||||
/* libbluray keeps its cache in $HOME/.cache/bluray and makes only the
|
||||
* last folder ("Error creating directory" in every disc's log) */
|
||||
snprintf(path, sizeof(path), "%s/.cache", app_dir);
|
||||
mkdir(path, 0777);
|
||||
fprintf(stderr, "VLC-PS5: shader caches in %s/cache\n", app_dir);
|
||||
}
|
||||
|
||||
@@ -378,7 +517,21 @@ void plat_init(void)
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
|
||||
report_unresolved_imports();
|
||||
/* the decoder library and its compute queue first, then full access: the
|
||||
* Helper answered in 60 ms with them loaded (console run 12), and both
|
||||
* fail after full access (0x80020063, 0x811D0111). vdec_load=0: after. */
|
||||
int hw_decode = boot_setting("hw_decode", 1), vdec_load = boot_setting("vdec_load", 1);
|
||||
if (!hw_decode)
|
||||
fprintf(stderr, "VLC-PS5: hardware decoding off (settings.txt): decoder library not loaded\n");
|
||||
if (hw_decode && vdec_load == 1) {
|
||||
load_video_decoder();
|
||||
jb_wait = 6;
|
||||
}
|
||||
request_full_access();
|
||||
if (hw_decode && vdec_load != 1)
|
||||
load_video_decoder();
|
||||
else if (vdec_ready && vlc_ps5_vdec_probe && plat_full_access())
|
||||
vlc_ps5_vdec_probe("after full access");
|
||||
use_app_dir();
|
||||
}
|
||||
|
||||
|
||||
+1496
-98
File diff suppressed because it is too large.
Load diff
+30
-2
@@ -24,6 +24,8 @@ struct VideoInfo {
|
||||
uint32_t width, height; /* visible size */
|
||||
float aspect; /* display aspect, sample aspect applied */
|
||||
bool ten_bit;
|
||||
int hdr; /* 0 SDR, 1 HDR10 (PQ), 2 HLG */
|
||||
bool hardware; /* on the console's video decoder */
|
||||
float fps; /* 0 if the file doesn't say */
|
||||
std::string codec, audio_codec;
|
||||
unsigned audio_channels;
|
||||
@@ -40,12 +42,20 @@ libvlc_instance_t *player_vlc();
|
||||
bool player_open(const std::string &path, int64_t start_ms, const std::vector<std::string> &options = {});
|
||||
/* The same with a media VLC made (an entry of a listed playlist, with the options
|
||||
* its list gave it); takes the reference. path: what it's called in the log. */
|
||||
bool player_open_media(libvlc_media_t *m, const std::string &path, int64_t start_ms);
|
||||
bool player_open_media(libvlc_media_t *m, const std::string &path, int64_t start_ms,
|
||||
const std::vector<std::string> &options = {});
|
||||
void player_stop();
|
||||
bool player_active(); /* a file is open (playing, paused, buffering) */
|
||||
bool player_ended(); /* the file played to its end (or failed) */
|
||||
bool player_failed();
|
||||
bool player_buffering(); /* opening or buffering: no picture moving yet */
|
||||
/* Disc menus: the main menu (DVD root, Blu-ray Top Menu) or a Blu-ray's
|
||||
* pop-up menu; whether the Blu-ray playing has one. */
|
||||
/* The Blu-ray region VLC plays as (A, B, C), from the next file. */
|
||||
std::string player_bluray_region();
|
||||
void player_set_bluray_region(const std::string ®ion);
|
||||
void player_disc_menu(bool popup);
|
||||
bool player_disc_has_popup();
|
||||
bool player_paused();
|
||||
void player_toggle_pause();
|
||||
int64_t player_time(); /* ms */
|
||||
@@ -62,7 +72,8 @@ std::vector<Track> player_subtitle_tracks();
|
||||
int player_subtitle_track();
|
||||
void player_set_subtitle_track(int id);
|
||||
/* Adds a subtitle file (.srt, .ass, ...) to what plays and selects it. */
|
||||
bool player_add_subtitle(const std::string &path);
|
||||
bool player_add_subtitle(const std::string &path); /* a local path, or a share's / a link's address */
|
||||
bool player_is_subtitle_name(const std::string &name); /* .srt, .ass, .vtt... */
|
||||
const VideoInfo &player_video_info();
|
||||
|
||||
/* A 360° video: where the view looks (degrees) and how wide it sees. */
|
||||
@@ -70,6 +81,8 @@ void player_view(float yaw, float pitch, float fov);
|
||||
|
||||
/* A DVD / Blu-ray menu: 0 activate, 1 up, 2 down, 3 left, 4 right. */
|
||||
void player_navigate(int action);
|
||||
/* A disc's menu is on screen (its current title is a menu). */
|
||||
bool player_in_menu();
|
||||
|
||||
/* The sound being heard, as n bands from bass to treble (0..1 each). */
|
||||
void player_spectrum(float *bands, int n);
|
||||
@@ -77,7 +90,18 @@ void player_spectrum(float *bands, int n);
|
||||
/* Render thread, every frame: */
|
||||
void video_upload(VkCommandBuffer cmd); /* before the render pass */
|
||||
bool video_has_picture();
|
||||
/* seconds since the video was opened */
|
||||
double player_open_age();
|
||||
/* An HDR video is showing and HDR10 output is wanted for it (settings.txt
|
||||
* hdr_output, the console's output). */
|
||||
bool video_wants_hdr_output();
|
||||
/* Match frame rate: films at 23.976 / 24 / 25 / 50 fps switch the TV to that
|
||||
* refresh while they play (saved; Off by default: some TVs blank a moment). */
|
||||
bool player_match_rate();
|
||||
const std::string &player_current_path(); /* what plays (or was last opened) */
|
||||
void player_set_match_rate(bool on);
|
||||
void video_draw(VkCommandBuffer cmd, float x, float y, float w, float h); /* in the pass */
|
||||
float video_picture_aspect(); /* the pictures VLC sends now: width / height (0: none yet) */
|
||||
void video_forget_picture(); /* back to the library */
|
||||
/* One line about the player in the log (state, time, picture slots, sound queue,
|
||||
* pictures decoded/shown/lost since the last line). */
|
||||
@@ -162,6 +186,10 @@ void player_set_debug_log(bool on);
|
||||
DecodeMode player_decode_mode();
|
||||
void player_set_decode_mode(DecodeMode mode); /* saved; applies from the next file */
|
||||
bool player_fast_decoding(); /* the current file decodes fast */
|
||||
/* Hardware decoding (the console's video decoder) or FFmpeg on the CPU:
|
||||
* saved; applies from the next video. */
|
||||
bool player_hw_decoding();
|
||||
void player_set_hw_decoding(bool on);
|
||||
/* Main thread, every frame while playing: watches for lost pictures. */
|
||||
enum PlayerEvent { PLAYER_EVENT_NONE, PLAYER_EVENT_WENT_FAST, PLAYER_EVENT_TOO_SLOW };
|
||||
PlayerEvent player_tick();
|
||||
+179
@@ -0,0 +1,179 @@
|
||||
/*
|
||||
* VLC-PS5: subtitle files that aren't UTF-8, made UTF-8 for VLC (see
|
||||
* subconv.h). Our own code; the conversion tables are GNU libiconv's.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
#include "subconv.h"
|
||||
|
||||
#include <iconv.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "platform.h"
|
||||
|
||||
namespace {
|
||||
|
||||
/* Valid UTF-8 (no overlongs, no surrogates, nothing past U+10FFFF). */
|
||||
bool is_utf8(const std::string &s)
|
||||
{
|
||||
const unsigned char *p = (const unsigned char *)s.data(), *end = p + s.size();
|
||||
while (p < end) {
|
||||
unsigned c = *p;
|
||||
if (c < 0x80) {
|
||||
p++;
|
||||
continue;
|
||||
}
|
||||
int n = c >= 0xF0 && c <= 0xF4 ? 3 : c >= 0xE0 ? 2 : c >= 0xC2 && c <= 0xDF ? 1 : -1;
|
||||
if (n < 0 || c > 0xF4 || end - p <= n)
|
||||
return false;
|
||||
uint32_t cp = c & (0x3F >> n);
|
||||
for (int i = 1; i <= n; i++) {
|
||||
if ((p[i] & 0xC0) != 0x80)
|
||||
return false;
|
||||
cp = cp << 6 | (p[i] & 0x3F);
|
||||
}
|
||||
if ((n == 2 && cp < 0x800) || (n == 3 && (cp < 0x10000 || cp > 0x10FFFF)) || (cp >= 0xD800 && cp <= 0xDFFF))
|
||||
return false;
|
||||
p += n + 1;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/* The code page subtitles in that language are usually saved in when they
|
||||
* aren't Unicode (what Windows' "ANSI" was for it). */
|
||||
const char *legacy_encoding(const std::string &lang)
|
||||
{
|
||||
std::string l = lang.substr(0, lang.find('-'));
|
||||
if (lang == "zh-TW" || lang == "zh-HK" || lang == "zht")
|
||||
return "BIG5-HKSCS";
|
||||
if (l == "zh" || l == "chi" || l == "zho")
|
||||
return "GB18030";
|
||||
if (l == "ja" || l == "jpn")
|
||||
return "CP932";
|
||||
if (l == "ko" || l == "kor")
|
||||
return "CP949";
|
||||
if (l == "ru" || l == "rus" || l == "uk" || l == "ukr" || l == "bg" || l == "bul" || l == "sr" || l == "mk" || l == "be")
|
||||
return "CP1251";
|
||||
if (l == "ar" || l == "ara" || l == "fa" || l == "per" || l == "fas" || l == "ur")
|
||||
return "CP1256";
|
||||
if (l == "he" || l == "heb")
|
||||
return "CP1255";
|
||||
if (l == "tr" || l == "tur")
|
||||
return "CP1254";
|
||||
if (l == "el" || l == "gre" || l == "ell")
|
||||
return "CP1253";
|
||||
if (l == "pl" || l == "pol" || l == "cs" || l == "cze" || l == "ces" || l == "sk" || l == "hu" || l == "hun" ||
|
||||
l == "ro" || l == "rum" || l == "hr" || l == "sl")
|
||||
return "CP1250";
|
||||
if (l == "th" || l == "tha")
|
||||
return "CP874";
|
||||
if (l == "vi" || l == "vie")
|
||||
return "CP1258";
|
||||
return "CP1252";
|
||||
}
|
||||
|
||||
bool convert(const std::string &in, const char *from, std::string *out)
|
||||
{
|
||||
iconv_t cd = iconv_open("UTF-8", from);
|
||||
if (cd == (iconv_t)-1)
|
||||
return false;
|
||||
out->clear();
|
||||
out->resize(in.size() * 4 + 16);
|
||||
char *src = (char *)in.data(), *dst = &(*out)[0];
|
||||
size_t left = in.size(), room = out->size();
|
||||
bool ok = true;
|
||||
while (left > 0) {
|
||||
if (iconv(cd, &src, &left, &dst, &room) == (size_t)-1) {
|
||||
/* a byte the code page hasn't got: U+FFFD, and on */
|
||||
if (room < 3) {
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
memcpy(dst, "\xEF\xBF\xBD", 3);
|
||||
dst += 3;
|
||||
room -= 3;
|
||||
src++;
|
||||
left--;
|
||||
}
|
||||
}
|
||||
iconv_close(cd);
|
||||
out->resize(out->size() - room);
|
||||
return ok;
|
||||
}
|
||||
|
||||
std::string copy_dir()
|
||||
{
|
||||
std::string d = std::string(plat_data_dir()) + "/cache";
|
||||
mkdir(d.c_str(), 0777);
|
||||
d += "/subtitles";
|
||||
mkdir(d.c_str(), 0777);
|
||||
d += "/converted";
|
||||
mkdir(d.c_str(), 0777);
|
||||
return d;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
std::string subconv_to_utf8(const std::string &bytes, const std::string &lang, std::string *from)
|
||||
{
|
||||
if (from)
|
||||
from->clear();
|
||||
const unsigned char *b = (const unsigned char *)bytes.data();
|
||||
std::string out;
|
||||
if (bytes.size() >= 2 && ((b[0] == 0xFF && b[1] == 0xFE) || (b[0] == 0xFE && b[1] == 0xFF))) {
|
||||
const char *enc = b[0] == 0xFF ? "UTF-16LE" : "UTF-16BE";
|
||||
if (convert(bytes.substr(2), enc, &out)) {
|
||||
if (from)
|
||||
*from = enc;
|
||||
return out;
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
if (is_utf8(bytes))
|
||||
return bytes;
|
||||
const char *enc = legacy_encoding(lang);
|
||||
if (!convert(bytes, enc, &out))
|
||||
return bytes;
|
||||
if (from)
|
||||
*from = enc;
|
||||
return out;
|
||||
}
|
||||
|
||||
std::string subconv_bytes(const std::string &bytes, const std::string &name, const std::string &lang)
|
||||
{
|
||||
std::string from;
|
||||
std::string utf8 = subconv_to_utf8(bytes, lang, &from);
|
||||
if (from.empty())
|
||||
return "";
|
||||
/* The name kept (VLC shows it, and finds the format by its extension). */
|
||||
std::string base = name.substr(name.rfind('/') + 1);
|
||||
std::string path = copy_dir() + "/" + base;
|
||||
FILE *f = fopen(path.c_str(), "wb");
|
||||
if (!f)
|
||||
return "";
|
||||
fwrite(utf8.data(), 1, utf8.size(), f);
|
||||
fclose(f);
|
||||
fprintf(stderr, "subconv: %s read as %s, UTF-8 copy %s\n", base.c_str(), from.c_str(), path.c_str());
|
||||
return path;
|
||||
}
|
||||
|
||||
std::string subconv_local(const std::string &path, const std::string &lang)
|
||||
{
|
||||
FILE *f = fopen(path.c_str(), "rb");
|
||||
if (!f)
|
||||
return path;
|
||||
std::string bytes;
|
||||
char buf[65536];
|
||||
size_t n;
|
||||
/* subtitle files are small: a big one is something else, left alone */
|
||||
while ((n = fread(buf, 1, sizeof(buf), f)) > 0 && bytes.size() < (16u << 20))
|
||||
bytes.append(buf, n);
|
||||
fclose(f);
|
||||
if (bytes.size() >= (16u << 20))
|
||||
return path;
|
||||
std::string copy = subconv_bytes(bytes, path, lang);
|
||||
return copy.empty() ? path : copy;
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* VLC-PS5: subtitle files that aren't UTF-8 (Windows-1252, GBK, Big5, Shift
|
||||
* JIS, Windows-1256...). The console's VLC has no iconv, so it read them as
|
||||
* UTF-8 and showed mangled letters; such a file is converted here (GNU
|
||||
* libiconv) to a UTF-8 copy in cache/subtitles/converted, which VLC gets
|
||||
* instead.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
/* The bytes of a subtitle file made UTF-8: as they are when they already are
|
||||
* (or the encoding can't be told), else converted from UTF-16 (by its BOM)
|
||||
* or from the legacy code page of lang ("zh-CN", "ar", "ru"...; "" = Western).
|
||||
* *from says which encoding it was read as ("" = left alone). */
|
||||
std::string subconv_to_utf8(const std::string &bytes, const std::string &lang, std::string *from = nullptr);
|
||||
|
||||
/* A local subtitle file ready for VLC: the path itself when it's UTF-8 (or
|
||||
* can't be read), else the path of a converted UTF-8 copy. */
|
||||
std::string subconv_local(const std::string &path, const std::string &lang);
|
||||
|
||||
/* The same for bytes already read (a file on a share or a link): the copy's
|
||||
* path, or "" when they're UTF-8 already and VLC can read the original. name:
|
||||
* the file's name, for the copy's. */
|
||||
std::string subconv_bytes(const std::string &bytes, const std::string &name, const std::string &lang);
|
||||
+73
-44
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* VLC-PS5's web page server: plain HTTP/1.1 on port 8080 for the local
|
||||
* network. One thread listens; each connection gets its own (at most 8), so a
|
||||
* long upload doesn't hold up the remote. Uploads stream to "<name>.part" and
|
||||
* long upload doesn't hold up the rest of the page. Uploads stream to "<name>.part" and
|
||||
* are renamed when complete, so the library never sees half a file.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
@@ -10,8 +10,8 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <arpa/inet.h>
|
||||
#include <ctype.h>
|
||||
#include <atomic>
|
||||
#include <deque>
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
@@ -41,8 +41,7 @@ const int MAX_CONNECTIONS = 8;
|
||||
|
||||
std::mutex lock;
|
||||
std::vector<WebPlace> places;
|
||||
WebStatus status;
|
||||
std::deque<WebCommand> commands;
|
||||
WebOsubInfo osub_info;
|
||||
WebUpload upload;
|
||||
bool finished;
|
||||
/* an OpenSubtitles key and account sent from the page */
|
||||
@@ -249,6 +248,56 @@ void handle_upload(int fd, const std::string &query, int64_t length, std::string
|
||||
respond(fd, ok ? 200 : 500, "text/plain", ok ? "ok" : "The upload stopped: connection or disk full");
|
||||
}
|
||||
|
||||
/* A file from the PS5 to the phone or computer: streamed from the disk in
|
||||
* 1 MiB pieces, so any size goes (a 40 GB film too), as an attachment so
|
||||
* the browser saves it instead of playing it. */
|
||||
void handle_download(int fd, const std::string &query)
|
||||
{
|
||||
std::string dir, name = query_value(query, "name");
|
||||
if (!place_path(query_value(query, "dir"), &dir) || !safe_name(name)) {
|
||||
respond(fd, 400, "text/plain", "That name or folder can't be used");
|
||||
return;
|
||||
}
|
||||
std::string path = dir + "/" + name;
|
||||
int in = open(path.c_str(), O_RDONLY);
|
||||
struct stat st;
|
||||
if (in < 0 || fstat(in, &st) != 0 || !S_ISREG(st.st_mode)) {
|
||||
if (in >= 0)
|
||||
close(in);
|
||||
respond(fd, 404, "text/plain", "not found");
|
||||
return;
|
||||
}
|
||||
/* the name for the browser: plain letters as they are, the rest %-coded */
|
||||
std::string coded;
|
||||
for (unsigned char c : name) {
|
||||
char hex[4];
|
||||
snprintf(hex, sizeof(hex), "%%%02X", c);
|
||||
coded += isalnum(c) || strchr("-._~", c) ? std::string(1, (char)c) : std::string(hex);
|
||||
}
|
||||
char head[1024];
|
||||
int n = snprintf(head, sizeof(head),
|
||||
"HTTP/1.1 200 OK\r\nContent-Type: application/octet-stream\r\nContent-Length: %lld\r\n"
|
||||
"Content-Disposition: attachment; filename*=UTF-8''%s\r\n"
|
||||
"Cache-Control: no-store\r\nConnection: close\r\n\r\n",
|
||||
(long long)st.st_size, coded.c_str());
|
||||
struct timeval tv = { 60, 0 }; /* a phone that stops reading lets go of the thread */
|
||||
setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv));
|
||||
bool ok = n > 0 && n < (int)sizeof(head) && write_all(fd, head, (size_t)n);
|
||||
std::vector<char> buf(1 << 20);
|
||||
int64_t sent = 0;
|
||||
while (ok) {
|
||||
ssize_t r = read(in, buf.data(), buf.size());
|
||||
if (r < 0 && errno == EINTR)
|
||||
continue;
|
||||
if (r <= 0)
|
||||
break;
|
||||
ok = write_all(fd, buf.data(), (size_t)r);
|
||||
sent += r;
|
||||
}
|
||||
close(in);
|
||||
fprintf(stderr, "web: %s %s\n", name.c_str(), sent == st.st_size ? "sent" : "stopped (connection)");
|
||||
}
|
||||
|
||||
void handle_files(int fd, const std::string &query)
|
||||
{
|
||||
std::string dir;
|
||||
@@ -317,6 +366,8 @@ void handle(int fd)
|
||||
respond(fd, 200, "application/json", out + "]");
|
||||
} else if (method == "GET" && path == "/api/files") {
|
||||
handle_files(fd, query);
|
||||
} else if (method == "GET" && path == "/api/download") {
|
||||
handle_download(fd, query);
|
||||
} else if (method == "PUT" && path == "/api/upload") {
|
||||
handle_upload(fd, query, length, body);
|
||||
} else if (method == "DELETE" && path == "/api/file") {
|
||||
@@ -328,38 +379,20 @@ void handle(int fd)
|
||||
finished = true; /* the library looks again */
|
||||
}
|
||||
respond(fd, ok ? 200 : 404, "text/plain", ok ? "ok" : "not found");
|
||||
} else if (method == "GET" && path == "/api/status") {
|
||||
WebStatus s;
|
||||
} else if (method == "GET" && path == "/api/opensubtitles") {
|
||||
WebOsubInfo s;
|
||||
bool waiting;
|
||||
{
|
||||
std::lock_guard<std::mutex> g(lock);
|
||||
s = status;
|
||||
s = osub_info;
|
||||
waiting = osub_sent; /* sent, not yet taken by the main thread */
|
||||
}
|
||||
std::string out = std::string("{\"playing\":") + (s.playing ? "true" : "false") +
|
||||
",\"paused\":" + (s.paused ? "true" : "false") +
|
||||
",\"title\":" + json_string(s.title) +
|
||||
",\"time\":" + std::to_string(s.time_ms) +
|
||||
",\"length\":" + std::to_string(s.length_ms) +
|
||||
",\"volume\":" + std::to_string(s.volume) + "}";
|
||||
std::string out = std::string("{\"key\":") + (s.has_key ? "true" : "false") +
|
||||
",\"checking\":" + (s.checking || waiting ? "true" : "false") +
|
||||
",\"failed\":" + (s.failed ? "true" : "false") +
|
||||
",\"user\":" + json_string(s.user) +
|
||||
",\"message\":" + json_string(s.message) + "}";
|
||||
respond(fd, 200, "application/json", out);
|
||||
} else if (method == "POST" && path == "/api/cmd") {
|
||||
std::string c = query_value(query, "c");
|
||||
int64_t v = atoll(query_value(query, "v").c_str());
|
||||
WebCommandKind k;
|
||||
bool known = true;
|
||||
if (c == "toggle") k = WEB_TOGGLE;
|
||||
else if (c == "jump") k = WEB_JUMP;
|
||||
else if (c == "seek") k = WEB_SEEK;
|
||||
else if (c == "next") k = WEB_NEXT;
|
||||
else if (c == "prev") k = WEB_PREV;
|
||||
else if (c == "vol") k = WEB_VOLUME;
|
||||
else if (c == "stop") k = WEB_STOP;
|
||||
else known = false;
|
||||
if (known) {
|
||||
std::lock_guard<std::mutex> g(lock);
|
||||
if (commands.size() < 32)
|
||||
commands.push_back({ k, v });
|
||||
}
|
||||
respond(fd, known ? 200 : 400, "text/plain", known ? "ok" : "unknown command");
|
||||
} else if (method == "POST" && path == "/api/opensubtitles") {
|
||||
/* a small form: the rest of its body, then key, user, pass */
|
||||
while ((int64_t)body.size() < length && length < 4096) {
|
||||
@@ -429,6 +462,12 @@ void web_start()
|
||||
a.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
if (bind(listen_fd, (sockaddr *)&a, sizeof(a)) == 0)
|
||||
break;
|
||||
if (errno == EACCES) {
|
||||
/* the sandbox: no port will do */
|
||||
fprintf(stderr, "web: not allowed to listen (sandboxed: the page needs full access)\n");
|
||||
p = LAST_PORT + 1;
|
||||
break;
|
||||
}
|
||||
fprintf(stderr, "web: port %d taken (errno %d)\n", p, errno);
|
||||
}
|
||||
if (p > LAST_PORT || listen(listen_fd, 8) != 0) {
|
||||
@@ -483,20 +522,10 @@ void web_set_places(const std::vector<WebPlace> &p)
|
||||
places = p;
|
||||
}
|
||||
|
||||
void web_set_status(const WebStatus &s)
|
||||
void web_set_osub_info(const WebOsubInfo &info)
|
||||
{
|
||||
std::lock_guard<std::mutex> g(lock);
|
||||
status = s;
|
||||
}
|
||||
|
||||
bool web_next_command(WebCommand *c)
|
||||
{
|
||||
std::lock_guard<std::mutex> g(lock);
|
||||
if (commands.empty())
|
||||
return false;
|
||||
*c = commands.front();
|
||||
commands.pop_front();
|
||||
return true;
|
||||
osub_info = info;
|
||||
}
|
||||
|
||||
WebUpload web_upload_state()
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* VLC-PS5's web page for phones and computers on the same network: send
|
||||
* videos and music to the console (no FTP), and a remote for what's playing.
|
||||
* videos and music to the console (no FTP), and an OpenSubtitles key.
|
||||
* A small HTTP server on its own threads; the main thread hands it what it
|
||||
* may show (web_set_*) and takes the remote's commands (web_next_command).
|
||||
* may show (web_set_*) and takes what arrived (web_take_*).
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
@@ -24,24 +24,13 @@ struct WebPlace {
|
||||
};
|
||||
void web_set_places(const std::vector<WebPlace> &places);
|
||||
|
||||
/* What the remote shows. */
|
||||
struct WebStatus {
|
||||
bool playing; /* a file is open */
|
||||
bool paused;
|
||||
std::string title;
|
||||
int64_t time_ms, length_ms;
|
||||
int volume; /* 0..200 */
|
||||
bool loop;
|
||||
/* What the page shows about subtitle downloads: never the key or the
|
||||
* password, only whether a key is saved, the account and the last check. */
|
||||
struct WebOsubInfo {
|
||||
bool has_key, checking, failed; /* failed: the last check went wrong */
|
||||
std::string user, message;
|
||||
};
|
||||
void web_set_status(const WebStatus &s);
|
||||
|
||||
/* The remote's buttons, for the main thread. */
|
||||
enum WebCommandKind { WEB_TOGGLE, WEB_JUMP, WEB_SEEK, WEB_NEXT, WEB_PREV, WEB_VOLUME, WEB_STOP };
|
||||
struct WebCommand {
|
||||
WebCommandKind kind;
|
||||
int64_t value; /* JUMP: ms (+/-), SEEK: ms, VOLUME: +/- percent */
|
||||
};
|
||||
bool web_next_command(WebCommand *c);
|
||||
void web_set_osub_info(const WebOsubInfo &info);
|
||||
|
||||
/* An upload in progress (for the TV), and whether one finished since asked. */
|
||||
struct WebUpload {
|
||||
|
||||
+514
-191
@@ -1,7 +1,9 @@
|
||||
/*
|
||||
* The page VLC-PS5 serves to phones and computers (see web.cc): send files
|
||||
* and a remote. One file, no outside resources (the console may have no
|
||||
* internet), sized for a phone first.
|
||||
* The page VLC-PS5 serves to phones and computers (see web.cc): send files to
|
||||
* the console and set up subtitle downloads. One file, no outside resources
|
||||
* (the console may have no internet). It looks like the app's Modern look:
|
||||
* black, VLC orange, a glowing tab bar whose highlight glides, panels that
|
||||
* slide in from the side you went to, rows with the orange focus bar.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
@@ -12,248 +14,569 @@ static const char WEB_PAGE[] = R"VLCPAGE(<!doctype html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
|
||||
<meta name="theme-color" content="#0b0b0f">
|
||||
<meta name="theme-color" content="#000000">
|
||||
<title>VLC for PS5</title>
|
||||
<style>
|
||||
:root {
|
||||
--bg: #0b0b0f; --panel: #16161d; --panel2: #1e1e27; --line: #2a2a35;
|
||||
--fg: #f4f4f7; --dim: #9a9aa8; --faint: #62626f; --accent: #ff8800; --accent2: #ff5e14;
|
||||
--ok: #3fd6a4; --bad: #ff5d6c;
|
||||
--sans: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
|
||||
--bg: #000; --bar: #0f0f13; --card: #121217; --raised: #1a1a21; --hi: #24242d; --line: #22222a;
|
||||
--fg: #f5f5f7; --dim: #a3a3b0; --faint: #6c6c79;
|
||||
--or: #ff8800; --or2: #ff5e14; --glow: rgba(255, 136, 0, .26); --soft: rgba(255, 136, 0, .1);
|
||||
--ok: #34d399; --bad: #f87171;
|
||||
--ease: cubic-bezier(.22, .8, .24, 1); --spring: cubic-bezier(.34, 1.4, .5, 1);
|
||||
--sans: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", sans-serif;
|
||||
}
|
||||
* { box-sizing: border-box; -webkit-tap-highlight-color: transparent; }
|
||||
html, body { margin: 0; background: var(--bg); color: var(--fg); font-family: var(--sans); }
|
||||
body { padding: env(safe-area-inset-top, 0) 16px calc(24px + env(safe-area-inset-bottom, 0)); max-width: 640px; margin: 0 auto; }
|
||||
header { display: flex; align-items: center; gap: 12px; padding: 20px 0 16px; }
|
||||
header svg { width: 34px; height: 34px; flex: none; }
|
||||
header h1 { font-size: 20px; margin: 0; letter-spacing: -0.01em; }
|
||||
header p { margin: 2px 0 0; color: var(--dim); font-size: 13px; }
|
||||
.tabs { display: grid; grid-template-columns: 1fr 1fr; gap: 6px; background: var(--panel); padding: 5px; border-radius: 12px; }
|
||||
.tabs button { font: inherit; font-weight: 600; font-size: 15px; color: var(--dim); background: none; border: 0; padding: 11px; border-radius: 9px; cursor: pointer; }
|
||||
.tabs button[aria-pressed="true"] { background: var(--accent); color: #140900; }
|
||||
section { margin-top: 18px; display: grid; gap: 14px; }
|
||||
.card { background: var(--panel); border: 1px solid var(--line); border-radius: 16px; padding: 16px; display: grid; gap: 12px; }
|
||||
label.small { font-size: 12px; color: var(--faint); text-transform: uppercase; letter-spacing: .08em; }
|
||||
select { font: inherit; color: var(--fg); background: var(--panel2); border: 1px solid var(--line); border-radius: 10px; padding: 11px 12px; width: 100%; }
|
||||
.drop { display: grid; place-items: center; gap: 6px; text-align: center; padding: 30px 16px; border: 2px dashed var(--line); border-radius: 14px; cursor: pointer; }
|
||||
.drop.over { border-color: var(--accent); background: rgba(255,136,0,.06); }
|
||||
.drop b { font-size: 17px; }
|
||||
.drop span { color: var(--dim); font-size: 13px; }
|
||||
html { background: var(--bg); }
|
||||
body { margin: 0; min-height: 100vh; color: var(--fg); font: 15px/1.45 var(--sans); background: var(--bg);
|
||||
overflow-x: hidden; padding-bottom: calc(24px + env(safe-area-inset-bottom, 0)); }
|
||||
button, input { font: inherit; color: inherit; }
|
||||
button { cursor: pointer; }
|
||||
:focus-visible { outline: 2px solid var(--or); outline-offset: 2px; }
|
||||
|
||||
/* a slow orange glow behind everything, like the app's backdrop */
|
||||
.aura { position: fixed; inset: -20vh -20vw auto; height: 70vh; pointer-events: none; z-index: 0;
|
||||
background: radial-gradient(60% 60% at 50% 0%, rgba(255, 120, 0, .07), transparent 70%);
|
||||
animation: breathe 9s ease-in-out infinite; }
|
||||
@keyframes breathe { 50% { opacity: .55; transform: scale(1.06); } }
|
||||
|
||||
/* title row: the cone and VLC, as in the app */
|
||||
header { position: relative; z-index: 2; max-width: 980px; margin: 0 auto;
|
||||
padding: calc(20px + env(safe-area-inset-top, 0)) 16px 0; display: flex; align-items: center; gap: 12px; }
|
||||
.cone { width: 40px; height: 40px; flex: none; animation: drop .7s var(--spring) both; }
|
||||
@keyframes drop { from { transform: translateY(-16px) scale(.8); opacity: 0; } }
|
||||
header h1 { margin: 0; font-size: 24px; font-weight: 750; letter-spacing: -.02em; line-height: 1.1; }
|
||||
header h1 small { display: block; font-size: 12.5px; font-weight: 500; color: var(--faint); letter-spacing: 0; }
|
||||
.link { margin-left: auto; display: inline-flex; align-items: center; gap: 8px; font-size: 13px; color: var(--dim);
|
||||
padding: 7px 12px; border-radius: 99px; background: var(--bar); border: 1px solid var(--line); }
|
||||
.link i { width: 8px; height: 8px; border-radius: 50%; background: var(--ok); position: relative; }
|
||||
.link i::after { content: ""; position: absolute; inset: -4px; border-radius: 50%; border: 2px solid var(--ok);
|
||||
opacity: 0; animation: ping 2.4s ease-out infinite; }
|
||||
@keyframes ping { 0% { transform: scale(.4); opacity: .7; } 80%, 100% { transform: scale(1.4); opacity: 0; } }
|
||||
.link.off i, .link.off i::after { background: var(--bad); border-color: var(--bad); }
|
||||
|
||||
/* the tab bar: a dark box, the highlight glides under the chosen tab */
|
||||
nav { position: sticky; top: 0; z-index: 3; padding: 14px 16px 12px; max-width: 980px; margin: 0 auto;
|
||||
backdrop-filter: blur(18px); -webkit-backdrop-filter: blur(18px); }
|
||||
.tabs { position: relative; display: grid; grid-template-columns: repeat(3, 1fr); background: var(--bar);
|
||||
border: 1px solid var(--line); border-radius: 18px; padding: 6px; max-width: 620px; margin: 0 auto;
|
||||
box-shadow: 0 10px 40px rgba(0, 0, 0, .6); }
|
||||
.tabs .hl { position: absolute; top: 6px; bottom: 6px; left: 6px; width: 0; border-radius: 13px;
|
||||
background: linear-gradient(180deg, #ff9a1f, var(--or)); box-shadow: 0 0 14px var(--glow), 0 0 0 1px rgba(255, 170, 60, .3) inset;
|
||||
transition: left .45s var(--spring), width .45s var(--spring); }
|
||||
.tabs button { position: relative; z-index: 1; border: 0; background: none; color: var(--dim); font-weight: 650;
|
||||
font-size: 15px; padding: 11px 8px; border-radius: 13px; display: flex; align-items: center; justify-content: center;
|
||||
gap: 8px; transition: color .3s; white-space: nowrap; }
|
||||
.tabs button svg { width: 18px; height: 18px; flex: none; transition: transform .4s var(--spring); }
|
||||
.tabs button:hover { color: var(--fg); }
|
||||
.tabs button[aria-selected="true"] { color: #fff; }
|
||||
.tabs button[aria-selected="true"] svg { transform: scale(1.12); }
|
||||
.tabs .n { min-width: 20px; height: 20px; padding: 0 6px; border-radius: 10px; font-size: 11.5px; font-weight: 750;
|
||||
display: inline-grid; place-items: center; background: var(--hi); color: var(--dim); transition: background .3s, color .3s; }
|
||||
.tabs button[aria-selected="true"] .n { background: rgba(0, 0, 0, .25); color: #fff; }
|
||||
.tabs .n:empty { display: none; }
|
||||
@media (max-width: 480px) { .tabs button .t { display: none; } .tabs button { padding: 12px 6px; } }
|
||||
|
||||
/* panels slide in from the side you moved to */
|
||||
main { position: relative; z-index: 1; max-width: 980px; margin: 0 auto; padding: 8px 16px 0; }
|
||||
.panel { display: none; }
|
||||
.panel.on { display: grid; gap: 16px; animation: var(--in, in-r) .5s var(--ease) both; }
|
||||
@keyframes in-r { from { opacity: 0; transform: translateX(36px); } }
|
||||
@keyframes in-l { from { opacity: 0; transform: translateX(-36px); } }
|
||||
.panel > * { animation: rise .55s var(--ease) both; }
|
||||
.panel > :nth-child(2) { animation-delay: .06s; } .panel > :nth-child(3) { animation-delay: .12s; }
|
||||
.panel > :nth-child(4) { animation-delay: .18s; }
|
||||
@keyframes rise { from { opacity: 0; transform: translateY(14px); } }
|
||||
h2 { margin: 6px 4px 0; font-size: 26px; font-weight: 750; letter-spacing: -.02em; }
|
||||
.lead { margin: -8px 4px 0; color: var(--dim); }
|
||||
.card { background: var(--card); border: 1px solid var(--line); border-radius: 20px; padding: 18px; }
|
||||
@media (min-width: 760px) { .card { padding: 24px; } h2 { font-size: 30px; } }
|
||||
|
||||
/* where files go: chips, the chosen one glows */
|
||||
.places { display: flex; flex-wrap: wrap; gap: 8px; min-width: 0; }
|
||||
.places button { border: 1px solid var(--line); background: var(--raised); color: var(--dim); border-radius: 12px;
|
||||
padding: 9px 14px; font-size: 14px; font-weight: 600; display: inline-flex; align-items: center; gap: 8px;
|
||||
transition: all .3s var(--ease); max-width: 100%; }
|
||||
.places button svg { width: 16px; height: 16px; flex: none; }
|
||||
.places button span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||||
.places button:hover { color: var(--fg); background: var(--hi); }
|
||||
.places button[aria-pressed="true"] { color: var(--fg); background: var(--soft); border-color: var(--or);
|
||||
box-shadow: 0 0 10px rgba(255, 136, 0, .12); }
|
||||
|
||||
/* the drop zone */
|
||||
.drop { position: relative; display: grid; place-items: center; text-align: center; gap: 4px; padding: 44px 16px;
|
||||
border-radius: 18px; cursor: pointer; background: var(--raised); overflow: hidden;
|
||||
transition: transform .35s var(--spring), background .3s; }
|
||||
.drop::before { content: ""; position: absolute; inset: 0; border-radius: inherit; padding: 2px;
|
||||
background: repeating-linear-gradient(90deg, var(--hi) 0 14px, transparent 14px 24px);
|
||||
-webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
|
||||
-webkit-mask-composite: xor; mask-composite: exclude; }
|
||||
.drop:hover { background: var(--hi); }
|
||||
.drop.over { transform: scale(1.02); background: var(--soft); }
|
||||
.drop.over::before { background: repeating-linear-gradient(90deg, var(--or) 0 14px, transparent 14px 24px);
|
||||
background-size: 24px 100%; animation: march .6s linear infinite; }
|
||||
@keyframes march { to { background-position: 24px 0; } }
|
||||
.drop .ic { width: 64px; height: 64px; border-radius: 20px; display: grid; place-items: center; margin-bottom: 10px;
|
||||
color: #fff; background: linear-gradient(180deg, #ff9a1f, var(--or2)); box-shadow: 0 6px 16px var(--glow);
|
||||
animation: float 3.2s ease-in-out infinite; }
|
||||
.drop .ic svg { width: 28px; height: 28px; }
|
||||
@keyframes float { 50% { transform: translateY(-6px); } }
|
||||
.drop b { font-size: 18px; font-weight: 700; }
|
||||
.drop span { color: var(--dim); font-size: 14px; }
|
||||
.drop input { display: none; }
|
||||
.big { font: inherit; font-weight: 700; font-size: 16px; color: #140900; background: var(--accent); border: 0; border-radius: 12px; padding: 13px 18px; cursor: pointer; }
|
||||
.list { display: grid; gap: 8px; }
|
||||
.item { display: grid; grid-template-columns: minmax(0,1fr) auto; gap: 4px 10px; align-items: center; background: var(--panel2); border-radius: 12px; padding: 10px 12px; }
|
||||
.item .name { font-size: 14px; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||||
.item .meta { grid-column: 1; font-size: 12px; color: var(--dim); font-variant-numeric: tabular-nums; }
|
||||
.item .bar { grid-column: 1 / -1; height: 5px; background: var(--line); border-radius: 3px; overflow: hidden; }
|
||||
.item .bar i { display: block; height: 100%; width: 0; background: linear-gradient(90deg, var(--accent2), var(--accent)); }
|
||||
.item.done .bar i { background: var(--ok); }
|
||||
.item.fail .bar i { background: var(--bad); }
|
||||
.del { font: inherit; font-size: 13px; color: var(--dim); background: none; border: 1px solid var(--line); border-radius: 8px; padding: 6px 10px; cursor: pointer; grid-row: 1 / span 2; grid-column: 2; }
|
||||
.empty { color: var(--faint); font-size: 14px; text-align: center; padding: 10px; }
|
||||
.now { display: grid; gap: 6px; }
|
||||
.now h2 { margin: 0; font-size: 18px; overflow-wrap: anywhere; }
|
||||
.now p { margin: 0; color: var(--dim); font-size: 13px; }
|
||||
input[type=range] { width: 100%; accent-color: var(--accent); }
|
||||
.times { display: flex; justify-content: space-between; color: var(--dim); font-size: 12px; font-variant-numeric: tabular-nums; }
|
||||
.pad { display: grid; grid-template-columns: repeat(5, 1fr); gap: 8px; }
|
||||
.pad button, .row button { font: inherit; font-weight: 700; color: var(--fg); background: var(--panel2); border: 1px solid var(--line); border-radius: 14px; aspect-ratio: 1; cursor: pointer; display: grid; place-items: center; }
|
||||
.pad button svg { width: 26px; height: 26px; fill: currentColor; }
|
||||
.pad button.main { background: var(--fg); color: var(--bg); }
|
||||
.row { display: grid; grid-template-columns: 1fr auto 1fr auto; gap: 8px; align-items: center; }
|
||||
.row button { aspect-ratio: auto; padding: 12px; font-size: 18px; }
|
||||
.row span { text-align: center; font-variant-numeric: tabular-nums; color: var(--dim); }
|
||||
.field { font: inherit; color: var(--fg); background: var(--panel2); border: 1px solid var(--line); border-radius: 10px; padding: 11px 12px; width: 100%; }
|
||||
.note { margin: 0; color: var(--dim); font-size: 13px; }
|
||||
.note a { color: var(--accent); }
|
||||
button:active { transform: scale(.97); }
|
||||
button:focus-visible, select:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
|
||||
footer { margin-top: 22px; color: var(--faint); font-size: 12px; text-align: center; }
|
||||
|
||||
/* rows: the app's list, a lighter row with the orange bar on the left */
|
||||
.rows { display: grid; gap: 6px; }
|
||||
.rows:empty { display: none; }
|
||||
.row { position: relative; display: grid; grid-template-columns: 44px minmax(0, 1fr) auto; align-items: center;
|
||||
gap: 14px; padding: 10px 12px 10px 14px; border-radius: 14px;
|
||||
transition: background .25s, box-shadow .25s; }
|
||||
.row::before { content: ""; position: absolute; left: 0; top: 14px; bottom: 14px; width: 4px; border-radius: 2px;
|
||||
background: var(--or); transform: scaleY(0); transition: transform .3s var(--spring); }
|
||||
.row:hover { background: var(--raised); box-shadow: 0 0 0 1px rgba(255, 136, 0, .14); }
|
||||
.row:hover::before { transform: scaleY(1); }
|
||||
.row.new { animation: pop .45s var(--spring) both; }
|
||||
@keyframes pop { from { opacity: 0; transform: translateY(10px) scale(.97); } }
|
||||
.row.gone { animation: out .35s var(--ease) both; }
|
||||
@keyframes out { to { opacity: 0; transform: translateX(30px); } }
|
||||
.row .ic { width: 44px; height: 44px; border-radius: 12px; background: var(--hi); display: grid; place-items: center;
|
||||
color: var(--dim); transition: color .25s, background .25s; }
|
||||
.row .ic svg { width: 22px; height: 22px; }
|
||||
.row:hover .ic { color: var(--or); background: var(--soft); }
|
||||
.row .name { font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||||
.row .meta { font-size: 13px; color: var(--dim); font-variant-numeric: tabular-nums; display: flex; gap: 8px; align-items: center; }
|
||||
.tag { font-size: 10.5px; font-weight: 750; letter-spacing: .04em; padding: 2px 7px; border-radius: 6px;
|
||||
background: var(--hi); color: var(--dim); text-transform: uppercase; }
|
||||
.bar { height: 5px; margin-top: 8px; background: var(--hi); border-radius: 3px; overflow: hidden; }
|
||||
.bar i { position: relative; display: block; height: 100%; width: 0; border-radius: 3px; overflow: hidden;
|
||||
background: linear-gradient(90deg, var(--or2), var(--or)); box-shadow: 0 0 6px var(--glow); transition: width .3s linear; }
|
||||
.bar i::after { content: ""; position: absolute; inset: 0; background: linear-gradient(90deg, transparent, rgba(255, 255, 255, .45), transparent);
|
||||
transform: translateX(-100%); animation: shine 1.3s ease-in-out infinite; }
|
||||
@keyframes shine { to { transform: translateX(100%); } }
|
||||
.row.done .bar i { background: var(--ok); box-shadow: 0 0 12px rgba(52, 211, 153, .5); }
|
||||
.row.done .bar i::after, .row.fail .bar i::after { display: none; }
|
||||
.row.fail .bar i { background: var(--bad); box-shadow: none; }
|
||||
.row.done .meta { color: var(--ok); } .row.fail .meta { color: var(--bad); }
|
||||
.act { border: 0; background: none; color: var(--faint); border-radius: 10px; padding: 8px 12px; font-size: 13.5px;
|
||||
font-weight: 600; transition: all .25s var(--ease); }
|
||||
.act:hover { color: var(--fg); background: var(--hi); }
|
||||
.act.sure { color: #fff; background: var(--bad); }
|
||||
.acts { display: flex; align-items: center; gap: 2px; }
|
||||
.act.dl { display: inline-flex; align-items: center; gap: 6px; text-decoration: none; }
|
||||
.act.dl svg { width: 16px; height: 16px; }
|
||||
.act.dl:hover { color: var(--or); background: var(--soft); }
|
||||
@media (max-width: 480px) { .act.dl span { display: none; } .act.dl { padding: 8px 10px; } }
|
||||
.round { width: 38px; height: 38px; padding: 0; display: grid; place-items: center; border-radius: 12px; flex: none; }
|
||||
.round svg { width: 18px; height: 18px; }
|
||||
.spin svg { animation: spin .7s var(--ease); }
|
||||
@keyframes spin { to { transform: rotate(360deg); } }
|
||||
.empty { display: grid; place-items: center; gap: 10px; padding: 36px 8px; color: var(--faint); text-align: center; }
|
||||
.empty svg { width: 54px; height: 54px; opacity: .5; }
|
||||
.headrow { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; margin-bottom: 14px; }
|
||||
|
||||
/* subtitles */
|
||||
.status { display: flex; align-items: center; gap: 14px; }
|
||||
.status .ic { width: 52px; height: 52px; border-radius: 16px; flex: none; display: grid; place-items: center;
|
||||
background: var(--hi); color: var(--faint); transition: all .4s var(--ease); }
|
||||
.status .ic svg { width: 26px; height: 26px; }
|
||||
.status.ok .ic { background: rgba(52, 211, 153, .14); color: var(--ok); }
|
||||
.status.bad .ic { background: rgba(248, 113, 113, .14); color: var(--bad); }
|
||||
.status b { display: block; font-size: 16px; } .status span { color: var(--dim); font-size: 13.5px; }
|
||||
.form { display: grid; gap: 14px; margin-top: 20px; }
|
||||
.form .two { display: grid; gap: 14px; }
|
||||
@media (min-width: 760px) { .form .two { grid-template-columns: 1fr 1fr; } }
|
||||
.field { position: relative; }
|
||||
.field input { width: 100%; padding: 22px 14px 8px; background: var(--raised); border: 1px solid var(--line);
|
||||
border-radius: 14px; transition: border-color .25s, background .25s, box-shadow .25s; }
|
||||
.field label { position: absolute; left: 15px; top: 15px; color: var(--faint); pointer-events: none;
|
||||
transition: all .25s var(--ease); }
|
||||
.field input:focus { outline: none; border-color: var(--or); background: #0b0b0e; box-shadow: 0 0 0 4px var(--soft); }
|
||||
.field input:focus + label, .field input:not(:placeholder-shown) + label { top: 6px; font-size: 11.5px; color: var(--or); }
|
||||
.field label em { font-style: normal; color: var(--faint); margin-left: 6px; }
|
||||
.go { position: relative; overflow: hidden; border: 0; border-radius: 14px; padding: 15px 18px; font-weight: 750; font-size: 16px;
|
||||
color: #fff; background: linear-gradient(180deg, #ff9a1f, var(--or)); box-shadow: 0 4px 14px var(--glow);
|
||||
transition: transform .2s var(--spring), box-shadow .3s, opacity .3s; }
|
||||
.go:hover { transform: translateY(-2px); box-shadow: 0 6px 18px var(--glow); }
|
||||
.go:active { transform: scale(.98); }
|
||||
.go:disabled { opacity: .55; cursor: default; transform: none; }
|
||||
.go.busy::after { content: ""; position: absolute; inset: 0; background: linear-gradient(90deg, transparent, rgba(255, 255, 255, .35), transparent);
|
||||
animation: shine 1s ease-in-out infinite; transform: translateX(-100%); }
|
||||
.help { color: var(--faint); font-size: 13.5px; margin: 0; }
|
||||
.steps { display: grid; gap: 12px; counter-reset: s; margin: 0; padding: 0; list-style: none; }
|
||||
.steps li { display: flex; gap: 12px; align-items: flex-start; color: var(--dim); font-size: 14px; }
|
||||
.steps li::before { counter-increment: s; content: counter(s); flex: none; width: 24px; height: 24px; border-radius: 8px;
|
||||
display: grid; place-items: center; font-size: 12px; font-weight: 750; background: var(--soft); color: var(--or); }
|
||||
.steps a { color: var(--or); font-weight: 600; text-decoration: none; }
|
||||
.steps a:hover { text-decoration: underline; }
|
||||
|
||||
/* toasts, as the app shows them */
|
||||
.toasts { position: fixed; z-index: 9; left: 50%; bottom: calc(20px + env(safe-area-inset-bottom, 0)); transform: translateX(-50%);
|
||||
display: grid; gap: 8px; justify-items: center; width: min(92vw, 420px); pointer-events: none; }
|
||||
.toast { display: flex; align-items: center; gap: 10px; padding: 12px 18px; border-radius: 16px; background: rgba(28, 28, 36, .92);
|
||||
backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px); border: 1px solid var(--line); font-weight: 600; font-size: 14.5px;
|
||||
box-shadow: 0 12px 40px rgba(0, 0, 0, .6); animation: tin .45s var(--spring) both; max-width: 100%; }
|
||||
.toast span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||||
.toast i { width: 9px; height: 9px; border-radius: 50%; background: var(--or); box-shadow: 0 0 10px var(--glow); flex: none; }
|
||||
.toast.ok i { background: var(--ok); box-shadow: 0 0 10px rgba(52, 211, 153, .6); }
|
||||
.toast.bad i { background: var(--bad); box-shadow: 0 0 10px rgba(248, 113, 113, .6); }
|
||||
.toast.bye { animation: tout .35s var(--ease) both; }
|
||||
@keyframes tin { from { opacity: 0; transform: translateY(20px) scale(.9); } }
|
||||
@keyframes tout { to { opacity: 0; transform: translateY(10px) scale(.95); } }
|
||||
footer { position: relative; z-index: 1; text-align: center; color: var(--faint); font-size: 12.5px; padding: 28px 16px 0; }
|
||||
@media (prefers-reduced-motion: reduce) { *, *::before, *::after { animation: none !important; transition: none !important; } }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="aura"></div>
|
||||
<header>
|
||||
<svg viewBox="0 0 64 64" aria-hidden="true"><path d="M32 4 9 56h46z" fill="#ff8800"/><path d="M24 22h16l2.6 6H21.4zM18.6 34h26.8l2.6 6H16z" fill="#fff"/><rect x="5" y="54" width="54" height="7" rx="2.5" fill="#ff5e14"/></svg>
|
||||
<div><h1>VLC for PS5</h1><p id="who">On your console</p></div>
|
||||
<svg class="cone" viewBox="0 0 64 64" aria-hidden="true"><path d="M32 4 9 56h46z" fill="#ff8800"/><path d="M24 22h16l2.6 6H21.4zM18.6 34h26.8l2.6 6H16z" fill="#fff"/><rect x="5" y="54" width="54" height="7" rx="2.5" fill="#ff5e14"/></svg>
|
||||
<h1>VLC<small>for PS5</small></h1>
|
||||
<span class="link" id="link"><i></i><span id="link-t">Connected</span></span>
|
||||
</header>
|
||||
|
||||
<div class="tabs" role="tablist">
|
||||
<button id="t-send" aria-pressed="true">Send files</button>
|
||||
<button id="t-remote" aria-pressed="false">Remote</button>
|
||||
</div>
|
||||
<nav><div class="tabs" role="tablist">
|
||||
<div class="hl" id="hl"></div>
|
||||
<button role="tab" data-tab="send"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 15V4M7 9l5-5 5 5M5 20h14"/></svg><span class="t">Send</span><span class="n" id="n-send"></span></button>
|
||||
<button role="tab" data-tab="files"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 7a2 2 0 0 1 2-2h4l2 2h8a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/></svg><span class="t">On the PS5</span><span class="n" id="n-files"></span></button>
|
||||
<button role="tab" data-tab="subs"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="5" width="18" height="14" rx="3"/><path d="M7 13h4M13 13h4M7 16h7"/></svg><span class="t">Subtitles</span></button>
|
||||
</div></nav>
|
||||
|
||||
<section id="p-send">
|
||||
<div class="card">
|
||||
<label class="small" for="place">Save to</label>
|
||||
<select id="place"></select>
|
||||
<label class="drop" id="drop">
|
||||
<input id="pick" type="file" multiple accept="video/*,audio/*,.mkv,.avi,.ts,.m2ts,.webm,.flac,.opus,.srt,.ass,.ssa,.vtt,.m3u,.m3u8,.pls">
|
||||
<b>Choose videos or music</b>
|
||||
<span>or drop them here. Subtitles (.srt, .ass) too.</span>
|
||||
</label>
|
||||
<div class="list" id="queue"></div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<label class="small">In this folder</label>
|
||||
<div class="list" id="files"><div class="empty">Loading…</div></div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<label class="small" for="os-key">Subtitle downloads (OpenSubtitles)</label>
|
||||
<p class="note">Paste your own free API key from opensubtitles.com (Profile › API consumers). An account is optional and gives more downloads a day.</p>
|
||||
<input class="field" id="os-key" placeholder="API key" autocomplete="off" autocapitalize="off" spellcheck="false">
|
||||
<input class="field" id="os-user" placeholder="User name (optional)" autocomplete="username" autocapitalize="off">
|
||||
<input class="field" id="os-pass" type="password" placeholder="Password (optional)" autocomplete="current-password">
|
||||
<button class="big" id="os-save">Save on the PS5</button>
|
||||
<p class="note" id="os-msg"></p>
|
||||
</div>
|
||||
</section>
|
||||
<main>
|
||||
<section class="panel" id="p-send">
|
||||
<h2>Send files</h2>
|
||||
<p class="lead">Videos, music, photos, subtitles, anything. They show up in VLC right away.</p>
|
||||
<div class="card" style="display:grid;gap:16px">
|
||||
<div class="places" data-places></div>
|
||||
<label class="drop" id="drop">
|
||||
<input id="pick" type="file" multiple>
|
||||
<div class="ic"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><path d="M12 15V4M7 9l5-5 5 5M5 20h14"/></svg></div>
|
||||
<b>Choose files</b>
|
||||
<span id="drop-t">or drop them anywhere on this page</span>
|
||||
</label>
|
||||
<div class="rows" id="queue"></div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section id="p-remote" hidden>
|
||||
<div class="card now">
|
||||
<h2 id="title">Nothing playing</h2>
|
||||
<p id="state">Start a video on the console</p>
|
||||
<input id="seek" type="range" min="0" max="1000" value="0" aria-label="Position">
|
||||
<div class="times"><span id="t-now">0:00</span><span id="t-len">0:00</span></div>
|
||||
</div>
|
||||
<div class="pad">
|
||||
<button data-c="prev" aria-label="Previous"><svg viewBox="0 0 24 24"><path d="M6 5h2v14H6zM9.5 12 19 5v14z"/></svg></button>
|
||||
<button data-c="jump" data-v="-10000" aria-label="Back 10 seconds"><svg viewBox="0 0 24 24"><path d="M11 6 3 12l8 6zM20 6l-8 6 8 6z"/></svg></button>
|
||||
<button data-c="toggle" class="main" aria-label="Play or pause"><svg viewBox="0 0 24 24" id="pp"><path d="M8 5v14l11-7z"/></svg></button>
|
||||
<button data-c="jump" data-v="10000" aria-label="Forward 10 seconds"><svg viewBox="0 0 24 24"><path d="m13 6 8 6-8 6zM4 6l8 6-8 6z"/></svg></button>
|
||||
<button data-c="next" aria-label="Next"><svg viewBox="0 0 24 24"><path d="M16 5h2v14h-2zM14.5 12 5 5v14z"/></svg></button>
|
||||
</div>
|
||||
<div class="row">
|
||||
<button data-c="vol" data-v="-10" aria-label="Volume down">−</button>
|
||||
<span id="vol">Volume 100%</span>
|
||||
<button data-c="vol" data-v="10" aria-label="Volume up">+</button>
|
||||
<button data-c="stop" aria-label="Stop">Stop</button>
|
||||
</div>
|
||||
</section>
|
||||
<section class="panel" id="p-files">
|
||||
<h2>On the PS5</h2>
|
||||
<p class="lead">What's in that folder: download a file to this device, or delete it from the PS5.</p>
|
||||
<div class="card">
|
||||
<div class="headrow"><div class="places" data-places></div>
|
||||
<button class="act round" id="refresh" aria-label="Refresh"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><path d="M20 11a8 8 0 1 0-2.3 5.7M20 4v7h-7"/></svg></button></div>
|
||||
<div class="rows" id="files"></div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<footer>Works on the same Wi-Fi as the PS5. Nothing leaves your home network.</footer>
|
||||
<section class="panel" id="p-subs">
|
||||
<h2>Subtitle downloads</h2>
|
||||
<p class="lead">VLC finds subtitles on OpenSubtitles with your own free API key.</p>
|
||||
<div class="card">
|
||||
<div class="status" id="os-status"><div class="ic"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><circle cx="8" cy="15" r="4"/><path d="m11 12 9-9M17 6l3 3M14 9l2 2"/></svg></div>
|
||||
<div><b id="os-title">No key yet</b><span id="os-sub">Paste one below to turn subtitle downloads on.</span></div></div>
|
||||
<form class="form" id="os-form" autocomplete="off">
|
||||
<div class="field"><input id="os-key" placeholder=" " autocapitalize="off" spellcheck="false"><label for="os-key">API key</label></div>
|
||||
<div class="two">
|
||||
<div class="field"><input id="os-user" placeholder=" " autocomplete="username" autocapitalize="off" spellcheck="false"><label for="os-user">User name<em>optional</em></label></div>
|
||||
<div class="field"><input id="os-pass" type="password" placeholder=" " autocomplete="current-password"><label for="os-pass">Password<em>optional</em></label></div>
|
||||
</div>
|
||||
<button class="go" id="os-save" type="submit">Save on the PS5</button>
|
||||
</form>
|
||||
</div>
|
||||
<div class="card" style="display:grid;gap:14px">
|
||||
<ol class="steps">
|
||||
<li><span>Sign in on <a href="https://www.opensubtitles.com/consumers" target="_blank" rel="noopener">opensubtitles.com/consumers</a> and create an API consumer.</span></li>
|
||||
<li><span>Copy its API key and paste it above.</span></li>
|
||||
<li><span>An account is optional: it gives more downloads a day.</span></li>
|
||||
</ol>
|
||||
<p class="help">The key stays on your PS5. This page never shows it again.</p>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
<footer>Works on the same network as the PS5. Nothing leaves your home.</footer>
|
||||
<div class="toasts" id="toasts"></div>
|
||||
|
||||
<script>
|
||||
const $ = s => document.querySelector(s);
|
||||
const fmtSize = b => b > 1e9 ? (b / 1e9).toFixed(2) + " GB" : (b / 1e6).toFixed(1) + " MB";
|
||||
const fmtTime = ms => { const s = Math.max(0, Math.floor(ms / 1000)), h = Math.floor(s / 3600),
|
||||
m = Math.floor(s / 60) % 60, x = String(s % 60).padStart(2, "0");
|
||||
return h ? h + ":" + String(m).padStart(2, "0") + ":" + x : m + ":" + x; };
|
||||
const esc = t => t.replace(/[&<>"]/g, c => ({ "&": "&", "<": "<", ">": ">", '"': """ })[c]);
|
||||
const $ = s => document.querySelector(s), $$ = s => [...document.querySelectorAll(s)];
|
||||
const esc = t => String(t).replace(/[&<>"]/g, c => ({ "&": "&", "<": "<", ">": ">", '"': """ })[c]);
|
||||
const size = b => b >= 1e9 ? (b / 1e9).toFixed(2) + " GB" : b >= 1e6 ? (b / 1e6).toFixed(1) + " MB"
|
||||
: Math.max(1, Math.round(b / 1e3)) + " KB";
|
||||
const ext = n => { const i = n.lastIndexOf("."); return i > 0 ? n.slice(i + 1).toLowerCase() : ""; };
|
||||
const save = (k, v) => { try { localStorage.setItem(k, v); } catch (e) {} };
|
||||
const load = k => { try { return localStorage.getItem(k); } catch (e) { return null; } };
|
||||
|
||||
/* OpenSubtitles: the key and account go to the console, which keeps them. */
|
||||
$("#os-save").onclick = async () => {
|
||||
const body = "key=" + encodeURIComponent($("#os-key").value.trim()) +
|
||||
"&user=" + encodeURIComponent($("#os-user").value.trim()) +
|
||||
"&pass=" + encodeURIComponent($("#os-pass").value);
|
||||
const r = await fetch("/api/opensubtitles", { method: "POST", body,
|
||||
headers: { "Content-Type": "application/x-www-form-urlencoded" } }).catch(() => null);
|
||||
$("#os-msg").textContent = r && r.ok ? "Saved. The PS5 checks it and shows the result."
|
||||
: "Couldn't reach the PS5";
|
||||
$("#os-pass").value = "";
|
||||
/* Icons by kind of file. */
|
||||
const P = 'fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"';
|
||||
const ICON = {
|
||||
video: `<svg viewBox="0 0 24 24" ${P}><rect x="3" y="5" width="18" height="14" rx="3"/><path d="m10 9 5 3-5 3z"/></svg>`,
|
||||
audio: `<svg viewBox="0 0 24 24" ${P}><path d="M9 18V5l11-2v13"/><circle cx="6" cy="18" r="3"/><circle cx="17" cy="16" r="3"/></svg>`,
|
||||
image: `<svg viewBox="0 0 24 24" ${P}><rect x="3" y="4" width="18" height="16" rx="3"/><circle cx="9" cy="10" r="2"/><path d="m21 16-5-5-9 9"/></svg>`,
|
||||
sub: `<svg viewBox="0 0 24 24" ${P}><rect x="3" y="5" width="18" height="14" rx="3"/><path d="M7 13h4M13 13h4M7 16h7"/></svg>`,
|
||||
zip: `<svg viewBox="0 0 24 24" ${P}><path d="M6 3h9l4 4v14H6z"/><path d="M11 3v2M11 7v2M11 11v2M10 15h2v3h-2z"/></svg>`,
|
||||
file: `<svg viewBox="0 0 24 24" ${P}><path d="M6 3h9l4 4v14H6z"/><path d="M14 3v5h5"/></svg>`,
|
||||
folder: `<svg viewBox="0 0 24 24" ${P}><path d="M3 7a2 2 0 0 1 2-2h4l2 2h8a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/></svg>`,
|
||||
drive: `<svg viewBox="0 0 24 24" ${P}><rect x="3" y="7" width="18" height="10" rx="3"/><path d="M17 12h.01M7 12h6"/></svg>`,
|
||||
};
|
||||
const KIND = [["video", "mp4 mkv avi mov ts m2ts mts webm wmv flv mpg mpeg m4v 3gp ogv vob iso"],
|
||||
["audio", "mp3 flac m4a aac ogg opus wav wma alac ape aiff m3u m3u8 pls"],
|
||||
["image", "jpg jpeg png gif bmp webp tga"], ["sub", "srt ass ssa vtt sub idx sup"], ["zip", "zip rar 7z"]];
|
||||
const kind = n => { const x = ext(n); for (const [k, l] of KIND) if (l.split(" ").includes(x)) return k; return "file"; };
|
||||
|
||||
/* Tabs. */
|
||||
function show(tab) {
|
||||
$("#t-send").setAttribute("aria-pressed", tab === "send");
|
||||
$("#t-remote").setAttribute("aria-pressed", tab === "remote");
|
||||
$("#p-send").hidden = tab !== "send";
|
||||
$("#p-remote").hidden = tab !== "remote";
|
||||
try { localStorage.setItem("vlcps5-tab", tab); } catch (e) {}
|
||||
/* Toasts. */
|
||||
function toast(text, cls = "") {
|
||||
const t = document.createElement("div");
|
||||
t.className = "toast " + cls;
|
||||
t.innerHTML = `<i></i><span>${esc(text)}</span>`;
|
||||
$("#toasts").append(t);
|
||||
while ($("#toasts").children.length > 3) $("#toasts").firstChild.remove();
|
||||
setTimeout(() => { t.classList.add("bye"); setTimeout(() => t.remove(), 350); }, 3200);
|
||||
}
|
||||
$("#t-send").onclick = () => show("send");
|
||||
$("#t-remote").onclick = () => show("remote");
|
||||
try { if (localStorage.getItem("vlcps5-tab") === "remote") show("remote"); } catch (e) {}
|
||||
|
||||
/* Places and the files in the chosen one. */
|
||||
/* Connection. */
|
||||
let wasOnline = true;
|
||||
function online(ok) {
|
||||
$("#link").classList.toggle("off", !ok);
|
||||
$("#link-t").textContent = ok ? "Connected" : "Can't reach the PS5";
|
||||
if (ok && !wasOnline) toast("Connected to the PS5 again", "ok");
|
||||
wasOnline = ok;
|
||||
}
|
||||
async function api(url, opts) {
|
||||
try { const r = await fetch(url, opts); online(true); return r; }
|
||||
catch (e) { online(false); return null; }
|
||||
}
|
||||
|
||||
/* Tabs: the highlight glides to the tab, the panel slides in from that side. */
|
||||
const TABS = ["send", "files", "subs"];
|
||||
let tab = null;
|
||||
function moveHl() {
|
||||
const b = $(`.tabs [data-tab="${tab}"]`), hl = $("#hl");
|
||||
if (!b) return;
|
||||
hl.style.left = b.offsetLeft + "px";
|
||||
hl.style.width = b.offsetWidth + "px";
|
||||
}
|
||||
function show(name, first) {
|
||||
if (name === tab) return;
|
||||
const from = TABS.indexOf(tab), to = TABS.indexOf(name);
|
||||
tab = name;
|
||||
save("vlcps5-tab", name);
|
||||
$$(".tabs button").forEach(b => b.setAttribute("aria-selected", b.dataset.tab === name));
|
||||
$$(".panel").forEach(p => p.classList.remove("on"));
|
||||
const p = $("#p-" + name);
|
||||
p.style.setProperty("--in", first ? "rise" : to < from ? "in-l" : "in-r");
|
||||
void p.offsetWidth;
|
||||
p.classList.add("on");
|
||||
/* the first time the highlight just sits there; after, it glides */
|
||||
const hl = $("#hl");
|
||||
if (first) hl.style.transition = "none";
|
||||
moveHl();
|
||||
if (first) requestAnimationFrame(() => requestAnimationFrame(() => hl.style.transition = ""));
|
||||
if (name === "files") loadFiles();
|
||||
}
|
||||
$$(".tabs button").forEach(b => b.onclick = () => show(b.dataset.tab));
|
||||
addEventListener("resize", moveHl);
|
||||
/* swipe across the page (a phone) to change tab */
|
||||
let sx = null, sy = 0;
|
||||
addEventListener("touchstart", e => { if (e.target.closest("input")) return; sx = e.touches[0].clientX; sy = e.touches[0].clientY; }, { passive: true });
|
||||
addEventListener("touchend", e => {
|
||||
if (sx === null) return;
|
||||
const dx = e.changedTouches[0].clientX - sx, dy = e.changedTouches[0].clientY - sy;
|
||||
sx = null;
|
||||
if (Math.abs(dx) > 70 && Math.abs(dx) > Math.abs(dy) * 1.6) {
|
||||
const i = TABS.indexOf(tab) + (dx < 0 ? 1 : -1);
|
||||
if (i >= 0 && i < TABS.length) show(TABS[i]);
|
||||
}
|
||||
});
|
||||
|
||||
/* Where files go: the same choice on both tabs. */
|
||||
let places = [], place = +load("vlcps5-place") || 0;
|
||||
function drawPlaces() {
|
||||
$$("[data-places]").forEach(box => {
|
||||
box.innerHTML = places.map((p, i) => `<button type="button" data-i="${i}" aria-pressed="${i === place}">` +
|
||||
`${/usb|ext|drive/i.test(p) ? ICON.drive : ICON.folder}<span>${esc(p)}</span></button>`).join("");
|
||||
});
|
||||
}
|
||||
async function loadPlaces() {
|
||||
const places = await (await fetch("/api/places")).json();
|
||||
$("#place").innerHTML = places.map((p, i) => `<option value="${i}">${esc(p)}</option>`).join("");
|
||||
const r = await api("/api/places");
|
||||
if (!r) return setTimeout(loadPlaces, 3000);
|
||||
places = await r.json();
|
||||
if (place >= places.length) place = 0;
|
||||
drawPlaces();
|
||||
loadFiles();
|
||||
}
|
||||
async function loadFiles() {
|
||||
const list = await (await fetch("/api/files?dir=" + $("#place").value)).json();
|
||||
$("#files").innerHTML = list.length ? list.map(f =>
|
||||
`<div class="item"><div class="name">${esc(f.name)}</div><div class="meta">${fmtSize(f.size)}</div>
|
||||
<button class="del" data-name="${esc(f.name)}">Delete</button></div>`).join("")
|
||||
: `<div class="empty">No files here yet</div>`;
|
||||
document.addEventListener("click", e => {
|
||||
const b = e.target.closest("[data-places] button");
|
||||
if (!b) return;
|
||||
place = +b.dataset.i;
|
||||
save("vlcps5-place", place);
|
||||
drawPlaces();
|
||||
loadFiles(true);
|
||||
});
|
||||
|
||||
/* Files in that place. Only rows that weren't there before animate. */
|
||||
let shown = null;
|
||||
async function loadFiles(fresh) {
|
||||
const r = await api("/api/files?dir=" + place);
|
||||
if (!r) return;
|
||||
const list = await r.json();
|
||||
if (fresh) shown = null;
|
||||
$("#n-files").textContent = list.length || "";
|
||||
$("#files").innerHTML = list.length ? list.map(f => {
|
||||
const k = kind(f.name), isNew = !shown || !shown.has(f.name);
|
||||
return `<div class="row${isNew ? " new" : ""}"><div class="ic">${ICON[k]}</div>
|
||||
<div style="min-width:0"><div class="name" title="${esc(f.name)}">${esc(f.name)}</div>
|
||||
<div class="meta">${ext(f.name) ? `<span class="tag">${esc(ext(f.name).slice(0, 4))}</span>` : ""}${size(f.size)}</div></div>
|
||||
<div class="acts"><a class="act dl" href="/api/download?dir=${place}&name=${encodeURIComponent(f.name)}" download="${esc(f.name)}" data-name="${esc(f.name)}" title="Download"><svg viewBox="0 0 24 24" ${P}><path d="M12 4v11M7 10l5 5 5-5M5 20h14"/></svg><span>Download</span></a>
|
||||
<button class="act del" data-name="${esc(f.name)}">Delete</button></div></div>`;
|
||||
}).join("") : `<div class="empty">${ICON.folder}<span>No files here yet</span></div>`;
|
||||
shown = new Set(list.map(f => f.name));
|
||||
}
|
||||
$("#place").onchange = loadFiles;
|
||||
$("#refresh").onclick = () => {
|
||||
const b = $("#refresh");
|
||||
b.classList.remove("spin"); void b.offsetWidth; b.classList.add("spin");
|
||||
loadFiles(true);
|
||||
};
|
||||
/* Delete: a first tap turns it red, a second one deletes. */
|
||||
$("#files").onclick = async e => {
|
||||
const d = e.target.closest(".dl");
|
||||
if (d) { toast("Downloading " + d.dataset.name); return; } /* the browser saves it */
|
||||
const b = e.target.closest(".del");
|
||||
if (!b || !confirm("Delete " + b.dataset.name + " from the PS5?")) return;
|
||||
await fetch("/api/file?dir=" + $("#place").value + "&name=" + encodeURIComponent(b.dataset.name), { method: "DELETE" });
|
||||
loadFiles();
|
||||
if (!b) return;
|
||||
if (!b.classList.contains("sure")) {
|
||||
b.classList.add("sure"); b.textContent = "Delete?";
|
||||
setTimeout(() => { b.classList.remove("sure"); b.textContent = "Delete"; }, 2500);
|
||||
return;
|
||||
}
|
||||
const row = b.closest(".row");
|
||||
const r = await api("/api/file?dir=" + place + "&name=" + encodeURIComponent(b.dataset.name), { method: "DELETE" });
|
||||
if (r && r.ok) {
|
||||
row.classList.add("gone");
|
||||
toast("Deleted " + b.dataset.name);
|
||||
setTimeout(loadFiles, 350);
|
||||
} else {
|
||||
toast("Couldn't delete it", "bad");
|
||||
}
|
||||
};
|
||||
|
||||
/* Uploads, one after another, each with its bar. */
|
||||
/* Uploads, one after another; the Send tab shows how far the queue is. */
|
||||
const queue = [];
|
||||
let busy = false;
|
||||
let current = null;
|
||||
function badge() {
|
||||
const left = queue.length + (current ? 1 : 0);
|
||||
$("#n-send").textContent = !left ? "" : current && current.pct != null && !queue.length ? current.pct + "%" : left;
|
||||
}
|
||||
function addFiles(files) {
|
||||
if (!files.length) return;
|
||||
for (const f of files) {
|
||||
const el = document.createElement("div");
|
||||
el.className = "item";
|
||||
el.innerHTML = `<div class="name">${esc(f.name)}</div><div class="meta">Waiting · ${fmtSize(f.size)}</div><div class="bar"><i></i></div>`;
|
||||
$("#queue").prepend(el);
|
||||
queue.push({ f, el, dir: $("#place").value });
|
||||
el.className = "row new";
|
||||
el.innerHTML = `<div class="ic">${ICON[kind(f.name)]}</div>
|
||||
<div style="min-width:0"><div class="name">${esc(f.name)}</div><div class="meta">Waiting · ${size(f.size)}</div><div class="bar"><i></i></div></div>
|
||||
<button class="act round stop" aria-label="Cancel"><svg viewBox="0 0 24 24" ${P}><path d="M6 6l12 12M18 6 6 18"/></svg></button>`;
|
||||
const job = { f, el, dir: place };
|
||||
el.querySelector(".stop").onclick = () => {
|
||||
if (current === job) { job.cancelled = true; job.xhr.abort(); }
|
||||
else { queue.splice(queue.indexOf(job), 1); el.classList.add("gone"); setTimeout(() => el.remove(), 350); badge(); }
|
||||
};
|
||||
$("#queue").append(el);
|
||||
queue.push(job);
|
||||
}
|
||||
toast(files.length === 1 ? "Sending " + files[0].name : "Sending " + files.length + " files");
|
||||
if (tab !== "send") show("send");
|
||||
next();
|
||||
}
|
||||
function next() {
|
||||
if (busy || !queue.length) return;
|
||||
busy = true;
|
||||
const { f, el, dir } = queue.shift();
|
||||
const xhr = new XMLHttpRequest(), t0 = Date.now();
|
||||
xhr.open("PUT", "/api/upload?dir=" + dir + "&name=" + encodeURIComponent(f.name));
|
||||
badge();
|
||||
if (current || !queue.length) return;
|
||||
const job = current = queue.shift();
|
||||
const { f, el } = job, meta = el.querySelector(".meta"), bar = el.querySelector(".bar i");
|
||||
const xhr = job.xhr = new XMLHttpRequest(), t0 = Date.now();
|
||||
xhr.open("PUT", "/api/upload?dir=" + job.dir + "&name=" + encodeURIComponent(f.name));
|
||||
xhr.upload.onprogress = e => {
|
||||
const p = e.loaded / f.size, mbs = e.loaded / 1e6 / Math.max(0.5, (Date.now() - t0) / 1000);
|
||||
el.querySelector(".bar i").style.width = (p * 100).toFixed(1) + "%";
|
||||
el.querySelector(".meta").textContent = `${Math.round(p * 100)}% · ${fmtSize(e.loaded)} of ${fmtSize(f.size)} · ${mbs.toFixed(1)} MB/s`;
|
||||
const p = f.size ? e.loaded / f.size : 1, mbs = e.loaded / 1e6 / Math.max(.5, (Date.now() - t0) / 1000);
|
||||
job.pct = Math.round(p * 100);
|
||||
bar.style.width = (p * 100).toFixed(1) + "%";
|
||||
meta.textContent = `${job.pct}% · ${size(e.loaded)} of ${size(f.size)} · ${mbs.toFixed(1)} MB/s`;
|
||||
badge();
|
||||
};
|
||||
xhr.onloadend = () => {
|
||||
const ok = xhr.status === 200;
|
||||
el.classList.add(ok ? "done" : "fail");
|
||||
el.querySelector(".bar i").style.width = "100%";
|
||||
el.querySelector(".meta").textContent = ok ? "On the PS5 · " + fmtSize(f.size) : "Failed: " + (xhr.responseText || "connection lost");
|
||||
busy = false;
|
||||
loadFiles();
|
||||
bar.style.width = "100%";
|
||||
meta.textContent = ok ? "On the PS5 · " + size(f.size) : job.cancelled ? "Cancelled" : "Failed: " + (xhr.responseText || "connection lost");
|
||||
el.querySelector(".stop").remove();
|
||||
if (ok) {
|
||||
toast(f.name + " is on the PS5", "ok");
|
||||
setTimeout(() => { el.classList.add("gone"); setTimeout(() => el.remove(), 350); }, 4000);
|
||||
} else if (!job.cancelled) {
|
||||
toast("Couldn't send " + f.name, "bad");
|
||||
}
|
||||
current = null;
|
||||
if (job.dir === place) loadFiles();
|
||||
next();
|
||||
};
|
||||
xhr.send(f);
|
||||
}
|
||||
$("#pick").onchange = e => { addFiles(e.target.files); e.target.value = ""; };
|
||||
$("#pick").onchange = e => { addFiles([...e.target.files]); e.target.value = ""; };
|
||||
/* Drop anywhere: the zone lights up and its border marches. */
|
||||
const drop = $("#drop");
|
||||
drop.ondragover = e => { e.preventDefault(); drop.classList.add("over"); };
|
||||
drop.ondragleave = () => drop.classList.remove("over");
|
||||
drop.ondrop = e => { e.preventDefault(); drop.classList.remove("over"); addFiles(e.dataTransfer.files); };
|
||||
let depth = 0;
|
||||
const dropText = on => { drop.classList.toggle("over", on); $("#drop-t").textContent = on ? "Let go to send" : "or drop them anywhere on this page"; };
|
||||
addEventListener("dragenter", e => { e.preventDefault(); if (depth++ === 0) { if (tab !== "send") show("send"); dropText(true); } });
|
||||
addEventListener("dragleave", () => { if (--depth <= 0) { depth = 0; dropText(false); } });
|
||||
addEventListener("dragover", e => e.preventDefault());
|
||||
addEventListener("drop", e => { e.preventDefault(); depth = 0; dropText(false); addFiles([...e.dataTransfer.files]); });
|
||||
addEventListener("beforeunload", e => { if (current) { e.preventDefault(); e.returnValue = ""; } });
|
||||
|
||||
/* Remote. */
|
||||
let seeking = false;
|
||||
async function poll() {
|
||||
try {
|
||||
const s = await (await fetch("/api/status")).json();
|
||||
$("#title").textContent = s.playing ? s.title : "Nothing playing";
|
||||
$("#state").textContent = s.playing ? (s.paused ? "Paused" : "Playing") : "Start a video on the console";
|
||||
if (!seeking) $("#seek").value = s.length ? Math.round(s.time / s.length * 1000) : 0;
|
||||
$("#seek").dataset.len = s.length;
|
||||
$("#t-now").textContent = fmtTime(s.time);
|
||||
$("#t-len").textContent = fmtTime(s.length);
|
||||
$("#vol").textContent = "Volume " + s.volume + "%";
|
||||
$("#pp").innerHTML = s.playing && !s.paused ? '<path d="M7 5h4v14H7zm6 0h4v14h-4z"/>' : '<path d="M8 5v14l11-7z"/>';
|
||||
} catch (e) {
|
||||
$("#state").textContent = "Can't reach the PS5: is VLC still open?";
|
||||
/* OpenSubtitles: the PS5 keeps the key and checks it; the card shows how that went. */
|
||||
let waiting = false;
|
||||
async function osubStatus() {
|
||||
const r = await api("/api/opensubtitles");
|
||||
if (!r) return;
|
||||
const s = await r.json();
|
||||
const st = $("#os-status");
|
||||
st.classList.toggle("ok", s.key && !s.failed && !s.checking);
|
||||
st.classList.toggle("bad", s.key && s.failed && !s.checking);
|
||||
$("#os-title").textContent = !s.key ? "No key yet" : s.checking ? "Checking the key…" : s.failed ? "The key didn't work" : "Subtitle downloads are on";
|
||||
$("#os-sub").textContent = !s.key ? "Paste one below to turn subtitle downloads on."
|
||||
: s.checking ? "The PS5 is asking OpenSubtitles." : s.message ? s.message + (s.user ? " · " + s.user : "")
|
||||
: s.user ? "Signed in as " + s.user : "Using your API key";
|
||||
if (waiting && !s.checking && s.message) {
|
||||
waiting = false;
|
||||
$("#os-save").classList.remove("busy");
|
||||
toast(s.message, s.failed ? "bad" : "ok");
|
||||
}
|
||||
}
|
||||
document.querySelectorAll("[data-c]").forEach(b => b.onclick = () =>
|
||||
fetch("/api/cmd?c=" + b.dataset.c + "&v=" + (b.dataset.v || 0), { method: "POST" }).then(poll));
|
||||
$("#seek").oninput = () => { seeking = true; };
|
||||
$("#seek").onchange = () => {
|
||||
const ms = Math.round($("#seek").value / 1000 * (+$("#seek").dataset.len || 0));
|
||||
fetch("/api/cmd?c=seek&v=" + ms, { method: "POST" }).then(() => { seeking = false; poll(); });
|
||||
$("#os-form").onsubmit = async e => {
|
||||
e.preventDefault();
|
||||
const key = $("#os-key").value.trim();
|
||||
if (!key) { toast("Paste your API key first", "bad"); $("#os-key").focus(); return; }
|
||||
const btn = $("#os-save");
|
||||
btn.disabled = true; btn.classList.add("busy");
|
||||
const body = "key=" + encodeURIComponent(key) + "&user=" + encodeURIComponent($("#os-user").value.trim()) +
|
||||
"&pass=" + encodeURIComponent($("#os-pass").value);
|
||||
const r = await api("/api/opensubtitles", { method: "POST", body,
|
||||
headers: { "Content-Type": "application/x-www-form-urlencoded" } });
|
||||
btn.disabled = false;
|
||||
$("#os-pass").value = "";
|
||||
if (r && r.ok) {
|
||||
$("#os-key").value = "";
|
||||
waiting = true;
|
||||
toast("Sent to the PS5, checking…");
|
||||
setTimeout(osubStatus, 600);
|
||||
setTimeout(() => { if (waiting) { waiting = false; btn.classList.remove("busy"); } }, 20000);
|
||||
} else {
|
||||
btn.classList.remove("busy");
|
||||
toast("Couldn't reach the PS5", "bad");
|
||||
}
|
||||
};
|
||||
setInterval(() => { if (!$("#p-remote").hidden) poll(); }, 1000);
|
||||
|
||||
/* first tab: the address's #send / #files / #subs, else the last one used */
|
||||
const want = location.hash.slice(1) || load("vlcps5-tab");
|
||||
show(TABS.includes(want) ? want : "send", true);
|
||||
addEventListener("load", moveHl);
|
||||
if (document.fonts) document.fonts.ready.then(moveHl);
|
||||
loadPlaces();
|
||||
poll();
|
||||
osubStatus();
|
||||
setInterval(osubStatus, 2500);
|
||||
setInterval(() => { if (!current && !document.hidden && tab === "files") loadFiles(); }, 15000);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Reference in new issue
Block a user