summaryrefslogtreecommitdiffstats
path: root/gst/dvdspu/gstspu-pgs.c
diff options
context:
space:
mode:
authorJan Schmidt <thaytan@noraisin.net>2009-05-20 08:55:40 +0100
committerJan Schmidt <thaytan@noraisin.net>2009-05-26 15:31:54 +0100
commit4e847cb4acd356112f56a101132d8438abe9fa03 (patch)
tree20c10a71131bcd6463cdf807ba659715b999ee6a /gst/dvdspu/gstspu-pgs.c
parent78cd406a76c71b2ebe5457e838471cd209afd6d0 (diff)
downloadgst-plugins-bad-4e847cb4acd356112f56a101132d8438abe9fa03.tar.gz
gst-plugins-bad-4e847cb4acd356112f56a101132d8438abe9fa03.tar.bz2
gst-plugins-bad-4e847cb4acd356112f56a101132d8438abe9fa03.zip
dvdspu: Add simple PGS handler that dumps the packet info
Add setcaps logic on the subpicture sink pad for configuring which subpicture format is arriving. Add the first piece of PGS subpicture handling by dumping the stream contents out to the terminal as the packets arrive. Add some more debug. Don't calculate the running time for our subpicture packets twice, once is enough.
Diffstat (limited to 'gst/dvdspu/gstspu-pgs.c')
-rw-r--r--gst/dvdspu/gstspu-pgs.c434
1 files changed, 434 insertions, 0 deletions
diff --git a/gst/dvdspu/gstspu-pgs.c b/gst/dvdspu/gstspu-pgs.c
new file mode 100644
index 00000000..de6a4151
--- /dev/null
+++ b/gst/dvdspu/gstspu-pgs.c
@@ -0,0 +1,434 @@
+#include <fcntl.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+
+#include <glib.h>
+#include <gst/gst.h>
+
+#include "gstspu-pgs.h"
+
+const struct PgsFrameRateEntry
+{
+ guint8 id;
+ guint fps_n;
+ guint fps_d;
+} PgsFrameRates[] = {
+ {
+ 64, 30000, 1001} /* 29.97 FPS */
+};
+
+gboolean in_presentation_segment = FALSE;
+guint8 *rle_data = NULL;
+guint32 rle_data_size = 0, rle_data_used = 0;
+PgsPaletteEntry palette[256];
+
+static void
+dump_bytes (guint8 * data, guint16 len)
+{
+ gint i;
+
+ /* Dump the numbers */
+ for (i = 0; i < len; i++) {
+ g_print ("0x%02x ", data[i]);
+ if (!((i + 1) % 16))
+ g_print ("\n");
+ }
+ if (len > 0 && (i % 16))
+ g_print ("\n");
+}
+
+static void
+dump_rle_data (guint8 * data, guint32 len)
+{
+ guint8 *end = data + len;
+ guint16 obj_w, obj_h;
+ gint i;
+ guint x = 0;
+
+ if (data + 4 > end)
+ return;
+
+ /* RLE data: */
+ obj_w = GST_READ_UINT16_BE (data);
+ obj_h = GST_READ_UINT16_BE (data + 2);
+ data += 4;
+ g_print ("RLE image is %ux%u\n", obj_w, obj_h);
+
+ while (data < end) {
+ guint8 pal_id;
+ guint16 run_len;
+
+ if (data[0] != 0) {
+ // g_print ("data 0x%02x\n", data[0]);
+ pal_id = *data++;
+ run_len = 1;
+ } else {
+ data++;
+
+ if (data + 1 > end)
+ return;
+ switch (data[0] & 0xC0) {
+ case 0x00:
+ //g_print ("data 0x%02x\n", data[0]);
+ run_len = (data[0] & 0x3f);
+ if (run_len > 0)
+ pal_id = 0;
+ data++;
+ break;
+ case 0x40:
+ if (data + 2 > end)
+ return;
+ //g_print ("data 0x%02x 0x%02x\n", data[0], data[1]);
+ run_len = ((data[0] << 8) | data[1]) & 0x3fff;
+ if (run_len > 0)
+ pal_id = 0;
+ data += 2;
+ break;
+ case 0x80:
+ if (data + 2 > end)
+ return;
+ //g_print ("data 0x%02x 0x%02x\n", data[0], data[1]);
+ run_len = (data[0] & 0x3f);
+ pal_id = data[1];
+ data += 2;
+ break;
+ case 0xC0:
+ if (data + 3 > end)
+ return;
+ //g_print ("data 0x%02x 0x%02x 0x%02x\n", data[0], data[1], data[2]);
+ run_len = ((data[0] << 8) | data[1]) & 0x3fff;
+ pal_id = data[2];
+ data += 3;
+ break;
+ }
+ }
+
+#if 1
+ if (palette[pal_id].A) {
+ for (i = 0; i < run_len; i++)
+ g_print ("%02x ", pal_id);
+ } else {
+ for (i = 0; i < run_len; i++)
+ g_print (" ");
+ }
+ x += run_len;
+ if (!run_len || x > obj_w) {
+ g_print ("\n");
+ x = 0;
+ }
+#else
+ g_print ("Run x: %d pix: %d col: %d\n", x, run_len, pal_id);
+ x += run_len;
+ if (x >= obj_w)
+ x = 0;
+#endif
+
+ };
+
+ g_print ("\n");
+}
+
+static int
+parse_presentation_segment (guint8 type, guint8 * payload, guint16 len)
+{
+ guint8 *end = payload + len;
+ guint16 vid_w, vid_h;
+ gint8 vid_fps;
+ guint16 composition_desc_no;
+ guint8 composition_desc_state;
+ guint8 pres_seg_flags;
+ guint8 palette_id;
+ guint8 n_objects;
+ gint i;
+
+ /* Parse video descriptor */
+ if (payload + 5 > end)
+ return 0;
+ vid_w = GST_READ_UINT16_BE (payload);
+ vid_h = GST_READ_UINT16_BE (payload + 2);
+ vid_fps = payload[4];
+ payload += 5;
+
+ /* Parse composition descriptor */
+ if (payload + 3 > end)
+ return 0;
+ composition_desc_no = GST_READ_UINT16_BE (payload);
+ composition_desc_state = payload[2];
+ payload += 3;
+
+ /* Parse other bits */
+ if (payload + 3 > end)
+ return 0;
+
+ pres_seg_flags = payload[0];
+ palette_id = payload[1];
+ n_objects = payload[2];
+ payload += 3;
+
+ g_print ("Video width %u height %u fps code %u\n", vid_w, vid_h, vid_fps);
+ g_print
+ ("Composition num %u state %u flags 0x%02x palette id %u n_objects %u\n",
+ composition_desc_no, composition_desc_state, pres_seg_flags, palette_id,
+ n_objects);
+
+ for (i = 0; i < (gint) n_objects; i++) {
+ guint16 obj_id;
+ guint8 win_id;
+ guint8 obj_flags;
+ guint16 x, y;
+
+ if (payload + 8 > end)
+ break;
+ obj_id = GST_READ_UINT16_BE (payload);
+ win_id = payload[2];
+ obj_flags = payload[3];
+ x = GST_READ_UINT16_BE (payload + 4);
+ y = GST_READ_UINT16_BE (payload + 6);
+ payload += 8;
+
+ g_print ("Composition object %d Object ID %u Window ID %u flags 0x%02x "
+ "x %u y %u\n", i, obj_id, win_id, obj_flags, x, y);
+
+ if (obj_flags & PGS_COMP_OBJECT_FLAG_CROPPED) {
+ guint16 crop_x, crop_y, crop_w, crop_h;
+ if (payload + 8 > end)
+ break;
+
+ crop_x = GST_READ_UINT16_BE (payload);
+ crop_y = GST_READ_UINT16_BE (payload + 2);
+ crop_w = GST_READ_UINT16_BE (payload + 4);
+ crop_h = GST_READ_UINT16_BE (payload + 6);
+ payload += 8;
+
+ g_print ("Cropping window x %u y %u w %u h %u\n",
+ crop_x, crop_y, crop_w, crop_h);
+ }
+ }
+
+ if (payload != end) {
+ g_print ("%u bytes left over:\n", end - payload);
+ dump_bytes (payload, end - payload);
+ }
+
+ return 0;
+}
+
+static int
+parse_set_palette (guint8 type, guint8 * payload, guint16 len)
+{
+ const gint PGS_PALETTE_ENTRY_SIZE = 5;
+ guint8 *end = payload + len;
+ guint8 palette_id;
+ guint8 palette_version;
+ gint n_entries, i;
+
+ if (len < 2) /* Palette command too short */
+ return 0;
+ palette_id = payload[0];
+ palette_version = payload[1];
+ payload += 2;
+
+ n_entries = (len - 2) / PGS_PALETTE_ENTRY_SIZE;
+
+ g_print ("Palette ID %u version %u. %d entries\n",
+ palette_id, palette_version, n_entries);
+ for (i = 0; i < n_entries; i++) {
+ guint8 n, Y, Cb, Cr, A;
+ n = payload[0];
+ palette[n].n = n;
+ palette[n].Y = Y = payload[1];
+ palette[n].Cb = Cb = payload[2];
+ palette[n].Cr = Cr = payload[3];
+ palette[n].A = A = payload[4];
+
+ g_print ("Entry %3d: Y %3d Cb %3d Cr %3d A %3d ", n, Y, Cb, Cr, A);
+ if (((i + 1) % 2) == 0)
+ g_print ("\n");
+
+ payload += PGS_PALETTE_ENTRY_SIZE;
+ }
+ for (i = n_entries; i < 256; i++) {
+ palette[i].n = i;
+ palette[i].A = 0;
+ }
+
+ if (n_entries > 0 && (i % 2))
+ g_print ("\n");
+
+ if (payload != end) {
+ g_print ("%u bytes left over:\n", end - payload);
+ dump_bytes (payload, end - payload);
+ }
+
+ return 0;
+}
+
+static int
+parse_set_window (guint8 type, guint8 * payload, guint16 len)
+{
+ guint8 *end = payload + len;
+ guint8 win_id, win_ver;
+ guint16 x, y, w, h;
+
+ if (payload + 10 > end)
+ return 0;
+
+ dump_bytes (payload, len);
+
+ /* FIXME: This is just a guess as to what the numbers mean: */
+ win_id = payload[0];
+ win_ver = payload[1];
+ x = GST_READ_UINT16_BE (payload + 2);
+ y = GST_READ_UINT16_BE (payload + 4);
+ w = GST_READ_UINT16_BE (payload + 6);
+ h = GST_READ_UINT16_BE (payload + 8);
+ payload += 10;
+
+ g_print ("Win ID %u version %d x %d y %d w %d h %d\n",
+ win_id, win_ver, x, y, w, h);
+
+ if (payload != end) {
+ g_print ("%u bytes left over:\n", end - payload);
+ dump_bytes (payload, end - payload);
+ }
+
+ return 0;
+}
+
+static int
+parse_set_object_data (guint8 type, guint8 * payload, guint16 len)
+{
+ guint8 *end = payload + len;
+ guint16 obj_id;
+ guint8 obj_ver, obj_flags;
+
+ if (payload + 4 > end)
+ return 0;
+ obj_id = GST_READ_UINT16_BE (payload);
+ obj_ver = payload[2];
+ obj_flags = payload[3];
+ payload += 4;
+
+ g_print ("Object ID %d ver %u flags 0x%02x\n", obj_id, obj_ver, obj_flags);
+
+ if (obj_flags & PGS_OBJECT_UPDATE_FLAG_START_RLE) {
+
+ if (payload + 3 > end)
+ return 0;
+
+ rle_data_size = GST_READ_UINT24_BE (payload);
+ payload += 3;
+
+ g_print ("%d bytes of RLE data, of %d bytes total.\n",
+ end - payload, rle_data_size);
+
+ rle_data = g_realloc (rle_data, rle_data_size);
+ rle_data_used = end - payload;
+ memcpy (rle_data, payload, end - payload);
+ payload = end;
+ } else {
+ g_print ("%d bytes of additional RLE data\n", end - payload);
+ if (rle_data_size < rle_data_used + end - payload)
+ return 0;
+
+ memcpy (rle_data + rle_data_used, payload, end - payload);
+ rle_data_used += end - payload;
+ payload = end;
+ }
+
+ if (rle_data_size == rle_data_used)
+ dump_rle_data (rle_data, rle_data_size);
+
+ if (payload != end) {
+ g_print ("%u bytes left over:\n", end - payload);
+ dump_bytes (payload, end - payload);
+ }
+
+ return 0;
+}
+
+static int
+parse_pgs_packet (guint8 type, guint8 * payload, guint16 len)
+{
+ int ret = 0;
+
+ if (!in_presentation_segment && type != PGS_COMMAND_PRESENTATION_SEGMENT) {
+ g_print ("Expected BEGIN PRESENTATION SEGMENT command. "
+ "Got command type 0x%02x len %u. Skipping\n", type, len);
+ return 0;
+ }
+
+ switch (type) {
+ case PGS_COMMAND_PRESENTATION_SEGMENT:
+ g_print ("*******************************************\n"
+ "Begin PRESENTATION_SEGMENT (0x%02x) packet len %u\n", type, len);
+ in_presentation_segment = TRUE;
+ ret = parse_presentation_segment (type, payload, len);
+ break;
+ case PGS_COMMAND_SET_OBJECT_DATA:
+ g_print ("*** Set Object Data (0x%02x) packet len %u\n", type, len);
+ ret = parse_set_object_data (type, payload, len);
+ break;
+ case PGS_COMMAND_SET_PALETTE:
+ g_print ("*** Set Palette (0x%02x) packet len %u\n", type, len);
+ ret = parse_set_palette (type, payload, len);
+ break;
+ case PGS_COMMAND_SET_WINDOW:
+ g_print ("*** Set Window command (0x%02x) packet len %u\n", type, len);
+ ret = parse_set_window (type, payload, len);
+ break;
+ case PGS_COMMAND_INTERACTIVE_SEGMENT:
+ g_print ("*** Interactive Segment command(0x%02x) packet len %u\n",
+ type, len);
+ dump_bytes (payload, len);
+ break;
+ case PGS_COMMAND_END_DISPLAY:
+ g_print ("*** End Display command (0x%02x) packet len %u\n", type, len);
+ in_presentation_segment = FALSE;
+ break;
+ default:
+ g_print ("*** Unknown command: type 0x%02x len %u. Skipping\n", type,
+ len);
+ break;
+ }
+ g_print ("\n");
+
+ return ret;
+}
+
+gint
+gstspu_dump_pgs_buffer (GstBuffer * buf)
+{
+ guint8 *pos, *end;
+ guint8 type;
+ guint16 packet_len;
+
+ pos = GST_BUFFER_DATA (buf);
+ end = pos + GST_BUFFER_SIZE (buf);
+
+ /* Need at least 3 bytes */
+ if (pos + 3 > end) {
+ g_print ("Not enough bytes to be a PGS packet\n");
+ return -1;
+ }
+
+ do {
+ type = *pos++;
+ packet_len = GST_READ_UINT16_BE (pos);
+ pos += 2;
+
+ if (pos + packet_len > end) {
+ g_print ("Invalid packet length %u (only have %u bytes)\n", packet_len,
+ end - pos);
+ return -1;
+ }
+
+ if (parse_pgs_packet (type, pos, packet_len))
+ return -1;
+
+ pos += packet_len;
+ } while (pos + 3 <= end);
+
+ return (pos - GST_BUFFER_DATA (buf));
+}