mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-10-02 08:42:32 +00:00
port teletextdec to 1.0
https://bugzilla.gnome.org/show_bug.cgi?id=733819
This commit is contained in:
parent
fe116092cd
commit
717f9a287d
5 changed files with 312 additions and 439 deletions
|
@ -427,7 +427,7 @@ GST_PLUGINS_NONPORTED=" cdxaparse \
|
||||||
gsettings \
|
gsettings \
|
||||||
musepack nas sdl timidity \
|
musepack nas sdl timidity \
|
||||||
acm wininet \
|
acm wininet \
|
||||||
xvid lv2 teletextdec sndio libvisual"
|
xvid lv2 sndio libvisual"
|
||||||
AC_SUBST(GST_PLUGINS_NONPORTED)
|
AC_SUBST(GST_PLUGINS_NONPORTED)
|
||||||
|
|
||||||
dnl these are all the gst plug-ins, compilable without additional libs
|
dnl these are all the gst plug-ins, compilable without additional libs
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
plugin_LTLIBRARIES = libgstteletextdec.la
|
plugin_LTLIBRARIES = libgstteletextdec.la
|
||||||
|
|
||||||
libgstteletextdec_la_SOURCES = gstteletextdec.c teletext.c
|
libgstteletextdec_la_SOURCES = gstteletextdec.c
|
||||||
|
|
||||||
libgstteletextdec_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) $(TELETEXTDEC_CFLAGS)
|
libgstteletextdec_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) $(TELETEXTDEC_CFLAGS)
|
||||||
libgstteletextdec_la_LIBADD = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_LIBS) $(TELETEXTDEC_LIBS)
|
libgstteletextdec_la_LIBADD = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_LIBS) $(TELETEXTDEC_LIBS)
|
||||||
|
|
|
@ -22,12 +22,13 @@
|
||||||
/**
|
/**
|
||||||
* SECTION:element-teletextdec
|
* SECTION:element-teletextdec
|
||||||
*
|
*
|
||||||
* Decode PES stream containing teletext information to RGBA stream
|
* Decode a stream of raw VBI packets containing teletext information to a RGBA
|
||||||
|
* stream.
|
||||||
*
|
*
|
||||||
* <refsect2>
|
* <refsect2>
|
||||||
* <title>Example launch line</title>
|
* <title>Example launch line</title>
|
||||||
* |[
|
* |[
|
||||||
* gst-launch -v -m filesrc location=recording.mpeg ! mpegtsdemux ! private/teletext ! teletextdec ! videoconvert ! ximagesink
|
* gst-launch -v -m filesrc location=recording.mpeg ! tsdemux ! teletextdec ! videoconvert ! ximagesink
|
||||||
* ]|
|
* ]|
|
||||||
* </refsect2>
|
* </refsect2>
|
||||||
*/
|
*/
|
||||||
|
@ -39,12 +40,15 @@
|
||||||
#include <gst/gst.h>
|
#include <gst/gst.h>
|
||||||
#include <gst/video/video.h>
|
#include <gst/video/video.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
#include "gstteletextdec.h"
|
#include "gstteletextdec.h"
|
||||||
|
|
||||||
GST_DEBUG_CATEGORY_STATIC (gst_teletextdec_debug);
|
GST_DEBUG_CATEGORY_STATIC (gst_teletextdec_debug);
|
||||||
#define GST_CAT_DEFAULT gst_teletextdec_debug
|
#define GST_CAT_DEFAULT gst_teletextdec_debug
|
||||||
|
|
||||||
|
#define parent_class gst_teletextdec_parent_class
|
||||||
|
|
||||||
#define SUBTITLES_PAGE 888
|
#define SUBTITLES_PAGE 888
|
||||||
#define MAX_SLICES 32
|
#define MAX_SLICES 32
|
||||||
#define DEFAULT_FONT_DESCRIPTION "verdana 12"
|
#define DEFAULT_FONT_DESCRIPTION "verdana 12"
|
||||||
|
@ -120,26 +124,25 @@ static const gchar *default_color_map[40] = {
|
||||||
"#FF00FF", "#00FFFF", "#EEEEEE"
|
"#FF00FF", "#00FFFF", "#EEEEEE"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* in RGBA mode, one character occupies 12 x 10 pixels. */
|
||||||
|
#define COLUMNS_TO_WIDTH(cols) ((cols) * 12)
|
||||||
|
#define ROWS_TO_HEIGHT(rows) ((rows) * 10)
|
||||||
|
|
||||||
static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
|
static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
|
||||||
GST_PAD_SINK,
|
GST_PAD_SINK,
|
||||||
GST_PAD_ALWAYS,
|
GST_PAD_ALWAYS,
|
||||||
GST_STATIC_CAPS
|
GST_STATIC_CAPS ("application/x-teletext;")
|
||||||
("video/mpeg,mpegversion=2,systemstream=TRUE ; private/teletext")
|
|
||||||
);
|
);
|
||||||
|
|
||||||
static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
|
static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
|
||||||
GST_PAD_SRC,
|
GST_PAD_SRC,
|
||||||
GST_PAD_ALWAYS,
|
GST_PAD_ALWAYS,
|
||||||
GST_STATIC_CAPS
|
GST_STATIC_CAPS
|
||||||
(GST_VIDEO_CAPS_RGBA "; text/plain ; text/html ; text/x-pango-markup")
|
(GST_VIDEO_CAPS_MAKE ("RGBA") ";"
|
||||||
|
"text/x-raw, format={utf-8,pango-markup} ;")
|
||||||
);
|
);
|
||||||
|
|
||||||
/* debug category for filtering log messages */
|
G_DEFINE_TYPE (GstTeletextDec, gst_teletextdec, GST_TYPE_ELEMENT);
|
||||||
#define DEBUG_INIT(bla) \
|
|
||||||
GST_DEBUG_CATEGORY_INIT (gst_teletextdec_debug, "teletext", 0, "Teletext decoder");
|
|
||||||
|
|
||||||
GST_BOILERPLATE_FULL (GstTeletextDec, gst_teletextdec, GstElement,
|
|
||||||
GST_TYPE_ELEMENT, DEBUG_INIT);
|
|
||||||
|
|
||||||
static void gst_teletextdec_set_property (GObject * object, guint prop_id,
|
static void gst_teletextdec_set_property (GObject * object, guint prop_id,
|
||||||
const GValue * value, GParamSpec * pspec);
|
const GValue * value, GParamSpec * pspec);
|
||||||
|
@ -147,61 +150,35 @@ static void gst_teletextdec_get_property (GObject * object, guint prop_id,
|
||||||
GValue * value, GParamSpec * pspec);
|
GValue * value, GParamSpec * pspec);
|
||||||
static void gst_teletextdec_finalize (GObject * object);
|
static void gst_teletextdec_finalize (GObject * object);
|
||||||
|
|
||||||
static GstStateChangeReturn gst_teletextdec_change_state (GstElement * element,
|
static GstStateChangeReturn gst_teletextdec_change_state (GstElement *
|
||||||
GstStateChange transition);
|
element, GstStateChange transition);
|
||||||
|
|
||||||
static GstFlowReturn gst_teletextdec_chain (GstPad * pad, GstBuffer * buf);
|
static GstFlowReturn gst_teletextdec_chain (GstPad * pad, GstObject * parent,
|
||||||
static gboolean gst_teletextdec_sink_setcaps (GstPad * pad, GstCaps * caps);
|
GstBuffer * buffer);
|
||||||
static gboolean gst_teletextdec_sink_event (GstPad * pad, GstEvent * event);
|
static gboolean gst_teletextdec_sink_event (GstPad * pad, GstObject * parent,
|
||||||
static GstPadLinkReturn gst_teletextdec_src_set_caps (GstPad * pad,
|
GstEvent * event);
|
||||||
GstCaps * caps);
|
static gboolean gst_teletextdec_src_event (GstPad * pad, GstObject * parent,
|
||||||
|
GstEvent * event);
|
||||||
|
|
||||||
static vbi_bool gst_teletextdec_convert (vbi_dvb_demux * dx, gpointer user_data,
|
|
||||||
const vbi_sliced * sliced, guint n_lines, gint64 pts);
|
|
||||||
static void gst_teletextdec_event_handler (vbi_event * ev, void *user_data);
|
static void gst_teletextdec_event_handler (vbi_event * ev, void *user_data);
|
||||||
|
|
||||||
static GstFlowReturn gst_teletextdec_push_page (GstTeletextDec * teletext);
|
static GstFlowReturn gst_teletextdec_push_page (GstTeletextDec * teletext);
|
||||||
static GstFlowReturn gst_teletextdec_export_text_page (GstTeletextDec *
|
static GstFlowReturn gst_teletextdec_export_text_page (GstTeletextDec *
|
||||||
teletext, vbi_page * page, GstBuffer ** buf);
|
teletext, vbi_page * page, GstBuffer ** buf);
|
||||||
static GstFlowReturn gst_teletextdec_export_html_page (GstTeletextDec *
|
|
||||||
teletext, vbi_page * page, GstBuffer ** buf);
|
|
||||||
static GstFlowReturn gst_teletextdec_export_rgba_page (GstTeletextDec *
|
static GstFlowReturn gst_teletextdec_export_rgba_page (GstTeletextDec *
|
||||||
teletext, vbi_page * page, GstBuffer ** buf);
|
teletext, vbi_page * page, GstBuffer ** buf);
|
||||||
static GstFlowReturn gst_teletextdec_export_pango_page (GstTeletextDec *
|
static GstFlowReturn gst_teletextdec_export_pango_page (GstTeletextDec *
|
||||||
teletext, vbi_page * page, GstBuffer ** buf);
|
teletext, vbi_page * page, GstBuffer ** buf);
|
||||||
|
|
||||||
|
|
||||||
static gboolean gst_teletextdec_push_preroll_buffer (GstTeletextDec * teletext);
|
|
||||||
static void gst_teletextdec_process_telx_buffer (GstTeletextDec * teletext,
|
static void gst_teletextdec_process_telx_buffer (GstTeletextDec * teletext,
|
||||||
GstBuffer * buf);
|
GstBuffer * buf);
|
||||||
static void gst_teletextdec_process_pes_buffer (GstTeletextDec * teletext,
|
static gboolean gst_teletextdec_extract_data_units (GstTeletextDec *
|
||||||
GstBuffer * buf);
|
teletext, GstTeletextFrame * f, const guint8 * packet, guint * offset,
|
||||||
static gboolean gst_teletextdec_extract_data_units (GstTeletextDec * teletext,
|
gsize size);
|
||||||
GstTeletextFrame * f, guint8 * packet, guint * offset, gint size);
|
|
||||||
|
|
||||||
static void gst_teletextdec_zvbi_init (GstTeletextDec * teletext);
|
static void gst_teletextdec_zvbi_init (GstTeletextDec * teletext);
|
||||||
static void gst_teletextdec_zvbi_clear (GstTeletextDec * teletext);
|
static void gst_teletextdec_zvbi_clear (GstTeletextDec * teletext);
|
||||||
|
|
||||||
/* GObject vmethod implementations */
|
|
||||||
|
|
||||||
static void
|
|
||||||
gst_teletextdec_base_init (gpointer klass)
|
|
||||||
{
|
|
||||||
GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
|
|
||||||
|
|
||||||
gst_element_class_set_static_metadata (element_class,
|
|
||||||
"Teletext decoder",
|
|
||||||
"Decoder",
|
|
||||||
"Decode PES or raw VBI stream containing teletext information to RGBA, HTML and text",
|
|
||||||
"Sebastian Pölsterl <sebp@k-d-w.org>, "
|
|
||||||
"Andoni Morales Alastruey <ylatuya@gmail.com>");
|
|
||||||
|
|
||||||
gst_element_class_add_pad_template (element_class,
|
|
||||||
gst_static_pad_template_get (&src_template));
|
|
||||||
gst_element_class_add_pad_template (element_class,
|
|
||||||
gst_static_pad_template_get (&sink_template));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* initialize the gstteletext's class */
|
/* initialize the gstteletext's class */
|
||||||
static void
|
static void
|
||||||
gst_teletextdec_class_init (GstTeletextDecClass * klass)
|
gst_teletextdec_class_init (GstTeletextDecClass * klass)
|
||||||
|
@ -245,18 +222,28 @@ gst_teletextdec_class_init (GstTeletextDecClass * klass)
|
||||||
"Font description used for the pango output.",
|
"Font description used for the pango output.",
|
||||||
DEFAULT_FONT_DESCRIPTION,
|
DEFAULT_FONT_DESCRIPTION,
|
||||||
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||||
|
|
||||||
|
gst_element_class_set_static_metadata (gstelement_class,
|
||||||
|
"Teletext decoder",
|
||||||
|
"Decoder",
|
||||||
|
"Decode a raw VBI stream containing teletext information to RGBA and text",
|
||||||
|
"Sebastian Pölsterl <sebp@k-d-w.org>, "
|
||||||
|
"Andoni Morales Alastruey <ylatuya@gmail.com>");
|
||||||
|
|
||||||
|
gst_element_class_add_pad_template (gstelement_class,
|
||||||
|
gst_static_pad_template_get (&src_template));
|
||||||
|
gst_element_class_add_pad_template (gstelement_class,
|
||||||
|
gst_static_pad_template_get (&sink_template));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* initialize the new element
|
/* initialize the new element
|
||||||
* initialize instance structure
|
* initialize instance structure
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
gst_teletextdec_init (GstTeletextDec * teletext, GstTeletextDecClass * klass)
|
gst_teletextdec_init (GstTeletextDec * teletext)
|
||||||
{
|
{
|
||||||
/* Create sink pad */
|
/* Create sink pad */
|
||||||
teletext->sinkpad = gst_pad_new_from_static_template (&sink_template, "sink");
|
teletext->sinkpad = gst_pad_new_from_static_template (&sink_template, "sink");
|
||||||
gst_pad_set_setcaps_function (teletext->sinkpad,
|
|
||||||
GST_DEBUG_FUNCPTR (gst_teletextdec_sink_setcaps));
|
|
||||||
gst_pad_set_chain_function (teletext->sinkpad,
|
gst_pad_set_chain_function (teletext->sinkpad,
|
||||||
GST_DEBUG_FUNCPTR (gst_teletextdec_chain));
|
GST_DEBUG_FUNCPTR (gst_teletextdec_chain));
|
||||||
gst_pad_set_event_function (teletext->sinkpad,
|
gst_pad_set_event_function (teletext->sinkpad,
|
||||||
|
@ -265,11 +252,11 @@ gst_teletextdec_init (GstTeletextDec * teletext, GstTeletextDecClass * klass)
|
||||||
|
|
||||||
/* Create src pad */
|
/* Create src pad */
|
||||||
teletext->srcpad = gst_pad_new_from_static_template (&src_template, "src");
|
teletext->srcpad = gst_pad_new_from_static_template (&src_template, "src");
|
||||||
gst_pad_set_setcaps_function (teletext->srcpad,
|
gst_pad_set_event_function (teletext->srcpad,
|
||||||
GST_DEBUG_FUNCPTR (gst_teletextdec_src_set_caps));
|
GST_DEBUG_FUNCPTR (gst_teletextdec_src_event));
|
||||||
gst_element_add_pad (GST_ELEMENT (teletext), teletext->srcpad);
|
gst_element_add_pad (GST_ELEMENT (teletext), teletext->srcpad);
|
||||||
|
|
||||||
teletext->demux = NULL;
|
teletext->segment = NULL;
|
||||||
teletext->decoder = NULL;
|
teletext->decoder = NULL;
|
||||||
teletext->pageno = 0x100;
|
teletext->pageno = 0x100;
|
||||||
teletext->subno = -1;
|
teletext->subno = -1;
|
||||||
|
@ -284,7 +271,7 @@ gst_teletextdec_init (GstTeletextDec * teletext, GstTeletextDecClass * klass)
|
||||||
teletext->rate_denominator = 1;
|
teletext->rate_denominator = 1;
|
||||||
|
|
||||||
teletext->queue = NULL;
|
teletext->queue = NULL;
|
||||||
teletext->queue_lock = g_mutex_new ();
|
g_mutex_init (&teletext->queue_lock);
|
||||||
|
|
||||||
teletext->frame = g_new0 (GstTeletextFrame, 1);
|
teletext->frame = g_new0 (GstTeletextFrame, 1);
|
||||||
teletext->frame->sliced_begin = g_new (vbi_sliced, MAX_SLICES);
|
teletext->frame->sliced_begin = g_new (vbi_sliced, MAX_SLICES);
|
||||||
|
@ -293,7 +280,8 @@ gst_teletextdec_init (GstTeletextDec * teletext, GstTeletextDecClass * klass)
|
||||||
|
|
||||||
teletext->last_ts = 0;
|
teletext->last_ts = 0;
|
||||||
|
|
||||||
teletext->process_buf_func = NULL;
|
teletext->export_func = NULL;
|
||||||
|
teletext->buf_pool = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -301,7 +289,7 @@ gst_teletextdec_finalize (GObject * object)
|
||||||
{
|
{
|
||||||
GstTeletextDec *teletext = GST_TELETEXTDEC (object);
|
GstTeletextDec *teletext = GST_TELETEXTDEC (object);
|
||||||
|
|
||||||
g_mutex_free (teletext->queue_lock);
|
g_mutex_clear (&teletext->queue_lock);
|
||||||
|
|
||||||
g_free (teletext->frame);
|
g_free (teletext->frame);
|
||||||
|
|
||||||
|
@ -321,9 +309,9 @@ gst_teletextdec_zvbi_init (GstTeletextDec * teletext)
|
||||||
VBI_EVENT_TTX_PAGE | VBI_EVENT_CAPTION,
|
VBI_EVENT_TTX_PAGE | VBI_EVENT_CAPTION,
|
||||||
gst_teletextdec_event_handler, teletext);
|
gst_teletextdec_event_handler, teletext);
|
||||||
|
|
||||||
g_mutex_lock (teletext->queue_lock);
|
g_mutex_lock (&teletext->queue_lock);
|
||||||
teletext->queue = g_queue_new ();
|
teletext->queue = g_queue_new ();
|
||||||
g_mutex_unlock (teletext->queue_lock);
|
g_mutex_unlock (&teletext->queue_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -333,10 +321,6 @@ gst_teletextdec_zvbi_clear (GstTeletextDec * teletext)
|
||||||
|
|
||||||
GST_LOG_OBJECT (teletext, "Clearing structures");
|
GST_LOG_OBJECT (teletext, "Clearing structures");
|
||||||
|
|
||||||
if (teletext->demux != NULL) {
|
|
||||||
vbi_dvb_demux_delete (teletext->demux);
|
|
||||||
teletext->demux = NULL;
|
|
||||||
}
|
|
||||||
if (teletext->decoder != NULL) {
|
if (teletext->decoder != NULL) {
|
||||||
vbi_decoder_delete (teletext->decoder);
|
vbi_decoder_delete (teletext->decoder);
|
||||||
teletext->decoder = NULL;
|
teletext->decoder = NULL;
|
||||||
|
@ -346,12 +330,12 @@ gst_teletextdec_zvbi_clear (GstTeletextDec * teletext)
|
||||||
teletext->frame = NULL;
|
teletext->frame = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
g_mutex_lock (teletext->queue_lock);
|
g_mutex_lock (&teletext->queue_lock);
|
||||||
if (teletext->queue != NULL) {
|
if (teletext->queue != NULL) {
|
||||||
g_queue_free (teletext->queue);
|
g_queue_free (teletext->queue);
|
||||||
teletext->queue = NULL;
|
teletext->queue = NULL;
|
||||||
}
|
}
|
||||||
g_mutex_unlock (teletext->queue_lock);
|
g_mutex_unlock (&teletext->queue_lock);
|
||||||
|
|
||||||
teletext->in_timestamp = GST_CLOCK_TIME_NONE;
|
teletext->in_timestamp = GST_CLOCK_TIME_NONE;
|
||||||
teletext->in_duration = GST_CLOCK_TIME_NONE;
|
teletext->in_duration = GST_CLOCK_TIME_NONE;
|
||||||
|
@ -417,21 +401,31 @@ gst_teletextdec_get_property (GObject * object, guint prop_id,
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
gst_teletextdec_sink_event (GstPad * pad, GstEvent * event)
|
gst_teletextdec_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
|
||||||
{
|
{
|
||||||
gboolean ret;
|
gboolean ret;
|
||||||
GstTeletextDec *teletext = GST_TELETEXTDEC (gst_pad_get_parent (pad));
|
GstTeletextDec *teletext = GST_TELETEXTDEC (parent);
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (teletext, "got event %s",
|
GST_DEBUG_OBJECT (teletext, "got event %s",
|
||||||
gst_event_type_get_name (GST_EVENT_TYPE (event)));
|
gst_event_type_get_name (GST_EVENT_TYPE (event)));
|
||||||
|
|
||||||
switch (GST_EVENT_TYPE (event)) {
|
switch (GST_EVENT_TYPE (event)) {
|
||||||
case GST_EVENT_NEWSEGMENT:
|
case GST_EVENT_SEGMENT:
|
||||||
/* maybe save and/or update the current segment (e.g. for output
|
/* maybe save and/or update the current segment (e.g. for output
|
||||||
* clipping) or convert the event into one in a different format
|
* clipping) or convert the event into one in a different format
|
||||||
* (e.g. BYTES to TIME) or drop it and set a flag to send a newsegment
|
* (e.g. BYTES to TIME) or drop it and set a flag to send a newsegment
|
||||||
* event in a different format later */
|
* event in a different format later */
|
||||||
ret = gst_pad_push_event (teletext->srcpad, event);
|
if (NULL == teletext->export_func) {
|
||||||
|
/* save the segment event and send it after sending caps. replace the
|
||||||
|
* old event if present. */
|
||||||
|
if (teletext->segment) {
|
||||||
|
gst_event_unref (teletext->segment);
|
||||||
|
}
|
||||||
|
teletext->segment = event;
|
||||||
|
ret = TRUE;
|
||||||
|
} else {
|
||||||
|
ret = gst_pad_push_event (teletext->srcpad, event);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case GST_EVENT_EOS:
|
case GST_EVENT_EOS:
|
||||||
/* end-of-stream, we should close down all stream leftovers here */
|
/* end-of-stream, we should close down all stream leftovers here */
|
||||||
|
@ -444,12 +438,31 @@ gst_teletextdec_sink_event (GstPad * pad, GstEvent * event)
|
||||||
ret = gst_pad_push_event (teletext->srcpad, event);
|
ret = gst_pad_push_event (teletext->srcpad, event);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
ret = gst_pad_event_default (pad, event);
|
ret = gst_pad_event_default (pad, parent, event);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
gst_object_unref (teletext);
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
gst_teletextdec_src_event (GstPad * pad, GstObject * parent, GstEvent * event)
|
||||||
|
{
|
||||||
|
gboolean ret;
|
||||||
|
GstTeletextDec *teletext = GST_TELETEXTDEC (parent);
|
||||||
|
|
||||||
|
switch (GST_EVENT_TYPE (event)) {
|
||||||
|
case GST_EVENT_RECONFIGURE:
|
||||||
|
/* setting export_func to NULL will cause the element to renegotiate caps
|
||||||
|
* before pushing a buffer. */
|
||||||
|
teletext->export_func = NULL;
|
||||||
|
ret = TRUE;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
ret = gst_pad_event_default (pad, parent, event);
|
||||||
|
break;
|
||||||
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -484,106 +497,6 @@ gst_teletextdec_change_state (GstElement * element, GstStateChange transition)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
|
||||||
gst_teletextdec_sink_setcaps (GstPad * pad, GstCaps * caps)
|
|
||||||
{
|
|
||||||
GstTeletextDec *teletext = GST_TELETEXTDEC (gst_pad_get_parent (pad));
|
|
||||||
GstStructure *structure = gst_caps_get_structure (caps, 0);
|
|
||||||
const gchar *mimetype = gst_structure_get_name (structure);
|
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (teletext, "%s:%s, caps=%" GST_PTR_FORMAT,
|
|
||||||
GST_DEBUG_PAD_NAME (pad), caps);
|
|
||||||
|
|
||||||
if (g_strcmp0 (mimetype, "private/teletext") == 0) {
|
|
||||||
teletext->process_buf_func = gst_teletextdec_process_telx_buffer;
|
|
||||||
goto accept_caps;
|
|
||||||
} else if (g_strcmp0 (mimetype, "video/mpeg") == 0) {
|
|
||||||
gint version;
|
|
||||||
gboolean is_systemstream;
|
|
||||||
|
|
||||||
if (!gst_structure_get_int (structure, "mpegversion", &version) ||
|
|
||||||
!gst_structure_get_boolean (structure, "systemstream",
|
|
||||||
&is_systemstream))
|
|
||||||
goto refuse_caps;
|
|
||||||
|
|
||||||
if (version != 2 || !is_systemstream)
|
|
||||||
goto refuse_caps;
|
|
||||||
|
|
||||||
teletext->process_buf_func = gst_teletextdec_process_pes_buffer;
|
|
||||||
teletext->demux = vbi_dvb_pes_demux_new (gst_teletextdec_convert, teletext);
|
|
||||||
goto accept_caps;
|
|
||||||
} else
|
|
||||||
goto refuse_caps;
|
|
||||||
|
|
||||||
accept_caps:
|
|
||||||
{
|
|
||||||
gst_object_unref (teletext);
|
|
||||||
return gst_teletextdec_push_preroll_buffer (teletext);
|
|
||||||
}
|
|
||||||
|
|
||||||
refuse_caps:
|
|
||||||
{
|
|
||||||
GST_ERROR_OBJECT (teletext,
|
|
||||||
"pad %s refused renegotiation to %" GST_PTR_FORMAT,
|
|
||||||
GST_PAD_NAME (pad), caps);
|
|
||||||
gst_object_unref (teletext);
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static gboolean
|
|
||||||
gst_teletextdec_src_set_caps (GstPad * pad, GstCaps * caps)
|
|
||||||
{
|
|
||||||
GstTeletextDec *teletext;
|
|
||||||
GstStructure *structure = NULL;
|
|
||||||
const gchar *mimetype;
|
|
||||||
GstPad *peer;
|
|
||||||
|
|
||||||
teletext = GST_TELETEXTDEC (gst_pad_get_parent (pad));
|
|
||||||
GST_DEBUG_OBJECT (teletext, "Linking teletext source pad");
|
|
||||||
|
|
||||||
if (gst_caps_is_empty (caps)) {
|
|
||||||
GST_ERROR_OBJECT (teletext,
|
|
||||||
"pad %s refused renegotiation to %" GST_PTR_FORMAT,
|
|
||||||
GST_PAD_NAME (pad), caps);
|
|
||||||
goto refuse_caps;
|
|
||||||
}
|
|
||||||
|
|
||||||
peer = gst_pad_get_peer (pad);
|
|
||||||
if (peer) {
|
|
||||||
gst_pad_set_caps (peer, caps);
|
|
||||||
gst_object_unref (peer);
|
|
||||||
}
|
|
||||||
|
|
||||||
structure = gst_caps_get_structure (caps, 0);
|
|
||||||
mimetype = gst_structure_get_name (structure);
|
|
||||||
|
|
||||||
if (g_strcmp0 (mimetype, "video/x-raw-rgb") == 0) {
|
|
||||||
teletext->output_format = GST_TELETEXTDEC_OUTPUT_FORMAT_RGBA;
|
|
||||||
GST_DEBUG_OBJECT (teletext, "Selected RGBA output format");
|
|
||||||
} else if (g_strcmp0 (mimetype, "text/html") == 0) {
|
|
||||||
teletext->output_format = GST_TELETEXTDEC_OUTPUT_FORMAT_HTML;
|
|
||||||
GST_DEBUG_OBJECT (teletext, "Selected HTML output format");
|
|
||||||
} else if (g_strcmp0 (mimetype, "text/plain") == 0) {
|
|
||||||
teletext->output_format = GST_TELETEXTDEC_OUTPUT_FORMAT_TEXT;
|
|
||||||
GST_DEBUG_OBJECT (teletext, "Selected text output format");
|
|
||||||
} else if (g_strcmp0 (mimetype, "text/x-pango-markup") == 0) {
|
|
||||||
teletext->output_format = GST_TELETEXTDEC_OUTPUT_FORMAT_PANGO;
|
|
||||||
GST_DEBUG_OBJECT (teletext, "Selected pango markup output format");
|
|
||||||
} else
|
|
||||||
goto refuse_caps;
|
|
||||||
|
|
||||||
gst_object_unref (teletext);
|
|
||||||
return TRUE;
|
|
||||||
|
|
||||||
|
|
||||||
refuse_caps:
|
|
||||||
{
|
|
||||||
gst_object_unref (teletext);
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gst_teletextdec_reset_frame (GstTeletextDec * teletext)
|
gst_teletextdec_reset_frame (GstTeletextDec * teletext)
|
||||||
{
|
{
|
||||||
|
@ -594,21 +507,13 @@ gst_teletextdec_reset_frame (GstTeletextDec * teletext)
|
||||||
teletext->frame->last_frame_line = 0;
|
teletext->frame->last_frame_line = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
gst_teletextdec_process_pes_buffer (GstTeletextDec * teletext, GstBuffer * buf)
|
|
||||||
{
|
|
||||||
vbi_dvb_demux_feed (teletext->demux, GST_BUFFER_DATA (buf),
|
|
||||||
GST_BUFFER_SIZE (buf));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gst_teletextdec_process_telx_buffer (GstTeletextDec * teletext, GstBuffer * buf)
|
gst_teletextdec_process_telx_buffer (GstTeletextDec * teletext, GstBuffer * buf)
|
||||||
{
|
{
|
||||||
guint8 *data = GST_BUFFER_DATA (buf);
|
GstMapInfo buf_map;
|
||||||
const gint size = GST_BUFFER_SIZE (buf);
|
|
||||||
guint offset = 0;
|
guint offset = 0;
|
||||||
gint res;
|
gint res;
|
||||||
|
gst_buffer_map (buf, &buf_map, GST_MAP_READ);
|
||||||
|
|
||||||
teletext->in_timestamp = GST_BUFFER_TIMESTAMP (buf);
|
teletext->in_timestamp = GST_BUFFER_TIMESTAMP (buf);
|
||||||
teletext->in_duration = GST_BUFFER_DURATION (buf);
|
teletext->in_duration = GST_BUFFER_DURATION (buf);
|
||||||
|
@ -617,10 +522,10 @@ gst_teletextdec_process_telx_buffer (GstTeletextDec * teletext, GstBuffer * buf)
|
||||||
gst_teletextdec_reset_frame (teletext);
|
gst_teletextdec_reset_frame (teletext);
|
||||||
}
|
}
|
||||||
|
|
||||||
while (offset < size) {
|
while (offset < buf_map.size) {
|
||||||
res =
|
res =
|
||||||
gst_teletextdec_extract_data_units (teletext, teletext->frame, data,
|
gst_teletextdec_extract_data_units (teletext, teletext->frame,
|
||||||
&offset, size);
|
buf_map.data, &offset, buf_map.size);
|
||||||
|
|
||||||
if (res == VBI_NEW_FRAME) {
|
if (res == VBI_NEW_FRAME) {
|
||||||
/* We have a new frame, it's time to feed the decoder */
|
/* We have a new frame, it's time to feed the decoder */
|
||||||
|
@ -646,32 +551,14 @@ gst_teletextdec_process_telx_buffer (GstTeletextDec * teletext, GstBuffer * buf)
|
||||||
gst_teletextdec_reset_frame (teletext);
|
gst_teletextdec_reset_frame (teletext);
|
||||||
} else if (res == VBI_ERROR) {
|
} else if (res == VBI_ERROR) {
|
||||||
gst_teletextdec_reset_frame (teletext);
|
gst_teletextdec_reset_frame (teletext);
|
||||||
return;
|
goto beach;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
beach:
|
||||||
|
gst_buffer_unmap (buf, &buf_map);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
static vbi_bool
|
|
||||||
gst_teletextdec_convert (vbi_dvb_demux * dx,
|
|
||||||
gpointer user_data, const vbi_sliced * sliced, guint n_lines, gint64 pts)
|
|
||||||
{
|
|
||||||
gdouble sample_time;
|
|
||||||
vbi_sliced *s;
|
|
||||||
|
|
||||||
GstTeletextDec *teletext = GST_TELETEXTDEC (user_data);
|
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (teletext, "Converting %u lines to decode", n_lines);
|
|
||||||
|
|
||||||
sample_time = pts * (1 / 90000.0);
|
|
||||||
|
|
||||||
s = g_memdup (sliced, n_lines * sizeof (vbi_sliced));
|
|
||||||
vbi_decode (teletext->decoder, s, n_lines, sample_time);
|
|
||||||
g_free (s);
|
|
||||||
|
|
||||||
return GST_FLOW_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gst_teletextdec_event_handler (vbi_event * ev, void *user_data)
|
gst_teletextdec_event_handler (vbi_event * ev, void *user_data)
|
||||||
{
|
{
|
||||||
|
@ -697,9 +584,9 @@ gst_teletextdec_event_handler (vbi_event * ev, void *user_data)
|
||||||
pi->pgno = pgno;
|
pi->pgno = pgno;
|
||||||
pi->subno = subno;
|
pi->subno = subno;
|
||||||
|
|
||||||
g_mutex_lock (teletext->queue_lock);
|
g_mutex_lock (&teletext->queue_lock);
|
||||||
g_queue_push_tail (teletext->queue, pi);
|
g_queue_push_tail (teletext->queue, pi);
|
||||||
g_mutex_unlock (teletext->queue_lock);
|
g_mutex_unlock (&teletext->queue_lock);
|
||||||
break;
|
break;
|
||||||
case VBI_EVENT_CAPTION:
|
case VBI_EVENT_CAPTION:
|
||||||
/* TODO: Handle subtitles in caption teletext pages */
|
/* TODO: Handle subtitles in caption teletext pages */
|
||||||
|
@ -711,29 +598,148 @@ gst_teletextdec_event_handler (vbi_event * ev, void *user_data)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gst_teletextdec_try_get_buffer_pool (GstTeletextDec * teletext, GstCaps * caps,
|
||||||
|
gssize size)
|
||||||
|
{
|
||||||
|
guint pool_bufsize, min_bufs, max_bufs;
|
||||||
|
GstStructure *poolcfg;
|
||||||
|
GstBufferPool *new_pool;
|
||||||
|
GstQuery *alloc = gst_query_new_allocation (caps, TRUE);
|
||||||
|
|
||||||
|
if (teletext->buf_pool) {
|
||||||
|
/* this function is called only on a caps/size change, so it's practically
|
||||||
|
* impossible that we'll be able to reuse the old pool. */
|
||||||
|
gst_buffer_pool_set_active (teletext->buf_pool, FALSE);
|
||||||
|
gst_object_unref (teletext->buf_pool);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!gst_pad_peer_query (teletext->srcpad, alloc)) {
|
||||||
|
GST_DEBUG_OBJECT (teletext, "Failed to query peer pad for allocation "
|
||||||
|
"parameters");
|
||||||
|
teletext->buf_pool = NULL;
|
||||||
|
goto beach;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gst_query_get_n_allocation_pools (alloc) > 0) {
|
||||||
|
gst_query_parse_nth_allocation_pool (alloc, 0, &new_pool, &pool_bufsize,
|
||||||
|
&min_bufs, &max_bufs);
|
||||||
|
} else {
|
||||||
|
new_pool = gst_buffer_pool_new ();
|
||||||
|
max_bufs = 0;
|
||||||
|
min_bufs = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
poolcfg = gst_buffer_pool_get_config (new_pool);
|
||||||
|
gst_buffer_pool_config_set_params (poolcfg, gst_caps_copy (caps), size,
|
||||||
|
min_bufs, max_bufs);
|
||||||
|
if (!gst_buffer_pool_set_config (new_pool, poolcfg)) {
|
||||||
|
GST_DEBUG_OBJECT (teletext, "Failed to configure the buffer pool");
|
||||||
|
gst_object_unref (new_pool);
|
||||||
|
teletext->buf_pool = NULL;
|
||||||
|
goto beach;
|
||||||
|
}
|
||||||
|
if (!gst_buffer_pool_set_active (new_pool, TRUE)) {
|
||||||
|
GST_DEBUG_OBJECT (teletext, "Failed to make the buffer pool active");
|
||||||
|
gst_object_unref (new_pool);
|
||||||
|
teletext->buf_pool = NULL;
|
||||||
|
goto beach;
|
||||||
|
}
|
||||||
|
|
||||||
|
teletext->buf_pool = new_pool;
|
||||||
|
|
||||||
|
beach:
|
||||||
|
gst_query_unref (alloc);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
gst_teletextdec_negotiate_caps (GstTeletextDec * teletext, guint width,
|
||||||
|
guint height)
|
||||||
|
{
|
||||||
|
guint i, caps_size;
|
||||||
|
gboolean rv = FALSE;
|
||||||
|
|
||||||
|
/* get the peer's caps filtered by our own ones. */
|
||||||
|
GstCaps *ourcaps = gst_pad_query_caps (teletext->srcpad, NULL);
|
||||||
|
GstCaps *peercaps = gst_pad_peer_query_caps (teletext->srcpad, ourcaps);
|
||||||
|
gst_caps_unref (ourcaps);
|
||||||
|
|
||||||
|
if (gst_caps_is_empty (peercaps)) {
|
||||||
|
goto beach;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* make them writable in case we need to fixate them (video/x-raw). */
|
||||||
|
peercaps = gst_caps_make_writable (peercaps);
|
||||||
|
caps_size = gst_caps_get_size (peercaps);
|
||||||
|
|
||||||
|
for (i = 0; i < caps_size; ++i) {
|
||||||
|
GstStructure *caps_struct = gst_caps_get_structure (peercaps, i);
|
||||||
|
const gchar *caps_name = gst_structure_get_name (caps_struct);
|
||||||
|
const gchar *caps_fmt = gst_structure_get_string (caps_struct, "format");
|
||||||
|
|
||||||
|
if (g_strcmp0 (caps_name, "video/x-raw") == 0) {
|
||||||
|
teletext->width = width;
|
||||||
|
teletext->height = height;
|
||||||
|
teletext->export_func = gst_teletextdec_export_rgba_page;
|
||||||
|
gst_structure_set (caps_struct,
|
||||||
|
"width", G_TYPE_INT, width,
|
||||||
|
"height", G_TYPE_INT, height,
|
||||||
|
"framerate", GST_TYPE_FRACTION, 0, 1, NULL);
|
||||||
|
break;
|
||||||
|
} else if ((g_strcmp0 (caps_name, "text/x-raw") == 0) &&
|
||||||
|
(g_strcmp0 (caps_fmt, "utf-8") == 0)) {
|
||||||
|
teletext->export_func = gst_teletextdec_export_text_page;
|
||||||
|
break;
|
||||||
|
} else if ((g_strcmp0 (caps_name, "text/x-raw") == 0) &&
|
||||||
|
(g_strcmp0 (caps_fmt, "pango-markup") == 0)) {
|
||||||
|
teletext->export_func = gst_teletextdec_export_pango_page;
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
goto beach;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!gst_pad_push_event (teletext->srcpad, gst_event_new_caps (peercaps))) {
|
||||||
|
goto beach;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* try to get a bufferpool from the peer pad in case of RGBA output. */
|
||||||
|
if (gst_teletextdec_export_rgba_page == teletext->export_func) {
|
||||||
|
gst_teletextdec_try_get_buffer_pool (teletext, peercaps,
|
||||||
|
width * height * sizeof (vbi_rgba));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* we can happily return a success now. */
|
||||||
|
rv = TRUE;
|
||||||
|
|
||||||
|
beach:
|
||||||
|
gst_caps_unref (peercaps);
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
/* this function does the actual processing
|
/* this function does the actual processing
|
||||||
*/
|
*/
|
||||||
static GstFlowReturn
|
static GstFlowReturn
|
||||||
gst_teletextdec_chain (GstPad * pad, GstBuffer * buf)
|
gst_teletextdec_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
|
||||||
{
|
{
|
||||||
GstTeletextDec *teletext = GST_TELETEXTDEC (GST_PAD_PARENT (pad));
|
GstTeletextDec *teletext = GST_TELETEXTDEC (parent);
|
||||||
GstFlowReturn ret = GST_FLOW_OK;
|
GstFlowReturn ret = GST_FLOW_OK;
|
||||||
|
|
||||||
teletext->in_timestamp = GST_BUFFER_TIMESTAMP (buf);
|
teletext->in_timestamp = GST_BUFFER_TIMESTAMP (buf);
|
||||||
teletext->in_duration = GST_BUFFER_DURATION (buf);
|
teletext->in_duration = GST_BUFFER_DURATION (buf);
|
||||||
|
|
||||||
teletext->process_buf_func (teletext, buf);
|
gst_teletextdec_process_telx_buffer (teletext, buf);
|
||||||
gst_buffer_unref (buf);
|
gst_buffer_unref (buf);
|
||||||
|
|
||||||
g_mutex_lock (teletext->queue_lock);
|
g_mutex_lock (&teletext->queue_lock);
|
||||||
if (!g_queue_is_empty (teletext->queue)) {
|
if (!g_queue_is_empty (teletext->queue)) {
|
||||||
ret = gst_teletextdec_push_page (teletext);
|
ret = gst_teletextdec_push_page (teletext);
|
||||||
if (ret != GST_FLOW_OK) {
|
if (ret != GST_FLOW_OK) {
|
||||||
g_mutex_unlock (teletext->queue_lock);
|
g_mutex_unlock (&teletext->queue_lock);
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
g_mutex_unlock (teletext->queue_lock);
|
g_mutex_unlock (&teletext->queue_lock);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
@ -760,9 +766,9 @@ gst_teletextdec_push_page (GstTeletextDec * teletext)
|
||||||
page_info *pi;
|
page_info *pi;
|
||||||
gint pgno, subno;
|
gint pgno, subno;
|
||||||
gboolean success;
|
gboolean success;
|
||||||
|
guint width, height;
|
||||||
|
|
||||||
pi = (page_info *) g_queue_pop_head (teletext->queue);
|
pi = g_queue_pop_head (teletext->queue);
|
||||||
|
|
||||||
pgno = vbi_bcd2dec (pi->pgno);
|
pgno = vbi_bcd2dec (pi->pgno);
|
||||||
subno = vbi_bcd2dec (pi->subno);
|
subno = vbi_bcd2dec (pi->subno);
|
||||||
|
|
||||||
|
@ -770,28 +776,31 @@ gst_teletextdec_push_page (GstTeletextDec * teletext)
|
||||||
|
|
||||||
success = vbi_fetch_vt_page (teletext->decoder, &page, pi->pgno, pi->subno,
|
success = vbi_fetch_vt_page (teletext->decoder, &page, pi->pgno, pi->subno,
|
||||||
VBI_WST_LEVEL_3p5, 25, FALSE);
|
VBI_WST_LEVEL_3p5, 25, FALSE);
|
||||||
|
g_free (pi);
|
||||||
if (G_UNLIKELY (!success))
|
if (G_UNLIKELY (!success))
|
||||||
goto fetch_page_failed;
|
goto fetch_page_failed;
|
||||||
|
|
||||||
switch (teletext->output_format) {
|
width = COLUMNS_TO_WIDTH (page.columns);
|
||||||
case GST_TELETEXTDEC_OUTPUT_FORMAT_TEXT:
|
height = ROWS_TO_HEIGHT (page.rows);
|
||||||
ret = gst_teletextdec_export_text_page (teletext, &page, &buf);
|
|
||||||
break;
|
/* if output_func is NULL, we need to (re-)negotiate. also, it is possible
|
||||||
case GST_TELETEXTDEC_OUTPUT_FORMAT_HTML:
|
* (though unlikely) that we received a page of a different size. */
|
||||||
ret = gst_teletextdec_export_html_page (teletext, &page, &buf);
|
if (G_UNLIKELY (NULL == teletext->export_func ||
|
||||||
break;
|
teletext->width != width || teletext->height != height)) {
|
||||||
case GST_TELETEXTDEC_OUTPUT_FORMAT_RGBA:
|
/* if negotiate_caps returns FALSE, that means we weren't able to
|
||||||
ret = gst_teletextdec_export_rgba_page (teletext, &page, &buf);
|
* negotiate. */
|
||||||
break;
|
if (G_UNLIKELY (!gst_teletextdec_negotiate_caps (teletext, width, height))) {
|
||||||
case GST_TELETEXTDEC_OUTPUT_FORMAT_PANGO:
|
ret = GST_FLOW_NOT_NEGOTIATED;
|
||||||
ret = gst_teletextdec_export_pango_page (teletext, &page, &buf);
|
goto push_failed;
|
||||||
break;
|
}
|
||||||
default:
|
if (G_UNLIKELY (teletext->segment)) {
|
||||||
g_assert_not_reached ();
|
gst_pad_push_event (teletext->srcpad, teletext->segment);
|
||||||
break;
|
teletext->segment = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
teletext->export_func (teletext, &page, &buf);
|
||||||
vbi_unref_page (&page);
|
vbi_unref_page (&page);
|
||||||
g_free (pi);
|
|
||||||
|
|
||||||
if (ret != GST_FLOW_OK)
|
if (ret != GST_FLOW_OK)
|
||||||
goto alloc_failed;
|
goto alloc_failed;
|
||||||
|
@ -799,8 +808,8 @@ gst_teletextdec_push_page (GstTeletextDec * teletext)
|
||||||
GST_BUFFER_TIMESTAMP (buf) = teletext->in_timestamp;
|
GST_BUFFER_TIMESTAMP (buf) = teletext->in_timestamp;
|
||||||
GST_BUFFER_DURATION (buf) = teletext->in_duration;
|
GST_BUFFER_DURATION (buf) = teletext->in_duration;
|
||||||
|
|
||||||
GST_INFO_OBJECT (teletext, "Pushing buffer of size %d",
|
GST_INFO_OBJECT (teletext, "Pushing buffer of size %" G_GSIZE_FORMAT,
|
||||||
GST_BUFFER_SIZE (buf));
|
gst_buffer_get_size (buf));
|
||||||
|
|
||||||
ret = gst_pad_push (teletext->srcpad, buf);
|
ret = gst_pad_push (teletext->srcpad, buf);
|
||||||
if (ret != GST_FLOW_OK)
|
if (ret != GST_FLOW_OK)
|
||||||
|
@ -830,13 +839,13 @@ push_failed:
|
||||||
}
|
}
|
||||||
|
|
||||||
static gchar **
|
static gchar **
|
||||||
gst_teletextdec_vbi_page_to_text_lines (GstTeletextDec * teletext,
|
gst_teletextdec_vbi_page_to_text_lines (guint start, guint stop, vbi_page *
|
||||||
guint start, guint stop, vbi_page * page)
|
page)
|
||||||
{
|
{
|
||||||
const guint lines_count = stop - start + 1;
|
const guint lines_count = stop - start + 1;
|
||||||
const guint line_length = page->columns;
|
const guint line_length = page->columns;
|
||||||
gchar **lines;
|
gchar **lines;
|
||||||
gint i;
|
guint i;
|
||||||
|
|
||||||
/* allocate a new NULL-terminated array of strings */
|
/* allocate a new NULL-terminated array of strings */
|
||||||
lines = (gchar **) g_malloc (sizeof (gchar *) * (lines_count + 1));
|
lines = (gchar **) g_malloc (sizeof (gchar *) * (lines_count + 1));
|
||||||
|
@ -858,8 +867,6 @@ static GstFlowReturn
|
||||||
gst_teletextdec_export_text_page (GstTeletextDec * teletext, vbi_page * page,
|
gst_teletextdec_export_text_page (GstTeletextDec * teletext, vbi_page * page,
|
||||||
GstBuffer ** buf)
|
GstBuffer ** buf)
|
||||||
{
|
{
|
||||||
GstCaps *caps;
|
|
||||||
GstFlowReturn ret;
|
|
||||||
gchar *text;
|
gchar *text;
|
||||||
guint size;
|
guint size;
|
||||||
|
|
||||||
|
@ -868,7 +875,7 @@ gst_teletextdec_export_text_page (GstTeletextDec * teletext, vbi_page * page,
|
||||||
GString *subs;
|
GString *subs;
|
||||||
guint i;
|
guint i;
|
||||||
|
|
||||||
lines = gst_teletextdec_vbi_page_to_text_lines (teletext, 1, 23, page);
|
lines = gst_teletextdec_vbi_page_to_text_lines (1, 23, page);
|
||||||
subs = g_string_new ("");
|
subs = g_string_new ("");
|
||||||
/* Strip white spaces and squash blank lines */
|
/* Strip white spaces and squash blank lines */
|
||||||
for (i = 0; i < 23; i++) {
|
for (i = 0; i < 23; i++) {
|
||||||
|
@ -892,52 +899,9 @@ gst_teletextdec_export_text_page (GstTeletextDec * teletext, vbi_page * page,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Allocate new buffer */
|
/* Allocate new buffer */
|
||||||
caps = gst_caps_new_simple ("text/plain", NULL);
|
*buf = gst_buffer_new_wrapped (text, size);
|
||||||
ret = gst_pad_alloc_buffer (teletext->srcpad, GST_BUFFER_OFFSET_NONE,
|
|
||||||
size, caps, &(*buf));
|
|
||||||
if (G_LIKELY (ret == GST_FLOW_OK))
|
|
||||||
GST_BUFFER_DATA (*buf) = GST_BUFFER_MALLOCDATA (*buf) = (guint8 *) text;
|
|
||||||
else
|
|
||||||
gst_buffer_unref (*buf);
|
|
||||||
|
|
||||||
gst_caps_unref (caps);
|
return GST_FLOW_OK;
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static GstFlowReturn
|
|
||||||
gst_teletextdec_export_html_page (GstTeletextDec * teletext, vbi_page * page,
|
|
||||||
GstBuffer ** buf)
|
|
||||||
{
|
|
||||||
GstCaps *caps;
|
|
||||||
GstFlowReturn ret;
|
|
||||||
gchar *html;
|
|
||||||
gssize size;
|
|
||||||
vbi_export *ex;
|
|
||||||
gchar *err;
|
|
||||||
|
|
||||||
if (!(ex = vbi_export_new ("html", &err))) {
|
|
||||||
GST_ELEMENT_ERROR (teletext, LIBRARY, SETTINGS,
|
|
||||||
("Can't open the HTML export module: %s", err), (NULL));
|
|
||||||
g_free (err);
|
|
||||||
return GST_FLOW_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* export to NULL to get size of the memory needed to allocate the page */
|
|
||||||
size = vbi_export_mem (ex, NULL, 0, page);
|
|
||||||
if (size < 0)
|
|
||||||
return GST_FLOW_ERROR;
|
|
||||||
html = g_malloc (size);
|
|
||||||
vbi_export_mem (ex, html, size, page);
|
|
||||||
|
|
||||||
/* Allocate new buffer */
|
|
||||||
caps = gst_caps_new_simple ("text/html", NULL);
|
|
||||||
ret = gst_pad_alloc_buffer (teletext->srcpad, GST_BUFFER_OFFSET_NONE,
|
|
||||||
size, caps, &(*buf));
|
|
||||||
if (G_LIKELY (ret == GST_FLOW_OK))
|
|
||||||
GST_BUFFER_DATA (*buf) = GST_BUFFER_MALLOCDATA (*buf) = (guint8 *) html;
|
|
||||||
|
|
||||||
gst_caps_unref (caps);
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static GstFlowReturn
|
static GstFlowReturn
|
||||||
|
@ -945,40 +909,34 @@ gst_teletextdec_export_rgba_page (GstTeletextDec * teletext, vbi_page * page,
|
||||||
GstBuffer ** buf)
|
GstBuffer ** buf)
|
||||||
{
|
{
|
||||||
guint size;
|
guint size;
|
||||||
GstCaps *caps, *out_caps;
|
GstBuffer *lbuf;
|
||||||
GstFlowReturn ret;
|
GstMapInfo buf_map;
|
||||||
gint width, height;
|
|
||||||
GstPadTemplate *templ;
|
|
||||||
|
|
||||||
/* one character occupies 12 x 10 pixels */
|
size = teletext->width * teletext->height * sizeof (vbi_rgba);
|
||||||
width = page->columns * 12;
|
|
||||||
height = page->rows * 10;
|
|
||||||
|
|
||||||
caps = gst_caps_new_simple ("video/x-raw-rgb",
|
/* Allocate new buffer, using the negotiated pool if available. */
|
||||||
"width", G_TYPE_INT, width,
|
if (teletext->buf_pool) {
|
||||||
"height", G_TYPE_INT, height,
|
GstFlowReturn acquire_rv =
|
||||||
"framerate", GST_TYPE_FRACTION, teletext->rate_numerator,
|
gst_buffer_pool_acquire_buffer (teletext->buf_pool, &lbuf, NULL);
|
||||||
teletext->rate_denominator, NULL);
|
if (acquire_rv != GST_FLOW_OK) {
|
||||||
|
return acquire_rv;
|
||||||
templ = gst_static_pad_template_get (&src_template);
|
}
|
||||||
out_caps = gst_caps_intersect (caps, gst_pad_template_get_caps (templ));
|
} else {
|
||||||
gst_caps_unref (caps);
|
lbuf = gst_buffer_new_allocate (NULL, size, NULL);
|
||||||
gst_object_unref (templ);
|
if (NULL == lbuf)
|
||||||
|
return GST_FLOW_ERROR;
|
||||||
size = (guint) width *(guint) height *sizeof (vbi_rgba);
|
|
||||||
|
|
||||||
ret = gst_pad_alloc_buffer_and_set_caps (teletext->srcpad,
|
|
||||||
GST_BUFFER_OFFSET_NONE, size, out_caps, &(*buf));
|
|
||||||
|
|
||||||
if (ret == GST_FLOW_OK) {
|
|
||||||
GST_DEBUG_OBJECT (teletext, "Creating image with %d rows and %d cols",
|
|
||||||
page->rows, page->columns);
|
|
||||||
vbi_draw_vt_page (page, VBI_PIXFMT_RGBA32_LE,
|
|
||||||
(vbi_rgba *) GST_BUFFER_DATA (*buf), FALSE, TRUE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
gst_caps_unref (out_caps);
|
if (!gst_buffer_map (lbuf, &buf_map, GST_MAP_WRITE)) {
|
||||||
return ret;
|
gst_buffer_unref (lbuf);
|
||||||
|
return GST_FLOW_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
vbi_draw_vt_page (page, VBI_PIXFMT_RGBA32_LE, buf_map.data, FALSE, TRUE);
|
||||||
|
gst_buffer_unmap (lbuf, &buf_map);
|
||||||
|
*buf = lbuf;
|
||||||
|
|
||||||
|
return GST_FLOW_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static GstFlowReturn
|
static GstFlowReturn
|
||||||
|
@ -990,10 +948,8 @@ gst_teletextdec_export_pango_page (GstTeletextDec * teletext, vbi_page * page,
|
||||||
gchar **colors;
|
gchar **colors;
|
||||||
gchar **lines;
|
gchar **lines;
|
||||||
GString *subs;
|
GString *subs;
|
||||||
GstCaps *caps;
|
guint start, stop, k;
|
||||||
GstFlowReturn ret;
|
gint i, j;
|
||||||
guint start, stop;
|
|
||||||
guint i, j;
|
|
||||||
|
|
||||||
colors = (gchar **) g_malloc (sizeof (gchar *) * (rows + 1));
|
colors = (gchar **) g_malloc (sizeof (gchar *) * (rows + 1));
|
||||||
colors[rows] = g_strdup ('\0');
|
colors[rows] = g_strdup ('\0');
|
||||||
|
@ -1013,77 +969,24 @@ gst_teletextdec_export_pango_page (GstTeletextDec * teletext, vbi_page * page,
|
||||||
/* get an array of strings with each line of the telext page */
|
/* get an array of strings with each line of the telext page */
|
||||||
start = teletext->subtitles_mode ? 1 : 0;
|
start = teletext->subtitles_mode ? 1 : 0;
|
||||||
stop = teletext->subtitles_mode ? rows - 2 : rows - 1;
|
stop = teletext->subtitles_mode ? rows - 2 : rows - 1;
|
||||||
lines = gst_teletextdec_vbi_page_to_text_lines (teletext, start, stop, page);
|
lines = gst_teletextdec_vbi_page_to_text_lines (start, stop, page);
|
||||||
|
|
||||||
/* format each line in pango markup */
|
/* format each line in pango markup */
|
||||||
subs = g_string_new ("");
|
subs = g_string_new ("");
|
||||||
for (i = start; i <= stop; i++) {
|
for (k = start; k <= stop; k++) {
|
||||||
g_string_append_printf (subs, PANGO_TEMPLATE,
|
g_string_append_printf (subs, PANGO_TEMPLATE,
|
||||||
teletext->font_description, colors[i], lines[i - start]);
|
teletext->font_description, colors[k], lines[k - start]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Allocate new buffer */
|
/* Allocate new buffer */
|
||||||
caps = gst_caps_new_simple ("text/x-pango-markup", NULL);
|
*buf = gst_buffer_new_wrapped (subs->str, subs->len + 1);
|
||||||
ret = gst_pad_alloc_buffer (teletext->srcpad, GST_BUFFER_OFFSET_NONE,
|
|
||||||
subs->len + 1, caps, &(*buf));
|
|
||||||
if (G_LIKELY (ret == GST_FLOW_OK))
|
|
||||||
GST_BUFFER_DATA (*buf) = GST_BUFFER_MALLOCDATA (*buf) =
|
|
||||||
(guint8 *) subs->str;
|
|
||||||
else
|
|
||||||
gst_buffer_unref (*buf);
|
|
||||||
|
|
||||||
g_strfreev (lines);
|
g_strfreev (lines);
|
||||||
g_strfreev (colors);
|
g_strfreev (colors);
|
||||||
g_string_free (subs, FALSE);
|
g_string_free (subs, FALSE);
|
||||||
gst_caps_unref (caps);
|
return GST_FLOW_OK;
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
|
||||||
gst_teletextdec_push_preroll_buffer (GstTeletextDec * teletext)
|
|
||||||
{
|
|
||||||
GstFlowReturn ret;
|
|
||||||
GstBuffer *buf;
|
|
||||||
gboolean res = TRUE;
|
|
||||||
GstStructure *structure;
|
|
||||||
const gchar *mimetype;
|
|
||||||
GstCaps *out_caps, *peer_caps, *pad_caps;
|
|
||||||
|
|
||||||
/* the stream is sparse, we send a dummy buffer for preroll */
|
|
||||||
peer_caps = gst_pad_peer_get_caps (teletext->srcpad);
|
|
||||||
pad_caps = gst_pad_get_caps (teletext->srcpad);
|
|
||||||
out_caps = gst_caps_intersect (pad_caps, peer_caps);
|
|
||||||
|
|
||||||
if (gst_caps_is_empty (out_caps)) {
|
|
||||||
res = FALSE;
|
|
||||||
goto beach;
|
|
||||||
}
|
|
||||||
|
|
||||||
gst_caps_truncate (out_caps);
|
|
||||||
structure = gst_caps_get_structure (out_caps, 0);
|
|
||||||
mimetype = gst_structure_get_name (structure);
|
|
||||||
if (g_strcmp0 (mimetype, "video/x-raw-rgb") == 0) {
|
|
||||||
/* omit preroll buffer for this format */
|
|
||||||
goto beach;
|
|
||||||
}
|
|
||||||
|
|
||||||
buf = gst_buffer_new_and_alloc (1);
|
|
||||||
GST_BUFFER_DATA (buf)[0] = 0;
|
|
||||||
gst_buffer_set_caps (buf, out_caps);
|
|
||||||
ret = gst_pad_push (teletext->srcpad, buf);
|
|
||||||
if (ret != GST_FLOW_OK)
|
|
||||||
res = FALSE;
|
|
||||||
|
|
||||||
beach:
|
|
||||||
{
|
|
||||||
gst_caps_unref (out_caps);
|
|
||||||
gst_caps_unref (pad_caps);
|
|
||||||
gst_caps_unref (peer_caps);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Converts the line_offset / field_parity byte of a VBI data unit. */
|
/* Converts the line_offset / field_parity byte of a VBI data unit. */
|
||||||
static void
|
static void
|
||||||
gst_teletextdec_lofp_to_line (guint * field, guint * field_line,
|
gst_teletextdec_lofp_to_line (guint * field, guint * field_line,
|
||||||
|
@ -1160,9 +1063,9 @@ gst_teletextdec_line_address (GstTeletextDec * teletext,
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
gst_teletextdec_extract_data_units (GstTeletextDec * teletext,
|
gst_teletextdec_extract_data_units (GstTeletextDec * teletext,
|
||||||
GstTeletextFrame * f, guint8 * packet, guint * offset, gint size)
|
GstTeletextFrame * f, const guint8 * packet, guint * offset, gsize size)
|
||||||
{
|
{
|
||||||
guint8 *data_unit;
|
const guint8 *data_unit;
|
||||||
guint i;
|
guint i;
|
||||||
|
|
||||||
while (*offset < size) {
|
while (*offset < size) {
|
||||||
|
@ -1243,3 +1146,18 @@ gst_teletextdec_extract_data_units (GstTeletextDec * teletext,
|
||||||
}
|
}
|
||||||
return VBI_SUCCESS;
|
return VBI_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
teletext_init (GstPlugin * teletext)
|
||||||
|
{
|
||||||
|
GST_DEBUG_CATEGORY_INIT (gst_teletextdec_debug, "teletext", 0,
|
||||||
|
"Teletext decoder");
|
||||||
|
return gst_element_register (teletext, "teletextdec", GST_RANK_NONE,
|
||||||
|
GST_TYPE_TELETEXTDEC);
|
||||||
|
}
|
||||||
|
|
||||||
|
GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
|
||||||
|
GST_VERSION_MINOR,
|
||||||
|
teletext,
|
||||||
|
"Teletext plugin",
|
||||||
|
teletext_init, VERSION, "LGPL", "GStreamer", "http://gstreamer.net/")
|
||||||
|
|
|
@ -41,16 +41,8 @@ typedef struct _GstTeletextDecClass GstTeletextDecClass;
|
||||||
typedef struct _GstTeletextFrame GstTeletextFrame;
|
typedef struct _GstTeletextFrame GstTeletextFrame;
|
||||||
typedef enum _GstTeletextOutputFormat GstTeletextOutputFormat;
|
typedef enum _GstTeletextOutputFormat GstTeletextOutputFormat;
|
||||||
|
|
||||||
enum _GstTeletextOutputFormat
|
typedef GstFlowReturn (*GstTeletextExportFunc) (GstTeletextDec * teletext,
|
||||||
{
|
vbi_page * page, GstBuffer ** buf);
|
||||||
GST_TELETEXTDEC_OUTPUT_FORMAT_RGBA,
|
|
||||||
GST_TELETEXTDEC_OUTPUT_FORMAT_TEXT,
|
|
||||||
GST_TELETEXTDEC_OUTPUT_FORMAT_HTML,
|
|
||||||
GST_TELETEXTDEC_OUTPUT_FORMAT_PANGO
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef void (*GstTeletextProcessBufferFunc) (GstTeletextDec *
|
|
||||||
teletext, GstBuffer * buf);
|
|
||||||
|
|
||||||
struct _GstTeletextDec
|
struct _GstTeletextDec
|
||||||
{
|
{
|
||||||
|
@ -58,6 +50,7 @@ struct _GstTeletextDec
|
||||||
|
|
||||||
GstPad *sinkpad;
|
GstPad *sinkpad;
|
||||||
GstPad *srcpad;
|
GstPad *srcpad;
|
||||||
|
GstEvent *segment;
|
||||||
|
|
||||||
GstClockTime in_timestamp;
|
GstClockTime in_timestamp;
|
||||||
GstClockTime in_duration;
|
GstClockTime in_duration;
|
||||||
|
@ -71,17 +64,22 @@ struct _GstTeletextDec
|
||||||
gchar *subtitles_template;
|
gchar *subtitles_template;
|
||||||
gchar *font_description;
|
gchar *font_description;
|
||||||
|
|
||||||
vbi_dvb_demux *demux;
|
|
||||||
vbi_decoder *decoder;
|
vbi_decoder *decoder;
|
||||||
vbi_export *exporter;
|
|
||||||
GQueue *queue;
|
GQueue *queue;
|
||||||
GMutex *queue_lock;
|
GMutex queue_lock;
|
||||||
|
|
||||||
GstTeletextFrame *frame;
|
GstTeletextFrame *frame;
|
||||||
float last_ts;
|
float last_ts;
|
||||||
GstTeletextOutputFormat output_format;
|
|
||||||
|
|
||||||
GstTeletextProcessBufferFunc process_buf_func;
|
GstTeletextExportFunc export_func;
|
||||||
|
|
||||||
|
/* negotiated size of the output image in RGBA mode. */
|
||||||
|
guint width;
|
||||||
|
guint height;
|
||||||
|
|
||||||
|
/* buffer pool received from the peer pad - used in RGBA output only. */
|
||||||
|
GstBufferPool *buf_pool;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _GstTeletextFrame
|
struct _GstTeletextFrame
|
||||||
|
|
|
@ -1,43 +0,0 @@
|
||||||
/*
|
|
||||||
* GStreamer
|
|
||||||
* Copyright (C) 2009 Sebastian Pölsterl <sebp@k-d-w.org>
|
|
||||||
*
|
|
||||||
* This library is free software; you can redistribute it and/or
|
|
||||||
* mod1ify it under the terms of the GNU Lesser General Public
|
|
||||||
* License as published by the Free Software Foundation; either
|
|
||||||
* version 2.1 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
|
|
||||||
* Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
|
||||||
* License along with this library; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
|
||||||
* Boston, MA 02110-1301 USA
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifdef HAVE_CONFIG_H
|
|
||||||
#include "config.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <gst/gst.h>
|
|
||||||
#include "gstteletextdec.h"
|
|
||||||
|
|
||||||
/* entry point to initialize the plug-in
|
|
||||||
* initialize the plug-in itself
|
|
||||||
* register the element factories and other features
|
|
||||||
*/
|
|
||||||
static gboolean
|
|
||||||
teletext_init (GstPlugin * teletext)
|
|
||||||
{
|
|
||||||
return gst_element_register (teletext, "teletextdec", GST_RANK_NONE,
|
|
||||||
GST_TYPE_TELETEXTDEC);
|
|
||||||
}
|
|
||||||
|
|
||||||
GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
|
|
||||||
GST_VERSION_MINOR,
|
|
||||||
teletext,
|
|
||||||
"Teletext plugin",
|
|
||||||
teletext_init, VERSION, "LGPL", "GStreamer", "http://gstreamer.net/")
|
|
Loading…
Reference in a new issue