1 /* GStreamer
2  * Copyright (C) 2009 Vincent Penquerc'h <ogg.k.ogg.k@googlemail.com>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
17  * Boston, MA 02110-1301, USA.
18  */
19 
20 #ifdef HAVE_CONFIG_H
21 #  include "config.h"
22 #endif
23 #include <string.h>
24 #include <kate/kate.h>
25 #include <gst/gst.h>
26 #include <gst/gstpad.h>
27 #include "gstkatespu.h"
28 
29 #define MAX_SPU_SIZE 53220
30 
31 GST_DEBUG_CATEGORY_EXTERN (gst_kateenc_debug);
32 GST_DEBUG_CATEGORY_EXTERN (gst_katedec_debug);
33 
34 /* taken off the dvdsubdec element */
35 const guint32 gst_kate_spu_default_clut[16] = {
36   0xb48080, 0x248080, 0x628080, 0xd78080,
37   0x808080, 0x808080, 0x808080, 0x808080,
38   0x808080, 0x808080, 0x808080, 0x808080,
39   0x808080, 0x808080, 0x808080, 0x808080
40 };
41 
42 #define GST_CAT_DEFAULT gst_kateenc_debug
43 
44 static void
gst_kate_spu_decode_colormap(GstKateEnc * ke,const guint8 * ptr)45 gst_kate_spu_decode_colormap (GstKateEnc * ke, const guint8 * ptr)
46 {
47   ke->spu_colormap[3] = ptr[0] >> 4;
48   ke->spu_colormap[2] = ptr[0] & 0x0f;
49   ke->spu_colormap[1] = ptr[1] >> 4;
50   ke->spu_colormap[0] = ptr[1] & 0x0f;
51 }
52 
53 static void
gst_kate_spu_decode_alpha(GstKateEnc * ke,const guint8 * ptr)54 gst_kate_spu_decode_alpha (GstKateEnc * ke, const guint8 * ptr)
55 {
56   ke->spu_alpha[3] = ptr[0] >> 4;
57   ke->spu_alpha[2] = ptr[0] & 0x0f;
58   ke->spu_alpha[1] = ptr[1] >> 4;
59   ke->spu_alpha[0] = ptr[1] & 0x0f;
60 }
61 
62 static void
gst_kate_spu_decode_area(GstKateEnc * ke,const guint8 * ptr)63 gst_kate_spu_decode_area (GstKateEnc * ke, const guint8 * ptr)
64 {
65   ke->spu_left = ((((guint16) ptr[0]) & 0xff) << 4) | (ptr[1] >> 4);
66   ke->spu_top = ((((guint16) ptr[3]) & 0xff) << 4) | (ptr[4] >> 4);
67   ke->spu_right = ((((guint16) ptr[1]) & 0x0f) << 8) | ptr[2];
68   ke->spu_bottom = ((((guint16) ptr[4]) & 0x0f) << 8) | ptr[5];
69   GST_DEBUG_OBJECT (ke, "SPU area %u %u -> %u %d", ke->spu_left, ke->spu_top,
70       ke->spu_right, ke->spu_bottom);
71 }
72 
73 static void
gst_kate_spu_decode_pixaddr(GstKateEnc * ke,const guint8 * ptr)74 gst_kate_spu_decode_pixaddr (GstKateEnc * ke, const guint8 * ptr)
75 {
76   ke->spu_pix_data[0] = GST_KATE_UINT16_BE (ptr + 0);
77   ke->spu_pix_data[1] = GST_KATE_UINT16_BE (ptr + 2);
78 }
79 
80 /* heavily inspired from dvdspudec */
81 static guint16
gst_kate_spu_decode_colcon(GstKateEnc * ke,const guint8 * ptr,guint16 sz)82 gst_kate_spu_decode_colcon (GstKateEnc * ke, const guint8 * ptr, guint16 sz)
83 {
84   guint16 nbytes = GST_KATE_UINT16_BE (ptr + 0);
85   guint16 nbytes_left = nbytes;
86 
87   GST_LOG_OBJECT (ke, "Number of bytes in color/contrast change command is %u",
88       nbytes);
89   if (G_UNLIKELY (nbytes < 2)) {
90     GST_WARNING_OBJECT (ke,
91         "Number of bytes in color/contrast change command is %u, should be at least 2",
92         nbytes);
93     return 0;
94   }
95   if (G_UNLIKELY (nbytes > sz)) {
96     GST_WARNING_OBJECT (ke,
97         "Number of bytes in color/contrast change command is %u, but the buffer "
98         "only contains %u byte(s)", nbytes, sz);
99     return 0;
100   }
101 
102   ptr += 2;
103   nbytes_left -= 2;
104 
105   /* we will just skip that data for now */
106   while (nbytes_left > 0) {
107     guint32 entry, nchanges, sz;
108     GST_LOG_OBJECT (ke, "Reading a color/contrast change entry, %u bytes left",
109         nbytes_left);
110     if (G_UNLIKELY (nbytes_left < 4)) {
111       GST_WARNING_OBJECT (ke,
112           "Not enough bytes to read a full color/contrast entry header");
113       break;
114     }
115     entry = GST_READ_UINT32_BE (ptr);
116     GST_LOG_OBJECT (ke, "Color/contrast change entry header is %08x", entry);
117     nchanges = CLAMP ((ptr[2] >> 4), 1, 8);
118     ptr += 4;
119     nbytes_left -= 4;
120     if (entry == 0x0fffffff) {
121       GST_LOG_OBJECT (ke,
122           "Encountered color/contrast change termination code, breaking, %u bytes left",
123           nbytes_left);
124       break;
125     }
126     GST_LOG_OBJECT (ke, "Color/contrast change entry has %u changes", nchanges);
127     sz = 6 * nchanges;
128     if (G_UNLIKELY (sz > nbytes_left)) {
129       GST_WARNING_OBJECT (ke,
130           "Not enough bytes to read a full color/contrast entry");
131       break;
132     }
133     ptr += sz;
134     nbytes_left -= sz;
135   }
136   return nbytes - nbytes_left;
137 }
138 
139 static inline guint8
gst_kate_spu_get_nybble(const guint8 * nybbles,size_t * nybble_offset)140 gst_kate_spu_get_nybble (const guint8 * nybbles, size_t * nybble_offset)
141 {
142   guint8 ret;
143 
144   ret = nybbles[(*nybble_offset) / 2];
145 
146   /* If the offset is even, we shift the answer down 4 bits, otherwise not */
147   if ((*nybble_offset) & 0x01)
148     ret &= 0x0f;
149   else
150     ret = ret >> 4;
151 
152   (*nybble_offset)++;
153 
154   return ret;
155 }
156 
157 static guint16
gst_kate_spu_get_rle_code(const guint8 * nybbles,size_t * nybble_offset)158 gst_kate_spu_get_rle_code (const guint8 * nybbles, size_t * nybble_offset)
159 {
160   guint16 code;
161 
162   code = gst_kate_spu_get_nybble (nybbles, nybble_offset);
163   if (code < 0x4) {             /* 4 .. f */
164     code = (code << 4) | gst_kate_spu_get_nybble (nybbles, nybble_offset);
165     if (code < 0x10) {          /* 1x .. 3x */
166       code = (code << 4) | gst_kate_spu_get_nybble (nybbles, nybble_offset);
167       if (code < 0x40) {        /* 04x .. 0fx */
168         code = (code << 4) | gst_kate_spu_get_nybble (nybbles, nybble_offset);
169       }
170     }
171   }
172   return code;
173 }
174 
175 static void
gst_kate_spu_crop_bitmap(GstKateEnc * ke,kate_bitmap * kb,guint16 * dx,guint16 * dy)176 gst_kate_spu_crop_bitmap (GstKateEnc * ke, kate_bitmap * kb, guint16 * dx,
177     guint16 * dy)
178 {
179   int top, bottom, left, right;
180   guint8 zero = 0;
181   size_t n, x, y, w, h;
182 
183 #if 0
184   /* find the zero */
185   zero = kb->pixels[0];
186   for (x = 0; x < kb->width; ++x) {
187     if (kb->pixels[x] != zero) {
188       GST_LOG_OBJECT (ke, "top line at %u is not zero: %u", x, kb->pixels[x]);
189       return;
190     }
191   }
192 #endif
193 
194   /* top */
195   for (top = 0; top < kb->height; ++top) {
196     int empty = 1;
197     for (x = 0; x < kb->width; ++x) {
198       if (G_UNLIKELY (kb->pixels[x + top * kb->width] != zero)) {
199         empty = 0;
200         break;
201       }
202     }
203     if (!empty)
204       break;
205   }
206 
207   /* bottom */
208   for (bottom = kb->height - 1; bottom >= top; --bottom) {
209     int empty = 1;
210     for (x = 0; x < kb->width; ++x) {
211       if (G_UNLIKELY (kb->pixels[x + bottom * kb->width] != zero)) {
212         empty = 0;
213         break;
214       }
215     }
216     if (!empty)
217       break;
218   }
219 
220   /* left */
221   for (left = 0; left < kb->width; ++left) {
222     int empty = 1;
223     for (y = top; y <= bottom; ++y) {
224       if (G_UNLIKELY (kb->pixels[left + y * kb->width] != zero)) {
225         empty = 0;
226         break;
227       }
228     }
229     if (!empty)
230       break;
231   }
232 
233   /* right */
234   for (right = kb->width - 1; right >= left; --right) {
235     int empty = 1;
236     for (y = top; y <= bottom; ++y) {
237       if (G_UNLIKELY (kb->pixels[right + y * kb->width] != zero)) {
238         empty = 0;
239         break;
240       }
241     }
242     if (!empty)
243       break;
244   }
245 
246 
247   w = right - left + 1;
248   h = bottom - top + 1;
249   GST_LOG_OBJECT (ke, "cropped from %" G_GSIZE_FORMAT " %" G_GSIZE_FORMAT
250       " to %" G_GSIZE_FORMAT " %" G_GSIZE_FORMAT, kb->width, kb->height, w, h);
251   *dx += left;
252   *dy += top;
253   n = 0;
254   for (y = 0; y < h; ++y) {
255     memmove (kb->pixels + n, kb->pixels + kb->width * (y + top) + left, w);
256     n += w;
257   }
258   kb->width = w;
259   kb->height = h;
260 }
261 
262 #define CHECK(x) G_STMT_START { \
263       guint16 _ = (x); \
264       if (G_UNLIKELY((_) > sz)) { \
265         GST_ELEMENT_ERROR (ke, STREAM, ENCODE, (NULL), ("Read outside buffer")); \
266         return GST_FLOW_ERROR; \
267       } \
268     } G_STMT_END
269 #define ADVANCE(x) G_STMT_START { \
270       guint16 _ = (x); ptr += (_); sz -= (_); \
271     } G_STMT_END
272 #define IGNORE(x) G_STMT_START { \
273       guint16 __ = (x); \
274       CHECK (__); \
275       ADVANCE (__); \
276     } G_STMT_END
277 
278 static GstFlowReturn
gst_kate_spu_decode_command_sequence(GstKateEnc * ke,GstBuffer * buf,guint16 command_sequence_offset)279 gst_kate_spu_decode_command_sequence (GstKateEnc * ke, GstBuffer * buf,
280     guint16 command_sequence_offset)
281 {
282   guint16 date;
283   guint16 next_command_sequence;
284   const guint8 *ptr;
285   GstMapInfo info;
286   guint16 sz;
287 
288   if (!gst_buffer_map (buf, &info, GST_MAP_READ)) {
289     GST_ERROR_OBJECT (ke, "Failed to map buffer");
290     return GST_FLOW_ERROR;
291   }
292 
293   if (command_sequence_offset >= info.size)
294     goto out_of_range;
295 
296   ptr = info.data + command_sequence_offset;
297   sz = info.size - command_sequence_offset;
298 
299   GST_DEBUG_OBJECT (ke, "Decoding command sequence at %u (%u bytes)",
300       command_sequence_offset, sz);
301 
302   CHECK (2);
303   date = GST_KATE_UINT16_BE (ptr);
304   ADVANCE (2);
305   GST_DEBUG_OBJECT (ke, "date %u", date);
306 
307   CHECK (2);
308   next_command_sequence = GST_KATE_UINT16_BE (ptr);
309   ADVANCE (2);
310   GST_DEBUG_OBJECT (ke, "next command sequence at %u", next_command_sequence);
311 
312   while (sz) {
313     guint8 cmd = *ptr++;
314     switch (cmd) {
315       case SPU_CMD_FSTA_DSP:   /* 0x00 */
316         GST_DEBUG_OBJECT (ke, "[0] DISPLAY");
317         break;
318       case SPU_CMD_DSP:        /* 0x01 */
319         GST_DEBUG_OBJECT (ke, "[1] SHOW");
320         ke->show_time = date;
321         break;
322       case SPU_CMD_STP_DSP:    /* 0x02 */
323         GST_DEBUG_OBJECT (ke, "[2] HIDE");
324         ke->hide_time = date;
325         break;
326       case SPU_CMD_SET_COLOR:  /* 0x03 */
327         GST_DEBUG_OBJECT (ke, "[3] SET COLOR");
328         CHECK (2);
329         gst_kate_spu_decode_colormap (ke, ptr);
330         ADVANCE (2);
331         break;
332       case SPU_CMD_SET_ALPHA:  /* 0x04 */
333         GST_DEBUG_OBJECT (ke, "[4] SET ALPHA");
334         CHECK (2);
335         gst_kate_spu_decode_alpha (ke, ptr);
336         ADVANCE (2);
337         break;
338       case SPU_CMD_SET_DAREA:  /* 0x05 */
339         GST_DEBUG_OBJECT (ke, "[5] SET DISPLAY AREA");
340         CHECK (6);
341         gst_kate_spu_decode_area (ke, ptr);
342         ADVANCE (6);
343         break;
344       case SPU_CMD_DSPXA:      /* 0x06 */
345         GST_DEBUG_OBJECT (ke, "[6] SET PIXEL ADDRESSES");
346         CHECK (4);
347         gst_kate_spu_decode_pixaddr (ke, ptr);
348         GST_DEBUG_OBJECT (ke, "  -> first pixel address %u",
349             ke->spu_pix_data[0]);
350         GST_DEBUG_OBJECT (ke, "  -> second pixel address %u",
351             ke->spu_pix_data[1]);
352         ADVANCE (4);
353         break;
354       case SPU_CMD_CHG_COLCON: /* 0x07 */
355         GST_DEBUG_OBJECT (ke, "[7] CHANGE COLOR/CONTRAST");
356         CHECK (2);
357         ADVANCE (gst_kate_spu_decode_colcon (ke, ptr, sz));
358         break;
359       case SPU_CMD_END:        /* 0xff */
360         GST_DEBUG_OBJECT (ke, "[0xff] END");
361         if (next_command_sequence != command_sequence_offset) {
362           GST_DEBUG_OBJECT (ke, "Jumping to next sequence at offset %u",
363               next_command_sequence);
364           gst_buffer_unmap (buf, &info);
365           return gst_kate_spu_decode_command_sequence (ke, buf,
366               next_command_sequence);
367         } else {
368           gst_buffer_unmap (buf, &info);
369           GST_DEBUG_OBJECT (ke, "No more sequences to decode");
370           return GST_FLOW_OK;
371         }
372         break;
373       default:
374         gst_buffer_unmap (buf, &info);
375         GST_ELEMENT_ERROR (ke, STREAM, ENCODE, (NULL),
376             ("Invalid SPU command: %u", cmd));
377         return GST_FLOW_ERROR;
378     }
379   }
380   gst_buffer_unmap (buf, &info);
381   GST_ELEMENT_ERROR (ke, STREAM, ENCODE, (NULL), ("Error parsing SPU"));
382   return GST_FLOW_ERROR;
383 
384   /* ERRORS */
385 out_of_range:
386   {
387     gst_buffer_unmap (buf, &info);
388     GST_ELEMENT_ERROR (ke, STREAM, DECODE, (NULL),
389         ("Command sequence offset %u is out of range %" G_GSIZE_FORMAT,
390             command_sequence_offset, info.size));
391     return GST_FLOW_ERROR;
392   }
393 }
394 
395 static inline int
gst_kate_spu_clamp(int value)396 gst_kate_spu_clamp (int value)
397 {
398   if (value < 0)
399     return 0;
400   if (value > 255)
401     return 255;
402   return value;
403 }
404 
405 static void
gst_kate_spu_yuv2rgb(int y,int u,int v,int * r,int * g,int * b)406 gst_kate_spu_yuv2rgb (int y, int u, int v, int *r, int *g, int *b)
407 {
408 #if 0
409   *r = gst_kate_spu_clamp (y + 1.371 * v);
410   *g = gst_kate_spu_clamp (y - 0.698 * v - 0.336 * u);
411   *b = gst_kate_spu_clamp (y + 1.732 * u);
412 #elif 0
413   *r = gst_kate_spu_clamp (y + u);
414   *g = gst_kate_spu_clamp (y - (76 * u - 26 * v) / 256);
415   *b = gst_kate_spu_clamp (y + v);
416 #else
417   y = (y - 16) * 255 / 219;
418   u = (u - 128) * 255 / 224;
419   v = (v - 128) * 255 / 224;
420 
421   *r = gst_kate_spu_clamp (y + 1.402 * v);
422   *g = gst_kate_spu_clamp (y - 0.34414 * u - 0.71414 * v);
423   *b = gst_kate_spu_clamp (y + 1.772 * u);
424 #endif
425 }
426 
427 static GstFlowReturn
gst_kate_spu_create_spu_palette(GstKateEnc * ke,kate_palette * kp)428 gst_kate_spu_create_spu_palette (GstKateEnc * ke, kate_palette * kp)
429 {
430   size_t n;
431 
432   kate_palette_init (kp);
433   kp->ncolors = 4;
434   kp->colors = (kate_color *) g_malloc (kp->ncolors * sizeof (kate_color));
435   if (G_UNLIKELY (!kp->colors)) {
436     GST_ELEMENT_ERROR (ke, STREAM, ENCODE, (NULL), ("Out of memory"));
437     return GST_FLOW_ERROR;
438   }
439 #if 1
440   for (n = 0; n < kp->ncolors; ++n) {
441     int idx = ke->spu_colormap[n];
442     guint32 color = ke->spu_clut[idx];
443     int y = (color >> 16) & 0xff;
444     int v = (color >> 8) & 0xff;
445     int u = color & 0xff;
446     int r, g, b;
447     gst_kate_spu_yuv2rgb (y, u, v, &r, &g, &b);
448     kp->colors[n].r = r;
449     kp->colors[n].g = g;
450     kp->colors[n].b = b;
451     kp->colors[n].a = ke->spu_alpha[n] * 17;
452   }
453 #else
454   /* just make a ramp from 0 to 255 for those non transparent colors */
455   for (n = 0; n < kp->ncolors; ++n)
456     if (ke->spu_alpha[n] == 0)
457       ++ntrans;
458 
459   for (n = 0; n < kp->ncolors; ++n) {
460     kp->colors[n].r = luma;
461     kp->colors[n].g = luma;
462     kp->colors[n].b = luma;
463     kp->colors[n].a = ke->spu_alpha[n] * 17;
464     if (ke->spu_alpha[n])
465       luma /= 2;
466   }
467 #endif
468 
469   return GST_FLOW_OK;
470 }
471 
472 GstFlowReturn
gst_kate_spu_decode_spu(GstKateEnc * ke,GstBuffer * buf,kate_region * kr,kate_bitmap * kb,kate_palette * kp)473 gst_kate_spu_decode_spu (GstKateEnc * ke, GstBuffer * buf, kate_region * kr,
474     kate_bitmap * kb, kate_palette * kp)
475 {
476   GstMapInfo info;
477   const guint8 *ptr;
478   size_t sz;
479   guint16 packet_size;
480   guint16 x, y;
481   size_t n;
482   guint8 *pixptr[2];
483   size_t nybble_offset[2];
484   size_t max_nybbles[2];
485   GstFlowReturn rflow;
486   guint16 next_command_sequence;
487   guint16 code;
488 
489   if (!gst_buffer_map (buf, &info, GST_MAP_READ)) {
490     GST_ERROR_OBJECT (ke, "Failed to map buffer");
491   }
492 
493   ptr = info.data;
494   sz = info.size;
495 
496   /* before decoding anything, initialize to sensible defaults */
497   memset (ke->spu_colormap, 0, sizeof (ke->spu_colormap));
498   memset (ke->spu_alpha, 0, sizeof (ke->spu_alpha));
499   ke->spu_top = ke->spu_left = 1;
500   ke->spu_bottom = ke->spu_right = 0;
501   ke->spu_pix_data[0] = ke->spu_pix_data[1] = 0;
502   ke->show_time = ke->hide_time = 0;
503 
504   /* read sizes and get to the start of the data */
505   CHECK (2);
506   packet_size = GST_KATE_UINT16_BE (ptr);
507   ADVANCE (2);
508   GST_DEBUG_OBJECT (ke, "packet size %d (GstBuffer size %" G_GSIZE_FORMAT ")",
509       packet_size, info.size);
510 
511   CHECK (2);
512   next_command_sequence = GST_KATE_UINT16_BE (ptr);
513   ADVANCE (2);
514   ptr = info.data + next_command_sequence;
515   sz = info.size - next_command_sequence;
516   GST_DEBUG_OBJECT (ke, "next command sequence at %u for %u",
517       next_command_sequence, (guint) sz);
518 
519   rflow = gst_kate_spu_decode_command_sequence (ke, buf, next_command_sequence);
520   if (G_UNLIKELY (rflow != GST_FLOW_OK)) {
521     gst_buffer_unmap (buf, &info);
522     return rflow;
523   }
524 
525   /* if no addresses or sizes were given, or if they define an empty SPU, nothing more to do */
526   if (G_UNLIKELY (ke->spu_right - ke->spu_left < 0
527           || ke->spu_bottom - ke->spu_top < 0 || ke->spu_pix_data[0] == 0
528           || ke->spu_pix_data[1] == 0)) {
529     GST_DEBUG_OBJECT (ke,
530         "left %d, right %d, top %d, bottom %d, pix data %d %d", ke->spu_left,
531         ke->spu_right, ke->spu_top, ke->spu_bottom, ke->spu_pix_data[0],
532         ke->spu_pix_data[1]);
533     GST_WARNING_OBJECT (ke, "SPU area is empty, nothing to encode");
534     kate_bitmap_init (kb);
535     kb->width = kb->height = 0;
536     gst_buffer_unmap (buf, &info);
537     return GST_FLOW_OK;
538   }
539 
540   /* create the palette */
541   rflow = gst_kate_spu_create_spu_palette (ke, kp);
542   if (G_UNLIKELY (rflow != GST_FLOW_OK)) {
543     gst_buffer_unmap (buf, &info);
544     return rflow;
545   }
546 
547   /* create the bitmap */
548   kate_bitmap_init (kb);
549   kb->width = ke->spu_right - ke->spu_left + 1;
550   kb->height = ke->spu_bottom - ke->spu_top + 1;
551   kb->bpp = 2;
552   kb->type = kate_bitmap_type_paletted;
553   kb->pixels = (unsigned char *) g_malloc (kb->width * kb->height);
554   if (G_UNLIKELY (!kb->pixels)) {
555     gst_buffer_unmap (buf, &info);
556     GST_ELEMENT_ERROR (ke, STREAM, ENCODE, (NULL),
557         ("Failed to allocate memory for pixel data"));
558     return GST_FLOW_ERROR;
559   }
560 
561   n = 0;
562   pixptr[0] = info.data + ke->spu_pix_data[0];
563   pixptr[1] = info.data + ke->spu_pix_data[1];
564   nybble_offset[0] = 0;
565   nybble_offset[1] = 0;
566   max_nybbles[0] = 2 * (packet_size - ke->spu_pix_data[0]);
567   max_nybbles[1] = 2 * (packet_size - ke->spu_pix_data[1]);
568   for (y = 0; y < kb->height; ++y) {
569     nybble_offset[y & 1] = GST_ROUND_UP_2 (nybble_offset[y & 1]);
570     for (x = 0; x < kb->width;) {
571       if (G_UNLIKELY (nybble_offset[y & 1] >= max_nybbles[y & 1])) {
572         GST_DEBUG_OBJECT (ke, "RLE overflow, clearing the remainder");
573         memset (kb->pixels + n, 0, kb->width - x);
574         n += kb->width - x;
575         break;
576       }
577       code = gst_kate_spu_get_rle_code (pixptr[y & 1], &nybble_offset[y & 1]);
578       if (code == 0) {
579         memset (kb->pixels + n, 0, kb->width - x);
580         n += kb->width - x;
581         break;
582       } else {
583         guint16 npixels = code >> 2;
584         guint16 pixel = code & 3;
585         if (npixels > kb->width - x) {
586           npixels = kb->width - x;
587         }
588         memset (kb->pixels + n, pixel, npixels);
589         n += npixels;
590         x += npixels;
591       }
592     }
593   }
594 
595   GST_LOG_OBJECT (ke, "%u/%u bytes left in the data packet",
596       (guint) (max_nybbles[0] - nybble_offset[0]),
597       (guint) (max_nybbles[1] - nybble_offset[1]));
598 
599   /* some streams seem to have huge uncropped SPUs, fix those up */
600   x = ke->spu_left;
601   y = ke->spu_top;
602   gst_kate_spu_crop_bitmap (ke, kb, &x, &y);
603 
604   /* create the region */
605   kate_region_init (kr);
606   if (ke->original_canvas_width > 0 && ke->original_canvas_height > 0) {
607     /* prefer relative sizes in case we're encoding for a different resolution
608        that what the SPU was created for */
609     kr->metric = kate_millionths;
610     kr->x = 1000000 * (size_t) x / ke->original_canvas_width;
611     kr->y = 1000000 * (size_t) y / ke->original_canvas_height;
612     kr->w = 1000000 * kb->width / ke->original_canvas_width;
613     kr->h = 1000000 * kb->height / ke->original_canvas_height;
614   } else {
615     kr->metric = kate_pixel;
616     kr->x = x;
617     kr->y = y;
618     kr->w = kb->width;
619     kr->h = kb->height;
620   }
621 
622   /* some SPUs have no hide time */
623   if (ke->hide_time == 0) {
624     GST_INFO_OBJECT (ke, "SPU has no hide time");
625     /* now, we don't know when the next SPU is scheduled to go, since we probably
626        haven't received it yet, so we'll just make it a 1 second delay, which is
627        probably going to end before the next one while being readable */
628     //ke->hide_time = ke->show_time + (1000 * 90 / 1024);
629   }
630   gst_buffer_unmap (buf, &info);
631 
632   return GST_FLOW_OK;
633 }
634 
635 #undef IGNORE
636 #undef ADVANCE
637 #undef CHECK
638 
639 #undef GST_CAT_DEFAULT
640 #define GST_CAT_DEFAULT gst_katedec_debug
641 
642 static void
gst_kate_spu_add_nybble(unsigned char * bytes,size_t nbytes,int nybble_offset,unsigned char nybble)643 gst_kate_spu_add_nybble (unsigned char *bytes, size_t nbytes, int nybble_offset,
644     unsigned char nybble)
645 {
646   unsigned char *ptr = bytes + nbytes + nybble_offset / 2;
647   if (!(nybble_offset & 1)) {
648     *ptr = nybble << 4;
649   } else {
650     *ptr |= nybble;
651   }
652 }
653 
654 static void
gst_kate_spu_rgb2yuv(int r,int g,int b,int * y,int * u,int * v)655 gst_kate_spu_rgb2yuv (int r, int g, int b, int *y, int *u, int *v)
656 {
657   *y = gst_kate_spu_clamp (r * 0.299 * 219 / 255 + g * 0.587 * 219 / 255 +
658       b * 0.114 * 219 / 255 + 16);
659   *u = gst_kate_spu_clamp (-r * 0.16874 * 224 / 255 - g * 0.33126 * 224 / 255 +
660       b * 0.5 * 224 / 255 + 128);
661   *v = gst_kate_spu_clamp (r * 0.5 * 224 / 255 - g * 0.41869 * 224 / 255 -
662       b * 0.08131 * 224 / 255 + 128);
663 }
664 
665 static void
gst_kate_spu_make_palette(GstKateDec * kd,int palette[4],const kate_palette * kp)666 gst_kate_spu_make_palette (GstKateDec * kd, int palette[4],
667     const kate_palette * kp)
668 {
669   int n;
670   GstStructure *structure;
671   GstEvent *event;
672   char name[16];
673   int y, u, v;
674 
675   palette[0] = 0;
676   palette[1] = 1;
677   palette[2] = 2;
678   palette[3] = 3;
679 
680   structure = gst_structure_new ("application/x-gst-dvd",
681       "event", G_TYPE_STRING, "dvd-spu-clut-change", NULL);
682 
683   /* Create a separate field for each value in the table. */
684   for (n = 0; n < 16; n++) {
685     guint32 color = 0;
686     if (n < 4) {
687       gst_kate_spu_rgb2yuv (kp->colors[n].r, kp->colors[n].g, kp->colors[n].b,
688           &y, &u, &v);
689       color = (y << 16) | (v << 8) | u;
690     }
691     g_snprintf (name, sizeof (name), "clut%02d", n);
692     gst_structure_set (structure, name, G_TYPE_INT, (int) color, NULL);
693   }
694 
695   /* Create the DVD event and put the structure into it. */
696   event = gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, structure);
697 
698   GST_LOG_OBJECT (kd, "preparing clut change event %" GST_PTR_FORMAT, event);
699   gst_pad_push_event (kd->srcpad, event);
700 }
701 
702 GstBuffer *
gst_kate_spu_encode_spu(GstKateDec * kd,const kate_event * ev)703 gst_kate_spu_encode_spu (GstKateDec * kd, const kate_event * ev)
704 {
705   kate_tracker kin;
706   unsigned char *bytes = NULL;
707   size_t nbytes = 0;
708   GstBuffer *buffer = NULL;
709   int ret;
710   int ocw, och;
711   int top, left, right, bottom;
712   int pass, line, row;
713   int lines_offset[2];
714   int first_commands_offset, second_commands_offset;
715   int nybble_count;
716   const kate_bitmap *kb;
717   const kate_palette *kp;
718   int palette[4];
719   int delay;
720 
721   /* we need a region, a bitmap, and a palette */
722   if (!ev || !ev->region || !ev->bitmap || !ev->palette)
723     return NULL;
724 
725   kb = ev->bitmap;
726   kp = ev->palette;
727 
728   /* these need particular properties */
729   if (kb->type != kate_bitmap_type_paletted || kb->bpp != 2)
730     return NULL;
731   if (kp->ncolors != 4)
732     return NULL;
733 
734   ret = kate_tracker_init (&kin, ev->ki, ev);
735   if (ret < 0) {
736     GST_WARNING_OBJECT (kd, "Failed to initialize kate tracker");
737     return NULL;
738   }
739 
740   ocw = ev->ki->original_canvas_width;
741   och = ev->ki->original_canvas_height;
742   ret = kate_tracker_update (&kin, (kate_float) 0, ocw, och, 0, 0, ocw, och);
743   if (ret < 0)
744     goto error;
745 
746   if (kin.has.region) {
747     top = (int) (kin.region_y + (kate_float) 0.5);
748     left = (int) (kin.region_x + (kate_float) 0.5);
749   } else {
750     GST_WARNING_OBJECT (kd,
751         "No region information to place SPU, placing at 0 0");
752     top = left = 0;
753   }
754   right = left + kb->width - 1;
755   bottom = top + kb->height - 1;
756 
757   /* Allocate space to build the SPU */
758   bytes = g_malloc (MAX_SPU_SIZE);
759   if (G_UNLIKELY (!bytes)) {
760     GST_WARNING_OBJECT (kd,
761         "Failed to allocate %" G_GSIZE_FORMAT " byte buffer", nbytes);
762     goto error;
763   }
764   nbytes = 4;
765   nybble_count = 0;
766 
767 #define CHKBUFSPC(nybbles) \
768   do { \
769     if ((nbytes + (nybbles + nybble_count + 1) / 2) > MAX_SPU_SIZE) { \
770       GST_WARNING_OBJECT (kd, "Not enough space in SPU buffer"); \
771       goto error; \
772     } \
773   } while(0)
774 
775   /* encode lines */
776   for (pass = 0; pass <= 1; ++pass) {
777     lines_offset[pass] = nbytes;
778     for (line = pass; line < bottom - top + 1; line += 2) {
779       const unsigned char *ptr = kb->pixels + line * kb->width;
780       for (row = 0; row < kb->width;) {
781         int run = 1;
782         while (row + run < kb->width && run < 255 && ptr[row + run] == ptr[row])
783           ++run;
784         if (run >= 63 && row + run == kb->width) {
785           /* special end of line marker */
786           CHKBUFSPC (4);
787           gst_kate_spu_add_nybble (bytes, nbytes, nybble_count++, 0);
788           gst_kate_spu_add_nybble (bytes, nbytes, nybble_count++, 0);
789           gst_kate_spu_add_nybble (bytes, nbytes, nybble_count++, 0);
790           gst_kate_spu_add_nybble (bytes, nbytes, nybble_count++, ptr[row]);
791         } else if (run >= 1 && run <= 3) {
792           CHKBUFSPC (1);
793           gst_kate_spu_add_nybble (bytes, nbytes, nybble_count++,
794               (run << 2) | ptr[row]);
795         } else if (run <= 15) {
796           CHKBUFSPC (2);
797           gst_kate_spu_add_nybble (bytes, nbytes, nybble_count++, run >> 2);
798           gst_kate_spu_add_nybble (bytes, nbytes, nybble_count++,
799               ((run & 3) << 2) | ptr[row]);
800         } else if (run <= 63) {
801           CHKBUFSPC (3);
802           gst_kate_spu_add_nybble (bytes, nbytes, nybble_count++, 0);
803           gst_kate_spu_add_nybble (bytes, nbytes, nybble_count++, run >> 2);
804           gst_kate_spu_add_nybble (bytes, nbytes, nybble_count++,
805               ((run & 3) << 2) | ptr[row]);
806         } else {
807           CHKBUFSPC (4);
808           gst_kate_spu_add_nybble (bytes, nbytes, nybble_count++, 0);
809           gst_kate_spu_add_nybble (bytes, nbytes, nybble_count++, (run >> 6));
810           gst_kate_spu_add_nybble (bytes, nbytes, nybble_count++,
811               (run >> 2) & 0xf);
812           gst_kate_spu_add_nybble (bytes, nbytes, nybble_count++,
813               ((run & 3) << 2) | ptr[row]);
814         }
815         row += run;
816       }
817       if (nybble_count & 1) {
818         CHKBUFSPC (1);
819         gst_kate_spu_add_nybble (bytes, nbytes, nybble_count++, 0);
820       }
821       nbytes += nybble_count / 2;
822       nybble_count = 0;
823     }
824   }
825   first_commands_offset = nbytes;
826 
827   gst_kate_spu_make_palette (kd, palette, kp);
828 
829   /* Commands header */
830   CHKBUFSPC (4 * 2);
831   bytes[nbytes++] = 0;
832   bytes[nbytes++] = 0;
833   /* link to next command chunk will be filled later, when we know where it is */
834   bytes[nbytes++] = 0;
835   bytes[nbytes++] = 0;
836 
837   CHKBUFSPC (3 * 2);
838   bytes[nbytes++] = SPU_CMD_SET_COLOR;
839   bytes[nbytes++] = (palette[3] << 4) | palette[2];
840   bytes[nbytes++] = (palette[1] << 4) | palette[0];
841 
842   CHKBUFSPC (3 * 2);
843   bytes[nbytes++] = SPU_CMD_SET_ALPHA;
844   bytes[nbytes++] =
845       ((kp->colors[palette[3]].a / 17) << 4) | (kp->colors[palette[2]].a / 17);
846   bytes[nbytes++] =
847       ((kp->colors[palette[1]].a / 17) << 4) | (kp->colors[palette[0]].a / 17);
848 
849   CHKBUFSPC (7 * 2);
850   bytes[nbytes++] = SPU_CMD_SET_DAREA;
851   bytes[nbytes++] = left >> 4;
852   bytes[nbytes++] = ((left & 0xf) << 4) | (right >> 8);
853   bytes[nbytes++] = right & 0xff;
854   bytes[nbytes++] = top >> 4;
855   bytes[nbytes++] = ((top & 0xf) << 4) | (bottom >> 8);
856   bytes[nbytes++] = bottom & 0xff;
857 
858   CHKBUFSPC (5 * 2);
859   bytes[nbytes++] = SPU_CMD_DSPXA;
860   bytes[nbytes++] = (lines_offset[0] >> 8) & 0xff;
861   bytes[nbytes++] = lines_offset[0] & 0xff;
862   bytes[nbytes++] = (lines_offset[1] >> 8) & 0xff;
863   bytes[nbytes++] = lines_offset[1] & 0xff;
864 
865   CHKBUFSPC (1 * 2);
866   bytes[nbytes++] = SPU_CMD_DSP;
867 
868   CHKBUFSPC (1 * 2);
869   bytes[nbytes++] = SPU_CMD_END;
870 
871   /* stop display chunk */
872   CHKBUFSPC (4 * 2);
873   second_commands_offset = nbytes;
874   bytes[first_commands_offset + 2] = (second_commands_offset >> 8) & 0xff;
875   bytes[first_commands_offset + 3] = second_commands_offset & 0xff;
876   delay = GST_KATE_GST_TO_STM (ev->end_time - ev->start_time);
877   bytes[nbytes++] = (delay >> 8) & 0xff;
878   bytes[nbytes++] = delay & 0xff;
879   /* close the loop by linking back to self */
880   bytes[nbytes++] = (second_commands_offset >> 8) & 0xff;
881   bytes[nbytes++] = second_commands_offset & 0xff;
882 
883   CHKBUFSPC (1 * 2);
884   bytes[nbytes++] = SPU_CMD_STP_DSP;
885 
886   CHKBUFSPC (1 * 2);
887   bytes[nbytes++] = SPU_CMD_END;
888 
889   /* Now that we know the size of the SPU, update the size and pointers */
890   bytes[0] = (nbytes >> 8) & 0xff;
891   bytes[1] = nbytes & 0xff;
892   bytes[2] = (first_commands_offset >> 8) & 0xff;
893   bytes[3] = first_commands_offset & 0xff;
894 
895   /* Create a buffer with those values */
896   buffer = gst_buffer_new_wrapped (bytes, nbytes);
897   if (G_UNLIKELY (!buffer)) {
898     GST_WARNING_OBJECT (kd,
899         "Failed to allocate %" G_GSIZE_FORMAT " byte buffer", nbytes);
900     goto error;
901   }
902   GST_BUFFER_OFFSET_END (buffer) = GST_SECOND * (ev->end_time);
903   GST_BUFFER_OFFSET (buffer) = GST_SECOND * (ev->start_time);
904   GST_BUFFER_TIMESTAMP (buffer) = GST_SECOND * (ev->start_time);
905   GST_BUFFER_DURATION (buffer) = GST_SECOND * (ev->end_time - ev->start_time);
906 
907   GST_DEBUG_OBJECT (kd, "SPU uses %" G_GSIZE_FORMAT " bytes", nbytes);
908 
909   kate_tracker_clear (&kin);
910   return buffer;
911 
912 error:
913   kate_tracker_clear (&kin);
914   g_free (bytes);
915   return NULL;
916 }
917