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

5.5 KiB
Raw Blame History

Рендеринг потокового видео (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 отправляет команду чтения:

    CdReadSector(/*Сектор начала*/, /*Кол-во секторов*/, /*Буфер в RAM*/);
    
  2. DMA (канал 3) копирует данные из буфера CD-ROM в RAM:

    • Используется двойная буферизация:
      • Пока DMA заполняет Буфер 1, CPU/MDEC обрабатывает Буфер 2.
    • Размер буфера обычно 1632 КБ (816 секторов).
  3. Ожидание завершения:

    CdReadSync(0); // Блокирующее ожидание
    

3. Декодирование видео через MDEC

  1. CPU настраивает MDEC (канал DMA 0/1):

    • Указывает адрес сжатых данных в RAM.
    • Запускает декодирование:
      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).
    • Пример:
      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).
    • Команда:
      li t0, 0x1F801810  // GP0
      li t1, 0xA0000000  // Команда "Draw Rectangle"
      sw t1, 0(t0)
      
  3. Синхронизация с VBlank:

    • Чтобы избежать артефактов, обновление кадра происходит во время VBlank:
      VSync(0);
      

5. Аудиосопровождение

  • ADPCM-аудио декодируется через SPU (канал DMA 4):
    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)

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! 🎥