Files
SergObsidian/PERSONAL PROJECTS/PS1 MDEC.md
2025-04-18 22:00:49 +05:00

146 lines
5.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

Рендеринг потокового видео (FMV, Full Motion Video) на PlayStation 1 — это сложный процесс, сочетающий чтение данных с CD-ROM, декодирование через MDEC (Motion DECoder) и вывод на экран через GPU. Вот пошаговое объяснение:
---
### **1. Подготовка данных на диске**
- Видео хранится в специальном формате **STR** (Sony's Video Format), который содержит:
- **Видеопоток** — сжатый через MPEG-1 (но упрощённый для PS1).
- **Аудиопоток** — ADPCM или CD-DA (Red Book Audio).
- **Субтитры/тайминг** — дополнительные данные.
Данные разбиты на **секторы CD-ROM (Mode 2 XA)**, где чередуются видео и аудио.
---
### **2. Загрузка данных с CD-ROM**
1. **CPU отправляет команду чтения**:
```c
CdReadSector(/*Сектор начала*/, /*Кол-во секторов*/, /*Буфер в RAM*/);
```
2. **DMA (канал 3) копирует данные** из буфера CD-ROM в RAM:
- Используется **двойная буферизация**:
- Пока DMA заполняет **Буфер 1**, CPU/MDEC обрабатывает **Буфер 2**.
- Размер буфера обычно **1632 КБ** (816 секторов).
3. **Ожидание завершения**:
```c
CdReadSync(0); // Блокирующее ожидание
```
---
### **3. Декодирование видео через MDEC**
1. **CPU настраивает MDEC** (канал DMA 0/1):
- Указывает адрес сжатых данных в RAM.
- Запускает декодирование:
```asm
li t0, 0x1F801820 // MDEC_CMD
li t1, 0x60000000 // Команда "Decode Macroblock"
sw t1, 0(t0)
```
2. **MDEC декодирует MPEG-1**:
- Кадр разбит на **макроблоки 16x16**.
- Используется **DCT (Discrete Cosine Transform)** + **RLE (Run-Length Encoding)**.
- На выходе — **RGB16 (15-битный)** или **YUV** пиксели.
3. **DMA (канал 1) копирует результат** в RAM:
- Готовые кадры сохраняются в **отдельный буфер** (например, 320x240, 16-бит).
---
### **4. Вывод на экран через GPU**
1. **CPU отправляет кадр в VRAM**:
- Через DMA (канал 2) или вручную (порт `GP0`).
- Пример:
```asm
li a0, 0x1F8010A0 // DMA GPU (канал 2)
la a1, frame_buffer
sw a1, 0(a0) // Источник
li a1, 0x01000200 // Размер + режим
sw a1, 4(a0)
```
2. **GPU выводит кадр**:
- Используется **полноэкранный спрайт** (Rectangular Texture).
- Команда:
```asm
li t0, 0x1F801810 // GP0
li t1, 0xA0000000 // Команда "Draw Rectangle"
sw t1, 0(t0)
```
3. **Синхронизация с VBlank**:
- Чтобы избежать артефактов, обновление кадра происходит **во время VBlank**:
```c
VSync(0);
```
---
### **5. Аудиосопровождение**
- **ADPCM-аудио** декодируется через SPU (канал DMA 4):
```c
SpuSetTransferMode(SPU_TRANSFER_BY_DMA);
SpuWrite(audio_buffer, audio_size);
```
- **CD-DA (Red Book)** воспроизводится напрямую с диска (аппаратно).
---
### **6. Оптимизации**
1. **Чередование данных (Interleaving)**:
- Видео и аудио секторы чередуются на диске для плавности.
- Пример структуры:
```
[VIDEO] [AUDIO] [VIDEO] [AUDIO]...
```
2. **Предзагрузка**:
- Игры заранее грузят несколько кадров в память.
3. **Пропуск кадров**:
- Если декодирование не успевает, PS1 пропускает кадры (например, в Resident Evil).
---
### **7. Пример кода (упрощённый цикл FMV)**
```c
void play_fmv() {
uint8_t video_buffer[32768];
uint16_t frame_buffer[320*240];
while (!fmv_finished) {
// 1. Чтение с CD-ROM
CdReadSector(current_sector, 16, video_buffer);
CdReadSync(0);
// 2. Декодирование через MDEC
MDEC_DecodeFrame(video_buffer, frame_buffer);
// 3. Вывод через GPU
GPU_SendFrame(frame_buffer);
// 4. Синхронизация
VSync(0);
current_sector += 16;
}
}
```
---
### **8. Проблемы и ограничения**
- **Низкое разрешение**: 320x240 (чаще 256x224 для экономии памяти).
- **Цветовые артефакты**: Из-за 15-битного RGB.
- **Задержки**: Если CD-ROM не успевает, видео тормозит.
---
### **Итог**
1. **Чтение** с CD-ROM через DMA.
2. **Декодирование** через MDEC.
3. **Вывод** через GPU.
4. **Синхронизация** с VBlank.
Именно так работали FMV в играх вроде *Metal Gear Solid* и *Final Fantasy VII*! 🎥