diff options
Diffstat (limited to 'gst')
-rw-r--r-- | gst/avi/Makefile.am | 6 | ||||
-rw-r--r-- | gst/avi/gstavi.c | 5 | ||||
-rw-r--r-- | gst/avi/gstavisubtitle.c | 207 | ||||
-rw-r--r-- | gst/avi/gstavisubtitle.h | 37 |
4 files changed, 252 insertions, 3 deletions
diff --git a/gst/avi/Makefile.am b/gst/avi/Makefile.am index aaf99648..71bbb56a 100644 --- a/gst/avi/Makefile.am +++ b/gst/avi/Makefile.am @@ -3,12 +3,14 @@ plugin_LTLIBRARIES = libgstavi.la libgstavi_la_SOURCES = \ gstavi.c \ gstavimux.c \ - gstavidemux.c + gstavidemux.c \ + gstavisubtitle.c noinst_HEADERS = \ avi-ids.h \ gstavimux.h \ - gstavidemux.h + gstavidemux.h \ + gstavisubtitle.h libgstavi_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) \ -I$(top_srcdir)/gst-libs diff --git a/gst/avi/gstavi.c b/gst/avi/gstavi.c index abf49efa..57ddf440 100644 --- a/gst/avi/gstavi.c +++ b/gst/avi/gstavi.c @@ -27,6 +27,7 @@ #include "gstavidemux.h" #include "gstavimux.h" +#include "gstavisubtitle.h" static gboolean plugin_init (GstPlugin * plugin) @@ -41,7 +42,9 @@ plugin_init (GstPlugin * plugin) if (!gst_element_register (plugin, "avidemux", GST_RANK_PRIMARY, GST_TYPE_AVI_DEMUX) || !gst_element_register (plugin, "avimux", GST_RANK_NONE, - GST_TYPE_AVI_MUX)) { + GST_TYPE_AVI_MUX) || + !gst_element_register (plugin, "avisubtitle", GST_RANK_NONE, + GST_TYPE_AVI_SUBTITLE)) { return FALSE; } diff --git a/gst/avi/gstavisubtitle.c b/gst/avi/gstavisubtitle.c new file mode 100644 index 00000000..2a1ff14b --- /dev/null +++ b/gst/avi/gstavisubtitle.c @@ -0,0 +1,207 @@ +/* GStreamer + * Copyright (C) <2007> Thijs Vermeir <thijsvermeir@gmail.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + + /* example of a subtitle chunk in an avi file + * 00000000 (0x8051700): 47 41 42 32 00 02 00 10 00 00 00 45 00 6e 00 67 GAB2.......E.n.g + * 00000010 (0x8051710): 00 6c 00 69 00 73 00 68 00 00 00 04 00 8e 00 00 .l.i.s.h........ + * 00000020 (0x8051720): 00 ef bb bf 31 0d 0a 30 30 3a 30 30 3a 30 30 2c ....1..00:00:00, + * 00000030 (0x8051730): 31 30 30 20 2d 2d 3e 20 30 30 3a 30 30 3a 30 32 100 --> 00:00:02 + * 00000040 (0x8051740): 2c 30 30 30 0d 0a 3c 62 3e 41 6e 20 55 54 46 38 ,000..<b>An UTF8 + * 00000050 (0x8051750): 20 53 75 62 74 69 74 6c 65 20 77 69 74 68 20 42 Subtitle with B + * 00000060 (0x8051760): 4f 4d 3c 2f 62 3e 0d 0a 0d 0a 32 0d 0a 30 30 3a OM</b>....2..00: + * 00000070 (0x8051770): 30 30 3a 30 32 2c 31 30 30 20 2d 2d 3e 20 30 30 00:02,100 --> 00 + * 00000080 (0x8051780): 3a 30 30 3a 30 34 2c 30 30 30 0d 0a 53 6f 6d 65 :00:04,000..Some + * 00000090 (0x8051790): 74 68 69 6e 67 20 6e 6f 6e 41 53 43 49 49 20 2d thing nonASCII - + * 000000a0 (0x80517a0): 20 c2 b5 c3 b6 c3 a4 c3 bc c3 9f 0d 0a 0d 0a .............. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <string.h> + +#include "gstavisubtitle.h" + +GST_DEBUG_CATEGORY_STATIC (avisubtitle_debug); +#define GST_CAT_DEFAULT avisubtitle_debug +GST_DEBUG_CATEGORY_EXTERN (GST_CAT_EVENT); + +static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ("application/x-subtitle-avi") + ); + +static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ("application/x-subtitle") + ); + +static GstFlowReturn gst_avi_subtitle_chain (GstPad * pad, GstBuffer * buffer); + +GST_BOILERPLATE (GstAviSubtitle, gst_avi_subtitle, GstElement, + GST_TYPE_ELEMENT); + +static GstBuffer * +gst_avi_subtitle_utf8_file (GstBuffer * buffer, guint offset) +{ + guint8 *file = GST_BUFFER_DATA (buffer) + offset; + + if (file[0] == 0xEF && file[1] == 0xBB && file[2] == 0xBF) { + /* UTF-8 */ + return gst_buffer_create_sub (buffer, offset + 3, + GST_BUFFER_SIZE (buffer) - offset - 3); + } + /* TODO Check for: + * 00 00 FE FF UTF-32, big-endian + * FF FE 00 00 UTF-32, little-endian + * FE FF UTF-16, big-endian + * FF FE UTF-16, little-endian + */ + + /* No BOM detected assuming UTF-8 */ + return gst_buffer_create_sub (buffer, offset, + GST_BUFFER_SIZE (buffer) - offset); +} + +static GstFlowReturn +gst_avi_subtitle_chain (GstPad * pad, GstBuffer * buffer) +{ + guint name_length, file_length; + gunichar2 *name; + + // gchar* name_utf8; + GstFlowReturn ret; + GstAviSubtitle *avisubtitle = GST_AVI_SUBTITLE (GST_PAD_PARENT (pad)); + + /* we expext only one buffer packet with the whole srt/ssa file in it */ + + /* check the magic word "GAB2\0" */ + if (GST_BUFFER_SIZE (buffer) <= 11 + || memcmp (GST_BUFFER_DATA (buffer), "GAB2\0", 5) != 0) + goto wrong_magic_word; + + /* next word must be 2 */ + if (GST_READ_UINT16_LE (GST_BUFFER_DATA (buffer) + 5) != 0x2) + goto wrong_fixed_word_1; + + name_length = GST_READ_UINT32_LE (GST_BUFFER_DATA (buffer) + 7); + GST_LOG ("length of name: %d", name_length); + if (GST_BUFFER_SIZE (buffer) <= 17 + name_length) + goto wrong_length_1; + + name = (gunichar2 *) & (GST_BUFFER_DATA (buffer)[11]); + // FIXME Take care for endianess in UTF-16 + // name_utf8 = g_utf16_to_utf8( name, name_length, NULL, NULL, NULL); + // GST_LOG("avi subtitle name: %s", name_utf8); + // g_free (name_utf8); + + /* next word must be 4 */ + if (GST_READ_UINT16_LE (GST_BUFFER_DATA (buffer) + 11 + name_length) != 0x4) + goto wrong_fixed_word_2; + + file_length = + GST_READ_UINT32_LE (GST_BUFFER_DATA (buffer) + 13 + name_length); + GST_LOG ("length srt/ssa file: %d", file_length); + + if (GST_BUFFER_SIZE (buffer) != 17 + name_length + file_length) + goto wrong_total_length; + + /* push the file over the src pad */ + ret = + gst_pad_push (avisubtitle->src, gst_avi_subtitle_utf8_file (buffer, + 17 + name_length)); + gst_buffer_unref (buffer); + + return ret; + + /* all the errors */ +wrong_magic_word: + GST_ELEMENT_ERROR (avisubtitle, STREAM, DECODE, NULL, ("Wrong magic word")); + gst_buffer_unref (buffer); + return GST_FLOW_ERROR; + +wrong_fixed_word_1: + GST_ELEMENT_ERROR (avisubtitle, STREAM, DECODE, NULL, + ("wrong fixed word: expected %d found %d", 2, + GST_READ_UINT16_LE (GST_BUFFER_DATA (buffer) + 5))); + gst_buffer_unref (buffer); + return GST_FLOW_ERROR; + +wrong_length_1: + GST_ELEMENT_ERROR (avisubtitle, STREAM, DECODE, NULL, + ("length of the buffer is too small (%d < %d)", GST_BUFFER_SIZE (buffer), + 17 + name_length)); + gst_buffer_unref (buffer); + return GST_FLOW_ERROR; + +wrong_fixed_word_2: + GST_ELEMENT_ERROR (avisubtitle, STREAM, DECODE, NULL, + ("wrong fixed word: expected %d found %d", 4, + GST_READ_UINT16_LE (GST_BUFFER_DATA (buffer) + 11 + name_length))); + gst_buffer_unref (buffer); + return GST_FLOW_ERROR; + +wrong_total_length: + GST_ELEMENT_ERROR (avisubtitle, STREAM, DECODE, NULL, + ("buffer size is wrong: need %d bytes, have %d bytes", + 17 + name_length + file_length, GST_BUFFER_SIZE (buffer))); + gst_buffer_unref (buffer); + return GST_FLOW_ERROR; +} + +static void +gst_avi_subtitle_base_init (gpointer klass) +{ + static const GstElementDetails gst_avi_demux_details = + GST_ELEMENT_DETAILS ("Avi subtitle parser", + "Codec/Demuxer", + "Parse avi subtitle stream", + "Thijs Vermeir <thijsvermeir@gmail.com>"); + GstElementClass *element_class = GST_ELEMENT_CLASS (klass); + + /* add the pad templates to the element */ + gst_element_class_add_pad_template (element_class, + gst_static_pad_template_get (&sink_template)); + gst_element_class_add_pad_template (element_class, + gst_static_pad_template_get (&src_template)); + + /* set the element details */ + gst_element_class_set_details (element_class, &gst_avi_demux_details); +} + +static void +gst_avi_subtitle_class_init (GstAviSubtitleClass * klass) +{ + GST_DEBUG_CATEGORY_INIT (avisubtitle_debug, "avisubtitle", 0, + "parse avi subtitle stream"); +} + +static void +gst_avi_subtitle_init (GstAviSubtitle * self, GstAviSubtitleClass * klass) +{ + self->src = gst_pad_new_from_static_template (&src_template, "src"); + gst_element_add_pad (GST_ELEMENT (self), self->src); + + self->sink = gst_pad_new_from_static_template (&sink_template, "sink"); + gst_element_add_pad (GST_ELEMENT (self), self->sink); + gst_pad_set_chain_function (self->sink, gst_avi_subtitle_chain); +} diff --git a/gst/avi/gstavisubtitle.h b/gst/avi/gstavisubtitle.h new file mode 100644 index 00000000..866466a7 --- /dev/null +++ b/gst/avi/gstavisubtitle.h @@ -0,0 +1,37 @@ + +#ifndef __GSTAVISUBTITLE_H__ +#define __GSTAVISUBTITLE_H__ + +#include <glib.h> +#include <glib-object.h> +#include <gst/gst.h> + +G_BEGIN_DECLS + +typedef struct _GstAviSubtitle GstAviSubtitle; +typedef struct _GstAviSubtitleClass GstAviSubtitleClass; + +#define GST_TYPE_AVI_SUBTITLE (gst_avi_subtitle_get_type ()) +#define GST_AVI_SUBTITLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_AVI_SUBTITLE, GstAviSubtitle)) +#define GST_AVI_SUBTITLE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_AVI_SUBTITLE, GstAviSubtitleClass)) +#define IS_GST_AVI_SUBTITLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_AVI_SUBTITLE)) +#define IS_GST_AVI_SUBTITLE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_AVI_SUBTITLE)) +#define GST_AVI_SUBTITLE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_AVI_SUBTITLE, GstAviSubtitleClass)) + +GType gst_avi_subtitle_get_type (void); + +struct _GstAviSubtitle +{ + GstElement parent; + + GstPad* src; + GstPad* sink; +}; + +struct _GstAviSubtitleClass +{ + GstElementClass parent; +}; + +G_END_DECLS +#endif |