remake ringbuffer
This commit is contained in:
parent
2bcc2dc21b
commit
757109f51c
@ -1,15 +1,15 @@
|
||||
#!/bin/sh
|
||||
|
||||
palette="palette.png"
|
||||
video="video.webm"
|
||||
# output="video_out.gif"
|
||||
video="kiss2x.mp4"
|
||||
# output="kiss2x_out.mp4"
|
||||
output="out/out_%d.bmp"
|
||||
|
||||
filters="scale=256x192:flags=lanczos:force_original_aspect_ratio=decrease,pad=256:192:-1:-1:color=black"
|
||||
|
||||
# video
|
||||
ffmpeg -i $video -vf "$filters,palettegen=max_colors=256:reserve_transparent=0:stats_mode=diff" -y $palette
|
||||
ffmpeg -i $video -i $palette -filter_complex "$filters,setpts=0.8*PTS[x];[x][1:v]paletteuse=dither=none" -y $output
|
||||
ffmpeg -i $video -i $palette -filter_complex "$filters[x];[x][1:v]paletteuse=dither=none" -y $output
|
||||
|
||||
# audio
|
||||
ffmpeg -i $video -f s16le -filter:a "atempo=1.25" -vn -ac 1 -ar 22050 -y music.raw
|
||||
ffmpeg -i $video -f s16le -vn -ac 1 -ar 22050 -y music.raw
|
308
src/main.cpp
308
src/main.cpp
@ -1,96 +1,133 @@
|
||||
#include "fastlz.h"
|
||||
#include "filesystem.h"
|
||||
#include "nds/arm9/background.h"
|
||||
#include "nds/arm9/console.h"
|
||||
#include "nds/cothread.h"
|
||||
#include "nds/dma.h"
|
||||
#include "nds/timers.h"
|
||||
#include "raylibds.hpp"
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <nds.h>
|
||||
#include <maxmod9.h>
|
||||
|
||||
#define PALETTE_SIZE 256
|
||||
#define FRAME_SIZE 256*192
|
||||
|
||||
// TODO: hardcode fix
|
||||
#define CHUNK_SIZE 10
|
||||
#define QUEUE_SIZE 6
|
||||
#define FRAMERATE 30
|
||||
#define VIDEO_TOTALFRAME 827
|
||||
|
||||
#define STREAM_CHUNK_SIZE 32000
|
||||
#define STREAM_QUEUE_SIZE 4
|
||||
#define MMSTREAM_BUF_SIZE 9600
|
||||
#define MMSTREAM_BUF_SIZE 800
|
||||
#define MUSIC_BUFFER_SIZE 16000
|
||||
|
||||
void wait_forever(const char* msg);
|
||||
void LoadNextChunk(void *output);
|
||||
void LoadNextChunk();
|
||||
void TimerCallback();
|
||||
void VBLCallback();
|
||||
void FrameStep();
|
||||
int ThreadEntrypoint(void *arg);
|
||||
int ThreadVideo(void *arg);
|
||||
mm_word on_stream_request( mm_word length, mm_addr dest, mm_stream_formats format );
|
||||
|
||||
class CircularQueue {
|
||||
public:
|
||||
int front, rear, size, current;
|
||||
CircularQueue(int s) {
|
||||
size = s;
|
||||
front = rear = -1;
|
||||
current = 0;
|
||||
}
|
||||
struct RingBuffer {
|
||||
char *buffer = nullptr;
|
||||
int head;
|
||||
int tail;
|
||||
int size;
|
||||
int count;
|
||||
|
||||
bool isFull() {
|
||||
return (front == 0 && rear == size - 1) || (rear == (front - 1) % (size - 1));
|
||||
}
|
||||
RingBuffer(size_t size_t)
|
||||
{
|
||||
buffer = (char*)malloc(size_t);
|
||||
size = size_t;
|
||||
head = 0;
|
||||
tail = 0;
|
||||
count = 0;
|
||||
}
|
||||
|
||||
bool isEmpty() {
|
||||
return front == -1;
|
||||
}
|
||||
~RingBuffer()
|
||||
{
|
||||
free(buffer);
|
||||
}
|
||||
|
||||
void push() {
|
||||
if (isFull()) {
|
||||
fprintf(stderr, "Queue is full. Cannot push\n");
|
||||
return;
|
||||
}
|
||||
int read(char *dest, size_t len)
|
||||
{
|
||||
if (count >= len)
|
||||
{
|
||||
count -= len;
|
||||
int linear_len = size - head;
|
||||
|
||||
if (isEmpty()) {
|
||||
front = rear = 0;
|
||||
} else {
|
||||
rear = (rear + 1) % size;
|
||||
}
|
||||
if (len < linear_len)
|
||||
memcpy(dest, &buffer[head], len);
|
||||
// swiCopy(&buffer[head], dest, len);
|
||||
else
|
||||
{
|
||||
memcpy(dest, &buffer[head], linear_len);
|
||||
memcpy(&dest[linear_len], buffer, len-linear_len);
|
||||
// swiCopy(&buffer[head], dest, linear_len);
|
||||
// swiCopy(buffer, &dest[linear_len], len-linear_len);
|
||||
}
|
||||
|
||||
current++;
|
||||
}
|
||||
head = (head+len) % size;
|
||||
|
||||
void pop() {
|
||||
if (isEmpty()) {
|
||||
fprintf(stderr, "Queue is empty. Cannot pop\n");
|
||||
return;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (front == rear) {
|
||||
front = rear = -1;
|
||||
} else {
|
||||
front = (front + 1) % size;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
current--;
|
||||
}
|
||||
int write(char *data, size_t len)
|
||||
{
|
||||
if (count+len <= size)
|
||||
{
|
||||
count += len;
|
||||
int linear_len = size - tail;
|
||||
|
||||
if (len < linear_len)
|
||||
memcpy(&buffer[tail], data, len);
|
||||
// swiCopy(data, &buffer[tail], len);
|
||||
else
|
||||
{
|
||||
memcpy(&buffer[tail], data, linear_len);
|
||||
memcpy(buffer, &data[linear_len], len-linear_len);
|
||||
// swiCopy(data, &buffer[tail], linear_len);
|
||||
// swiCopy(&data[linear_len], buffer, len-linear_len);
|
||||
}
|
||||
|
||||
tail = (tail+len) % size;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
int ptr_background;
|
||||
int ptr_subbackground;
|
||||
FILE *file_image = nullptr;
|
||||
FILE *file_video = nullptr;
|
||||
FILE *file_music = nullptr;
|
||||
int file_music_len;
|
||||
int file_video_len;
|
||||
|
||||
int chunk_current = 0;
|
||||
int framecounter = 0;
|
||||
|
||||
uint8_t *frame_decompress;
|
||||
uint8_t *frame_buffer;
|
||||
uint8_t *stream_buffer;
|
||||
RingBuffer music_rb(MUSIC_BUFFER_SIZE);
|
||||
void *music_btemp;
|
||||
|
||||
int stream_index;
|
||||
int stream_buffer_current;
|
||||
bool stream_need_update = false;
|
||||
RingBuffer video_rb(FRAME_SIZE*CHUNK_SIZE*QUEUE_SIZE);
|
||||
void *video_btemp;
|
||||
void *video_decompress;
|
||||
void *video_compress;
|
||||
|
||||
CircularQueue frame_queue(QUEUE_SIZE);
|
||||
CircularQueue stream_queue(STREAM_QUEUE_SIZE);
|
||||
|
||||
int music_buffer_size = 4000*16;
|
||||
u32 timer_video_start = 0;
|
||||
u32 timer_video_end = 0;
|
||||
u32 timer_video_avg = 0;
|
||||
|
||||
int main(void) {
|
||||
|
||||
@ -101,27 +138,28 @@ int main(void) {
|
||||
vramSetBankC(VRAM_C_SUB_BG);
|
||||
vramSetBankF(VRAM_F_TEX_PALETTE);
|
||||
|
||||
// consoleDemoInit();
|
||||
consoleDemoInit();
|
||||
consoleDebugInit(DebugDevice_NOCASH);
|
||||
|
||||
frame_decompress = (uint8_t*)malloc(FRAME_SIZE*CHUNK_SIZE);
|
||||
frame_buffer = (uint8_t*)malloc(FRAME_SIZE*CHUNK_SIZE*QUEUE_SIZE);
|
||||
stream_buffer = (uint8_t*)malloc(STREAM_CHUNK_SIZE*STREAM_QUEUE_SIZE);
|
||||
|
||||
sassert(
|
||||
frame_buffer != nullptr ||
|
||||
frame_decompress != nullptr ||
|
||||
stream_buffer != nullptr,
|
||||
"failed to allocate memmory");
|
||||
video_decompress = malloc(FRAME_SIZE*CHUNK_SIZE);
|
||||
video_compress = malloc(FRAME_SIZE*CHUNK_SIZE);
|
||||
video_btemp = malloc(FRAME_SIZE);
|
||||
music_btemp = malloc(MUSIC_BUFFER_SIZE);
|
||||
|
||||
bool nitrofs = nitroFSInit(NULL);
|
||||
sassert(nitrofs, "error nitrofs");
|
||||
|
||||
file_image = fopen("nitro:/image.bin", "rb");
|
||||
sassert(file_image != nullptr, "failed to load image.bin");
|
||||
file_video = fopen("nitro:/image.bin", "rb");
|
||||
sassert(file_video != nullptr, "failed to load image.bin");
|
||||
fseek(file_video, 0, SEEK_END);
|
||||
file_video_len = ftell(file_video);
|
||||
fseek(file_video, 0, SEEK_SET);
|
||||
|
||||
file_music = fopen("nitro:/music.raw", "rb");
|
||||
sassert(file_image != nullptr, "failed to load music.raw");
|
||||
sassert(file_music != nullptr, "failed to load music.raw");
|
||||
fseek(file_music, 0, SEEK_END);
|
||||
file_music_len = ftell(file_music);
|
||||
fseek(file_music, 0, SEEK_SET);
|
||||
|
||||
int pal_len;
|
||||
unsigned char* pal = Raylib::LoadFile("nitro:/palette.bin", pal_len);
|
||||
@ -135,18 +173,18 @@ int main(void) {
|
||||
|
||||
free(pal);
|
||||
|
||||
while(!frame_queue.isFull()) {
|
||||
frame_queue.push();
|
||||
LoadNextChunk(&frame_buffer[FRAME_SIZE*CHUNK_SIZE*frame_queue.rear]);
|
||||
Raylib::nocashMessageFormat("preload video");
|
||||
while(video_rb.size-video_rb.count >= FRAME_SIZE*CHUNK_SIZE) {
|
||||
LoadNextChunk();
|
||||
video_rb.write((char*)video_decompress, FRAME_SIZE*CHUNK_SIZE);
|
||||
}
|
||||
|
||||
while(!stream_queue.isFull()) {
|
||||
stream_queue.push();
|
||||
fread(&stream_buffer[STREAM_CHUNK_SIZE*stream_queue.rear], sizeof(uint8_t), STREAM_CHUNK_SIZE, file_music);
|
||||
{
|
||||
Raylib::nocashMessageFormat("preload music");
|
||||
int len = music_rb.size - music_rb.count;
|
||||
fread(music_btemp, sizeof(char), len, file_music);
|
||||
music_rb.write((char*)music_btemp, len);
|
||||
}
|
||||
stream_index = 0;
|
||||
|
||||
DC_FlushAll();
|
||||
|
||||
mm_ds_system sys;
|
||||
sys.mod_count = 0;
|
||||
@ -163,16 +201,58 @@ int main(void) {
|
||||
mystream.timer = MM_TIMER2;
|
||||
mystream.manual = false;
|
||||
|
||||
timerStart(0, ClockDivider_1024, TIMER_FREQ_1024(FRAMERATE), TimerCallback);
|
||||
timerStart(3, ClockDivider_1024, TIMER_FREQ_1024(FRAMERATE), TimerCallback);
|
||||
cothread_create(ThreadEntrypoint, NULL, 0, COTHREAD_DETACHED);
|
||||
cothread_create(ThreadVideo, NULL, 0, COTHREAD_DETACHED);
|
||||
|
||||
mmStreamOpen( &mystream );
|
||||
|
||||
cpuStartTiming(0);
|
||||
|
||||
while(1) {
|
||||
cothread_yield_irq(IRQ_VBLANK);
|
||||
scanKeys();
|
||||
|
||||
if (keysUp() & KEY_A) break;
|
||||
|
||||
printf("\033[4;2H\033[Kvideo buffer: %i", video_rb.count);
|
||||
printf("\033[5;2H\033[Kmusic buffer: %i", music_rb.count);
|
||||
printf("\033[6;2H\033[Kprogress: %0.f%%", ((float)framecounter/VIDEO_TOTALFRAME)*100);
|
||||
|
||||
static int frame = 0;
|
||||
frame++;
|
||||
|
||||
if (frame % 30 == 0)
|
||||
{
|
||||
printf("\033[8;2H\033[Kavg decoding time: %" PRIu32 "ms", timerTicks2msec(timer_video_avg/30));
|
||||
timer_video_avg = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ThreadVideo(void *arg)
|
||||
{
|
||||
while(1) {
|
||||
cothread_yield();
|
||||
|
||||
if (file_video != nullptr && video_rb.size-video_rb.count >= FRAME_SIZE*CHUNK_SIZE)
|
||||
{
|
||||
timer_video_start = cpuGetTiming();
|
||||
|
||||
LoadNextChunk();
|
||||
video_rb.write((char*)video_decompress, FRAME_SIZE*CHUNK_SIZE);
|
||||
|
||||
timer_video_end = cpuGetTiming();
|
||||
timer_video_avg += timer_video_end - timer_video_start;
|
||||
|
||||
if (ftell(file_video) == file_video_len)
|
||||
{
|
||||
fclose(file_video);
|
||||
file_video = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -181,24 +261,23 @@ int main(void) {
|
||||
int ThreadEntrypoint(void *arg)
|
||||
{
|
||||
while(1) {
|
||||
if (!frame_queue.isFull())
|
||||
{
|
||||
frame_queue.push();
|
||||
LoadNextChunk(&frame_buffer[FRAME_SIZE*CHUNK_SIZE*frame_queue.rear]);
|
||||
}
|
||||
cothread_yield();
|
||||
|
||||
if (!stream_queue.isFull())
|
||||
if (file_music != nullptr && music_rb.count < MUSIC_BUFFER_SIZE/2)
|
||||
{
|
||||
stream_queue.push();
|
||||
int len = music_rb.size - music_rb.count;
|
||||
|
||||
if ((file_music_len - ftell(file_music)) < len)
|
||||
{
|
||||
memset(music_btemp, 0, MUSIC_BUFFER_SIZE);
|
||||
fread(music_btemp, sizeof(char), (file_music_len - ftell(file_music)), file_music);
|
||||
fclose(file_music);
|
||||
file_music = nullptr;
|
||||
} else
|
||||
fread(music_btemp, sizeof(char), len, file_music);
|
||||
|
||||
fread(stream_buffer+ stream_queue.rear*STREAM_CHUNK_SIZE, sizeof(uint8_t), STREAM_CHUNK_SIZE, file_music);
|
||||
if (feof(file_music)) {
|
||||
memset(stream_buffer+ stream_queue.rear*STREAM_CHUNK_SIZE, 0, STREAM_CHUNK_SIZE);
|
||||
mmStreamClose();
|
||||
}
|
||||
music_rb.write((char*)music_btemp, len);
|
||||
}
|
||||
cothread_yield();
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -206,16 +285,11 @@ int ThreadEntrypoint(void *arg)
|
||||
|
||||
void FrameStep()
|
||||
{
|
||||
// if (feof(file_image)) return;
|
||||
|
||||
dmaCopyAsynch(&frame_buffer[FRAME_SIZE*CHUNK_SIZE*frame_queue.front + FRAME_SIZE*chunk_current], bgGetGfxPtr(ptr_background), FRAME_SIZE);
|
||||
dmaCopyAsynch(&frame_buffer[FRAME_SIZE*CHUNK_SIZE*frame_queue.front + FRAME_SIZE*chunk_current], bgGetGfxPtr(ptr_subbackground), FRAME_SIZE);
|
||||
|
||||
chunk_current++;
|
||||
|
||||
if (chunk_current >= CHUNK_SIZE) {
|
||||
chunk_current = 0;
|
||||
frame_queue.pop();
|
||||
if (video_rb.count)
|
||||
{
|
||||
video_rb.read((char*)video_btemp, FRAME_SIZE);
|
||||
dmaCopyAsynch(video_btemp, bgGetGfxPtr(ptr_background), FRAME_SIZE);
|
||||
framecounter++;
|
||||
}
|
||||
}
|
||||
|
||||
@ -224,17 +298,16 @@ void TimerCallback()
|
||||
FrameStep();
|
||||
}
|
||||
|
||||
void LoadNextChunk(void *output)
|
||||
void LoadNextChunk()
|
||||
{
|
||||
uint32_t compress_size;
|
||||
fread(&compress_size, sizeof(uint32_t), 1, file_image);
|
||||
fread(&compress_size, sizeof(uint32_t), 1, file_video);
|
||||
|
||||
fread(frame_decompress, sizeof(uint8_t), compress_size, file_image);
|
||||
fastlz_decompress(frame_decompress, compress_size, output, FRAME_SIZE*CHUNK_SIZE);
|
||||
fread(video_compress, sizeof(uint8_t), compress_size, file_video);
|
||||
fastlz_decompress(video_compress, compress_size, video_decompress, FRAME_SIZE*CHUNK_SIZE);
|
||||
}
|
||||
|
||||
mm_word on_stream_request( mm_word length, mm_addr dest, mm_stream_formats format ) {
|
||||
|
||||
size_t samplesize = 1;
|
||||
switch(format){
|
||||
case MM_STREAM_8BIT_MONO: samplesize = 1; break;
|
||||
@ -244,29 +317,12 @@ mm_word on_stream_request( mm_word length, mm_addr dest, mm_stream_formats forma
|
||||
}
|
||||
int len = length*samplesize;
|
||||
|
||||
if (feof(file_music))
|
||||
if (music_rb.count >= len)
|
||||
{
|
||||
mmStreamClose();
|
||||
uint8_t temp[len];
|
||||
memset(temp, 0, len);
|
||||
DC_FlushAll();
|
||||
dmaCopyAsynch(temp, dest, len);
|
||||
return length;
|
||||
music_rb.read((char*)dest, len);
|
||||
}
|
||||
|
||||
int bytesToCopy = std::min(len, STREAM_CHUNK_SIZE-stream_index);
|
||||
dmaCopyAsynch(stream_buffer + stream_queue.front*STREAM_CHUNK_SIZE + stream_index, dest, bytesToCopy);
|
||||
stream_index += bytesToCopy;
|
||||
if (music_rb.count < len && file_music == nullptr) mmStreamClose();
|
||||
|
||||
if (stream_index >= STREAM_CHUNK_SIZE)
|
||||
{
|
||||
stream_queue.pop();
|
||||
stream_index = len - bytesToCopy;
|
||||
// stream_index = 0;
|
||||
|
||||
dmaCopyAsynch(stream_buffer + stream_queue.front*STREAM_CHUNK_SIZE, dest+bytesToCopy, stream_index);
|
||||
}
|
||||
|
||||
// return bytesToCopy/2;
|
||||
return length;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user