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.
20 #include "gstsparrow.h"
29 typedef struct sparrow_play_s
{
34 GstBuffer
*old_frames
[OLD_FRAMES
];
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
);
49 sparrow_frame_t
*old_frame
= &sparrow
->shared
->index
[player
->jpeg_index
];
50 int next
= old_frame
->successors
[0];
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
){
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
77 /*clamp in pseudo gamma space*/
78 int gj
= player
->lut_hi
[jpegpix
];
79 int gi
= player
->lut_hi
[inpix
];
83 return player
->lut_lo
[diff
];
87 int diff
= jpegpix
- inpix
;
94 int diff
= jpegpix
- inpix
;
96 return -diff
; /*or -diff /2 */
100 /* simplest possible (average)*/
101 guint sum
= player
->lut_hi
[inpix
] + jpegpix
;
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?
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]);
132 static inline guint8
one_subpixel_lagged(sparrow_play_t
*player
, guint8 inpix
,
133 guint8 jpegpix
, guint8 oldpix
){
135 int error
= MAX(inpix
- oldpix
, 0) >> 1;
136 int diff
= jpegpix
- error
;
143 static inline guint8
one_subpixel_lagged(sparrow_play_t
*player
, guint8 inpix
,
144 guint8 jpegpix
, guint8 oldpix
){
146 //jpegpix -= oldpix >> 1;
148 int target
= 2 * jpegpix
- oldpix
;
149 int diff
= (target
- inpix
) >> 1;
159 do_one_pixel_lagged(sparrow_play_t
*player
, guint8
*outpix
, guint8
*inpix
, guint8
*jpegpix
,
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]);
170 play_from_full_lut(GstSparrow
*sparrow
, guint8
*in
, guint8
*out
){
171 GST_DEBUG("play_from_full_lut\n");
173 memset(out
, 0, sparrow
->out
.size
); /*is this necessary? (only for outside
174 screen map, maybe in-loop might be
177 sparrow_play_t
*player
= sparrow
->helper_struct
;
180 guint32
*out32
= (guint32
*)out
;
181 guint32
*in32
= (guint32
*)in
;
182 set_up_jpeg(sparrow
, player
);
183 GST_DEBUG("in %p out %p", in
, out
);
185 guint8
*jpeg_row
= player
->image_row
;
187 for (oy
= 0; oy
< sparrow
->out
.height
; oy
++){
188 //GST_DEBUG("about to read line to %p", jpeg_row);
189 read_one_line(sparrow
, jpeg_row
);
190 for (ox
= 0; ox
< sparrow
->out
.width
; ox
++, i
++){
191 int x
= sparrow
->map_lut
[i
].x
;
192 int y
= sparrow
->map_lut
[i
].y
;
194 guint8
*inpix
= (guint8
*)&in32
[y
* sparrow
->in
.width
+ x
];
195 /*do_one_pixel(sparrow,
198 &jpeg_row[ox * PIXSIZE]);*/
199 do_one_pixel_lagged(player
,
202 &jpeg_row
[ox
* PIXSIZE
],
203 &old_frame
[i
* PIXSIZE
]
211 finish_reading_jpeg(sparrow
);
213 if (DEBUG_PLAY
&& sparrow
->debug
){
214 debug_frame(sparrow
, out
, sparrow
->out
.width
, sparrow
->out
.height
, PIXSIZE
);
219 store_old_frame(GstSparrow
*sparrow
, GstBuffer
*outbuf
){
220 sparrow_play_t
*player
= sparrow
->helper_struct
;
221 GstBuffer
*head
= player
->old_frames
[player
->old_frames_head
];
224 gst_buffer_ref(head
);
226 player
->old_frames_head
++;
227 player
->old_frames_head
%= OLD_FRAMES
;
231 drop_old_frame(GstSparrow
*sparrow
, GstBuffer
*outbuf
){
232 sparrow_play_t
*player
= sparrow
->helper_struct
;
233 GstBuffer
*tail
= player
->old_frames
[player
->old_frames_tail
];
235 gst_buffer_unref(tail
);
237 player
->old_frames_tail
++;
238 player
->old_frames_tail
%= OLD_FRAMES
;
242 INVISIBLE sparrow_state
243 mode_play(GstSparrow
*sparrow
, GstBuffer
*inbuf
, GstBuffer
*outbuf
){
244 guint8
*in
= GST_BUFFER_DATA(inbuf
);
245 guint8
*out
= GST_BUFFER_DATA(outbuf
);
246 store_old_frame(sparrow
, outbuf
);
247 play_from_full_lut(sparrow
, in
, out
);
248 drop_old_frame(sparrow
, outbuf
);
249 return SPARROW_STATUS_QUO
;
252 static const double GAMMA
= 1.5;
253 static const double INV_GAMMA
= 1.0 / 1.5;
254 static const double FALSE_CEILING
= 275;
257 init_gamma_lut(sparrow_play_t
*player
){
258 for (int i
= 0; i
< 256; i
++){
260 1. perform inverse gamma calculation (-> linear colour space)
266 x
= 1 - pow(x
, INV_GAMMA
);
267 x
= pow(x
, GAMMA
) * FALSE_CEILING
;
271 player
->lut
[i
] = (guint8
)x
;
275 INVISIBLE
void init_play(GstSparrow
*sparrow
){
276 GST_DEBUG("starting play mode\n");
277 init_jpeg_src(sparrow
);
278 sparrow_play_t
*player
= zalloc_aligned_or_die(sizeof(sparrow_play_t
));
279 player
->image_row
= zalloc_aligned_or_die(sparrow
->out
.width
* PIXSIZE
);
280 sparrow
->helper_struct
= player
;
281 init_gamma_lut(player
);
282 GST_DEBUG("finished init_play\n");
285 INVISIBLE
void finalise_play(GstSparrow
*sparrow
){
286 GST_DEBUG("leaving play mode\n");