2 * Copyright (C) 2009 Vincent Penquerc'h <ogg.k.ogg.k@googlemail.com>
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.
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.
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.
24 #include <kate/kate.h>
26 #include <gst/gstpad.h>
27 #include "gstkatespu.h"
29 #define MAX_SPU_SIZE 53220
31 GST_DEBUG_CATEGORY_EXTERN (gst_kateenc_debug);
32 GST_DEBUG_CATEGORY_EXTERN (gst_katedec_debug);
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
42 #define GST_CAT_DEFAULT gst_kateenc_debug
45 gst_kate_spu_decode_colormap (GstKateEnc * ke, const guint8 * ptr)
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;
54 gst_kate_spu_decode_alpha (GstKateEnc * ke, const guint8 * ptr)
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;
63 gst_kate_spu_decode_area (GstKateEnc * ke, const guint8 * ptr)
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);
74 gst_kate_spu_decode_pixaddr (GstKateEnc * ke, const guint8 * ptr)
76 ke->spu_pix_data[0] = GST_KATE_UINT16_BE (ptr + 0);
77 ke->spu_pix_data[1] = GST_KATE_UINT16_BE (ptr + 2);
80 /* heavily inspired from dvdspudec */
82 gst_kate_spu_decode_colcon (GstKateEnc * ke, const guint8 * ptr)
84 guint16 nbytes = GST_KATE_UINT16_BE (ptr + 0);
85 guint16 nbytes_left = nbytes;
87 GST_LOG_OBJECT (ke, "Number of bytes in color/contrast change command is %u",
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",
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",
104 if (G_UNLIKELY (nbytes_left < 4)) {
105 GST_WARNING_OBJECT (ke,
106 "Not enough bytes to read a full color/contrast entry header");
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);
114 if (entry == 0x0fffffff) {
116 "Encountered color/contrast change termination code, breaking, %u bytes left",
120 GST_LOG_OBJECT (ke, "Color/contrast change entry has %u changes", nchanges);
122 if (G_UNLIKELY (sz > nbytes_left)) {
123 GST_WARNING_OBJECT (ke,
124 "Not enough bytes to read a full color/contrast entry");
130 return nbytes - nbytes_left;
134 gst_kate_spu_get_nybble (const guint8 * nybbles, size_t * nybble_offset)
138 ret = nybbles[(*nybble_offset) / 2];
140 /* If the offset is even, we shift the answer down 4 bits, otherwise not */
141 if ((*nybble_offset) & 0x01)
152 gst_kate_spu_get_rle_code (const guint8 * nybbles, size_t * nybble_offset)
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);
170 gst_kate_spu_crop_bitmap (GstKateEnc * ke, kate_bitmap * kb, guint16 * dx,
173 int top, bottom, left, right;
175 size_t n, x, y, w, h;
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]);
189 for (top = 0; top < kb->height; ++top) {
191 for (x = 0; x < kb->width; ++x) {
192 if (G_UNLIKELY (kb->pixels[x + top * kb->width] != zero)) {
202 for (bottom = kb->height - 1; bottom >= top; --bottom) {
204 for (x = 0; x < kb->width; ++x) {
205 if (G_UNLIKELY (kb->pixels[x + bottom * kb->width] != zero)) {
215 for (left = 0; left < kb->width; ++left) {
217 for (y = top; y <= bottom; ++y) {
218 if (G_UNLIKELY (kb->pixels[left + y * kb->width] != zero)) {
228 for (right = kb->width - 1; right >= left; --right) {
230 for (y = top; y <= bottom; ++y) {
231 if (G_UNLIKELY (kb->pixels[right + y * kb->width] != zero)) {
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);
248 for (y = 0; y < h; ++y) {
249 memmove (kb->pixels + n, kb->pixels + kb->width * (y + top) + left, w);
256 #define CHECK(x) G_STMT_START { \
258 if (G_UNLIKELY((_) > sz)) { \
259 GST_ELEMENT_ERROR (ke, STREAM, ENCODE, (NULL), ("Read outside buffer")); \
260 return GST_FLOW_ERROR; \
263 #define ADVANCE(x) G_STMT_START { \
264 guint16 _ = (x); ptr += (_); sz -= (_); \
266 #define IGNORE(x) G_STMT_START { \
273 gst_kate_spu_decode_command_sequence (GstKateEnc * ke, GstBuffer * buf,
274 guint16 command_sequence_offset)
277 guint16 next_command_sequence;
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;
288 ptr = GST_BUFFER_DATA (buf) + command_sequence_offset;
289 sz = GST_BUFFER_SIZE (buf) - command_sequence_offset;
291 GST_DEBUG_OBJECT (ke, "Decoding command sequence at %u (%u bytes)",
292 command_sequence_offset, sz);
295 date = GST_KATE_UINT16_BE (ptr);
297 GST_DEBUG_OBJECT (ke, "date %u", date);
300 next_command_sequence = GST_KATE_UINT16_BE (ptr);
302 GST_DEBUG_OBJECT (ke, "next command sequence at %u", next_command_sequence);
307 case SPU_CMD_FSTA_DSP: /* 0x00 */
308 GST_DEBUG_OBJECT (ke, "[0] DISPLAY");
310 case SPU_CMD_DSP: /* 0x01 */
311 GST_DEBUG_OBJECT (ke, "[1] SHOW");
312 ke->show_time = date;
314 case SPU_CMD_STP_DSP: /* 0x02 */
315 GST_DEBUG_OBJECT (ke, "[2] HIDE");
316 ke->hide_time = date;
318 case SPU_CMD_SET_COLOR: /* 0x03 */
319 GST_DEBUG_OBJECT (ke, "[3] SET COLOR");
321 gst_kate_spu_decode_colormap (ke, ptr);
324 case SPU_CMD_SET_ALPHA: /* 0x04 */
325 GST_DEBUG_OBJECT (ke, "[4] SET ALPHA");
327 gst_kate_spu_decode_alpha (ke, ptr);
330 case SPU_CMD_SET_DAREA: /* 0x05 */
331 GST_DEBUG_OBJECT (ke, "[5] SET DISPLAY AREA");
333 gst_kate_spu_decode_area (ke, ptr);
336 case SPU_CMD_DSPXA: /* 0x06 */
337 GST_DEBUG_OBJECT (ke, "[6] SET PIXEL ADDRESSES");
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]);
346 case SPU_CMD_CHG_COLCON: /* 0x07 */
347 GST_DEBUG_OBJECT (ke, "[7] CHANGE COLOR/CONTRAST");
349 ADVANCE (gst_kate_spu_decode_colcon (ke, ptr));
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);
359 GST_DEBUG_OBJECT (ke, "No more sequences to decode");
364 GST_ELEMENT_ERROR (ke, STREAM, ENCODE, (NULL),
365 ("Invalid SPU command: %u", cmd));
366 return GST_FLOW_ERROR;
369 GST_ELEMENT_ERROR (ke, STREAM, ENCODE, (NULL), ("Error parsing SPU"));
370 return GST_FLOW_ERROR;
374 gst_kate_spu_clamp (int value)
384 gst_kate_spu_yuv2rgb (int y, int u, int v, int *r, int *g, int *b)
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);
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);
395 y = (y - 16) * 255 / 219;
396 u = (u - 128) * 255 / 224;
397 v = (v - 128) * 255 / 224;
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);
406 gst_kate_spu_create_spu_palette (GstKateEnc * ke, kate_palette * kp)
410 kate_palette_init (kp);
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;
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;
425 gst_kate_spu_yuv2rgb (y, u, v, &r, &g, &b);
429 kp->colors[n].a = ke->spu_alpha[n] * 17;
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)
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])
451 gst_kate_spu_decode_spu (GstKateEnc * ke, GstBuffer * buf, kate_region * kr,
452 kate_bitmap * kb, kate_palette * kp)
454 const guint8 *ptr = GST_BUFFER_DATA (buf);
455 size_t sz = GST_BUFFER_SIZE (buf);
460 size_t nybble_offset[2];
461 size_t max_nybbles[2];
463 guint16 next_command_sequence;
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;
474 /* read sizes and get to the start of the data */
476 packet_size = GST_KATE_UINT16_BE (ptr);
478 GST_DEBUG_OBJECT (ke, "packet size %u (GstBuffer size %u)", packet_size,
479 GST_BUFFER_SIZE (buf));
482 next_command_sequence = GST_KATE_UINT16_BE (ptr);
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);
489 rflow = gst_kate_spu_decode_command_sequence (ke, buf, next_command_sequence);
490 if (G_UNLIKELY (rflow != GST_FLOW_OK))
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;
507 /* create the palette */
508 rflow = gst_kate_spu_create_spu_palette (ke, kp);
509 if (G_UNLIKELY (rflow != GST_FLOW_OK))
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;
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;
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);
541 code = gst_kate_spu_get_rle_code (pixptr[y & 1], &nybble_offset[y & 1]);
543 memset (kb->pixels + n, 0, kb->width - x);
547 guint16 npixels = code >> 2;
548 guint16 pixel = code & 3;
549 if (npixels > kb->width - x) {
550 npixels = kb->width - x;
552 memset (kb->pixels + n, pixel, npixels);
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]));
563 /* some streams seem to have huge uncropped SPUs, fix those up */
566 gst_kate_spu_crop_bitmap (ke, kb, &x, &y);
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;
579 kr->metric = kate_pixel;
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);
602 #undef GST_CAT_DEFAULT
603 #define GST_CAT_DEFAULT gst_katedec_debug
606 gst_kate_spu_add_nybble (unsigned char *bytes, size_t nbytes, int nybble_offset,
607 unsigned char nybble)
609 unsigned char *ptr = bytes + nbytes + nybble_offset / 2;
610 if (!(nybble_offset & 1)) {
618 gst_kate_spu_rgb2yuv (int r, int g, int b, int *y, int *u, int *v)
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);
629 gst_kate_spu_make_palette (GstKateDec * kd, int palette[4],
630 const kate_palette * kp)
633 GstStructure *structure;
643 structure = gst_structure_new ("application/x-gst-dvd",
644 "event", G_TYPE_STRING, "dvd-spu-clut-change", NULL);
646 /* Create a separate field for each value in the table. */
647 for (n = 0; n < 16; n++) {
650 gst_kate_spu_rgb2yuv (kp->colors[n].r, kp->colors[n].g, kp->colors[n].b,
652 color = (y << 16) | (v << 8) | u;
654 g_snprintf (name, sizeof (name), "clut%02d", n);
655 gst_structure_set (structure, name, G_TYPE_INT, (int) color, NULL);
658 /* Create the DVD event and put the structure into it. */
659 event = gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, structure);
661 GST_LOG_OBJECT (kd, "preparing clut change event %" GST_PTR_FORMAT, event);
662 gst_pad_push_event (kd->srcpad, event);
666 gst_kate_spu_encode_spu (GstKateDec * kd, const kate_event * ev)
669 unsigned char *bytes = NULL;
671 GstBuffer *buffer = NULL;
674 int top, left, right, bottom;
677 int first_commands_offset, second_commands_offset;
679 const kate_bitmap *kb;
680 const kate_palette *kp;
684 /* we need a region, a bitmap, and a palette */
685 if (!ev || !ev->region || !ev->bitmap || !ev->palette)
691 /* these need particular properties */
692 if (kb->type != kate_bitmap_type_paletted || kb->bpp != 2)
694 if (kp->ncolors != 4)
697 ret = kate_tracker_init (&kin, ev->ki, ev);
699 GST_WARNING_OBJECT (kd, "Failed to initialize kate tracker");
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);
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);
713 GST_WARNING_OBJECT (kd,
714 "No region information to place SPU, placing at 0 0");
717 right = left + kb->width - 1;
718 bottom = top + kb->height - 1;
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);
730 #define CHKBUFSPC(nybbles) \
732 if ((nbytes + (nybbles + nybble_count + 1) / 2) > MAX_SPU_SIZE) { \
733 GST_WARNING_OBJECT (kd, "Not enough space in SPU buffer"); \
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;) {
745 while (row + run < kb->width && run < 255 && ptr[row + run] == ptr[row])
747 if (run >= 63 && row + run == kb->width) {
748 /* special end of line marker */
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) {
756 gst_kate_spu_add_nybble (bytes, nbytes, nybble_count++,
757 (run << 2) | ptr[row]);
758 } else if (run <= 15) {
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) {
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]);
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++,
775 gst_kate_spu_add_nybble (bytes, nbytes, nybble_count++,
776 ((run & 3) << 2) | ptr[row]);
780 if (nybble_count & 1) {
782 gst_kate_spu_add_nybble (bytes, nbytes, nybble_count++, 0);
784 nbytes += nybble_count / 2;
788 first_commands_offset = nbytes;
790 gst_kate_spu_make_palette (kd, palette, kp);
792 /* Commands header */
796 /* link to next command chunk will be filled later, when we know where it is */
801 bytes[nbytes++] = SPU_CMD_SET_COLOR;
802 bytes[nbytes++] = (palette[3] << 4) | palette[2];
803 bytes[nbytes++] = (palette[1] << 4) | palette[0];
806 bytes[nbytes++] = SPU_CMD_SET_ALPHA;
808 ((kp->colors[palette[3]].a / 17) << 4) | (kp->colors[palette[2]].a / 17);
810 ((kp->colors[palette[1]].a / 17) << 4) | (kp->colors[palette[0]].a / 17);
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;
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;
829 bytes[nbytes++] = SPU_CMD_DSP;
832 bytes[nbytes++] = SPU_CMD_END;
834 /* stop display chunk */
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;
847 bytes[nbytes++] = SPU_CMD_STP_DSP;
850 bytes[nbytes++] = SPU_CMD_END;
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;
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);
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);
873 GST_DEBUG_OBJECT (kd, "SPU uses %" G_GSIZE_FORMAT " bytes", nbytes);
875 kate_tracker_clear (&kin);
879 kate_tracker_clear (&kin);