fix stupoiderrors in frame cycling
[sparrow.git] / play.c
blobbc09469befbac176dd06387cb70e74d86d6c400b
1 /* Copyright (C) <2010> Douglas Bagnall <douglas@halo.gen.nz>
3 * This library is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU Library General Public
5 * License as published by the Free Software Foundation; either
6 * version 2 of the License, or (at your option) any later version.
8 * This library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Library General Public License for more details.
13 * You should have received a copy of the GNU Library General Public
14 * License along with this library; if not, write to the
15 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
16 * Boston, MA 02111-1307, USA.
19 #include "sparrow.h"
20 #include "gstsparrow.h"
22 #include <string.h>
23 #include <math.h>
25 #define DEBUG_PLAY 0
26 #define OLD_FRAMES 4
29 typedef struct sparrow_play_s{
30 guint8 lut_hi[256];
31 guint8 lut_lo[256];
32 guint8 *image_row;
33 guint jpeg_index;
34 GstBuffer *old_frames[OLD_FRAMES];
35 int old_frames_head;
36 int old_frames_tail;
37 } sparrow_play_t;
40 static void
41 set_up_jpeg(GstSparrow *sparrow, sparrow_play_t *player){
42 /*XXX pick a jpeg, somehow*/
43 /*first, chance of random jump anywhere. */
44 if (rng_uniform(sparrow) < 1.0 / 500){
45 player->jpeg_index = RANDINT(sparrow, 0, sparrow->shared->image_count);
46 GST_DEBUG("CHANGE_SHOT: random jump: %d to %d", player->jpeg_index, player->jpeg_index);
48 else {
49 sparrow_frame_t *old_frame = &sparrow->shared->index[player->jpeg_index];
50 int next = old_frame->successors[0];
51 if (!next){
52 int i = RANDINT(sparrow, 1, 8);
53 next = old_frame->successors[i];
54 GST_DEBUG("CHANGE_SHOT: %d to %d (option %d)", player->jpeg_index, next, i);
56 player->jpeg_index = next;
59 sparrow_frame_t *frame = &sparrow->shared->index[player->jpeg_index];
60 guint8 *src = sparrow->shared->jpeg_blob + frame->offset;
61 guint size = frame->jpeg_size;
62 GST_DEBUG("blob is %p, offset %d, src %p, size %d\n",
63 sparrow->shared->jpeg_blob, frame->offset, src, size);
65 begin_reading_jpeg(sparrow, src, size);
69 static inline guint8 one_subpixel(sparrow_play_t *player, guint8 inpix, guint8 jpegpix){
70 //jpeg is target.
71 //there is diff. (in gamma space)
72 // compensate for diff (only).
73 // if the pixel needs to be darker, send nothing
74 // if it needs to be brighter, send difference.
75 //XXX difference needs gamma scaling
76 #if 0
77 /*clamp in pseudo gamma space*/
78 int gj = player->lut_hi[jpegpix];
79 int gi = player->lut_hi[inpix];
80 int diff = gj - gi;
81 if (diff < 0)
82 return 0;
83 return player->lut_lo[diff];
84 #endif
85 #if 1
86 /*clamp */
87 int diff = jpegpix - inpix;
88 if (diff < 0)
89 return 0;
90 return diff;
91 #endif
92 #if 0
93 /*full mirror */
94 int diff = jpegpix - inpix;
95 if (diff < 0)
96 return -diff; /*or -diff /2 */
97 return diff;
98 #endif
99 #if 0
100 /* simplest possible (average)*/
101 guint sum = player->lut_hi[inpix] + jpegpix;
102 return sum >> 1;
103 #endif
107 UNUSED static inline void
108 do_one_pixel(GstSparrow *sparrow, guint8 *outpix, guint8 *inpix, guint8 *jpegpix){
109 /* rather than cancel the whole other one, we need to calculate the
110 difference from the desired image, and only compensate by that
111 amount. If a lot of negative compensation (i.e, trying to blacken)
112 is needed, then it is time to raise the black level for the next
113 round (otherwise, lower the black level). Use sum of
114 compensations?, or count? or thresholded? or squared (via LUT)?
116 How are relative calculations calculated via LUT?
118 1. pre scale
119 2. combine
120 3. re scale
123 sparrow_play_t *player = sparrow->helper_struct;
124 outpix[0] = one_subpixel(player, inpix[0], jpegpix[0]);
125 outpix[1] = one_subpixel(player, inpix[1], jpegpix[1]);
126 outpix[2] = one_subpixel(player, inpix[2], jpegpix[2]);
127 outpix[3] = one_subpixel(player, inpix[3], jpegpix[3]);
130 #define GENTLE 1
131 #if GENTLE
132 static inline guint8 one_subpixel_lagged(sparrow_play_t *player, guint8 inpix,
133 guint8 jpegpix, guint8 oldpix){
134 /*clamp */
135 int error = MAX(inpix - oldpix, 0) >> 1;
136 int diff = jpegpix - error;
137 if (diff < 0)
138 return 0;
139 return diff;
142 #else
143 static inline guint8 one_subpixel_lagged(sparrow_play_t *player, guint8 inpix,
144 guint8 jpegpix, guint8 oldpix){
145 /*clamp */
146 //jpegpix -= oldpix >> 1;
147 //inpix += oldpix;
148 int target = 2 * jpegpix - oldpix;
149 int diff = (target - inpix) >> 1;
150 if (diff < 0)
151 return 0;
152 if (diff > 255)
153 return 255;
154 return diff;
156 #endif
158 static inline void
159 do_one_pixel_lagged(sparrow_play_t *player, guint8 *outpix, guint8 *inpix, guint8 *jpegpix,
160 guint8 *oldframe){
161 outpix[0] = one_subpixel_lagged(player, inpix[0], jpegpix[0], oldframe[0]);
162 outpix[1] = one_subpixel_lagged(player, inpix[1], jpegpix[1], oldframe[1]);
163 outpix[2] = one_subpixel_lagged(player, inpix[2], jpegpix[2], oldframe[2]);
164 outpix[3] = one_subpixel_lagged(player, inpix[3], jpegpix[3], oldframe[3]);
169 static void
170 play_from_full_lut(GstSparrow *sparrow, guint8 *in, guint8 *out){
171 GST_DEBUG("play_from_full_lut\n");
172 #if 0
173 memset(out, 0, sparrow->out.size); /*is this necessary? (only for outside
174 screen map, maybe in-loop might be
175 quicker) */
176 #endif
177 sparrow_play_t *player = sparrow->helper_struct;
178 guint i;
179 int ox, oy;
180 guint32 *out32 = (guint32 *)out;
181 guint32 *in32 = (guint32 *)in;
182 GstBuffer *oldbuf = player->old_frames[player->old_frames_tail];
183 guint8 *old_frame;
184 if (oldbuf){
185 old_frame = (guint8 *)GST_BUFFER_DATA(oldbuf);
187 else { /*boot strapping: use current frame */
188 old_frame = out;
191 set_up_jpeg(sparrow, player);
192 GST_DEBUG("in %p out %p", in, out);
194 guint8 *jpeg_row = player->image_row;
195 i = 0;
196 for (oy = 0; oy < sparrow->out.height; oy++){
197 //GST_DEBUG("about to read line to %p", jpeg_row);
198 read_one_line(sparrow, jpeg_row);
199 for (ox = 0; ox < sparrow->out.width; ox++, i++){
200 int x = sparrow->map_lut[i].x;
201 int y = sparrow->map_lut[i].y;
202 if (x || y){
203 guint8 *inpix = (guint8*)&in32[y * sparrow->in.width + x];
204 /*do_one_pixel(sparrow,
205 &out[i * PIXSIZE],
206 inpix,
207 &jpeg_row[ox * PIXSIZE]);*/
208 do_one_pixel_lagged(player,
209 &out[i * PIXSIZE],
210 inpix,
211 &jpeg_row[ox * PIXSIZE],
212 &old_frame[i * PIXSIZE]
215 else {
216 out32[i] = 0;
220 finish_reading_jpeg(sparrow);
222 if (DEBUG_PLAY && sparrow->debug){
223 debug_frame(sparrow, out, sparrow->out.width, sparrow->out.height, PIXSIZE);
227 static void
228 store_old_frame(GstSparrow *sparrow, GstBuffer *outbuf){
229 sparrow_play_t *player = sparrow->helper_struct;
230 player->old_frames[player->old_frames_head] = outbuf;
231 gst_buffer_ref(outbuf);
232 player->old_frames_head++;
233 player->old_frames_head %= OLD_FRAMES;
236 static void
237 drop_old_frame(GstSparrow *sparrow, GstBuffer *outbuf){
238 sparrow_play_t *player = sparrow->helper_struct;
239 GstBuffer *tail = player->old_frames[player->old_frames_tail];
240 if (tail){
241 gst_buffer_unref(tail);
243 player->old_frames_tail++;
244 player->old_frames_tail %= OLD_FRAMES;
248 INVISIBLE sparrow_state
249 mode_play(GstSparrow *sparrow, GstBuffer *inbuf, GstBuffer *outbuf){
250 guint8 *in = GST_BUFFER_DATA(inbuf);
251 guint8 *out = GST_BUFFER_DATA(outbuf);
252 store_old_frame(sparrow, outbuf);
253 play_from_full_lut(sparrow, in, out);
254 drop_old_frame(sparrow, outbuf);
255 return SPARROW_STATUS_QUO;
258 static const double GAMMA = 1.5;
259 static const double INV_GAMMA = 1.0 / 1.5;
260 static const double FALSE_CEILING = 275;
262 static void
263 init_gamma_lut(sparrow_play_t *player){
264 for (int i = 0; i < 256; i++){
265 /* for each colour:
266 1. perform inverse gamma calculation (-> linear colour space)
267 2. negate
268 3 undo gamma.
270 double x;
271 x = i / 255.01;
272 x = 1 - pow(x, INV_GAMMA);
273 x = pow(x, GAMMA) * FALSE_CEILING;
274 if (x > 255){
275 x = 255;
277 player->lut[i] = (guint8)x;
281 INVISIBLE void init_play(GstSparrow *sparrow){
282 GST_DEBUG("starting play mode\n");
283 init_jpeg_src(sparrow);
284 sparrow_play_t *player = zalloc_aligned_or_die(sizeof(sparrow_play_t));
285 player->image_row = zalloc_aligned_or_die(sparrow->out.width * PIXSIZE);
286 player->old_frames_head = MIN(sparrow->lag, OLD_FRAMES - 1) || 1;
287 GST_INFO("using old frame lag of %d\n", player->old_frames_head);
288 sparrow->helper_struct = player;
289 init_gamma_lut(player);
290 GST_DEBUG("finished init_play\n");
293 INVISIBLE void finalise_play(GstSparrow *sparrow){
294 GST_DEBUG("leaving play mode\n");