[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"project-81934":3},{"id":4,"name":5,"fullName":6,"owner":7,"repo":5,"description":8,"homepage":9,"htmlUrl":9,"language":10,"languages":9,"totalLinesOfCode":9,"stars":11,"forks":12,"watchers":13,"openIssues":12,"contributorsCount":14,"subscribersCount":14,"size":14,"stars1d":15,"stars7d":13,"stars30d":16,"stars90d":14,"forks30d":14,"starsTrendScore":12,"compositeScore":17,"rankGlobal":9,"rankLanguage":9,"license":9,"archived":18,"fork":18,"defaultBranch":19,"hasWiki":20,"hasPages":18,"topics":21,"createdAt":9,"pushedAt":9,"updatedAt":22,"readmeContent":23,"aiSummary":24,"trendingCount":14,"starSnapshotCount":14,"syncStatus":13,"lastSyncTime":25,"discoverSource":26},81934,"JellyFin-PS3","Tuggs-Bunny\u002FJellyFin-PS3","Tuggs-Bunny","A homebrew Jellyfin client for the PlayStation 3",null,"C",28,3,2,0,1,4,42.21,false,"main",true,[],"2026-06-12 04:01:36","\u003Cdiv align=\"center\">\n  \u003Cimg src=\"ICON0.PNG\" alt=\"JellyFin PS3 banner\">\n\u003C\u002Fdiv>\n# JellyFin PS3\n\nA native PS3 homebrew Jellyfin client written in C using PSL1GHT, targeting Evilnat CFW or HEN.\n\nGoal: consumer-quality media playback on PS3 — the second-best media player on the platform, modelled architecturally on Movian.\n\n---\n\n## Features\n\n- XMB-style UI with animated wave background\n- Browse Movies, TV Shows, and Collections libraries\n- TV show browser — Series → Seasons → Episodes\n- Collections browser — Collection → Movies\n- Live search across your Jellyfin library (fires on every keystroke)\n- Custom on-screen keyboard for login and search\n- Open Sans + Material Icons font rendering via stb_truetype\n- Hardware H.264 decode via PS3 VDEC (SPU-accelerated)\n- Movian-style temporal frame blending — smooth 60fps display loop with crossfade between decoded 24fps frames\n- Bresenham 2:3 pulldown, locked to hardware vsync via `gcmSetVBlankHandler`\n- AV sync locked to within ±5ms using audio PTS clock + EMA smoothing\n- MP3 audio decode via minimp3 with PCM ring buffer\n- Interleaved stereo DMA audio output at 48kHz\n- Double-buffered RSX GPU blit via custom vertex\u002Ffragment shaders\n- Jellyfin PlaybackInfo POST with PS3 H.264 transcode profile (720p)\n- `.pkg` packaging via PSL1GHT built-in `ppu_rules` flow (APPID: `JFPS30000`)\n- Crash log written to `\u002Fdev_hdd0\u002Fgame\u002FJFPS30000\u002FUSRDIR\u002Fcrash_log.txt`\n- Async ring-buffer logging system\n\n---\n\n## Requirements\n\n- PS3 with Evilnat CFW or HEN (CEX)\n- PSL1GHT toolchain (`ppu-gcc` at `\u002Fusr\u002Flocal\u002Fps3dev\u002Fppu\u002Fbin\u002F`)\n- Jellyfin server reachable from your PS3 (local network recommended; port-forwarded remote also works)\n- `sfo.xml` at `~\u002Fps3dev\u002Fps3py\u002Fsfo.xml` (used by `ppu_rules` for `.pkg` target)\n\n---\n\n## Building\n\n```bash\n# Build SELF only\nmake clean && make\n\n# Build installable PKG\nmake pkg\n```\n\nOutput: `JellyFin---PS3.self` and `JellyFin---PS3.pkg`\n\nTransfer the SELF to your PS3 via FTP or USB and launch through webMAN or multiMAN, or install the PKG directly.\n\n---\n\n## Controls\n\n### Menus\n\n| Button      | Action                          |\n|-------------|---------------------------------|\n| X           | Select \u002F confirm                |\n| O           | Back                            |\n| D-pad       | Navigate                        |\n| L1 \u002F R1     | Cycle tabs                      |\n| Triangle    | Item info overlay               |\n| L1 \u002F R1     | Prev\u002Fnext page (season browser) |\n\n### Media Player\n\n| Button | Action     |\n|--------|------------|\n| Start  | Stop \u002F exit player |\n\n### Search\n\n| Button   | Action                              |\n|----------|-------------------------------------|\n| D-pad    | Move cursor on keyboard \u002F in results|\n| X        | Type character \u002F play result        |\n| Triangle | Toggle caps lock                    |\n| O \u002F CLEAR| Reset search, return to keyboard    |\n| Down     | Jump from keyboard to results       |\n| Up       | Jump from first result back to keyboard |\n\n---\n\n## Video Pipeline\n\n```\nHTTP stream (MPEG-TS)\n        │\n        ▼\n  Decode thread\n  stream_read() → 188-byte TS packets\n        │\n        ▼\n  video_feed_ts()\n  TS demuxer → PAT\u002FPMT → PES reassembly\n        │\n        ├─ Audio PES → adec_push_pes() → minimp3 → PCM ring buffer\n        │\n        └─ Video PES → vdecDecodeAu() → VDEC (SPU H.264)\n                │\n                ▼\n         VDEC callback\n         vdec_pull_frame() → YUV → ARGB\n                │\n                ▼\n         Jitter buffer (16 slots, ~28 MB at 720p)\n         PTS + per-frame duration stored per slot\n                │\n                ▼\n         Upload thread (priority 850)\n         memcpy → RSX-local texture (double-buffered)\n         Also uploads frame B for blend\n                │\n                ▼\n         Display loop (Movian-style, 60fps)\n         timing_flip_due() ← Bresenham accumulator\n         gcmSetVBlankHandler ← hardware vsync at 59.94 Hz\n                │\n                ▼\n         RSX GPU blit\n         Crossfade shader blends frame A → B mid-pulldown\n         rsxSync() → flip()\n```\n\n**FPS detection:** VDEC `frame_rate_code` maps to exact fractional fps (ISO 13818-2). Display refresh rate queried via `videoGetState` — 59.94 Hz detected and used for Bresenham accumulator.\n\n**Temporal blending:** Each decoded frame carries a remaining duration (us). The display loop consumes vblank periods from that budget. When a frame's remaining duration falls below one vblank period and the next frame is available, the shader crossfades A→B based on the fractional time remaining — eliminating judder on 24fps content without a fixed pulldown pattern.\n\n**AV sync:** `avsync_compute_diff()` computes video PTS minus audio PTS. An EMA smooths it over time; `avsync_biased_period()` nudges each vblank period ±5000 µs to correct drift. Locked = |EMA| \u003C 41 667 µs (~1 frame at 24fps).\n\n---\n\n## Audio Pipeline\n\n```\nAudio PES packets (MP3, type 0x03)\n        │\n        ▼\n  adec_push_pes()\n  PES header stripped (9 + buf[8] bytes)\n        │\n        ▼\n  minimp3 decode loop\n  mp3dec_decode_frame() → 1152 samples\u002Fframe\n  short PCM → float32, interleaved L\u002FR\n        │\n        ▼\n  PCM ring buffer (8192 sample-pairs, ~170ms at 48kHz)\n        │\n        ▼\n  Audio thread (priority 750)\n  sysEventQueueReceive() → DMA event\n  Blocks up to 100ms waiting for 256 samples\n        │\n        ▼\n  PS3 audio DMA (8 blocks × 256 samples, 48kHz)\n  Interleaved layout: L0 R0 L1 R1 … (per SDK spec)\n```\n\n**AV clock:** `audio_get_clock_us()` returns PTS-based time once the first PES with a valid PTS is decoded; falls back to DMA block counter at startup.\n\n---\n\n## Threading Model\n\n| Thread         | Priority | Role                                         |\n|----------------|----------|----------------------------------------------|\n| Display (main) | default  | Bresenham gate, RSX blit, flip, input poll   |\n| Decode         | 800      | TS demux, VDEC submit, jitter buffer fill     |\n| Upload         | 850      | memcpy jitter buffer → RSX texture (A + B)   |\n| Audio          | 750      | DMA event loop, PCM ring drain               |\n| Async log      | default  | Ring-buffer drain to player_log.txt          |\n\n---\n\n## File Structure\n\n```\nJellyFin---PS3\u002F\n├── Makefile\n├── ICON0.PNG\n└── source\u002F\n    ├── main.cpp              # Entry point, crash_log\n    ├── player.cpp\u002Fh          # Playback orchestrator — thread management, display loop\n    ├── video.cpp\u002Fh           # VDEC init, H.264 decode, jitter buffer, fps detection\n    ├── audio.cpp\u002Fh           # Audio port, DMA ring buffer, audio thread, PTS clock\n    ├── adec.cpp\u002Fh            # MP3 decode via minimp3, PCM ring buffer\n    ├── stream.cpp\u002Fh          # HTTP MPEG-TS reader (chunked transfer, TS ring buffer)\n    ├── http.cpp\u002Fh            # HTTP client\n    ├── jellyfin_api.cpp\u002Fh    # Jellyfin REST API (auth, libraries, items, PlaybackInfo)\n    ├── ui.cpp\u002Fh              # Main menu, browse\u002Fsearch loop, OSK, tab detection\n    ├── ui_visuals.cpp\u002Fh      # XMB draw calls — tabs, item lists, keyboard, search results\n    ├── ui_wave.cpp\u002Fh         # Animated wave background (RSX)\n    ├── bitmap.cpp\u002Fh          # Image loading\n    ├── timing.cpp\u002Fh          # Frame pacing, Bresenham accumulator, AV sync EMA\n    ├── rsxutil.cpp\u002Fh         # RSX helpers, shader blit\n    ├── video_shaders.h       # Vertex\u002Ffragment shader ucode (YUV→ARGB + crossfade blend)\n    ├── wave_shaders.h        # Wave background shader ucode\n    ├── plog.h                # Async logging\n    ├── minimp3.h             # Embedded MP3 decoder\n    ├── stb_truetype.h        # TTF rasterizer\n    ├── opensans_regular.h    # Open Sans Regular (embedded)\n    ├── opensans_bold.h       # Open Sans Bold (embedded)\n    ├── material_icons.h      # Material Icons (embedded)\n    └── font8x8.xpm           # Fallback bitmap font\n```\n\n---\n\n## Status\n\n| Feature                  | Status                                                            |\n|--------------------------|-------------------------------------------------------------------|\n| Login \u002F Auth             | ✅ Working                                                        |\n| Movie browsing           | ✅ Working                                                        |\n| TV show browsing         | ✅ Working (Series → Seasons → Episodes)                          |\n| Collections browsing     | ✅ Working                                                        |\n| Search                   | ✅ Working (live, keystroke-driven)                               |\n| Item info overlay        | ✅ Working (overview, rating, genres, studios, video\u002Faudio info)  |\n| Video playback           | ✅ Working (720p H.264, Movian-style 60fps display loop)          |\n| Temporal frame blending  | ✅ Working (crossfade shader, eliminates 2:3 judder)              |\n| Audio playback           | ✅ Working (48kHz stereo MP3, zero silence blocks)                |\n| AV sync                  | ✅ Locked (±5ms via PTS clock + EMA bias)                         |\n| PlaybackInfo \u002F transcode | ✅ Working (H.264 720p profile, PlaySessionId extracted)          |\n| PKG packaging            | ✅ Working (`make pkg`, APPID `JFPS30000`)                        |\n| Music library            | ⚠️ not implemented                                                |\n\n---\n\n## Logging\n\nDuring playback, async log output is written to `player_log.txt` in the app's working directory. The crash log at `\u002Fdev_hdd0\u002Fgame\u002FJFPS30000\u002FUSRDIR\u002Fcrash_log.txt` is written synchronously at key lifecycle checkpoints and survives crashes that prevent the async logger from flushing.\n\n---\n\n## License\n\nMIT\n","JellyFin-PS3 是一个为 PlayStation 3 设计的自制 Jellyfin 客户端。该项目使用 C 语言和 PSL1GHT 开发，旨在为运行 Evilnat 自定义固件或 HEN 的 PS3 提供接近消费级质量的媒体播放体验。其核心功能包括XMB风格界面、支持电影、电视剧及收藏夹浏览、实时搜索以及硬件加速H.264解码等，同时通过时间帧混合技术实现流畅的60fps视频回放。此外，它还具备精确到±5毫秒内的音视频同步能力。此项目非常适合那些希望在PS3上享受高质量家庭媒体库内容但又不满足于现有选项的用户。","2026-06-11 04:07:14","CREATED_QUERY"]