-
Notifications
You must be signed in to change notification settings - Fork 0
/
video_player.c
executable file
·137 lines (113 loc) · 3.74 KB
/
video_player.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
#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;
}
}