Files
SergObsidian/PERSONAL PROJECTS/PS1 DOCS/PS1 MDEC.md
2025-04-19 00:51:05 +05:00

222 lines
9.9 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.
-----------------
# Функция `DecDCTvlc2` в библиотеке PsyQ для PlayStation 1
Функция `DecDCTvlc2` является частью аппаратно-оптимизированной библиотеки декодирования видеоданных в реальном времени для PlayStation 1. Она выполняет декодирование **переменнодлинных кодов (VLC - Variable Length Coding)** в процессе декомпрессии **DCT (Discrete Cosine Transform)** данных, обычно используемых в видеоформатах типа MPEG.
## Основное назначение
`DecDCTvlc2` декодирует:
1. Битовые потоки с переменнодлинным кодированием (VLC)
2. Коэффициенты DCT после обратного зигзаг-сканирования
3. Данные в формате, используемом аппаратным декодером PS1
## Технические детали
```c
void DecDCTvlc2(unsigned short *data, int *macroblock);
```
Где:
- `data` - указатель на входной битовый поток VLC
- `macroblock` - указатель на выходной буфер для декодированных данных макроблока (6 блоков по 64 элемента: 4 яркостных, 2 цветностных)
## Особенности реализации
1. **Аппаратное ускорение** - использует специальные возможности графического процессора PS1
2. **Оптимизировано для MPEG-подобных потоков** - но не является полным MPEG-декодером
3. **Работает с макроблоками** - 16x16 пикселей (4 блока яркости Y, 1 блок каждой цветности Cr/Cb)
4. **Требует предварительной настройки** - через `DecDCTin()`, `DecDCTout()` и другие функции видеоцепи
## Пример использования
```c
#include <libetc.h>
#include <libgte.h>
#include <libgpu.h>
#include <libds.h>
#include <libsn.h>
void decode_video_frame(unsigned short *vlc_data) {
// Буфер для декодированного макроблока (6 блоков по 64 коэффициента)
int macroblock[6*64];
// Настройка ввода/вывода декодера
DecDCTin(vlc_data, 0);
DecDCTout((unsigned char*)macroblock, 0);
// Декодирование VLC-потока
DecDCTvlc2(vlc_data, macroblock);
// Дальнейшая обработка декодированных данных...
}
```
## Типичный контекст использования
1. **Декодирование внутрикадровых (I-кадров) MPEG-видео**
2. **Обработка видеопотоков в реальном времени**
3. **Специальные эффекты с использованием DCT-данных**
4. **Собственные алгоритмы видеокомпрессии**
## Важные нюансы
1. **Не является полным MPEG-декодером** - требует дополнительной логики для полного декодирования видео
2. **Требует точного соответствия формату данных** - входной поток должен быть правильно сформирован
3. **Работает в паре с другими функциями DCT-цепи**:
- `DecDCTin()` - настройка входного буфера
- `DecDCTout()` - настройка выходного буфера
- `DecDCToutCallback()` - установка callback'а по завершении
4. **Использует аппаратные возможности PS1** - дает значительный выигрыш в производительности по сравнению с программной реализацией
Функция `DecDCTvlc2` представляет собой низкоуровневый инструмент для работы с видео на PS1 и требует глубокого понимания принципов DCT-компрессии и форматов видеоданных, используемых на этой платформе.