Flipper/Applications/Official/DEV_FW/source/grnch/badapple/video_player.c
2022-12-28 22:34:27 -08:00

138 lines
3.6 KiB
C

#include <stdbool.h>
#include <furi.h>
#include "bad_apple.h"
#include "video_player.h"
#define TAG "video_player"
static void vp_decode_rle(BadAppleCtx* ctx);
static void vp_decode_delta(BadAppleCtx* ctx);
int vp_play_frame(BadAppleCtx* ctx) {
// Check frame type
// FURI_LOG_D(TAG, "Buffer offset: %04lx", ctx->file_buffer_offset);
uint8_t b = bad_apple_read_byte(ctx);
// FURI_LOG_D(TAG, "Frame byte: %02x", b);
switch(b) {
case 1: // PFrame (delta)
vp_decode_delta(ctx);
break;
case 2: // IFrame (rle)
vp_decode_rle(ctx);
break;
case 3: // DFrame (duplicate)
break;
case 4: // next page (not supported)
case 5: // end
default:
return 0;
}
return 1;
}
static inline void vp_write_pixel(BadAppleCtx* ctx, bool color) {
if(color) {
// White
ctx->framebuffer[ctx->frame_write_offset / 8] &= ~(1 << (ctx->frame_write_offset % 8));
} else {
// Black
ctx->framebuffer[ctx->frame_write_offset / 8] |= (1 << (ctx->frame_write_offset % 8));
}
++ctx->frame_write_offset;
}
static inline void vp_set_rect_fast(BadAppleCtx* ctx, int x, int y) {
ctx->frame_write_offset = y * VIDEO_WIDTH + x;
}
static void vp_decode_rle(BadAppleCtx* ctx) {
int i = 0;
int repeat_byte = bad_apple_read_byte(ctx);
// Set rect to video area
vp_set_rect_fast(ctx, 0, 0);
while(i < VIDEO_WIDTH * VIDEO_HEIGHT) {
int count;
unsigned pixels;
int j;
int b = bad_apple_read_byte(ctx);
if(b == repeat_byte) {
count = bad_apple_read_byte(ctx);
if(count == 0) count = 256;
pixels = bad_apple_read_byte(ctx);
} else {
count = 1;
pixels = (unsigned)b;
}
for(j = 0; j < count; ++j) {
bool out_color;
int k;
unsigned loop_pixels = pixels;
for(k = 0; k < 8; ++k) {
if(loop_pixels & 0x80)
out_color = COLOR_WHITE;
else
out_color = COLOR_BLACK;
vp_write_pixel(ctx, out_color);
loop_pixels <<= 1;
++i;
}
}
}
}
static void vp_decode_delta(BadAppleCtx* ctx) {
int frame_header[(VIDEO_HEIGHT + 7) / 8];
uint i;
int fh_byte = 0;
int fh_index = 0;
for(i = 0; i < sizeof(frame_header) / sizeof(frame_header[0]); ++i) {
frame_header[i] = bad_apple_read_byte(ctx);
}
for(i = 0; i < VIDEO_HEIGHT; ++i) {
if(i % 8 == 0) fh_byte = frame_header[fh_index++];
if(fh_byte & 0x80) {
int j;
int sl_byte = 0;
for(j = 0; j < VIDEO_WIDTH;) {
if(j % (8 * 8) == 0) sl_byte = bad_apple_read_byte(ctx);
if(sl_byte & 0x80) {
unsigned out_color;
int k;
unsigned pixel_group = bad_apple_read_byte(ctx);
// Note: this needs to be revised for screen width not multiple of 8
vp_set_rect_fast(ctx, j, i);
for(k = 0; k < 8 && j < VIDEO_WIDTH; ++k, ++j) {
if(pixel_group & 0x80)
out_color = COLOR_WHITE;
else
out_color = COLOR_BLACK;
vp_write_pixel(ctx, out_color);
pixel_group <<= 1;
}
} else {
j += 8;
}
sl_byte <<= 1;
}
}
fh_byte <<= 1;
}
}