summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog35
-rw-r--r--ext/resindvd/Makefile.am11
-rw-r--r--ext/resindvd/gstmpegdemux.c28
-rwxr-xr-xext/resindvd/resin-play5
-rw-r--r--ext/resindvd/resindvdbin.c122
-rw-r--r--ext/resindvd/resindvdbin.h13
-rw-r--r--ext/resindvd/resindvdsrc.c193
-rw-r--r--ext/resindvd/resindvdsrc.h7
-rw-r--r--ext/resindvd/rsnaudiomunge.c22
-rw-r--r--ext/resindvd/rsnbasesrc.c3
-rw-r--r--ext/resindvd/rsnparsetter.c405
-rw-r--r--ext/resindvd/rsnparsetter.h54
-rw-r--r--ext/resindvd/rsnwrappedbuffer.c152
-rw-r--r--ext/resindvd/rsnwrappedbuffer.h69
14 files changed, 973 insertions, 146 deletions
diff --git a/ChangeLog b/ChangeLog
index 2f02035b..b207fbb0 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,38 @@
+2008-07-11 Jan Schmidt <thaytan@noraisin.net>
+
+ * docs/plugins/.cvsignore:
+ Ignore *-undeclared.txt
+
+ * ext/resindvd/rsnaudiomunge.c:
+ Turn g_print's into debug statements.
+
+ * ext/resindvd/resin-play:
+ * ext/resindvd/Makefile.am:
+ * ext/resindvd/resindvdbin.c:
+ * ext/resindvd/resindvdbin.h:
+ * ext/resindvd/rsnparsetter.c:
+ * ext/resindvd/rsnparsetter.h:
+ * ext/resindvd/rsnwrappedbuffer.c:
+ * ext/resindvd/rsnwrappedbuffer.h:
+ Add a bloated implementation of a really simple idea: Replace the
+ pixel-aspect-ratio in the output video with a prescribed one when
+ necessary. There must be an easier way.
+
+ Split the dvdspu out of the resindvdbin and put out the subpicture
+ stream on the subpicture pad.
+
+ * ext/resindvd/gstmpegdemux.c:
+ Send video-aspect events down the pipe from the demuxer.
+
+ * ext/resindvd/resindvdsrc.c:
+ * ext/resindvd/resindvdsrc.h:
+ Handle timed-stills somewhat using g_cond_timed_wait, with a FIXME
+ to make it use clock-waiting later.
+
+ * ext/resindvd/rsnbasesrc.c:
+ Don't overwrite the last_stop in the basesrc segment after a seamless
+ seek.
+
2008-07-10 Zaheer Abbas Merali <zaheerabbas at merali dot org>
* gst/mpegtsparse/mpegtspacketizer.c:
diff --git a/ext/resindvd/Makefile.am b/ext/resindvd/Makefile.am
index 9f4d3c8f..ace8fc33 100644
--- a/ext/resindvd/Makefile.am
+++ b/ext/resindvd/Makefile.am
@@ -12,10 +12,12 @@ libresindvd_la_SOURCES = \
resindvdsrc.c \
gstmpegdesc.c \
gstmpegdemux.c \
- gstpesfilter.c
+ gstpesfilter.c \
+ rsnparsetter.c \
+ rsnwrappedbuffer.c
-libresindvd_la_CFLAGS = $(GST_BASE_CFLAGS) $(GST_CFLAGS) $(DVDNAV_CFLAGS)
-libresindvd_la_LIBADD = $(GST_BASE_LIBS) $(GST_LIBS) $(DVDNAV_LIBS)
+libresindvd_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(GST_CFLAGS) $(DVDNAV_CFLAGS)
+libresindvd_la_LIBADD = $(GST_PLUGINS_BASE_CFLAGS) -lgstvideo-$(GST_MAJORMINOR) $(GST_BASE_LIBS) $(GST_LIBS) $(DVDNAV_LIBS)
libresindvd_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
noinst_HEADERS = resindvdbin.h \
@@ -27,4 +29,5 @@ noinst_HEADERS = resindvdbin.h \
gstmpegdefs.h \
gstmpegdesc.h \
gstmpegdemux.h \
- gstpesfilter.h
+ gstpesfilter.h \
+ rsnparsetter.h
diff --git a/ext/resindvd/gstmpegdemux.c b/ext/resindvd/gstmpegdemux.c
index 5e1da719..358acfa0 100644
--- a/ext/resindvd/gstmpegdemux.c
+++ b/ext/resindvd/gstmpegdemux.c
@@ -35,7 +35,7 @@
/* The SCR_MUNGE value is used to offset the scr_adjust value, to avoid
* ever generating a negative timestamp */
-#define SCR_MUNGE (2 * GST_SECOND)
+#define SCR_MUNGE (10 * GST_SECOND)
/* We clamp scr delta with 0 so negative bytes won't be possible */
#define GSTTIME_TO_BYTES(time) \
@@ -266,6 +266,7 @@ gst_flups_demux_create_stream (GstFluPSDemux * demux, gint id, gint stream_type)
case ST_GST_VIDEO_MPEG1_OR_2:
{
gint mpeg_version = 1;
+
if (stream_type == ST_VIDEO_MPEG2 ||
(stream_type == ST_GST_VIDEO_MPEG1_OR_2 && demux->is_mpeg2_pack)) {
mpeg_version = 2;
@@ -584,19 +585,35 @@ gst_flups_demux_handle_dvd_event (GstFluPSDemux * demux, GstEvent * event)
if (strcmp (type, "dvd-lang-codes") == 0) {
GstEvent **p_ev;
+
/* Store the language codes event on the element, then iterate over the
* streams it specifies and retrieve them. The stream creation code then
* creates the pad appropriately and sends tag events as needed */
p_ev = &demux->lang_codes;
gst_event_replace (p_ev, event);
- GST_ERROR_OBJECT (demux, "*********************\nLang codes event %s",
- gst_structure_to_string (structure));
-
GST_DEBUG_OBJECT (demux, "Handling language codes event");
- /* Create a video pad to ensure have it before emit no more pads */
+ /* Create a video pad to ensure it exists before emit no more pads */
temp = gst_flups_demux_get_stream (demux, 0xe0, ST_VIDEO_MPEG2);
+ /* Send a video format event downstream */
+ {
+ gboolean is_widescreen, is_pal;
+
+ if (gst_structure_get_boolean (structure,
+ "video-widescreen", &is_widescreen) &&
+ gst_structure_get_boolean (structure, "video-pal-format", &is_pal)) {
+ GstEvent *v_format;
+ GstStructure *v_struct;
+
+ v_struct = gst_structure_new ("application/x-gst-dvd",
+ "event", G_TYPE_STRING, "dvd-video-format",
+ "video-widescreen", G_TYPE_BOOLEAN, is_widescreen,
+ "video-pal-format", G_TYPE_BOOLEAN, is_pal, NULL);
+ v_format = gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, v_struct);
+ gst_pad_push_event (temp->pad, v_format);
+ }
+ }
/* Read out the languages for audio streams and request each one that
* is present */
@@ -646,6 +663,7 @@ gst_flups_demux_handle_dvd_event (GstFluPSDemux * demux, GstEvent * event)
/* And subtitle streams */
for (i = 0; i < MAX_DVD_SUBPICTURE_STREAMS; i++) {
gint stream_format;
+
g_snprintf (cur_stream_name, 32, "subpicture-%d-format", i);
if (!gst_structure_get_int (structure, cur_stream_name, &stream_format))
diff --git a/ext/resindvd/resin-play b/ext/resindvd/resin-play
index c2368116..f4211e19 100755
--- a/ext/resindvd/resin-play
+++ b/ext/resindvd/resin-play
@@ -7,5 +7,6 @@ else
fi
gst-launch rsndvdbin name=dvd "$DEVICE_OPT" \
- dvd. ! ffmpegcolorspace ! videoscale ! autovideosink \
- dvd. ! audioconvert ! autoaudiosink
+ dvd. ! dvdspu name=spu ! ffmpegcolorspace ! videoscale ! ximagesink force-aspect-ratio=true \
+ dvd. ! spu. \
+ dvd. ! audioconvert ! autoaudiosink $@
diff --git a/ext/resindvd/resindvdbin.c b/ext/resindvd/resindvdbin.c
index 81d511a0..14583bab 100644
--- a/ext/resindvd/resindvdbin.c
+++ b/ext/resindvd/resindvdbin.c
@@ -29,6 +29,7 @@
#include "resindvdsrc.h"
#include "rsnstreamselector.h"
#include "rsnaudiomunge.h"
+#include "rsnparsetter.h"
#include "gstmpegdemux.h"
@@ -58,13 +59,23 @@ static GstStaticPadTemplate video_src_template =
GST_STATIC_PAD_TEMPLATE ("video",
GST_PAD_SRC,
GST_PAD_SOMETIMES,
- GST_STATIC_CAPS_ANY);
+ GST_STATIC_CAPS
+ ("video/mpeg, mpegversion=(int) { 1, 2 }, systemstream=false")
+ );
static GstStaticPadTemplate audio_src_template =
-GST_STATIC_PAD_TEMPLATE ("audio",
+ GST_STATIC_PAD_TEMPLATE ("audio",
GST_PAD_SRC,
GST_PAD_SOMETIMES,
- GST_STATIC_CAPS_ANY);
+ GST_STATIC_CAPS ("audio/x-raw-int;audio/x-raw-float")
+ );
+
+static GstStaticPadTemplate subpicture_src_template =
+GST_STATIC_PAD_TEMPLATE ("subpicture",
+ GST_PAD_SRC,
+ GST_PAD_SOMETIMES,
+ GST_STATIC_CAPS ("video/x-dvd-subpicture")
+ );
static void rsn_dvdbin_do_init (GType rsn_dvdbin_type);
static void rsn_dvdbin_finalize (GObject * object);
@@ -103,6 +114,8 @@ rsn_dvdbin_base_init (gpointer gclass)
gst_static_pad_template_get (&video_src_template));
gst_element_class_add_pad_template (element_class,
gst_static_pad_template_get (&audio_src_template));
+ gst_element_class_add_pad_template (element_class,
+ gst_static_pad_template_get (&subpicture_src_template));
gst_element_class_set_details (element_class, &element_details);
element_class->change_state = GST_DEBUG_FUNCPTR (rsn_dvdbin_change_state);
@@ -365,53 +378,56 @@ create_elements (RsnDvdBin * dvdbin)
g_signal_connect (G_OBJECT (dvdbin->pieces[DVD_ELEM_VIDDEC]),
"new-decoded-pad", G_CALLBACK (viddec_pad_added), dvdbin);
+#if 1
+ if (!try_create_piece (dvdbin, DVD_ELEM_PARSET, NULL, RSN_TYPE_RSNPARSETTER,
+ "rsnparsetter", "Aspect ratio adjustment"))
+ return FALSE;
+#else
+ if (!try_create_piece (dvdbin, DVD_ELEM_PARSET, "identity", 0,
+ "rsnparsetter", "Aspect ratio adjustment"))
+ return FALSE;
+#endif
+
if (!try_create_piece (dvdbin, DVD_ELEM_VIDQ, "queue", 0, "vid_q",
"video decoder buffer"))
return FALSE;
+ src = gst_element_get_static_pad (dvdbin->pieces[DVD_ELEM_PARSET], "src");
+ sink = gst_element_get_static_pad (dvdbin->pieces[DVD_ELEM_VIDQ], "sink");
+ if (src == NULL || sink == NULL)
+ goto failed_vidq_connect;
+ if (GST_PAD_LINK_FAILED (gst_pad_link (src, sink)))
+ goto failed_vidq_connect;
+
g_object_set (dvdbin->pieces[DVD_ELEM_VIDQ],
"max-size-time", G_GUINT64_CONSTANT (0), "max-size-bytes", 0,
"max-size-buffers", 3, NULL);
+ src = gst_element_get_static_pad (dvdbin->pieces[DVD_ELEM_VIDQ], "src");
+ if (src == NULL)
+ goto failed_vidq_ghost;
+ ghost = gst_ghost_pad_new ("video", src);
+ if (ghost == NULL)
+ goto failed_vidq_ghost;
+ if (!gst_element_add_pad (GST_ELEMENT (dvdbin), ghost))
+ goto failed_vidq_ghost;
+ gst_object_unref (src);
+ ghost = src = sink = NULL;
+
if (!try_create_piece (dvdbin, DVD_ELEM_SPU_SELECT, NULL,
RSN_TYPE_STREAM_SELECTOR, "subpselect", "Subpicture stream selector"))
return FALSE;
- if (!try_create_piece (dvdbin, DVD_ELEM_SPU, "dvdspu", 0, "spu",
- "Subpicture overlay"))
- return FALSE;
-
- sink = gst_element_get_static_pad (dvdbin->pieces[DVD_ELEM_SPU], "video");
- src = gst_element_get_static_pad (dvdbin->pieces[DVD_ELEM_VIDQ], "src");
- if (src == NULL || sink == NULL)
- goto failed_spu_connect;
- if (GST_PAD_LINK_FAILED (gst_pad_link (src, sink)))
- goto failed_spu_connect;
- gst_object_unref (sink);
- gst_object_unref (src);
- src = sink = NULL;
-
- sink =
- gst_element_get_static_pad (dvdbin->pieces[DVD_ELEM_SPU], "subpicture");
src = gst_element_get_static_pad (dvdbin->pieces[DVD_ELEM_SPU_SELECT], "src");
- if (src == NULL || sink == NULL)
- goto failed_spu_connect;
- if (GST_PAD_LINK_FAILED (gst_pad_link (src, sink)))
- goto failed_spu_connect;
- gst_object_unref (sink);
- gst_object_unref (src);
- src = sink = NULL;
-
- src = gst_element_get_static_pad (dvdbin->pieces[DVD_ELEM_SPU], "src");
if (src == NULL)
goto failed_spu_ghost;
- ghost = gst_ghost_pad_new ("video", src);
+ ghost = gst_ghost_pad_new ("subpicture", src);
if (ghost == NULL)
goto failed_spu_ghost;
if (!gst_element_add_pad (GST_ELEMENT (dvdbin), ghost))
goto failed_spu_ghost;
gst_object_unref (src);
- src = sink = NULL;
+ ghost = src = sink = NULL;
if (!try_create_piece (dvdbin, DVD_ELEM_AUD_SELECT, NULL,
RSN_TYPE_STREAM_SELECTOR, "audioselect", "Audio stream selector"))
@@ -468,43 +484,41 @@ create_elements (RsnDvdBin * dvdbin)
if (!gst_element_add_pad (GST_ELEMENT (dvdbin), ghost))
goto failed_aud_ghost;
gst_object_unref (src);
- src = sink = NULL;
+ ghost = src = sink = NULL;
return TRUE;
failed_connect:
GST_ELEMENT_ERROR (dvdbin, CORE, FAILED, (NULL),
("Could not connect DVD source and demuxer elements"));
- return FALSE;
-failed_spu_connect:
+ goto error_out;
+failed_vidq_connect:
GST_ELEMENT_ERROR (dvdbin, CORE, FAILED, (NULL),
- ("Could not connect DVD video buffer and spu elements"));
- if (src != NULL)
- gst_object_unref (src);
- if (sink != NULL)
- gst_object_unref (sink);
- return FALSE;
+ ("Could not connect DVD aspect ratio adjuster and video buffer elements"));
+ goto error_out;
+failed_vidq_ghost:
+ GST_ELEMENT_ERROR (dvdbin, CORE, FAILED, (NULL),
+ ("Could not ghost SPU output pad"));
+ goto error_out;
failed_spu_ghost:
GST_ELEMENT_ERROR (dvdbin, CORE, FAILED, (NULL),
("Could not ghost SPU output pad"));
- if (src != NULL)
- gst_object_unref (src);
- if (ghost != NULL)
- gst_object_unref (ghost);
- return FALSE;
+ goto error_out;
failed_aud_connect:
GST_ELEMENT_ERROR (dvdbin, CORE, FAILED, (NULL),
("Could not connect DVD audio decoder"));
- if (src != NULL)
- gst_object_unref (src);
- if (sink != NULL)
- gst_object_unref (sink);
- return FALSE;
+ goto error_out;
failed_aud_ghost:
GST_ELEMENT_ERROR (dvdbin, CORE, FAILED, (NULL),
("Could not ghost audio output pad"));
+ goto error_out;
+error_out:
if (ghost != NULL)
gst_object_unref (ghost);
+ if (src != NULL)
+ gst_object_unref (src);
+ if (sink != NULL)
+ gst_object_unref (sink);
return FALSE;
}
@@ -578,7 +592,7 @@ demux_pad_added (GstElement * element, GstPad * pad, RsnDvdBin * dvdbin)
GstCaps *caps;
GstStructure *s;
- GST_ERROR_OBJECT (dvdbin, "New pad: %" GST_PTR_FORMAT, pad);
+ GST_DEBUG_OBJECT (dvdbin, "New pad: %" GST_PTR_FORMAT, pad);
caps = gst_pad_get_caps (pad);
if (caps == NULL) {
@@ -622,7 +636,7 @@ demux_pad_added (GstElement * element, GstPad * pad, RsnDvdBin * dvdbin)
mq_pad = connect_thru_mq (dvdbin, pad);
if (mq_pad == NULL)
goto failed;
- GST_ERROR_OBJECT (dvdbin, "Linking new pad %" GST_PTR_FORMAT
+ GST_DEBUG_OBJECT (dvdbin, "Linking new pad %" GST_PTR_FORMAT
" through multiqueue to %" GST_PTR_FORMAT, pad, dest_pad);
}
@@ -648,9 +662,9 @@ viddec_pad_added (GstElement * element, GstPad * pad, gboolean last,
{
GstPad *q_pad;
- GST_ERROR_OBJECT (dvdbin, "New video pad: %" GST_PTR_FORMAT, pad);
+ GST_DEBUG_OBJECT (dvdbin, "New video pad: %" GST_PTR_FORMAT, pad);
- q_pad = gst_element_get_static_pad (dvdbin->pieces[DVD_ELEM_VIDQ], "sink");
+ q_pad = gst_element_get_static_pad (dvdbin->pieces[DVD_ELEM_PARSET], "sink");
gst_pad_link (pad, q_pad);
gst_object_unref (q_pad);
@@ -663,7 +677,7 @@ auddec_pad_added (GstElement * element, GstPad * pad, gboolean last,
{
GstPad *out_pad;
- GST_ERROR_OBJECT (dvdbin, "New audio pad: %" GST_PTR_FORMAT, pad);
+ GST_DEBUG_OBJECT (dvdbin, "New audio pad: %" GST_PTR_FORMAT, pad);
out_pad =
gst_element_get_static_pad (dvdbin->pieces[DVD_ELEM_AUD_MUNGE], "sink");
diff --git a/ext/resindvd/resindvdbin.h b/ext/resindvd/resindvdbin.h
index 87f4261e..7844e94a 100644
--- a/ext/resindvd/resindvdbin.h
+++ b/ext/resindvd/resindvdbin.h
@@ -44,12 +44,13 @@ typedef struct _RsnDvdBinClass RsnDvdBinClass;
#define DVD_ELEM_MQUEUE 2
#define DVD_ELEM_SPU 3
#define DVD_ELEM_VIDDEC 4
-#define DVD_ELEM_AUDDEC 5
-#define DVD_ELEM_VIDQ 6
-#define DVD_ELEM_SPU_SELECT 7
-#define DVD_ELEM_AUD_SELECT 8
-#define DVD_ELEM_AUD_MUNGE 9
-#define DVD_ELEM_LAST 10
+#define DVD_ELEM_PARSET 5
+#define DVD_ELEM_AUDDEC 6
+#define DVD_ELEM_VIDQ 7
+#define DVD_ELEM_SPU_SELECT 8
+#define DVD_ELEM_AUD_SELECT 9
+#define DVD_ELEM_AUD_MUNGE 10
+#define DVD_ELEM_LAST 11
struct _RsnDvdBin
{
diff --git a/ext/resindvd/resindvdsrc.c b/ext/resindvd/resindvdsrc.c
index ce733667..3f06855e 100644
--- a/ext/resindvd/resindvdsrc.c
+++ b/ext/resindvd/resindvdsrc.c
@@ -344,6 +344,12 @@ rsn_dvdsrc_start (RsnBaseSrc * bsrc)
src->in_menu = FALSE;
src->active_button = -1;
+
+ src->cur_spu_phys_stream = -1;
+ src->cur_spu_forced_only = FALSE;
+ memset (src->cur_clut, 0, sizeof (guint32) * 16);
+ src->cur_audio_phys_stream = -1;
+
g_mutex_unlock (src->dvd_lock);
return TRUE;
@@ -494,36 +500,46 @@ rsn_dvdsrc_do_still (resinDvdSrc * src, int duration)
GstEvent *seg_event;
GstSegment *segment = &(GST_BASE_SRC (src)->segment);
- g_print ("**** STILL FRAME. Duration %d ****\n", duration);
+ if (src->in_still_state == FALSE) {
+ g_print ("**** STILL FRAME. Duration %d ****\n", duration);
+ /* Send a close-segment event, and a dvd-still start
+ * event, then sleep */
+ s = gst_structure_new ("application/x-gst-dvd",
+ "event", G_TYPE_STRING, "dvd-still",
+ "still-state", G_TYPE_BOOLEAN, TRUE, NULL);
+ still_event = gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, s);
- /* Send a close-segment event, and a dvd-still start
- * event, then sleep */
- s = gst_structure_new ("application/x-gst-dvd",
- "event", G_TYPE_STRING, "dvd-still",
- "still-state", G_TYPE_BOOLEAN, TRUE, NULL);
- still_event = gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, s);
+ gst_segment_set_last_stop (segment, GST_FORMAT_TIME, src->cur_end_ts);
- gst_segment_set_last_stop (segment, GST_FORMAT_TIME, src->cur_end_ts);
+ seg_event = gst_event_new_new_segment_full (TRUE,
+ segment->rate, segment->applied_rate, segment->format,
+ segment->start, segment->last_stop, segment->time);
- seg_event = gst_event_new_new_segment_full (TRUE,
- segment->rate, segment->applied_rate, segment->format,
- segment->start, segment->last_stop, segment->time);
+ /* Grab any pending highlight event to send too */
+ hl_event = src->highlight_event;
+ src->highlight_event = NULL;
- /* Grab any pending highlight event to send too */
- hl_event = src->highlight_event;
- src->highlight_event = NULL;
+ /* Now, send the events. We need to drop the dvd lock while doing so,
+ * and then check after if we got flushed */
+ g_mutex_unlock (src->dvd_lock);
+ gst_pad_push_event (GST_BASE_SRC_PAD (src), still_event);
+ gst_pad_push_event (GST_BASE_SRC_PAD (src), seg_event);
+ if (hl_event) {
+ g_print ("Sending highlight event before still\n");
+ gst_pad_push_event (GST_BASE_SRC_PAD (src), hl_event);
+ }
+ g_mutex_lock (src->dvd_lock);
- /* Now, send the events. We need to drop the dvd lock while doing so,
- * and then check after if we got flushed */
- g_mutex_unlock (src->dvd_lock);
- gst_pad_push_event (GST_BASE_SRC_PAD (src), still_event);
- gst_pad_push_event (GST_BASE_SRC_PAD (src), seg_event);
- if (hl_event)
- gst_pad_push_event (GST_BASE_SRC_PAD (src), hl_event);
- g_mutex_lock (src->dvd_lock);
+ g_mutex_lock (src->branch_lock);
+
+ src->in_still_state = TRUE;
+ } else {
+ GST_DEBUG_OBJECT (src, "Re-entering still wait");
+ g_mutex_lock (src->branch_lock);
+ }
- g_mutex_lock (src->branch_lock);
if (src->branching) {
+ GST_INFO_OBJECT (src, "Branching - aborting still");
g_mutex_unlock (src->branch_lock);
return TRUE;
}
@@ -535,29 +551,63 @@ rsn_dvdsrc_do_still (resinDvdSrc * src, int duration)
* don't skip it
*/
src->need_segment = TRUE;
+
g_mutex_unlock (src->dvd_lock);
+ GST_LOG_OBJECT (src, "Entering cond_wait still");
g_cond_wait (src->still_cond, src->branch_lock);
+ GST_LOG_OBJECT (src, "cond_wait still over, branching = %d",
+ src->branching);
+
if (src->branching) {
g_mutex_unlock (src->branch_lock);
g_mutex_lock (src->dvd_lock);
return TRUE;
}
+ src->in_still_state = FALSE;
+
g_mutex_unlock (src->branch_lock);
g_mutex_lock (src->dvd_lock);
} else {
+ GTimeVal end_time;
+ gboolean was_signalled;
+
+ g_get_current_time (&end_time);
+ g_time_val_add (&end_time, duration * G_USEC_PER_SEC);
+
/* FIXME: Implement timed stills by sleeping on the clock, possibly
* in multiple steps if we get paused/unpaused */
- if (dvdnav_still_skip (src->dvdnav) != DVDNAV_STATUS_OK)
+ g_mutex_unlock (src->dvd_lock);
+ GST_LOG_OBJECT (src, "cond_timed_wait still");
+ was_signalled =
+ g_cond_timed_wait (src->still_cond, src->branch_lock, &end_time);
+ was_signalled |= src->branching;
+
+ g_mutex_unlock (src->branch_lock);
+ g_mutex_lock (src->dvd_lock);
+
+ if (was_signalled) {
+ /* Signalled - must be flushing */
+ GST_LOG_OBJECT (src,
+ "cond_timed_wait still over. Signalled, branching = %d",
+ src->branching);
+ return TRUE;
+ }
+
+ /* Else timed out, end the still */
+ GST_DEBUG_OBJECT (src,
+ "Timed still of %d secs over, calling dvdnav_still_skip", duration);
+
+ if (dvdnav_still_skip (src->dvdnav) != DVDNAV_STATUS_OK) {
return FALSE;
+ }
- /* Later: We'll only do this if the still isn't interrupted: */
+ /* Tell downstream the still is over.
+ * Later: We'll only do this if the still isn't interrupted: */
s = gst_structure_new ("application/x-gst-dvd",
"event", G_TYPE_STRING, "dvd-still",
- "still-state", G_TYPE_BOOLEAN, TRUE, NULL);
+ "still-state", G_TYPE_BOOLEAN, FALSE, NULL);
still_event = gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, s);
- g_mutex_unlock (src->branch_lock);
-
g_mutex_unlock (src->dvd_lock);
gst_pad_push_event (GST_BASE_SRC_PAD (src), still_event);
g_mutex_lock (src->dvd_lock);
@@ -596,6 +646,7 @@ rsn_dvdsrc_step (resinDvdSrc * src, gboolean have_dvd_lock)
src->next_is_nav_block = FALSE;
src->next_nav_ts = GST_CLOCK_TIME_NONE;
src->alloc_buf = NULL;
+ src->in_still_state = FALSE;
break;
case DVDNAV_NAV_PACKET:
{
@@ -605,6 +656,8 @@ rsn_dvdsrc_step (resinDvdSrc * src, gboolean have_dvd_lock)
GstClockTimeDiff new_base_time = ifotime_to_gsttime (&pci->pci_gi.e_eltm);
gboolean discont = FALSE;
+ src->in_still_state = FALSE;
+
if (new_start_ptm != src->cur_end_ts)
discont = TRUE;
@@ -655,15 +708,13 @@ rsn_dvdsrc_step (resinDvdSrc * src, gboolean have_dvd_lock)
}
case DVDNAV_STOP:
/* End of the disc. EOS */
- g_print ("STOP found. End of disc\n");
+ dvdnav_reset (src->dvdnav);
ret = GST_FLOW_UNEXPECTED;
break;
case DVDNAV_STILL_FRAME:
{
dvdnav_still_event_t *info = (dvdnav_still_event_t *) data;
- g_print ("STILL frame duration %d\n", info->length);
-
if (!have_dvd_lock) {
/* At a still frame but can't block, handle it later */
return GST_FLOW_WOULD_BLOCK;
@@ -764,7 +815,7 @@ rsn_dvdsrc_step (resinDvdSrc * src, gboolean have_dvd_lock)
src->highlight_event = NULL;
g_mutex_unlock (src->dvd_lock);
- g_print ("Highlight change - button: %d\n", src->active_button);
+ g_print ("Sending highlight event - button %d\n", src->active_button);
gst_pad_push_event (GST_BASE_SRC_PAD (src), hl_event);
g_mutex_lock (src->dvd_lock);
}
@@ -860,8 +911,6 @@ rsn_dvdsrc_create (RsnPushSrc * psrc, GstBuffer ** outbuf)
gst_pad_push_event (GST_BASE_SRC_PAD (src), audio_select_event);
}
- g_mutex_lock (src->dvd_lock);
-
if (src->need_segment) {
/* Seamless segment update */
GstEvent *seek;
@@ -871,6 +920,9 @@ rsn_dvdsrc_create (RsnPushSrc * psrc, GstBuffer ** outbuf)
gst_element_send_event (GST_ELEMENT (src), seek);
src->need_segment = FALSE;
}
+
+ g_mutex_lock (src->dvd_lock);
+
if (src->cur_end_ts != GST_CLOCK_TIME_NONE)
gst_segment_set_last_stop (segment, GST_FORMAT_TIME, src->cur_end_ts);
@@ -1037,15 +1089,8 @@ rsn_dvdsrc_handle_navigation_event (resinDvdSrc * src, GstEvent * event)
channel_hop = TRUE;
}
} else if (g_str_equal (key, "period")) {
- gint title = 0;
- gint part = 0;
-
- if (dvdnav_current_title_info (src->dvdnav, &title, &part) && title > 0) {
- if (dvdnav_part_play (src->dvdnav, title, part + 1) ==
- DVDNAV_STATUS_ERR)
- dvdnav_next_pg_search (src->dvdnav);
- channel_hop = TRUE;
- }
+ dvdnav_next_pg_search (src->dvdnav);
+ channel_hop = TRUE;
} else {
g_print ("Unknown keypress: %s\n", key);
}
@@ -1152,6 +1197,10 @@ rsn_dvdsrc_prepare_audio_stream_event (resinDvdSrc * src, guint8 phys_stream)
GstStructure *s;
GstEvent *e;
+ if (phys_stream == src->cur_audio_phys_stream)
+ return;
+ src->cur_audio_phys_stream = phys_stream;
+
s = gst_structure_new ("application/x-gst-dvd",
"event", G_TYPE_STRING, "dvd-set-audio-track",
"physical-id", G_TYPE_INT, (gint) phys_stream, NULL);
@@ -1170,6 +1219,14 @@ rsn_dvdsrc_prepare_spu_stream_event (resinDvdSrc * src, guint8 phys_stream,
GstStructure *s;
GstEvent *e;
+ if (phys_stream == src->cur_spu_phys_stream &&
+ forced_only == src->cur_spu_forced_only) {
+ g_print ("Not preparing SPU change\n");
+ return;
+ }
+ src->cur_spu_phys_stream = phys_stream;
+ src->cur_spu_forced_only = forced_only;
+
s = gst_structure_new ("application/x-gst-dvd",
"event", G_TYPE_STRING, "dvd-set-subpicture-track",
"physical-id", G_TYPE_INT, (gint) phys_stream,
@@ -1186,6 +1243,7 @@ static gboolean
rsn_dvdsrc_prepare_streamsinfo_event (resinDvdSrc * src)
{
vtsi_mat_t *vts_attr;
+ video_attr_t *v_attr;
audio_attr_t *a_attrs;
subp_attr_t *s_attrs;
gint n_audio, n_subp;
@@ -1194,6 +1252,7 @@ rsn_dvdsrc_prepare_streamsinfo_event (resinDvdSrc * src)
gint i;
gchar lang_code[3] = { '\0', '\0', '\0' };
gchar *t;
+ gboolean is_widescreen;
if (src->vts_attrs == NULL || src->vts_n >= src->vts_attrs->len) {
if (src->vts_attrs)
@@ -1207,6 +1266,7 @@ rsn_dvdsrc_prepare_streamsinfo_event (resinDvdSrc * src)
if (src->vts_n == 0) {
/* VMGM info */
vts_attr = NULL;
+ v_attr = &src->vmgm_attr.vmgm_video_attr;
a_attrs = &src->vmgm_attr.vmgm_audio_attr;
n_audio = MIN (1, src->vmgm_attr.nr_of_vmgm_audio_streams);
s_attrs = &src->vmgm_attr.vmgm_subp_attr;
@@ -1214,6 +1274,7 @@ rsn_dvdsrc_prepare_streamsinfo_event (resinDvdSrc * src)
} else if (src->in_menu) {
/* VTSM attrs */
vts_attr = &g_array_index (src->vts_attrs, vtsi_mat_t, src->vts_n);
+ v_attr = &vts_attr->vtsm_video_attr;
a_attrs = &vts_attr->vtsm_audio_attr;
n_audio = vts_attr->nr_of_vtsm_audio_streams;
s_attrs = &vts_attr->vtsm_subp_attr;
@@ -1221,6 +1282,7 @@ rsn_dvdsrc_prepare_streamsinfo_event (resinDvdSrc * src)
} else {
/* VTS domain */
vts_attr = &g_array_index (src->vts_attrs, vtsi_mat_t, src->vts_n);
+ v_attr = &vts_attr->vts_video_attr;
a_attrs = vts_attr->vts_audio_attr;
n_audio = vts_attr->nr_of_vts_audio_streams;
s_attrs = vts_attr->vts_subp_attr;
@@ -1232,6 +1294,13 @@ rsn_dvdsrc_prepare_streamsinfo_event (resinDvdSrc * src)
"event", G_TYPE_STRING, "dvd-lang-codes", NULL);
e = gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, s);
+ /* video */
+ is_widescreen = (v_attr->display_aspect_ratio != 0);
+ gst_structure_set (s, "video-pal-format", G_TYPE_BOOLEAN,
+ (v_attr->video_format != 0), NULL);
+ gst_structure_set (s, "video-widescreen", G_TYPE_BOOLEAN, is_widescreen,
+ NULL);
+
/* audio */
if (n_audio == 0) {
/* Always create at least one audio stream */
@@ -1301,6 +1370,10 @@ rsn_dvdsrc_prepare_clut_change_event (resinDvdSrc * src, const guint32 * clut)
gchar name[16];
int i;
+ if (memcmp (src->cur_clut, clut, sizeof (guint32) * 16) == 0)
+ return;
+ memcpy (src->cur_clut, clut, sizeof (guint32) * 16);
+
structure = gst_structure_new ("application/x-gst-dvd",
"event", G_TYPE_STRING, "dvd-spu-clut-change", NULL);
@@ -1492,9 +1565,9 @@ rsn_dvdsrc_nav_clock_cb (GstClock * clock, GstClockTime time, GstClockID id,
if (time < base_time + cur->running_ts)
break; /* Next NAV is in the future */
- g_print ("Activating nav pack for with TS %" GST_TIME_FORMAT
- " at running TS %" GST_TIME_FORMAT "\n",
- GST_TIME_ARGS (cur->ts), GST_TIME_ARGS (cur->running_ts));
+ GST_DEBUG_OBJECT (src, "Activating nav pack for with TS %" GST_TIME_FORMAT
+ " at running TS %" GST_TIME_FORMAT, GST_TIME_ARGS (cur->ts),
+ GST_TIME_ARGS (cur->running_ts));
rsn_dvdsrc_activate_nav_block (src, cur->buffer);
gst_buffer_unref (cur->buffer);
@@ -1523,29 +1596,31 @@ rsn_dvdsrc_schedule_nav_cb (resinDvdSrc * src, RsnDvdPendingNav * next_nav)
{
GstClock *clock;
GstClockTime base_ts;
- GstState cur_state;
- gst_element_get_state (GST_ELEMENT (src), &cur_state, NULL, 0);
- if (cur_state != GST_STATE_PLAYING)
+ GST_OBJECT_LOCK (src);
+ if (GST_STATE (src) != GST_STATE_PLAYING) {
+ GST_OBJECT_UNLOCK (src);
return; /* Not in playing state yet */
+ }
- GST_OBJECT_LOCK (src);
clock = GST_ELEMENT_CLOCK (src);
- if (clock)
- gst_object_ref (clock);
base_ts = GST_ELEMENT (src)->base_time;
- GST_OBJECT_UNLOCK (src);
- if (clock == NULL)
+ if (clock == NULL) {
+ GST_OBJECT_UNLOCK (src);
return;
+ }
+ gst_object_ref (clock);
+
+ src->nav_clock_id = gst_clock_new_single_shot_id (clock,
+ base_ts + next_nav->running_ts);
+
+ GST_OBJECT_UNLOCK (src);
GST_LOG_OBJECT (src, "Schedule nav pack for running TS %" GST_TIME_FORMAT,
GST_TIME_ARGS (next_nav->running_ts));
- src->nav_clock_id = gst_clock_new_single_shot_id (clock,
- base_ts + next_nav->running_ts);
gst_clock_id_wait_async (src->nav_clock_id, rsn_dvdsrc_nav_clock_cb, src);
-
gst_object_unref (clock);
}
@@ -1725,10 +1800,10 @@ rsn_dvdsrc_do_seek (RsnBaseSrc * bsrc, GstSegment * segment)
g_mutex_unlock (src->dvd_lock);
}
- g_print ("Entering prepare_next_block after seek\n");
+ GST_LOG_OBJECT (src, "Entering prepare_next_block after seek");
if (rsn_dvdsrc_prepare_next_block (src, FALSE) != GST_FLOW_OK)
goto fail;
- g_print ("prepare_next_block after seek done\n");
+ GST_LOG_OBJECT (src, "prepare_next_block after seek done");
segment->format = GST_FORMAT_TIME;
/* The first TS output: */
diff --git a/ext/resindvd/resindvdsrc.h b/ext/resindvd/resindvdsrc.h
index 0b273da7..c0fa8e1d 100644
--- a/ext/resindvd/resindvdsrc.h
+++ b/ext/resindvd/resindvdsrc.h
@@ -88,6 +88,7 @@ struct _resinDvdSrc
gboolean flushing_seek;
gboolean need_segment;
gboolean active_highlight;
+ gboolean in_still_state;
GstBuffer *alloc_buf;
GstBuffer *next_buf;
@@ -128,6 +129,12 @@ struct _resinDvdSrc
gboolean have_pci;
pci_t cur_pci;
+
+ /* Current state tracking */
+ gint8 cur_audio_phys_stream;
+ gint8 cur_spu_phys_stream;
+ gboolean cur_spu_forced_only;
+ guint32 cur_clut[16];
};
struct _resinDvdSrcClass
diff --git a/ext/resindvd/rsnaudiomunge.c b/ext/resindvd/rsnaudiomunge.c
index f0429ee9..457be163 100644
--- a/ext/resindvd/rsnaudiomunge.c
+++ b/ext/resindvd/rsnaudiomunge.c
@@ -273,8 +273,6 @@ rsn_audiomunge_sink_event (GstPad * pad, GstEvent * event)
switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_FLUSH_STOP:
rsn_audiomunge_reset (munge);
-
- g_print ("*********** AUDIO MUNGE: FLUSH\n");
ret = gst_pad_push_event (munge->srcpad, event);
break;
case GST_EVENT_NEWSEGMENT:
@@ -299,11 +297,6 @@ rsn_audiomunge_sink_event (GstPad * pad, GstEvent * event)
rate, arate, format, start, stop, time);
if (munge->have_audio) {
- g_print ("*********** AUDIO MUNGE NEWSEG: start %" GST_TIME_FORMAT
- " stop %" GST_TIME_FORMAT " accum now %" GST_TIME_FORMAT
- "\n", GST_TIME_ARGS (start), GST_TIME_ARGS (stop),
- GST_TIME_ARGS (segment->accum));
-
ret = gst_pad_push_event (munge->srcpad, event);
break;
}
@@ -319,21 +312,23 @@ rsn_audiomunge_sink_event (GstPad * pad, GstEvent * event)
* in the closing segment.
*/
if (segment->accum >= AUDIO_FILL_THRESHOLD || munge->in_still) {
- g_print ("*********** Send audio mebbe: accum = %" GST_TIME_FORMAT
+ g_print ("*********** Sending audio fill: accum = %" GST_TIME_FORMAT
" still-state=%d\n", GST_TIME_ARGS (segment->accum),
munge->in_still);
+
/* Just generate a 100ms silence buffer for now. FIXME: Fill the gap */
if (rsn_audiomunge_make_audio (munge, segment->start,
GST_SECOND / 10) == GST_FLOW_OK)
munge->have_audio = TRUE;
} else {
- g_print ("*********** below thresh: accum = %" GST_TIME_FORMAT
- "\n", GST_TIME_ARGS (segment->accum));
+ GST_LOG_OBJECT (munge, "Not sending audio fill buffer: "
+ "segment accum below thresh: accum = %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (segment->accum));
}
- g_print ("*********** AUDIO MUNGE NEWSEG: start %" GST_TIME_FORMAT
- " stop %" GST_TIME_FORMAT " accum now %" GST_TIME_FORMAT
- "\n", GST_TIME_ARGS (start), GST_TIME_ARGS (stop),
+ GST_DEBUG_OBJECT (munge, "Sending newsegment: start %" GST_TIME_FORMAT
+ " stop %" GST_TIME_FORMAT " accum now %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (start), GST_TIME_ARGS (stop),
GST_TIME_ARGS (segment->accum));
ret = gst_pad_push_event (munge->srcpad, event);
@@ -342,6 +337,7 @@ rsn_audiomunge_sink_event (GstPad * pad, GstEvent * event)
case GST_EVENT_CUSTOM_DOWNSTREAM:
{
const GstStructure *s = gst_event_get_structure (event);
+
if (s && gst_structure_has_name (s, "application/x-gst-dvd"))
rsn_audiomunge_handle_dvd_event (munge, event);
diff --git a/ext/resindvd/rsnbasesrc.c b/ext/resindvd/rsnbasesrc.c
index 220b350c..abbdf5e4 100644
--- a/ext/resindvd/rsnbasesrc.c
+++ b/ext/resindvd/rsnbasesrc.c
@@ -1046,9 +1046,6 @@ rsn_base_src_perform_seek (RsnBaseSrc * src, GstEvent * event, gboolean unlock)
FALSE, seeksegment.rate, seeksegment.applied_rate,
seeksegment.format, seeksegment.last_stop,
seeksegment.stop, seeksegment.time);
-
- gst_segment_set_last_stop (&src->segment, GST_FORMAT_TIME,
- seeksegment.last_stop);
}
if (src->segment.flags & GST_SEEK_FLAG_SEGMENT) {
diff --git a/ext/resindvd/rsnparsetter.c b/ext/resindvd/rsnparsetter.c
new file mode 100644
index 00000000..65de2ac3
--- /dev/null
+++ b/ext/resindvd/rsnparsetter.c
@@ -0,0 +1,405 @@
+/*
+ * Copyright (C) 2008 Jan Schmidt <thaytan@noraisin.net>
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <gst/gst.h>
+#include <gst/video/video.h>
+#include <string.h>
+
+#include "rsnparsetter.h"
+#include "rsnwrappedbuffer.h"
+
+GST_DEBUG_CATEGORY_STATIC (rsn_parsetter_debug);
+#define GST_CAT_DEFAULT rsn_parsetter_debug
+
+static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("video/x-raw-rgb; video/x-raw-yuv")
+ );
+
+static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("video/x-raw-rgb; video/x-raw-yuv")
+ );
+
+static void rsn_parsetter_register_extra (GType rsn_parsetter_type);
+
+GST_BOILERPLATE_FULL (RsnParSetter, rsn_parsetter, GstElement,
+ GST_TYPE_ELEMENT, rsn_parsetter_register_extra);
+
+static void rsn_parsetter_finalize (GObject * object);
+static GstFlowReturn rsn_parsetter_chain (GstPad * pad, GstBuffer * buf);
+static gboolean rsn_parsetter_sink_event (GstPad * pad, GstEvent * event);
+static gboolean rsn_parsetter_sink_setcaps (GstPad * pad, GstCaps * caps);
+static GstFlowReturn rsn_parsetter_sink_bufferalloc (GstPad * pad,
+ guint64 offset, guint size, GstCaps * caps, GstBuffer ** buf);
+
+static GstCaps *rsn_parsetter_src_getcaps (GstPad * pad);
+static GstCaps *rsn_parsetter_convert_caps (RsnParSetter * parset,
+ GstCaps * caps, gboolean widescreen);
+static gboolean rsn_parsetter_check_caps (RsnParSetter * parset,
+ GstCaps * caps);
+
+static void
+rsn_parsetter_register_extra (GType rsn_parsetter_type)
+{
+ GST_DEBUG_CATEGORY_INIT (rsn_parsetter_debug, "rsnparsetter", 0,
+ "Resin DVD aspect ratio adjuster");
+}
+
+static void
+rsn_parsetter_base_init (gpointer gclass)
+{
+ static GstElementDetails element_details = {
+ "Resin Aspect Ratio Setter",
+ "Filter/Video",
+ "Overrides caps on video buffers to force a particular display ratio",
+ "Jan Schmidt <thaytan@noraisin.net>"
+ };
+ GstElementClass *element_class = GST_ELEMENT_CLASS (gclass);
+
+ gst_element_class_add_pad_template (element_class,
+ gst_static_pad_template_get (&src_factory));
+ gst_element_class_add_pad_template (element_class,
+ gst_static_pad_template_get (&sink_factory));
+ gst_element_class_set_details (element_class, &element_details);
+}
+
+static void
+rsn_parsetter_class_init (RsnParSetterClass * klass)
+{
+ GObjectClass *gobject_class;
+ GstElementClass *gstelement_class;
+
+ gobject_class = (GObjectClass *) klass;
+ gstelement_class = (GstElementClass *) klass;
+
+ gobject_class->finalize = rsn_parsetter_finalize;
+}
+
+static void
+rsn_parsetter_init (RsnParSetter * parset, RsnParSetterClass * gclass)
+{
+ parset->sinkpad = gst_pad_new_from_static_template (&sink_factory, "sink");
+ gst_pad_set_getcaps_function (parset->sinkpad,
+ GST_DEBUG_FUNCPTR (gst_pad_proxy_getcaps));
+ gst_pad_set_chain_function (parset->sinkpad,
+ GST_DEBUG_FUNCPTR (rsn_parsetter_chain));
+ gst_pad_set_event_function (parset->sinkpad,
+ GST_DEBUG_FUNCPTR (rsn_parsetter_sink_event));
+ gst_pad_set_setcaps_function (parset->sinkpad,
+ GST_DEBUG_FUNCPTR (rsn_parsetter_sink_setcaps));
+ gst_pad_set_bufferalloc_function (parset->sinkpad,
+ GST_DEBUG_FUNCPTR (rsn_parsetter_sink_bufferalloc));
+ gst_element_add_pad (GST_ELEMENT (parset), parset->sinkpad);
+
+ parset->srcpad = gst_pad_new_from_static_template (&src_factory, "src");
+ gst_pad_set_getcaps_function (parset->srcpad,
+ GST_DEBUG_FUNCPTR (rsn_parsetter_src_getcaps));
+ gst_element_add_pad (GST_ELEMENT (parset), parset->srcpad);
+
+ parset->caps_lock = g_mutex_new ();
+}
+
+static void
+rsn_parsetter_finalize (GObject * object)
+{
+ RsnParSetter *parset = RSN_PARSETTER (object);
+
+ gst_caps_replace (&parset->outcaps, NULL);
+ gst_caps_replace (&parset->in_caps_last, NULL);
+ gst_caps_replace (&parset->in_caps_converted, NULL);
+
+ g_mutex_free (parset->caps_lock);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static GstFlowReturn
+rsn_parsetter_chain (GstPad * pad, GstBuffer * buf)
+{
+ RsnParSetter *parset = RSN_PARSETTER (GST_OBJECT_PARENT (pad));
+
+ /* If this is a buffer we wrapped up earlier, unwrap it now */
+ if (RSN_IS_WRAPPEDBUFFER (buf)) {
+ RsnWrappedBuffer *wrap_buf = RSN_WRAPPEDBUFFER (buf);
+
+ if (wrap_buf->owner == GST_ELEMENT (parset)) {
+ buf = rsn_wrappedbuffer_unwrap_and_unref (wrap_buf);
+ GST_DEBUG_OBJECT (parset, "Unwrapping %p yields buffer %p with caps %"
+ GST_PTR_FORMAT, wrap_buf, buf, GST_BUFFER_CAPS (buf));
+ }
+ }
+
+ if (parset->outcaps != GST_BUFFER_CAPS (buf)) {
+ if (parset->override_outcaps == FALSE &&
+ gst_caps_is_equal (parset->outcaps, GST_BUFFER_CAPS (buf))) {
+ /* Just update our output caps var */
+ gst_caps_replace (&parset->outcaps, GST_BUFFER_CAPS (buf));
+ goto out;
+ }
+
+ /* Replace the caps on the output buffer */
+ buf = gst_buffer_make_metadata_writable (buf);
+ gst_buffer_set_caps (buf, parset->outcaps);
+
+ GST_DEBUG_OBJECT (parset,
+ "Replacing caps on buffer %p with caps %" GST_PTR_FORMAT,
+ buf, parset->outcaps);
+ }
+
+out:
+ return gst_pad_push (parset->srcpad, buf);
+}
+
+static gboolean
+rsn_parsetter_sink_event (GstPad * pad, GstEvent * event)
+{
+ RsnParSetter *parset = RSN_PARSETTER (gst_pad_get_parent (pad));
+ const GstStructure *structure = gst_event_get_structure (event);
+
+ if (structure != NULL &&
+ gst_structure_has_name (structure, "application/x-gst-dvd")) {
+ const char *type = gst_structure_get_string (structure, "event");
+ if (type == NULL)
+ goto out;
+
+ if (strcmp (type, "dvd-video-format") == 0) {
+ gboolean is_widescreen;
+
+ gst_structure_get_boolean (structure, "video-widescreen", &is_widescreen);
+
+ GST_DEBUG_OBJECT (parset, "Video is %s",
+ parset->is_widescreen ? "16:9" : "4:3");
+
+ g_mutex_lock (parset->caps_lock);
+ if (parset->is_widescreen != is_widescreen) {
+ /* Force caps check */
+ gst_caps_replace (&parset->in_caps_last, NULL);
+ gst_caps_replace (&parset->in_caps_converted, NULL);
+ }
+ parset->is_widescreen = is_widescreen;
+
+ /* FIXME: Added for testing: */
+ // parset->is_widescreen = FALSE;
+
+ g_mutex_unlock (parset->caps_lock);
+ }
+ }
+
+out:
+ gst_object_unref (GST_OBJECT (parset));
+ return gst_pad_event_default (pad, event);
+}
+
+static GstCaps *
+rsn_parsetter_src_getcaps (GstPad * pad)
+{
+ RsnParSetter *parset = RSN_PARSETTER (gst_pad_get_parent (pad));
+ GstCaps *ret;
+ const GstCaps *templ_caps = gst_pad_get_pad_template_caps (pad);
+
+ ret = gst_pad_peer_get_caps (parset->sinkpad);
+ if (ret == NULL)
+ ret = gst_caps_copy (templ_caps);
+ else {
+ GstCaps *temp;
+ temp = gst_caps_intersect (templ_caps, ret);
+ gst_caps_unref (ret);
+ ret = rsn_parsetter_convert_caps (parset, temp, parset->is_widescreen);
+ gst_caps_unref (temp);
+ }
+
+ gst_object_unref (parset);
+ return ret;
+}
+
+static gboolean
+rsn_parsetter_check_caps (RsnParSetter * parset, GstCaps * caps)
+{
+ GstStructure *s;
+ gint width, height;
+ gint par_n, par_d;
+ guint dar_n, dar_d;
+ gboolean ret = FALSE;
+
+ g_mutex_lock (parset->caps_lock);
+
+ if (caps == parset->in_caps_last ||
+ gst_caps_is_equal (caps, parset->in_caps_last)) {
+ ret = parset->in_caps_was_ok;
+ goto out;
+ }
+
+ /* Calculate the DAR from the incoming caps, and return TRUE if it matches
+ * the required DAR, FALSE if not */
+ s = gst_caps_get_structure (caps, 0);
+ if (s == NULL)
+ goto out;
+
+ if (!gst_structure_get_int (s, "width", &width) ||
+ !gst_structure_get_int (s, "height", &height))
+ goto out;
+
+ if (!gst_structure_get_fraction (s, "pixel-aspect-ratio", &par_n, &par_d))
+ par_n = par_d = 1;
+
+ if (!gst_video_calculate_display_ratio (&dar_n, &dar_d, width, height,
+ par_n, par_d, 1, 1))
+ goto out;
+
+ GST_DEBUG_OBJECT (parset,
+ "Incoming video caps now: w %d h %d PAR %d/%d = DAR %d/%d",
+ width, height, par_n, par_d, dar_n, dar_d);
+
+ if (parset->is_widescreen) {
+ if (dar_n == 16 && dar_d == 9)
+ ret = TRUE;
+ } else {
+ if (dar_n == 4 && dar_d == 3)
+ ret = TRUE;
+ }
+
+ gst_caps_replace (&parset->in_caps_last, caps);
+ gst_caps_replace (&parset->in_caps_converted, NULL);
+ parset->in_caps_was_ok = ret;
+
+out:
+ g_mutex_unlock (parset->caps_lock);
+ return ret;
+}
+
+static GstCaps *
+rsn_parsetter_convert_caps (RsnParSetter * parset, GstCaps * caps,
+ gboolean widescreen)
+{
+ /* Duplicate the given caps, with a PAR that provides the desired DAR */
+ GstCaps *outcaps;
+ GstStructure *s;
+ gint width, height;
+ gint par_n, par_d;
+ guint dar_n, dar_d;
+ GValue par = { 0, };
+
+ g_mutex_lock (parset->caps_lock);
+ if (caps == parset->in_caps_last && parset->in_caps_converted) {
+ outcaps = gst_caps_ref (parset->in_caps_converted);
+ goto out;
+ }
+
+ outcaps = gst_caps_copy (caps);
+
+ /* Calculate the DAR from the incoming caps, and return TRUE if it matches
+ * the required DAR, FALSE if not */
+ s = gst_caps_get_structure (outcaps, 0);
+ if (s == NULL)
+ goto out;
+
+ if (!gst_structure_get_int (s, "width", &width) ||
+ !gst_structure_get_int (s, "height", &height))
+ goto out;
+
+ if (widescreen) {
+ dar_n = 16;
+ dar_d = 9;
+ } else {
+ dar_n = 4;
+ dar_d = 3;
+ }
+
+ par_n = dar_n * height;
+ par_d = dar_d * width;
+
+ g_value_init (&par, GST_TYPE_FRACTION);
+ gst_value_set_fraction (&par, par_n, par_d);
+ gst_structure_set_value (s, "pixel-aspect-ratio", &par);
+ g_value_unset (&par);
+
+ gst_caps_replace (&parset->in_caps_converted, outcaps);
+out:
+ g_mutex_unlock (parset->caps_lock);
+ return outcaps;
+}
+
+static gboolean
+rsn_parsetter_sink_setcaps (GstPad * pad, GstCaps * caps)
+{
+ /* Check the new incoming caps against our current DAR, and mark
+ * whether the buffers will need adjusting */
+ RsnParSetter *parset = RSN_PARSETTER (gst_pad_get_parent (pad));
+
+ if (rsn_parsetter_check_caps (parset, caps)) {
+ parset->override_outcaps = FALSE;
+ gst_caps_replace (&parset->outcaps, caps);
+ } else {
+ GstCaps *override_caps = rsn_parsetter_convert_caps (parset, caps,
+ parset->is_widescreen);
+ if (parset->outcaps)
+ gst_caps_unref (parset->outcaps);
+ parset->outcaps = override_caps;
+
+ parset->override_outcaps = TRUE;
+ }
+
+ GST_DEBUG_OBJECT (parset, "caps changed: need_override now = %d",
+ parset->override_outcaps);
+
+ gst_object_unref (parset);
+ return TRUE;
+}
+
+static GstFlowReturn
+rsn_parsetter_sink_bufferalloc (GstPad * pad, guint64 offset, guint size,
+ GstCaps * caps, GstBuffer ** buf)
+{
+ RsnParSetter *parset = RSN_PARSETTER (gst_pad_get_parent (pad));
+ GstFlowReturn ret;
+
+ GST_LOG_OBJECT (parset, "Entering bufferalloc");
+
+ if (rsn_parsetter_check_caps (parset, caps)) {
+ ret = gst_pad_alloc_buffer (parset->srcpad, offset, size, caps, buf);
+ GST_LOG_OBJECT (parset, "Not wrapping buf %p", *buf);
+ } else {
+ /* Allocate and wrap a downstream buffer */
+ GstBuffer *orig_buf;
+ GstBuffer *outbuf;
+ GstCaps *override_caps = rsn_parsetter_convert_caps (parset, caps,
+ parset->is_widescreen);
+
+ ret = gst_pad_alloc_buffer (parset->srcpad, offset, size,
+ override_caps, &orig_buf);
+ gst_caps_unref (override_caps);
+
+ if (ret != GST_FLOW_OK)
+ return ret;
+
+ outbuf = (GstBuffer *) rsn_wrapped_buffer_new (orig_buf);
+ if (!outbuf) {
+ /* FIXME: Throw error */
+ return GST_FLOW_ERROR;
+ }
+
+ rsn_wrapped_buffer_set_owner (RSN_WRAPPEDBUFFER (outbuf),
+ GST_ELEMENT (parset));
+
+ gst_buffer_set_caps (outbuf, caps);
+
+ GST_LOG_OBJECT (parset,
+ "Wrapped ds buf %p with caps %" GST_PTR_FORMAT
+ " into new buf %p with caps %" GST_PTR_FORMAT,
+ orig_buf, GST_BUFFER_CAPS (orig_buf), outbuf, GST_BUFFER_CAPS (outbuf));
+
+ *buf = outbuf;
+ }
+
+ gst_object_unref (GST_OBJECT (parset));
+
+ return ret;
+}
diff --git a/ext/resindvd/rsnparsetter.h b/ext/resindvd/rsnparsetter.h
new file mode 100644
index 00000000..5e89bb1c
--- /dev/null
+++ b/ext/resindvd/rsnparsetter.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2008 Jan Schmidt <thaytan@noraisin.net>
+ */
+
+#ifndef __RSN_PARSETTER_H__
+#define __RSN_PARSETTER_H__
+
+#include <gst/gst.h>
+
+#include "rsnwrappedbuffer.h"
+
+G_BEGIN_DECLS
+
+#define RSN_TYPE_RSNPARSETTER \
+ (rsn_parsetter_get_type())
+#define RSN_PARSETTER(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),RSN_TYPE_RSNPARSETTER,RsnParSetter))
+#define RSN_PARSETTER_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),RSN_TYPE_RSNPARSETTER,RsnParSetterClass))
+#define RSN_IS_PARSETTER(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),RSN_TYPE_RSNPARSETTER))
+#define RSN_IS_PARSETTER_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),RSN_TYPE_RSNPARSETTER))
+
+typedef struct _RsnParSetter RsnParSetter;
+typedef struct _RsnParSetterClass RsnParSetterClass;
+
+struct _RsnParSetter
+{
+ GstElement element;
+
+ GstPad *sinkpad, *srcpad;
+
+ gboolean override_outcaps;
+ GstCaps *outcaps;
+
+ gboolean is_widescreen;
+
+ GMutex *caps_lock;
+ GstCaps *in_caps_last;
+ gboolean in_caps_was_ok;
+ GstCaps *in_caps_converted;
+};
+
+struct _RsnParSetterClass
+{
+ GstElementClass parent_class;
+};
+
+GType rsn_parsetter_get_type (void);
+
+G_END_DECLS
+
+#endif /* __RSN_PARSETTER_H__ */
diff --git a/ext/resindvd/rsnwrappedbuffer.c b/ext/resindvd/rsnwrappedbuffer.c
new file mode 100644
index 00000000..e394e429
--- /dev/null
+++ b/ext/resindvd/rsnwrappedbuffer.c
@@ -0,0 +1,152 @@
+/* GStreamer
+ * Copyright (C) 2008 Jan Schmidt <thaytan@noraisin.net>
+ *
+ * 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.
+ */
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <string.h>
+
+#include <gst/gst.h>
+
+#include "rsnwrappedbuffer.h"
+
+GST_BOILERPLATE (RsnWrappedBuffer, rsn_wrappedbuffer,
+ GstBuffer, GST_TYPE_BUFFER);
+
+static gboolean
+rsn_wrapped_buffer_default_release (GstElement * owner, RsnWrappedBuffer * buf);
+
+static void rsn_wrapped_buffer_finalize (RsnWrappedBuffer * wrap_buf);
+
+static void
+rsn_wrappedbuffer_base_init (gpointer gclass)
+{
+}
+
+static void
+rsn_wrappedbuffer_class_init (RsnWrappedBufferClass * klass)
+{
+ GstMiniObjectClass *mini_object_class = GST_MINI_OBJECT_CLASS (klass);
+
+ mini_object_class->finalize = (GstMiniObjectFinalizeFunction)
+ rsn_wrapped_buffer_finalize;
+}
+
+static void
+rsn_wrappedbuffer_init (RsnWrappedBuffer * buf, RsnWrappedBufferClass * gclass)
+{
+ buf->release = rsn_wrapped_buffer_default_release;
+}
+
+static void
+rsn_wrapped_buffer_finalize (RsnWrappedBuffer * wrap_buf)
+{
+ if (wrap_buf->release) {
+ /* Release might increment the refcount to recycle and return TRUE,
+ * in which case, exit without chaining up */
+ if (wrap_buf->release (wrap_buf->owner, wrap_buf))
+ return;
+ }
+
+ GST_MINI_OBJECT_CLASS (parent_class)->finalize (GST_MINI_OBJECT (wrap_buf));
+}
+
+RsnWrappedBuffer *
+rsn_wrapped_buffer_new (GstBuffer * buf_to_wrap)
+{
+ RsnWrappedBuffer *buf;
+ g_return_val_if_fail (buf_to_wrap, NULL);
+
+ buf = (RsnWrappedBuffer *) gst_mini_object_new (RSN_TYPE_WRAPPEDBUFFER);
+ if (buf == NULL)
+ return NULL;
+
+ buf->wrapped_buffer = buf_to_wrap;
+
+ GST_BUFFER_DATA (buf) = GST_BUFFER_DATA (buf_to_wrap);
+ GST_BUFFER_SIZE (buf) = GST_BUFFER_SIZE (buf_to_wrap);
+ gst_buffer_copy_metadata (GST_BUFFER (buf), buf_to_wrap, GST_BUFFER_COPY_ALL);
+
+ /* If the wrapped buffer isn't writable, make sure this one isn't either */
+ if (!gst_buffer_is_writable (buf_to_wrap))
+ GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_READONLY);
+
+ return buf;
+}
+
+void
+rsn_wrapped_buffer_set_owner (RsnWrappedBuffer * wrapped_buf,
+ GstElement * owner)
+{
+ g_return_if_fail (wrapped_buf != NULL);
+
+ if (wrapped_buf->owner)
+ gst_object_unref (wrapped_buf->owner);
+
+ if (owner)
+ wrapped_buf->owner = gst_object_ref (owner);
+ else
+ wrapped_buf->owner = NULL;
+}
+
+void
+rsn_wrapped_buffer_set_releasefunc (RsnWrappedBuffer * wrapped_buf,
+ RsnWrappedBufferReleaseFunc release_func)
+{
+ g_return_if_fail (wrapped_buf != NULL);
+
+ wrapped_buf->release = release_func;
+}
+
+static gboolean
+rsn_wrapped_buffer_default_release (GstElement * owner, RsnWrappedBuffer * buf)
+{
+ g_return_val_if_fail (buf != NULL, FALSE);
+ g_return_val_if_fail (buf->wrapped_buffer != NULL, FALSE);
+
+ gst_buffer_unref (buf->wrapped_buffer);
+ if (buf->owner)
+ gst_object_unref (buf->owner);
+
+ return FALSE;
+}
+
+GstBuffer *
+rsn_wrappedbuffer_unwrap_and_unref (RsnWrappedBuffer * wrap_buf)
+{
+ GstBuffer *buf;
+ gboolean is_readonly;
+
+ g_return_val_if_fail (wrap_buf != NULL, NULL);
+ g_return_val_if_fail (wrap_buf->wrapped_buffer != NULL, NULL);
+
+ buf = gst_buffer_ref (wrap_buf->wrapped_buffer);
+
+ /* Copy changed metadata back to the wrapped buffer from the wrapper,
+ * except the the read-only flag and the caps. */
+ is_readonly = GST_BUFFER_FLAG_IS_SET (wrap_buf, GST_BUFFER_FLAG_READONLY);
+ gst_buffer_copy_metadata (buf, GST_BUFFER (wrap_buf),
+ GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS);
+ if (!is_readonly)
+ GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_READONLY);
+
+ gst_buffer_unref (GST_BUFFER (wrap_buf));
+
+ return buf;
+}
diff --git a/ext/resindvd/rsnwrappedbuffer.h b/ext/resindvd/rsnwrappedbuffer.h
new file mode 100644
index 00000000..7c6a0e73
--- /dev/null
+++ b/ext/resindvd/rsnwrappedbuffer.h
@@ -0,0 +1,69 @@
+/* GStreamer
+ * Copyright (C) 2008 Jan Schmidt <thaytan@noraisin.net>
+ *
+ * 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.
+ */
+
+#ifndef __RSN_WRAPPERBUFFER_H__
+#define __RSN_WRAPPERBUFFER_H__
+
+#include <gst/gst.h>
+
+G_BEGIN_DECLS
+
+#define RSN_TYPE_WRAPPEDBUFFER (rsn_wrappedbuffer_get_type())
+#define RSN_WRAPPEDBUFFER(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj), RSN_TYPE_WRAPPEDBUFFER, \
+ RsnWrappedBuffer))
+#define RSN_WRAPPEDBUFFER_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass), RSN_TYPE_WRAPPEDBUFFER, \
+ RsnWrappedBufferClass))
+#define RSN_IS_WRAPPEDBUFFER(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj), RSN_TYPE_WRAPPEDBUFFER))
+#define RSN_IS_WRAPPEDBUFFER_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass), RSN_TYPE_WRAPPEDBUFFER))
+
+typedef struct _RsnWrappedBuffer RsnWrappedBuffer;
+typedef struct _RsnWrappedBufferClass RsnWrappedBufferClass;
+
+typedef gboolean (*RsnWrappedBufferReleaseFunc)(GstElement *owner,
+ RsnWrappedBuffer *buf);
+
+struct _RsnWrappedBuffer {
+ GstBuffer buffer;
+ GstBuffer *wrapped_buffer;
+
+ GstElement *owner;
+ RsnWrappedBufferReleaseFunc release;
+};
+
+struct _RsnWrappedBufferClass
+{
+ GstBufferClass parent_class;
+};
+
+RsnWrappedBuffer *rsn_wrapped_buffer_new (GstBuffer *buf_to_wrap);
+GstBuffer *rsn_wrappedbuffer_unwrap_and_unref (RsnWrappedBuffer *wrap_buf);
+void rsn_wrapped_buffer_set_owner (RsnWrappedBuffer *wrapped_buf,
+ GstElement *owner);
+void rsn_wrapped_buffer_set_releasefunc (RsnWrappedBuffer *wrapped_buf,
+ RsnWrappedBufferReleaseFunc release_func);
+
+GType rsn_wrappedbuffer_get_type (void);
+
+G_END_DECLS
+
+#endif