store ring of old buffers
[sparrow.git] / play.c
blob3af35bc7727871e2acdae74ea271c632d61bb2fa
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 INITIAL_BLACK 32
27 #define MIN_BLACK 0
28 #define MAX_BLACK 160
29 #define OLD_FRAMES 4
32 typedef struct sparrow_play_s{
33 guint8 lut_hi[256];
34 guint8 lut_lo[256];
35 guint8 *image_row;
36 guint8 black_level;
37 guint jpeg_index;
38 GstBuffer *old_frames[OLD_FRAMES];
39 int old_frames_head;
40 int old_frames_tail;
41 } sparrow_play_t;
44 static void
45 set_up_jpeg(GstSparrow *sparrow, sparrow_play_t *player){
46 /*XXX pick a jpeg, somehow*/
47 /*first, chance of random jump anywhere. */
48 if (rng_uniform(sparrow) < 1.0 / 500){
49 player->jpeg_index = RANDINT(sparrow, 0, sparrow->shared->image_count);
50 GST_DEBUG("CHANGE_SHOT: random jump: %d to %d", player->jpeg_index, player->jpeg_index);
52 else {
53 sparrow_frame_t *old_frame = &sparrow->shared->index[player->jpeg_index];
54 int next = old_frame->successors[0];
55 if (!next){
56 int i = RANDINT(sparrow, 1, 8);
57 next = old_frame->successors[i];
58 GST_DEBUG("CHANGE_SHOT: %d to %d (option %d)", player->jpeg_index, next, i);
60 player->jpeg_index = next;
63 sparrow_frame_t *frame = &sparrow->shared->index[player->jpeg_index];
64 guint8 *src = sparrow->shared->jpeg_blob + frame->offset;
65 guint size = frame->jpeg_size;
66 GST_DEBUG("blob is %p, offset %d, src %p, size %d\n",
67 sparrow->shared->jpeg_blob, frame->offset, src, size);
69 begin_reading_jpeg(sparrow, src, size);
73 static inline guint8 one_subpixel(sparrow_play_t *player, guint8 inpix, guint8 jpegpix){
74 //jpeg is target.
75 //there is diff. (in gamma space)
76 // compensate for diff (only).
77 // if the pixel needs to be darker, send nothing
78 // if it needs to be brighter, send difference.
79 //XXX difference needs gamma scaling
80 #if 1
81 int diff = jpegpix - inpix;
82 if (diff < 0)
83 return 0;
84 return diff;
85 #else
86 /* simplest possible (average)*/
87 guint sum = player->lut[inpix] + jpegpix;
88 return sum >> 1;
89 #endif
92 static inline void
93 do_one_pixel(GstSparrow *sparrow, guint8 *outpix, guint8 *inpix, guint8 *jpegpix){
94 /* rather than cancel the whole other one, we need to calculate the
95 difference from the desired image, and only compensate by that
96 amount. If a lot of negative compensation (i.e, trying to blacken)
97 is needed, then it is time to raise the black level for the next
98 round (otherwise, lower the black level). Use sum of
99 compensations?, or count? or thresholded? or squared (via LUT)?
101 How are relative calculations calculated via LUT?
103 1. pre scale
104 2. combine
105 3. re scale
108 sparrow_play_t *player = sparrow->helper_struct;
109 //guint8 black = player->black_level;
111 int r = ib[sparrow->in.rbyte];
112 int g = ib[sparrow->in.gbyte];
113 int b = ib[sparrow->in.bbyte];
115 //outpix[0] = player->lut[inpix[0]];
116 //outpix[1] = player->lut[inpix[1]];
117 //outpix[2] = player->lut[inpix[2]];
118 //outpix[3] = player->lut[inpix[3]];
119 outpix[0] = one_subpixel(player, inpix[0], jpegpix[0]);
120 outpix[1] = one_subpixel(player, inpix[1], jpegpix[1]);
121 outpix[2] = one_subpixel(player, inpix[2], jpegpix[2]);
122 outpix[3] = one_subpixel(player, inpix[3], jpegpix[3]);
126 static void
127 play_from_full_lut(GstSparrow *sparrow, guint8 *in, guint8 *out){
128 GST_DEBUG("play_from_full_lut\n");
129 #if 0
130 memset(out, 0, sparrow->out.size); /*is this necessary? (only for outside
131 screen map, maybe in-loop might be
132 quicker) */
133 #endif
134 sparrow_play_t *player = sparrow->helper_struct;
135 guint i;
136 int ox, oy;
137 guint32 *out32 = (guint32 *)out;
138 guint32 *in32 = (guint32 *)in;
139 set_up_jpeg(sparrow, player);
140 GST_DEBUG("in %p out %p", in, out);
142 guint8 *jpeg_row = player->image_row;
143 i = 0;
144 for (oy = 0; oy < sparrow->out.height; oy++){
145 //GST_DEBUG("about to read line to %p", jpeg_row);
146 read_one_line(sparrow, jpeg_row);
147 for (ox = 0; ox < sparrow->out.width; ox++, i++){
148 int x = sparrow->map_lut[i].x;
149 int y = sparrow->map_lut[i].y;
150 if (x || y){
151 guint8 *inpix = (guint8*)&in32[y * sparrow->in.width + x];
152 do_one_pixel(sparrow,
153 &out[i * PIXSIZE],
154 inpix,
155 &jpeg_row[ox * PIXSIZE]);
157 else {
158 out32[i] = 0;
162 finish_reading_jpeg(sparrow);
164 if (DEBUG_PLAY && sparrow->debug){
165 debug_frame(sparrow, out, sparrow->out.width, sparrow->out.height, PIXSIZE);
169 static void
170 store_old_frame(GstSparrow *sparrow, GstBuffer *outbuf){
171 sparrow_play_t *player = sparrow->helper_struct;
172 GstBuffer *head = player->old_frames[player->old_frames_head];
173 if (head){
174 head = outbuf;
175 gst_buffer_ref(head);
177 player->old_frames_head++;
178 player->old_frames_head %= OLD_FRAMES;
181 static void
182 drop_old_frame(GstSparrow *sparrow, GstBuffer *outbuf){
183 sparrow_play_t *player = sparrow->helper_struct;
184 GstBuffer *tail = player->old_frames[player->old_frames_tail];
185 if (tail){
186 gst_buffer_unref(tail);
188 player->old_frames_tail++;
189 player->old_frames_tail %= OLD_FRAMES;
193 INVISIBLE sparrow_state
194 mode_play(GstSparrow *sparrow, GstBuffer *inbuf, GstBuffer *outbuf){
195 guint8 *in = GST_BUFFER_DATA(inbuf);
196 guint8 *out = GST_BUFFER_DATA(outbuf);
197 store_old_frame(sparrow, outbuf);
198 play_from_full_lut(sparrow, in, out);
199 drop_old_frame(sparrow, outbuf);
200 return SPARROW_STATUS_QUO;
203 static const double GAMMA = 1.5;
204 static const double INV_GAMMA = 1.0 / 1.5;
205 static const double FALSE_CEILING = 275;
207 static void
208 init_gamma_lut(sparrow_play_t *player){
209 for (int i = 0; i < 256; i++){
210 /* for each colour:
211 1. perform inverse gamma calculation (-> linear colour space)
212 2. negate
213 3 undo gamma.
215 double x;
216 x = i / 255.01;
217 x = 1 - pow(x, INV_GAMMA);
218 x = pow(x, GAMMA) * FALSE_CEILING;
219 if (x > 255){
220 x = 255;
222 player->lut[i] = (guint8)x;
226 INVISIBLE void init_play(GstSparrow *sparrow){
227 GST_DEBUG("starting play mode\n");
228 init_jpeg_src(sparrow);
229 sparrow_play_t *player = zalloc_aligned_or_die(sizeof(sparrow_play_t));
230 player->image_row = zalloc_aligned_or_die(sparrow->out.width * PIXSIZE);
231 player->black_level = INITIAL_BLACK;
232 sparrow->helper_struct = player;
233 init_gamma_lut(player);
234 GST_DEBUG("finished init_play\n");
237 INVISIBLE void finalise_play(GstSparrow *sparrow){
238 GST_DEBUG("leaving play mode\n");