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