From 42d24ab5fbab1fc9cde6914445a1876a92413966 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Mon, 4 May 2009 12:30:26 +0200 Subject: faac: Implement preset interface --- ext/faac/gstfaac.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'ext') diff --git a/ext/faac/gstfaac.c b/ext/faac/gstfaac.c index 22484ffb..638e65b1 100644 --- a/ext/faac/gstfaac.c +++ b/ext/faac/gstfaac.c @@ -118,9 +118,17 @@ gst_faac_get_type (void) 0, (GInstanceInitFunc) gst_faac_init, }; + const GInterfaceInfo preset_interface_info = { + NULL, /* interface_init */ + NULL, /* interface_finalize */ + NULL /* interface_data */ + }; gst_faac_type = g_type_register_static (GST_TYPE_ELEMENT, "GstFaac", &gst_faac_info, 0); + + g_type_add_interface_static (gst_faac_type, GST_TYPE_PRESET, + &preset_interface_info); } return gst_faac_type; -- cgit v1.2.1 From 296caf466014e11e73a67e8ec27d32f6e78b0a9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Mon, 4 May 2009 12:31:58 +0200 Subject: xvid: Implement Preset interface --- ext/xvid/gstxvidenc.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'ext') diff --git a/ext/xvid/gstxvidenc.c b/ext/xvid/gstxvidenc.c index ea6d3aed..40b5be22 100644 --- a/ext/xvid/gstxvidenc.c +++ b/ext/xvid/gstxvidenc.c @@ -199,9 +199,17 @@ gst_xvidenc_get_type (void) 0, (GInstanceInitFunc) gst_xvidenc_init, }; + const GInterfaceInfo preset_interface_info = { + NULL, /* interface_init */ + NULL, /* interface_finalize */ + NULL /* interface_data */ + }; xvidenc_type = g_type_register_static (GST_TYPE_ELEMENT, "GstXvidEnc", &xvidenc_info, 0); + + g_type_add_interface_static (xvidenc_type, GST_TYPE_PRESET, + &preset_interface_info); } return xvidenc_type; } -- cgit v1.2.1 From e9e52d0a9d9fdafc3ee499a9151f8ffbc22752af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Mon, 4 May 2009 12:33:41 +0200 Subject: mpeg2enc: Implement Preset interface --- ext/mpeg2enc/gstmpeg2enc.cc | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) (limited to 'ext') diff --git a/ext/mpeg2enc/gstmpeg2enc.cc b/ext/mpeg2enc/gstmpeg2enc.cc index e96e8124..21be81fb 100644 --- a/ext/mpeg2enc/gstmpeg2enc.cc +++ b/ext/mpeg2enc/gstmpeg2enc.cc @@ -99,7 +99,21 @@ static void gst_mpeg2enc_get_property (GObject * object, static void gst_mpeg2enc_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec); -GST_BOILERPLATE (GstMpeg2enc, gst_mpeg2enc, GstElement, GST_TYPE_ELEMENT); +static void +_do_init (GType object_type) +{ + const GInterfaceInfo preset_interface_info = { + NULL, /* interface_init */ + NULL, /* interface_finalize */ + NULL /* interface_data */ + }; + + g_type_add_interface_static (object_type, GST_TYPE_PRESET, + &preset_interface_info); +} + +GST_BOILERPLATE_FULL (GstMpeg2enc, gst_mpeg2enc, GstElement, GST_TYPE_ELEMENT, + _do_init); static void gst_mpeg2enc_base_init (gpointer klass) -- cgit v1.2.1 From c53e4b8efcd5bcf8589b9d98af37cf7331b6dd05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Mon, 4 May 2009 12:34:59 +0200 Subject: jp2kenc: Implement preset interface --- ext/jp2k/gstjasperenc.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) (limited to 'ext') diff --git a/ext/jp2k/gstjasperenc.c b/ext/jp2k/gstjasperenc.c index 47818eb3..9e6e17c9 100644 --- a/ext/jp2k/gstjasperenc.c +++ b/ext/jp2k/gstjasperenc.c @@ -94,7 +94,21 @@ static GstFlowReturn gst_jasper_enc_chain (GstPad * pad, GstBuffer * buffer); typedef GstJasperEnc GstJp2kEnc; typedef GstJasperEncClass GstJp2kEncClass; -GST_BOILERPLATE (GstJp2kEnc, gst_jasper_enc, GstElement, GST_TYPE_ELEMENT); +static void +_do_init (GType object_type) +{ + const GInterfaceInfo preset_interface_info = { + NULL, /* interface_init */ + NULL, /* interface_finalize */ + NULL /* interface_data */ + }; + + g_type_add_interface_static (object_type, GST_TYPE_PRESET, + &preset_interface_info); +} + +GST_BOILERPLATE_FULL (GstJp2kEnc, gst_jasper_enc, GstElement, GST_TYPE_ELEMENT, + _do_init); static void gst_jasper_enc_base_init (gpointer g_class) -- cgit v1.2.1 From f3105eccd26d69ae022d1a9fc8c510339f8337f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Mon, 4 May 2009 12:36:17 +0200 Subject: dirac: Implement preset interface --- ext/dirac/gstdiracenc.cc | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) (limited to 'ext') diff --git a/ext/dirac/gstdiracenc.cc b/ext/dirac/gstdiracenc.cc index f3be8202..11372f89 100644 --- a/ext/dirac/gstdiracenc.cc +++ b/ext/dirac/gstdiracenc.cc @@ -148,7 +148,21 @@ GST_STATIC_PAD_TEMPLATE ("src", GST_STATIC_CAPS ("video/x-dirac") ); -GST_BOILERPLATE (GstDiracEnc, gst_dirac_enc, GstElement, GST_TYPE_ELEMENT); +static void +_do_init (GType object_type) +{ + const GInterfaceInfo preset_interface_info = { + NULL, /* interface_init */ + NULL, /* interface_finalize */ + NULL /* interface_data */ + }; + + g_type_add_interface_static (object_type, GST_TYPE_PRESET, + &preset_interface_info); +} + +GST_BOILERPLATE_FULL (GstDiracEnc, gst_dirac_enc, GstElement, GST_TYPE_ELEMENT, + _do_init); static void gst_dirac_enc_base_init (gpointer g_class) -- cgit v1.2.1 From 44f0d31ba385ee644a8bd64efc64679c2e92e7eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Mon, 4 May 2009 12:37:31 +0200 Subject: celt: Implement preset interface --- ext/celt/gstceltenc.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'ext') diff --git a/ext/celt/gstceltenc.c b/ext/celt/gstceltenc.c index 11b57e55..58ed7571 100644 --- a/ext/celt/gstceltenc.c +++ b/ext/celt/gstceltenc.c @@ -106,9 +106,16 @@ static void gst_celt_enc_setup_interfaces (GType celtenc_type) { static const GInterfaceInfo tag_setter_info = { NULL, NULL, NULL }; + const GInterfaceInfo preset_interface_info = { + NULL, /* interface_init */ + NULL, /* interface_finalize */ + NULL /* interface_data */ + }; g_type_add_interface_static (celtenc_type, GST_TYPE_TAG_SETTER, &tag_setter_info); + g_type_add_interface_static (celtenc_type, GST_TYPE_PRESET, + &preset_interface_info); GST_DEBUG_CATEGORY_INIT (celtenc_debug, "celtenc", 0, "Celt encoder"); } -- cgit v1.2.1 From 874549b5360ad897e11f809e929d62803a7b5f2f Mon Sep 17 00:00:00 2001 From: Jan Schmidt Date: Tue, 5 May 2009 11:34:26 +0100 Subject: resindvd: Make the next/prev angle switching cycle at the ends When the current angle is 1 and prev_angle is requested, loop to the maximum angle and vice versa for next_angle --- ext/resindvd/resindvdsrc.c | 34 +++++++++++++++++++++++++--------- 1 file changed, 25 insertions(+), 9 deletions(-) (limited to 'ext') diff --git a/ext/resindvd/resindvdsrc.c b/ext/resindvd/resindvdsrc.c index a2f31610..ab0fdef9 100644 --- a/ext/resindvd/resindvdsrc.c +++ b/ext/resindvd/resindvdsrc.c @@ -1172,6 +1172,7 @@ static RsnNavResult rsn_dvdsrc_do_command (resinDvdSrc * src, GstNavigationCommand command) { RsnNavResult result = RSN_NAV_RESULT_NONE; + gint new_angle = 0; switch (command) { case GST_NAVIGATION_COMMAND_DVD_MENU: @@ -1212,25 +1213,40 @@ rsn_dvdsrc_do_command (resinDvdSrc * src, GstNavigationCommand command) case GST_NAVIGATION_COMMAND_PREV_ANGLE:{ gint32 cur, agls; - if (dvdnav_get_angle_info (src->dvdnav, &cur, &agls) == DVDNAV_STATUS_OK - && cur > 0 - && dvdnav_angle_change (src->dvdnav, cur - 1) == DVDNAV_STATUS_OK) - GST_INFO_OBJECT (src, "Switched to angle %d", cur - 1); - /* Angle switches are seamless and involve no branching */ + if (dvdnav_get_angle_info (src->dvdnav, &cur, &agls) == DVDNAV_STATUS_OK) { + if (cur > 0 && + dvdnav_angle_change (src->dvdnav, cur - 1) == DVDNAV_STATUS_OK) { + new_angle = cur - 1; + } else if (cur == 1 && + dvdnav_angle_change (src->dvdnav, agls) == DVDNAV_STATUS_OK) { + new_angle = agls; + } + /* Angle switches are seamless and involve no branching */ + } break; } case GST_NAVIGATION_COMMAND_NEXT_ANGLE:{ gint32 cur, agls; - if (dvdnav_get_angle_info (src->dvdnav, &cur, &agls) == DVDNAV_STATUS_OK - && dvdnav_angle_change (src->dvdnav, cur + 1) == DVDNAV_STATUS_OK) - GST_INFO_OBJECT (src, "Switched to angle %d", cur + 1); - /* Angle switches are seamless and involve no branching */ + if (dvdnav_get_angle_info (src->dvdnav, &cur, &agls) == DVDNAV_STATUS_OK) { + if (cur < agls + && dvdnav_angle_change (src->dvdnav, cur + 1) == DVDNAV_STATUS_OK) { + new_angle = cur + 1; + } else if (cur == agls + && dvdnav_angle_change (src->dvdnav, 1) == DVDNAV_STATUS_OK) { + new_angle = 1; + } + /* Angle switches are seamless and involve no branching */ + } break; } default: break; } + if (new_angle) { + GST_INFO_OBJECT (src, "Switched to angle %d", new_angle); + } + return result; } -- cgit v1.2.1 From 491583b6482fd6287653b8c6fb49494dd44b4261 Mon Sep 17 00:00:00 2001 From: Jan Schmidt Date: Tue, 5 May 2009 13:14:47 +0100 Subject: resindvd: send angles-changed messages when appropriate When the current angle changes, or the number of available angles changes, send an angles-changed message to let the app know. --- ext/resindvd/resindvdsrc.c | 59 ++++++++++++++++++++++++++++++++++++++++++---- ext/resindvd/resindvdsrc.h | 3 +++ 2 files changed, 57 insertions(+), 5 deletions(-) (limited to 'ext') diff --git a/ext/resindvd/resindvdsrc.c b/ext/resindvd/resindvdsrc.c index ab0fdef9..35cf8e15 100644 --- a/ext/resindvd/resindvdsrc.c +++ b/ext/resindvd/resindvdsrc.c @@ -391,6 +391,9 @@ rsn_dvdsrc_start (RsnBaseSrc * bsrc) src->active_button = -1; + src->angles_changed = FALSE; + src->n_angles = 0; + src->cur_spu_phys_stream = -1; src->cur_spu_forced_only = FALSE; memset (src->cur_clut, 0, sizeof (guint32) * 16); @@ -859,6 +862,7 @@ rsn_dvdsrc_step (resinDvdSrc * src, gboolean have_dvd_lock) break; case DVDNAV_CELL_CHANGE:{ dvdnav_cell_change_event_t *event = (dvdnav_cell_change_event_t *) data; + gint n_angles, cur; src->pgc_duration = MPEGTIME_TO_GSTTIME (event->pgc_length); /* event->cell_start has the wrong time - it doesn't handle @@ -874,6 +878,12 @@ rsn_dvdsrc_step (resinDvdSrc * src, gboolean have_dvd_lock) rsn_dvdsrc_prepare_streamsinfo_event (src); + if (dvdnav_get_angle_info (src->dvdnav, &cur, + &n_angles) == DVDNAV_STATUS_OK && src->n_angles != n_angles) { + src->angles_changed = TRUE; + src->n_angles = n_angles; + } + break; } case DVDNAV_SPU_CLUT_CHANGE: @@ -998,6 +1008,7 @@ rsn_dvdsrc_create (RsnPushSrc * psrc, GstBuffer ** outbuf) GstEvent *spu_select_event = NULL; GstEvent *audio_select_event = NULL; GstEvent *highlight_event = NULL; + GstMessage *angles_msg = NULL; *outbuf = NULL; @@ -1020,6 +1031,18 @@ rsn_dvdsrc_create (RsnPushSrc * psrc, GstBuffer ** outbuf) clut_event = src->clut_event; src->clut_event = NULL; + if (src->angles_changed) { + gint cur, agls; + if (dvdnav_get_angle_info (src->dvdnav, &cur, &agls) == DVDNAV_STATUS_OK) { + + angles_msg = + gst_navigation_message_new_angles_changed (GST_OBJECT_CAST (src), + cur, agls); + src->n_angles = agls; + } + src->angles_changed = FALSE; + } + g_mutex_unlock (src->dvd_lock); /* Push in-band events now that we've dropped the dvd_lock, before @@ -1089,6 +1112,10 @@ rsn_dvdsrc_create (RsnPushSrc * psrc, GstBuffer ** outbuf) gst_pad_push_event (GST_BASE_SRC_PAD (src), highlight_event); } + if (angles_msg) { + gst_element_post_message (GST_ELEMENT_CAST (src), angles_msg); + } + return ret; } @@ -1172,7 +1199,6 @@ static RsnNavResult rsn_dvdsrc_do_command (resinDvdSrc * src, GstNavigationCommand command) { RsnNavResult result = RSN_NAV_RESULT_NONE; - gint new_angle = 0; switch (command) { case GST_NAVIGATION_COMMAND_DVD_MENU: @@ -1213,6 +1239,7 @@ rsn_dvdsrc_do_command (resinDvdSrc * src, GstNavigationCommand command) case GST_NAVIGATION_COMMAND_PREV_ANGLE:{ gint32 cur, agls; + gint new_angle = 0; if (dvdnav_get_angle_info (src->dvdnav, &cur, &agls) == DVDNAV_STATUS_OK) { if (cur > 0 && dvdnav_angle_change (src->dvdnav, cur - 1) == DVDNAV_STATUS_OK) { @@ -1222,11 +1249,16 @@ rsn_dvdsrc_do_command (resinDvdSrc * src, GstNavigationCommand command) new_angle = agls; } /* Angle switches are seamless and involve no branching */ + if (new_angle) { + src->angles_changed = TRUE; + GST_INFO_OBJECT (src, "Switched to angle %d", new_angle); + } } break; } case GST_NAVIGATION_COMMAND_NEXT_ANGLE:{ gint32 cur, agls; + gint new_angle = 0; if (dvdnav_get_angle_info (src->dvdnav, &cur, &agls) == DVDNAV_STATUS_OK) { if (cur < agls && dvdnav_angle_change (src->dvdnav, cur + 1) == DVDNAV_STATUS_OK) { @@ -1236,6 +1268,10 @@ rsn_dvdsrc_do_command (resinDvdSrc * src, GstNavigationCommand command) new_angle = 1; } /* Angle switches are seamless and involve no branching */ + if (new_angle) { + src->angles_changed = TRUE; + GST_INFO_OBJECT (src, "Switched to angle %d", new_angle); + } } break; } @@ -1243,10 +1279,6 @@ rsn_dvdsrc_do_command (resinDvdSrc * src, GstNavigationCommand command) break; } - if (new_angle) { - GST_INFO_OBJECT (src, "Switched to angle %d", new_angle); - } - return result; } @@ -1258,6 +1290,7 @@ rsn_dvdsrc_handle_navigation_event (resinDvdSrc * src, GstEvent * event) RsnNavResult nav_res = RSN_NAV_RESULT_NONE; GstNavigationEventType etype = gst_navigation_event_get_type (event); GstMessage *mouse_over_msg = NULL; + GstMessage *angles_msg = NULL; switch (etype) { case GST_NAVIGATION_EVENT_KEY_PRESS:{ @@ -1438,6 +1471,18 @@ rsn_dvdsrc_handle_navigation_event (resinDvdSrc * src, GstEvent * event) hl_event = src->highlight_event; src->highlight_event = NULL; + if (src->angles_changed) { + gint cur, agls; + if (dvdnav_get_angle_info (src->dvdnav, &cur, &agls) == DVDNAV_STATUS_OK) { + + angles_msg = + gst_navigation_message_new_angles_changed (GST_OBJECT_CAST (src), + cur, agls); + src->n_angles = agls; + } + src->angles_changed = FALSE; + } + g_mutex_unlock (src->dvd_lock); if (hl_event) { @@ -1451,6 +1496,10 @@ rsn_dvdsrc_handle_navigation_event (resinDvdSrc * src, GstEvent * event) gst_element_post_message (GST_ELEMENT_CAST (src), mouse_over_msg); } + if (angles_msg) { + gst_element_post_message (GST_ELEMENT_CAST (src), angles_msg); + } + return TRUE; not_running: if (have_lock) diff --git a/ext/resindvd/resindvdsrc.h b/ext/resindvd/resindvdsrc.h index 61fa5d19..bfcb7497 100644 --- a/ext/resindvd/resindvdsrc.h +++ b/ext/resindvd/resindvdsrc.h @@ -114,6 +114,8 @@ struct _resinDvdSrc GstEvent *audio_select_event; GstEvent *highlight_event; + gboolean angles_changed; + /* GList of NAV packets awaiting activation, and the * running times to activate them. */ GSList *pending_nav_blocks; @@ -129,6 +131,7 @@ struct _resinDvdSrc gint8 cur_spu_phys_stream; gboolean cur_spu_forced_only; guint32 cur_clut[16]; + gint n_angles; }; struct _resinDvdSrcClass -- cgit v1.2.1 From f7fad4a88b56dd74b14070886c8e86bb14942b20 Mon Sep 17 00:00:00 2001 From: Jan Schmidt Date: Tue, 5 May 2009 13:18:20 +0100 Subject: resindvd: Don't send highlight-reset messages when not needed Fix a small bug that results in the SPU highlight being reset more often than is necessary - ie, clearing it when it's already cleared. --- ext/resindvd/resindvdsrc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'ext') diff --git a/ext/resindvd/resindvdsrc.c b/ext/resindvd/resindvdsrc.c index 35cf8e15..389b9016 100644 --- a/ext/resindvd/resindvdsrc.c +++ b/ext/resindvd/resindvdsrc.c @@ -1798,7 +1798,7 @@ rsn_dvdsrc_update_highlight (resinDvdSrc * src) if (button == 0) { /* No highlight available, or no button selected - clear the SPU */ - if (src->active_button < 1) { + if (src->active_button != 0) { src->active_button = 0; s = gst_structure_new ("application/x-gst-dvd", "event", -- cgit v1.2.1 From a5fbb123cab57358325b9cd94d2e8de50361f0c1 Mon Sep 17 00:00:00 2001 From: Jan Schmidt Date: Wed, 6 May 2009 21:19:13 +0100 Subject: resindvd: Send a title tag when we change chapter/menu/angle Allow apps like Totem to display a nicer title that reflects the current position on the disc. --- ext/resindvd/resindvdsrc.c | 78 ++++++++++++++++++++++++++++++++++++++++++---- ext/resindvd/resindvdsrc.h | 4 +++ 2 files changed, 76 insertions(+), 6 deletions(-) (limited to 'ext') diff --git a/ext/resindvd/resindvdsrc.c b/ext/resindvd/resindvdsrc.c index 389b9016..ba800efe 100644 --- a/ext/resindvd/resindvdsrc.c +++ b/ext/resindvd/resindvdsrc.c @@ -374,6 +374,8 @@ rsn_dvdsrc_start (RsnBaseSrc * bsrc) } } + dvdnav_get_title_string (src->dvdnav, &src->disc_name); + src->first_seek = TRUE; src->running = TRUE; src->branching = FALSE; @@ -388,6 +390,8 @@ rsn_dvdsrc_start (RsnBaseSrc * bsrc) src->vts_n = 0; src->in_menu = FALSE; + src->title_n = -1; + src->part_n = -1; src->active_button = -1; @@ -519,6 +523,8 @@ rsn_dvdsrc_stop (RsnBaseSrc * bsrc) src->highlight_event = NULL; } + src->disc_name = NULL; + if (src->dvdnav) { if (dvdnav_close (src->dvdnav) != DVDNAV_STATUS_OK) { GST_ELEMENT_ERROR (src, RESOURCE, CLOSE, (NULL), @@ -725,6 +731,71 @@ get_current_pgc (resinDvdSrc * src) return pgc; } +static void +update_title_info (resinDvdSrc * src) +{ + gint n_angles, cur_agl; + gint title_n, part_n; + + if (dvdnav_get_angle_info (src->dvdnav, &cur_agl, + &n_angles) == DVDNAV_STATUS_OK && src->n_angles != n_angles) { + src->angles_changed = TRUE; + src->n_angles = n_angles; + } + + if (dvdnav_current_title_info (src->dvdnav, &title_n, + &part_n) == DVDNAV_STATUS_OK) { + if (title_n != src->title_n || part_n != src->part_n || src->angles_changed) { + gchar *title_str = NULL; + + src->title_n = title_n; + src->part_n = part_n; + + if (title_n == 0) { + static const char *dvd_menu_map[] = { + NULL, NULL, "Title", "Root", + "Subpicture", "Audio", "Angle", "Part" + }; + + /* In a menu */ + if (part_n >= 0 && part_n < G_N_ELEMENTS (dvd_menu_map) + && dvd_menu_map[part_n]) { + title_str = g_strdup_printf ("DVD %s Menu", dvd_menu_map[part_n]); + } else { + title_str = g_strdup ("DVD Menu"); + } + } else { + /* In a title */ + if (n_angles > 1) { + title_str = g_strdup_printf ("Title %i, Chapter %i, Angle %i of %i", + title_n, part_n, cur_agl, n_angles); + + } else { + title_str = g_strdup_printf ("Title %i, Chapter %i", title_n, part_n); + } + } + + if (src->disc_name && src->disc_name[0]) { + /* We have a name for this disc, publish it */ + if (title_str) { + gchar *new_title_str = + g_strdup_printf ("%s, %s", title_str, src->disc_name); + g_free (title_str); + title_str = new_title_str; + } else { + title_str = g_strdup (src->disc_name); + } + } + if (title_str) { + GstTagList *tags = gst_tag_list_new (); + gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_TITLE, + title_str, NULL); + gst_element_found_tags (GST_ELEMENT_CAST (src), tags); + } + } + } +} + static GstFlowReturn rsn_dvdsrc_step (resinDvdSrc * src, gboolean have_dvd_lock) { @@ -862,7 +933,6 @@ rsn_dvdsrc_step (resinDvdSrc * src, gboolean have_dvd_lock) break; case DVDNAV_CELL_CHANGE:{ dvdnav_cell_change_event_t *event = (dvdnav_cell_change_event_t *) data; - gint n_angles, cur; src->pgc_duration = MPEGTIME_TO_GSTTIME (event->pgc_length); /* event->cell_start has the wrong time - it doesn't handle @@ -878,11 +948,7 @@ rsn_dvdsrc_step (resinDvdSrc * src, gboolean have_dvd_lock) rsn_dvdsrc_prepare_streamsinfo_event (src); - if (dvdnav_get_angle_info (src->dvdnav, &cur, - &n_angles) == DVDNAV_STATUS_OK && src->n_angles != n_angles) { - src->angles_changed = TRUE; - src->n_angles = n_angles; - } + update_title_info (src); break; } diff --git a/ext/resindvd/resindvdsrc.h b/ext/resindvd/resindvdsrc.h index bfcb7497..f55b454f 100644 --- a/ext/resindvd/resindvdsrc.h +++ b/ext/resindvd/resindvdsrc.h @@ -58,6 +58,8 @@ struct _resinDvdSrc gchar *device; dvdnav_t *dvdnav; + const char *disc_name; + /* dvd_reader instance is used to load and cache VTS/VMG ifo info */ dvd_reader_t *dvdread; @@ -72,6 +74,8 @@ struct _resinDvdSrc /* Current playback location: VTS 0 = VMG, plus in_menu or not */ gint vts_n; gboolean in_menu; + gint title_n; /* Title num */ + gint part_n; /* Part num */ gboolean running; gboolean discont; -- cgit v1.2.1 From 77aefd58709b2151b59430f944eec80f18201b7f Mon Sep 17 00:00:00 2001 From: Jan Schmidt Date: Wed, 6 May 2009 21:48:30 +0100 Subject: resindvd: Don't open all VTS ifo at the start Load each VTS ifo the first time the disc enters that VTS, rather than scanning them all at the start. --- ext/resindvd/resindvdsrc.c | 53 +++++++++++++++++++++++++++++----------------- 1 file changed, 33 insertions(+), 20 deletions(-) (limited to 'ext') diff --git a/ext/resindvd/resindvdsrc.c b/ext/resindvd/resindvdsrc.c index ba800efe..54a39be1 100644 --- a/ext/resindvd/resindvdsrc.c +++ b/ext/resindvd/resindvdsrc.c @@ -421,7 +421,6 @@ fail: static gboolean read_vts_info (resinDvdSrc * src) { - gint i; gint n_vts; if (src->vts_attrs) { @@ -450,28 +449,48 @@ read_vts_info (resinDvdSrc * src) return FALSE; g_array_set_size (src->vts_attrs, n_vts + 1); - for (i = 1; i <= n_vts; i++) { - ifo_handle_t *ifo = ifoOpen (src->dvdread, i); + return TRUE; +} + +static vtsi_mat_t * +get_vts_attr (resinDvdSrc * src, gint n) +{ + vtsi_mat_t *vts_attr; + + if (src->vts_attrs == NULL || n >= src->vts_attrs->len) { + if (src->vts_attrs) + GST_ERROR_OBJECT (src, "No stream info for VTS %d (have %d)", n, + src->vts_attrs->len); + else + GST_ERROR_OBJECT (src, "No stream info"); + return NULL; + } + + vts_attr = &g_array_index (src->vts_attrs, vtsi_mat_t, src->vts_n); + + /* Check if we have read this VTS ifo yet */ + if (vts_attr->vtsm_vobs == 0) { + ifo_handle_t *ifo = ifoOpen (src->dvdread, n); if (!ifo) { - GST_ERROR ("Can't open VTS %d", i); - return FALSE; + GST_ERROR ("Can't open VTS %d", n); + return NULL; } GST_DEBUG ("VTS %d, Menu has %d audio %d subpictures. " - "Title has %d and %d", i, + "Title has %d and %d", n, ifo->vtsi_mat->nr_of_vtsm_audio_streams, ifo->vtsi_mat->nr_of_vtsm_subp_streams, ifo->vtsi_mat->nr_of_vts_audio_streams, ifo->vtsi_mat->nr_of_vts_subp_streams); - memcpy (&g_array_index (src->vts_attrs, vtsi_mat_t, i), + memcpy (&g_array_index (src->vts_attrs, vtsi_mat_t, n), ifo->vtsi_mat, sizeof (vtsi_mat_t)); ifoClose (ifo); - } + }; - return TRUE; + return vts_attr; } static gboolean @@ -1646,15 +1665,6 @@ rsn_dvdsrc_prepare_streamsinfo_event (resinDvdSrc * src) gboolean have_audio; gboolean have_subp; - if (src->vts_attrs == NULL || src->vts_n >= src->vts_attrs->len) { - if (src->vts_attrs) - GST_ERROR_OBJECT (src, "No stream info for VTS %d (have %d)", src->vts_n, - src->vts_attrs->len); - else - GST_ERROR_OBJECT (src, "No stream info"); - return FALSE; - } - if (src->vts_n == 0) { /* VMGM info */ vts_attr = NULL; @@ -1665,7 +1675,7 @@ rsn_dvdsrc_prepare_streamsinfo_event (resinDvdSrc * src) n_subp = MIN (1, src->vmgm_attr.nr_of_vmgm_subp_streams); } else if (src->in_menu) { /* VTSM attrs */ - vts_attr = &g_array_index (src->vts_attrs, vtsi_mat_t, src->vts_n); + vts_attr = get_vts_attr (src, 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; @@ -1673,7 +1683,7 @@ rsn_dvdsrc_prepare_streamsinfo_event (resinDvdSrc * src) n_subp = vts_attr->nr_of_vtsm_subp_streams; } else { /* VTS domain */ - vts_attr = &g_array_index (src->vts_attrs, vtsi_mat_t, src->vts_n); + vts_attr = get_vts_attr (src, 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; @@ -1681,6 +1691,9 @@ rsn_dvdsrc_prepare_streamsinfo_event (resinDvdSrc * src) n_subp = vts_attr->nr_of_vts_subp_streams; } + if (src->vts_n > 0 && vts_attr == NULL) + return FALSE; + GST_DEBUG_OBJECT (src, "Preparing streamsinfo for %d audio and " "%d subpicture streams", n_audio, n_subp); -- cgit v1.2.1 From 67dd3c11f47f1afd3508e3b45a3023ce9612fe67 Mon Sep 17 00:00:00 2001 From: Christian Schaller Date: Thu, 7 May 2009 17:53:42 +0100 Subject: Add ranks to various muxers and encoders in -bad --- ext/faac/gstfaac.c | 3 ++- ext/mpeg2enc/gstmpeg2enc.cc | 2 +- ext/x264/gstx264enc.c | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) (limited to 'ext') diff --git a/ext/faac/gstfaac.c b/ext/faac/gstfaac.c index 638e65b1..0dc8a42a 100644 --- a/ext/faac/gstfaac.c +++ b/ext/faac/gstfaac.c @@ -806,7 +806,8 @@ gst_faac_change_state (GstElement * element, GstStateChange transition) static gboolean plugin_init (GstPlugin * plugin) { - return gst_element_register (plugin, "faac", GST_RANK_NONE, GST_TYPE_FAAC); + return gst_element_register (plugin, "faac", GST_RANK_SECONDARY, + GST_TYPE_FAAC); } GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, diff --git a/ext/mpeg2enc/gstmpeg2enc.cc b/ext/mpeg2enc/gstmpeg2enc.cc index 21be81fb..64008b16 100644 --- a/ext/mpeg2enc/gstmpeg2enc.cc +++ b/ext/mpeg2enc/gstmpeg2enc.cc @@ -717,7 +717,7 @@ plugin_init (GstPlugin * plugin) mjpeg_default_handler_verbosity (0); return gst_element_register (plugin, "mpeg2enc", - GST_RANK_NONE, GST_TYPE_MPEG2ENC); + GST_RANK_SECONDARY, GST_TYPE_MPEG2ENC); } GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, diff --git a/ext/x264/gstx264enc.c b/ext/x264/gstx264enc.c index 37f53cce..fcafdd3d 100644 --- a/ext/x264/gstx264enc.c +++ b/ext/x264/gstx264enc.c @@ -1303,7 +1303,7 @@ plugin_init (GstPlugin * plugin) "h264 encoding element"); return gst_element_register (plugin, "x264enc", - GST_RANK_NONE, GST_TYPE_X264_ENC); + GST_RANK_PRIMARY, GST_TYPE_X264_ENC); } GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, -- cgit v1.2.1 From 3c073e45c0aa28e0088cc517ea442d31c4bc09a9 Mon Sep 17 00:00:00 2001 From: Christian Schaller Date: Sat, 9 May 2009 12:42:25 +0100 Subject: Add a more representative example preset file for x264 --- ext/x264/GstX264Enc.prs | 56 ++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 48 insertions(+), 8 deletions(-) (limited to 'ext') diff --git a/ext/x264/GstX264Enc.prs b/ext/x264/GstX264Enc.prs index daf60a77..887247a3 100644 --- a/ext/x264/GstX264Enc.prs +++ b/ext/x264/GstX264Enc.prs @@ -2,12 +2,52 @@ version=0.10 element-name=GstX264Enc -# see http://mewiki.project357.com/wiki/X264_Settings for x264 properties - -# lower default bitrate -# turn of cabac for devices that do not support main-profile -[just-an-example] -_meta/comment=use for mobile pocket video player -_meta/device=pocketvideo -bitrate=1024 +[Pass 1] +pass=pass1 + +[Pass 2] +pass=pass2 + +[Pass 3] +pass=pass3 + +[Profile Baseline] +_meta/comment=Baseline Profile +bframes=0 cabac=false +dct8x8=false + +[Profile Main] +_meta/comment=Main Profile +cabac=true +dct8x8=false + +[Profile High] +_meta/comment=High Profile +cabac=true +dct8x8=true + +[Quality Low] +_meta/comment=Low quality +pass=qual +quantizer=27 +subme=4 +threads=0 + +[Quality Normal] +_meta/comment=Normal quality +pass=qual +quantizer=21 +me=umh +subme=6 +ref=3 +threads=0 + +[Quality High] +_meta/comment=High quality +pass=qual +quantizer=18 +me=umh +subme=6 +ref=3 +threads=0 -- cgit v1.2.1 From 028efb726c73504887e7d40198d7114c029634bb Mon Sep 17 00:00:00 2001 From: Christian Schaller Date: Sat, 9 May 2009 23:47:39 +0100 Subject: Remove wrong stuff from preset file --- ext/x264/GstX264Enc.prs | 9 --------- 1 file changed, 9 deletions(-) (limited to 'ext') diff --git a/ext/x264/GstX264Enc.prs b/ext/x264/GstX264Enc.prs index 887247a3..84c76a94 100644 --- a/ext/x264/GstX264Enc.prs +++ b/ext/x264/GstX264Enc.prs @@ -2,15 +2,6 @@ version=0.10 element-name=GstX264Enc -[Pass 1] -pass=pass1 - -[Pass 2] -pass=pass2 - -[Pass 3] -pass=pass3 - [Profile Baseline] _meta/comment=Baseline Profile bframes=0 -- cgit v1.2.1 From 270cd7c421118af2d6f86535c495e216b5e821d2 Mon Sep 17 00:00:00 2001 From: Jan Schmidt Date: Fri, 8 May 2009 10:43:27 +0100 Subject: resindvd: Implement navigation command change message and query Send messages when the available DVD navigation commands changes, and handle navigation commands and angles queries. --- ext/resindvd/resindvdsrc.c | 72 ++++++++++++++++++++++++++++++++++++++++++++++ ext/resindvd/resindvdsrc.h | 1 + 2 files changed, 73 insertions(+) (limited to 'ext') diff --git a/ext/resindvd/resindvdsrc.c b/ext/resindvd/resindvdsrc.c index 54a39be1..22f6430b 100644 --- a/ext/resindvd/resindvdsrc.c +++ b/ext/resindvd/resindvdsrc.c @@ -134,6 +134,7 @@ static gboolean rsn_dvdsrc_src_event (RsnBaseSrc * basesrc, GstEvent * event); static gboolean rsn_dvdsrc_src_query (RsnBaseSrc * basesrc, GstQuery * query); static GstClockTime ifotime_to_gsttime (dvd_time_t * ifo_time); +static void rsn_dvdsrc_send_commands_changed (resinDvdSrc * src); static GstClockTime ifotime_to_gsttime (dvd_time_t * ifo_time) @@ -398,6 +399,8 @@ rsn_dvdsrc_start (RsnBaseSrc * bsrc) src->angles_changed = FALSE; src->n_angles = 0; + src->commands_changed = TRUE; + src->cur_spu_phys_stream = -1; src->cur_spu_forced_only = FALSE; memset (src->cur_clut, 0, sizeof (guint32) * 16); @@ -1062,6 +1065,57 @@ branching: return GST_FLOW_WRONG_STATE; } +/* Send app a bus message that the available commands have changed */ +static void +rsn_dvdsrc_send_commands_changed (resinDvdSrc * src) +{ + GstMessage *cmds_msg = + gst_navigation_message_new_commands_changed (GST_OBJECT_CAST (src)); + gst_element_post_message (GST_ELEMENT_CAST (src), cmds_msg); +} + +static gboolean +rsn_dvdsrc_handle_cmds_query (resinDvdSrc * src, GstQuery * query) +{ + return FALSE; +} + +static gboolean +rsn_dvdsrc_handle_angles_query (resinDvdSrc * src, GstQuery * query) +{ + gint cur_agl, n_angles; + gboolean res = FALSE; + + g_mutex_lock (src->dvd_lock); + if (dvdnav_get_angle_info (src->dvdnav, &cur_agl, + &n_angles) == DVDNAV_STATUS_OK) { + gst_navigation_query_set_angles (query, cur_agl, n_angles); + res = TRUE; + } + g_mutex_unlock (src->dvd_lock); + + return res; +} + +static gboolean +rsn_dvdsrc_handle_navigation_query (resinDvdSrc * src, + GstNavigationQueryType nq_type, GstQuery * query) +{ + gboolean res; + switch (nq_type) { + case GST_NAVIGATION_QUERY_COMMANDS: + res = rsn_dvdsrc_handle_cmds_query (src, query); + break; + case GST_NAVIGATION_QUERY_ANGLES: + res = rsn_dvdsrc_handle_angles_query (src, query); + break; + default: + res = FALSE; + } + + return res; +} + static GstFlowReturn rsn_dvdsrc_prepare_next_block (resinDvdSrc * src, gboolean have_dvd_lock) { @@ -1094,6 +1148,7 @@ rsn_dvdsrc_create (RsnPushSrc * psrc, GstBuffer ** outbuf) GstEvent *audio_select_event = NULL; GstEvent *highlight_event = NULL; GstMessage *angles_msg = NULL; + gboolean cmds_changed = FALSE; *outbuf = NULL; @@ -1128,6 +1183,11 @@ rsn_dvdsrc_create (RsnPushSrc * psrc, GstBuffer ** outbuf) src->angles_changed = FALSE; } + if (src->commands_changed) { + cmds_changed = TRUE; + src->commands_changed = FALSE; + } + g_mutex_unlock (src->dvd_lock); /* Push in-band events now that we've dropped the dvd_lock, before @@ -1201,6 +1261,9 @@ rsn_dvdsrc_create (RsnPushSrc * psrc, GstBuffer ** outbuf) gst_element_post_message (GST_ELEMENT_CAST (src), angles_msg); } + if (cmds_changed) + rsn_dvdsrc_send_commands_changed (src); + return ret; } @@ -2261,6 +2324,15 @@ rsn_dvdsrc_src_query (RsnBaseSrc * basesrc, GstQuery * query) } g_mutex_unlock (src->dvd_lock); break; + case GST_QUERY_CUSTOM: + { + GstNavigationQueryType nq_type = gst_navigation_query_get_type (query); + if (nq_type != GST_NAVIGATION_QUERY_INVALID) + res = rsn_dvdsrc_handle_navigation_query (src, nq_type, query); + else + res = GST_BASE_SRC_CLASS (parent_class)->query (basesrc, query); + break; + } default: res = GST_BASE_SRC_CLASS (parent_class)->query (basesrc, query); break; diff --git a/ext/resindvd/resindvdsrc.h b/ext/resindvd/resindvdsrc.h index f55b454f..fd03466a 100644 --- a/ext/resindvd/resindvdsrc.h +++ b/ext/resindvd/resindvdsrc.h @@ -119,6 +119,7 @@ struct _resinDvdSrc GstEvent *highlight_event; gboolean angles_changed; + gboolean commands_changed; /* GList of NAV packets awaiting activation, and the * running times to activate them. */ -- cgit v1.2.1 From 86d908589c4ef2d715e4f015c2455a19de322a51 Mon Sep 17 00:00:00 2001 From: Jan Schmidt Date: Fri, 8 May 2009 14:20:32 +0100 Subject: resindvd: Send title info message when current angle is switched. Make sure we send an update title tag when the current angle or available angles changes. --- ext/resindvd/resindvdsrc.c | 12 ++++++++---- ext/resindvd/resindvdsrc.h | 3 ++- 2 files changed, 10 insertions(+), 5 deletions(-) (limited to 'ext') diff --git a/ext/resindvd/resindvdsrc.c b/ext/resindvd/resindvdsrc.c index 22f6430b..b95e5c4a 100644 --- a/ext/resindvd/resindvdsrc.c +++ b/ext/resindvd/resindvdsrc.c @@ -398,6 +398,7 @@ rsn_dvdsrc_start (RsnBaseSrc * bsrc) src->angles_changed = FALSE; src->n_angles = 0; + src->cur_angle = 0; src->commands_changed = TRUE; @@ -761,17 +762,20 @@ update_title_info (resinDvdSrc * src) if (dvdnav_get_angle_info (src->dvdnav, &cur_agl, &n_angles) == DVDNAV_STATUS_OK && src->n_angles != n_angles) { + /* Make sure we send an angles-changed message soon */ src->angles_changed = TRUE; - src->n_angles = n_angles; } if (dvdnav_current_title_info (src->dvdnav, &title_n, &part_n) == DVDNAV_STATUS_OK) { - if (title_n != src->title_n || part_n != src->part_n || src->angles_changed) { + if (title_n != src->title_n || part_n != src->part_n || + src->n_angles != n_angles || src->cur_angle != cur_agl) { gchar *title_str = NULL; src->title_n = title_n; src->part_n = part_n; + src->n_angles = n_angles; + src->cur_angle = cur_agl; if (title_n == 0) { static const char *dvd_menu_map[] = { @@ -1178,7 +1182,6 @@ rsn_dvdsrc_create (RsnPushSrc * psrc, GstBuffer ** outbuf) angles_msg = gst_navigation_message_new_angles_changed (GST_OBJECT_CAST (src), cur, agls); - src->n_angles = agls; } src->angles_changed = FALSE; } @@ -1626,9 +1629,10 @@ rsn_dvdsrc_handle_navigation_event (resinDvdSrc * src, GstEvent * event) angles_msg = gst_navigation_message_new_angles_changed (GST_OBJECT_CAST (src), cur, agls); - src->n_angles = agls; } src->angles_changed = FALSE; + + update_title_info (src); } g_mutex_unlock (src->dvd_lock); diff --git a/ext/resindvd/resindvdsrc.h b/ext/resindvd/resindvdsrc.h index fd03466a..0d883744 100644 --- a/ext/resindvd/resindvdsrc.h +++ b/ext/resindvd/resindvdsrc.h @@ -76,6 +76,8 @@ struct _resinDvdSrc gboolean in_menu; gint title_n; /* Title num */ gint part_n; /* Part num */ + gint n_angles; /* number of angles */ + gint cur_angle; /* current angle */ gboolean running; gboolean discont; @@ -136,7 +138,6 @@ struct _resinDvdSrc gint8 cur_spu_phys_stream; gboolean cur_spu_forced_only; guint32 cur_clut[16]; - gint n_angles; }; struct _resinDvdSrcClass -- cgit v1.2.1 From 9f01bd64349cc14c25991cea5e054f286ab732bf Mon Sep 17 00:00:00 2001 From: Jan Schmidt Date: Fri, 8 May 2009 14:23:48 +0100 Subject: resindvd: Remove per-menu description from the TITLE tag The part number reported while in a menu doesn't reflect the selected menu, so it's pointless to use it to report which menu we're in (Audio, Angle etc). Just report "DVD Menu" in the title tag instead. --- ext/resindvd/resindvdsrc.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) (limited to 'ext') diff --git a/ext/resindvd/resindvdsrc.c b/ext/resindvd/resindvdsrc.c index b95e5c4a..7b6a7415 100644 --- a/ext/resindvd/resindvdsrc.c +++ b/ext/resindvd/resindvdsrc.c @@ -778,18 +778,8 @@ update_title_info (resinDvdSrc * src) src->cur_angle = cur_agl; if (title_n == 0) { - static const char *dvd_menu_map[] = { - NULL, NULL, "Title", "Root", - "Subpicture", "Audio", "Angle", "Part" - }; - /* In a menu */ - if (part_n >= 0 && part_n < G_N_ELEMENTS (dvd_menu_map) - && dvd_menu_map[part_n]) { - title_str = g_strdup_printf ("DVD %s Menu", dvd_menu_map[part_n]); - } else { - title_str = g_strdup ("DVD Menu"); - } + title_str = g_strdup ("DVD Menu"); } else { /* In a title */ if (n_angles > 1) { -- cgit v1.2.1 From f2f79cd4108add0071f868c5d8e8857d3421c707 Mon Sep 17 00:00:00 2001 From: Jan Schmidt Date: Fri, 8 May 2009 16:06:01 +0100 Subject: resindvd: Simplify some stuff. Remove an unnecessary LOG message. Skip attempting to schedule a nav block unless we're in PLAYING. Take a lock slightly later, when we actually need it. Remove a noisy LOG message. --- ext/resindvd/resindvdsrc.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'ext') diff --git a/ext/resindvd/resindvdsrc.c b/ext/resindvd/resindvdsrc.c index 7b6a7415..479a883a 100644 --- a/ext/resindvd/resindvdsrc.c +++ b/ext/resindvd/resindvdsrc.c @@ -665,7 +665,7 @@ rsn_dvdsrc_do_still (resinDvdSrc * src, int duration) /* FIXME: Implement timed stills by sleeping on the clock, possibly * in multiple steps if we get paused/unpaused */ g_mutex_unlock (src->dvd_lock); - GST_LOG_OBJECT (src, "cond_timed_wait still"); + GST_LOG_OBJECT (src, "cond_timed_wait still for %d sec", duration); was_signalled = g_cond_timed_wait (src->still_cond, src->branch_lock, &end_time); was_signalled |= src->branching; @@ -2109,19 +2109,19 @@ rsn_dvdsrc_nav_clock_cb (GstClock * clock, GstClockTime time, GstClockID id, return TRUE; } +/* Called with dvd_lock held */ static void rsn_dvdsrc_schedule_nav_cb (resinDvdSrc * src, RsnDvdPendingNav * next_nav) { GstClock *clock; GstClockTime base_ts; - GST_OBJECT_LOCK (src); if (!src->in_playing) { GST_LOG_OBJECT (src, "Not scheduling NAV block - state != PLAYING"); - GST_OBJECT_UNLOCK (src); return; /* Not in playing state yet */ } + GST_OBJECT_LOCK (src); clock = GST_ELEMENT_CLOCK (src); base_ts = GST_ELEMENT (src)->base_time; @@ -2144,6 +2144,7 @@ rsn_dvdsrc_schedule_nav_cb (resinDvdSrc * src, RsnDvdPendingNav * next_nav) gst_object_unref (clock); } +/* Called with dvd_lock held */ static void rsn_dvdsrc_check_nav_blocks (resinDvdSrc * src) { @@ -2154,9 +2155,10 @@ rsn_dvdsrc_check_nav_blocks (resinDvdSrc * src) return; /* Something already scheduled */ } if (src->pending_nav_blocks == NULL) { - GST_LOG_OBJECT (src, "No NAV blocks to schedule"); return; /* No nav blocks available yet */ } + if (!src->in_playing) + return; /* Not in playing state yet */ GST_LOG_OBJECT (src, "Installing NAV callback"); next_nav = (RsnDvdPendingNav *) src->pending_nav_blocks->data; @@ -2164,8 +2166,6 @@ rsn_dvdsrc_check_nav_blocks (resinDvdSrc * src) rsn_dvdsrc_schedule_nav_cb (src, next_nav); } -/* Use libdvdread to read and cache info from the IFO file about - * streams in each VTS */ static gboolean rsn_dvdsrc_src_event (RsnBaseSrc * basesrc, GstEvent * event) { -- cgit v1.2.1 From c0854113a18003cc4a717a49b674f7a2038fa602 Mon Sep 17 00:00:00 2001 From: Jan Schmidt Date: Fri, 8 May 2009 16:27:31 +0100 Subject: resindvd: Ensure we send a title tag in the first play section. --- ext/resindvd/resindvdsrc.c | 79 ++++++++++++++++++++++++---------------------- 1 file changed, 42 insertions(+), 37 deletions(-) (limited to 'ext') diff --git a/ext/resindvd/resindvdsrc.c b/ext/resindvd/resindvdsrc.c index 479a883a..f479da2a 100644 --- a/ext/resindvd/resindvdsrc.c +++ b/ext/resindvd/resindvdsrc.c @@ -767,48 +767,54 @@ update_title_info (resinDvdSrc * src) } if (dvdnav_current_title_info (src->dvdnav, &title_n, - &part_n) == DVDNAV_STATUS_OK) { - if (title_n != src->title_n || part_n != src->part_n || - src->n_angles != n_angles || src->cur_angle != cur_agl) { - gchar *title_str = NULL; - - src->title_n = title_n; - src->part_n = part_n; - src->n_angles = n_angles; - src->cur_angle = cur_agl; - - if (title_n == 0) { - /* In a menu */ - title_str = g_strdup ("DVD Menu"); - } else { - /* In a title */ - if (n_angles > 1) { - title_str = g_strdup_printf ("Title %i, Chapter %i, Angle %i of %i", - title_n, part_n, cur_agl, n_angles); + &part_n) != DVDNAV_STATUS_OK) { + if (!src->in_menu) + return; /* Can't update now */ + /* Must be in the first play sequence */ + title_n = -1; + part_n = 0; + } + + if (title_n != src->title_n || part_n != src->part_n || + src->n_angles != n_angles || src->cur_angle != cur_agl) { + gchar *title_str = NULL; + + src->title_n = title_n; + src->part_n = part_n; + src->n_angles = n_angles; + src->cur_angle = cur_agl; + + if (title_n == 0) { + /* In a menu */ + title_str = g_strdup ("DVD Menu"); + } else if (title_n > 0) { + /* In a title */ + if (n_angles > 1) { + title_str = g_strdup_printf ("Title %i, Chapter %i, Angle %i of %i", + title_n, part_n, cur_agl, n_angles); - } else { - title_str = g_strdup_printf ("Title %i, Chapter %i", title_n, part_n); - } + } else { + title_str = g_strdup_printf ("Title %i, Chapter %i", title_n, part_n); } + } - if (src->disc_name && src->disc_name[0]) { - /* We have a name for this disc, publish it */ - if (title_str) { - gchar *new_title_str = - g_strdup_printf ("%s, %s", title_str, src->disc_name); - g_free (title_str); - title_str = new_title_str; - } else { - title_str = g_strdup (src->disc_name); - } - } + if (src->disc_name && src->disc_name[0]) { + /* We have a name for this disc, publish it */ if (title_str) { - GstTagList *tags = gst_tag_list_new (); - gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_TITLE, - title_str, NULL); - gst_element_found_tags (GST_ELEMENT_CAST (src), tags); + gchar *new_title_str = + g_strdup_printf ("%s, %s", title_str, src->disc_name); + g_free (title_str); + title_str = new_title_str; + } else { + title_str = g_strdup (src->disc_name); } } + if (title_str) { + GstTagList *tags = gst_tag_list_new (); + gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_TITLE, + title_str, NULL); + gst_element_found_tags (GST_ELEMENT_CAST (src), tags); + } } } @@ -911,7 +917,6 @@ rsn_dvdsrc_step (resinDvdSrc * src, gboolean have_dvd_lock) src->next_is_nav_block = FALSE; src->next_nav_ts = GST_CLOCK_TIME_NONE; } - break; } case DVDNAV_STOP: -- cgit v1.2.1 From 64b6d247d4428ce3dadcbe8729cc891a8891c7db Mon Sep 17 00:00:00 2001 From: Jan Schmidt Date: Fri, 8 May 2009 16:29:20 +0100 Subject: resindvd: Rename the audio munger debug category Rename a debug category: rsn_audiomunge -> rsnaudiomunge. --- ext/resindvd/rsnaudiomunge.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'ext') diff --git a/ext/resindvd/rsnaudiomunge.c b/ext/resindvd/rsnaudiomunge.c index fc7e552f..c44d7d2e 100644 --- a/ext/resindvd/rsnaudiomunge.c +++ b/ext/resindvd/rsnaudiomunge.c @@ -86,8 +86,8 @@ rsn_audiomunge_class_init (RsnAudioMungeClass * klass) "Jan Schmidt " }; - GST_DEBUG_CATEGORY_INIT (rsn_audiomunge_debug, "rsn_audiomunge", - 0, "Resin audio stream regulator"); + GST_DEBUG_CATEGORY_INIT (rsn_audiomunge_debug, "rsnaudiomunge", + 0, "ResinDVD audio stream regulator"); gst_element_class_add_pad_template (element_class, gst_static_pad_template_get (&src_template)); -- cgit v1.2.1 From 79f653fde8d6ff1ecee3147ca8afb42f8cec981a Mon Sep 17 00:00:00 2001 From: Jan Schmidt Date: Mon, 11 May 2009 11:06:03 +0100 Subject: resindvd: Change the audiomunge debug output. Make sure we always show information about the segment events passing through, even when pre-roll audio buffers aren't going to be needed. --- ext/resindvd/rsnaudiomunge.c | 51 +++++++++++++++++++++++--------------------- 1 file changed, 27 insertions(+), 24 deletions(-) (limited to 'ext') diff --git a/ext/resindvd/rsnaudiomunge.c b/ext/resindvd/rsnaudiomunge.c index c44d7d2e..6368c49a 100644 --- a/ext/resindvd/rsnaudiomunge.c +++ b/ext/resindvd/rsnaudiomunge.c @@ -288,15 +288,12 @@ rsn_audiomunge_sink_event (GstPad * pad, GstEvent * event) gst_segment_set_newsegment_full (segment, update, rate, arate, format, start, stop, time); - if (munge->have_audio) { - ret = gst_pad_push_event (munge->srcpad, event); - break; - } - /* * FIXME: - * If the accum >= threshold or we're in a still frame and there's been - * no audio received, then we need to generate some audio data. + * If this is a segment update and accum >= threshold, + * or we're in a still frame and there's been no audio received, + * then we need to generate some audio data. + * * If caused by a segment start update (time advancing in a gap) adjust * the new-segment and send the buffer. * @@ -304,32 +301,38 @@ rsn_audiomunge_sink_event (GstPad * pad, GstEvent * event) * in the closing segment. */ if (!update) { - GST_DEBUG_OBJECT (munge, "Sending newsegment: start %" GST_TIME_FORMAT - " stop %" GST_TIME_FORMAT " accum now %" GST_TIME_FORMAT, + GST_DEBUG_OBJECT (munge, + "Sending newsegment: update %d start %" GST_TIME_FORMAT " stop %" + GST_TIME_FORMAT " accum now %" GST_TIME_FORMAT, update, GST_TIME_ARGS (start), GST_TIME_ARGS (stop), GST_TIME_ARGS (segment->accum)); ret = gst_pad_push_event (munge->srcpad, event); } - if (segment->accum >= AUDIO_FILL_THRESHOLD || munge->in_still) { - GST_DEBUG_OBJECT (munge, - "Sending audio fill: accum = %" GST_TIME_FORMAT " still-state=%d", - 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 { - GST_LOG_OBJECT (munge, "Not sending audio fill buffer: " - "segment accum below thresh: accum = %" GST_TIME_FORMAT, - GST_TIME_ARGS (segment->accum)); + if (!munge->have_audio) { + if ((update && segment->accum >= AUDIO_FILL_THRESHOLD) + || munge->in_still) { + GST_DEBUG_OBJECT (munge, + "Sending audio fill with ts %" GST_TIME_FORMAT ": accum = %" + GST_TIME_FORMAT " still-state=%d", GST_TIME_ARGS (segment->start), + 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 { + GST_LOG_OBJECT (munge, "Not sending audio fill buffer: " + "Not segment update, or segment accum below thresh: accum = %" + GST_TIME_FORMAT, GST_TIME_ARGS (segment->accum)); + } } if (update) { - GST_DEBUG_OBJECT (munge, "Sending newsegment: start %" GST_TIME_FORMAT - " stop %" GST_TIME_FORMAT " accum now %" GST_TIME_FORMAT, + GST_DEBUG_OBJECT (munge, + "Sending newsegment: update %d start %" GST_TIME_FORMAT " stop %" + GST_TIME_FORMAT " accum now %" GST_TIME_FORMAT, update, GST_TIME_ARGS (start), GST_TIME_ARGS (stop), GST_TIME_ARGS (segment->accum)); -- cgit v1.2.1 From 4204b644ef31c498ba27847dec3e8d6dbfd4eedd Mon Sep 17 00:00:00 2001 From: Jan Schmidt Date: Mon, 11 May 2009 14:17:42 +0100 Subject: resindvd: Manage timed still sequences better Make timed still frames work better by extending the current segment when needed, and restarting the still sequence with the correct remaining duration when the wait it interrupted by activation of a highlight NAV packet. --- ext/resindvd/resindvdsrc.c | 71 +++++++++++++++++++++++++++++++++------------- ext/resindvd/resindvdsrc.h | 3 ++ 2 files changed, 54 insertions(+), 20 deletions(-) (limited to 'ext') diff --git a/ext/resindvd/resindvdsrc.c b/ext/resindvd/resindvdsrc.c index f479da2a..15a2408d 100644 --- a/ext/resindvd/resindvdsrc.c +++ b/ext/resindvd/resindvdsrc.c @@ -590,6 +590,12 @@ rsn_dvdsrc_do_still (resinDvdSrc * src, int duration) if (src->in_still_state == FALSE) { GST_DEBUG_OBJECT (src, "**** Start STILL FRAME. Duration %d ****", duration); + + if (duration == 255) + src->still_time_remaining = GST_CLOCK_TIME_NONE; + else + src->still_time_remaining = GST_SECOND * duration; + /* Send a close-segment event, and a dvd-still start * event, then sleep */ s = gst_structure_new ("application/x-gst-dvd", @@ -622,7 +628,9 @@ rsn_dvdsrc_do_still (resinDvdSrc * src, int duration) src->in_still_state = TRUE; } else { - GST_DEBUG_OBJECT (src, "Re-entering still wait"); + GST_DEBUG_OBJECT (src, + "Re-entering still wait with %" GST_TIME_FORMAT " remaining", + GST_TIME_ARGS (src->still_time_remaining)); g_mutex_lock (src->branch_lock); } @@ -659,26 +667,42 @@ rsn_dvdsrc_do_still (resinDvdSrc * src, int duration) GTimeVal end_time; gboolean was_signalled; - g_get_current_time (&end_time); - g_time_val_add (&end_time, duration * G_USEC_PER_SEC); + if (src->still_time_remaining > 0) { + g_get_current_time (&end_time); + g_time_val_add (&end_time, src->still_time_remaining / GST_USECOND); - /* FIXME: Implement timed stills by sleeping on the clock, possibly - * in multiple steps if we get paused/unpaused */ - g_mutex_unlock (src->dvd_lock); - GST_LOG_OBJECT (src, "cond_timed_wait still for %d sec", duration); - was_signalled = - g_cond_timed_wait (src->still_cond, src->branch_lock, &end_time); - was_signalled |= src->branching; + /* Implement timed stills by sleeping, possibly + * in multiple steps if we get paused/unpaused */ + g_mutex_unlock (src->dvd_lock); + GST_LOG_OBJECT (src, "cond_timed_wait still for %d sec", duration); + 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); + 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; + if (was_signalled) { + /* Signalled - must be flushing */ + GTimeVal cur_time; + GstClockTimeDiff remain; + + g_get_current_time (&cur_time); + remain = + (end_time.tv_sec - cur_time.tv_sec) * GST_SECOND + + (end_time.tv_usec - cur_time.tv_usec) * GST_USECOND; + if (remain < 0) + src->still_time_remaining = 0; + else + src->still_time_remaining = remain; + + GST_LOG_OBJECT (src, + "cond_timed_wait still aborted by signal with %" GST_TIME_FORMAT + " remaining. branching = %d", + GST_TIME_ARGS (src->still_time_remaining), src->branching); + + return TRUE; + } } /* Else timed out, end the still */ @@ -690,12 +714,17 @@ rsn_dvdsrc_do_still (resinDvdSrc * src, int duration) } /* Tell downstream the still is over. - * Later: We'll only do this if the still isn't interrupted: */ + * We 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, FALSE, NULL); still_event = gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, s); + /* If the segment was too short in a timed still, it may need extending */ + if (segment->last_stop < segment->start + GST_SECOND * duration) + gst_segment_set_last_stop (segment, GST_FORMAT_TIME, + segment->start + (GST_SECOND * duration)); + g_mutex_unlock (src->dvd_lock); gst_pad_push_event (GST_BASE_SRC_PAD (src), still_event); g_mutex_lock (src->dvd_lock); @@ -2040,8 +2069,10 @@ rsn_dvdsrc_activate_nav_block (resinDvdSrc * src, GstBuffer * nav_buf) /* highlight might change, let's check */ rsn_dvdsrc_update_highlight (src); - if (src->highlight_event) + if (src->highlight_event && src->in_still_state) { + GST_LOG_OBJECT (src, "Signalling still condition due to highlight change"); g_cond_broadcast (src->still_cond); + } } static void diff --git a/ext/resindvd/resindvdsrc.h b/ext/resindvd/resindvdsrc.h index 0d883744..d30140ea 100644 --- a/ext/resindvd/resindvdsrc.h +++ b/ext/resindvd/resindvdsrc.h @@ -90,6 +90,9 @@ struct _resinDvdSrc gboolean was_mouse_over; + /* Remaining time to wait in a timed still: */ + GstClockTime still_time_remaining; + GstBuffer *alloc_buf; GstBuffer *next_buf; /* TRUE if the next_buf is a nav block that needs enqueueing */ -- cgit v1.2.1 From d7cabb080134403871f7962bf226b36197b4d6c3 Mon Sep 17 00:00:00 2001 From: Jan Schmidt Date: Mon, 11 May 2009 16:09:56 +0100 Subject: resindvd: Increase the amount of filler audio generated When creating a filler audio buffer in rsnaudiomunge, generate a bit more, as audio sinks don't seem to preroll otherwise. This needs a better algorithm in general, to intelligently fill the gap, rather than hard-coding a value. --- ext/resindvd/rsnaudiomunge.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'ext') diff --git a/ext/resindvd/rsnaudiomunge.c b/ext/resindvd/rsnaudiomunge.c index 6368c49a..50d33be7 100644 --- a/ext/resindvd/rsnaudiomunge.c +++ b/ext/resindvd/rsnaudiomunge.c @@ -318,9 +318,9 @@ rsn_audiomunge_sink_event (GstPad * pad, GstEvent * event) GST_TIME_FORMAT " still-state=%d", GST_TIME_ARGS (segment->start), GST_TIME_ARGS (segment->accum), munge->in_still); - /* Just generate a 100ms silence buffer for now. FIXME: Fill the gap */ + /* Just generate a 200ms silence buffer for now. FIXME: Fill the gap */ if (rsn_audiomunge_make_audio (munge, segment->start, - GST_SECOND / 10) == GST_FLOW_OK) + GST_SECOND / 5) == GST_FLOW_OK) munge->have_audio = TRUE; } else { GST_LOG_OBJECT (munge, "Not sending audio fill buffer: " -- cgit v1.2.1 From 11a7e37325cae90f43a02d61cedd4ad09a2b21fd Mon Sep 17 00:00:00 2001 From: Jan Schmidt Date: Mon, 11 May 2009 17:50:41 +0100 Subject: resindvd: Modify the segment update logic Send segment updates to the audio and subpicture pads more frequently, but less often to the video pad, where timestamps appear less often. This helps with gap filling on some DVDs. --- ext/resindvd/gstmpegdemux.c | 12 ++++++++++-- ext/resindvd/gstmpegdemux.h | 1 + 2 files changed, 11 insertions(+), 2 deletions(-) (limited to 'ext') diff --git a/ext/resindvd/gstmpegdemux.c b/ext/resindvd/gstmpegdemux.c index d41ded0b..ed4b3d93 100644 --- a/ext/resindvd/gstmpegdemux.c +++ b/ext/resindvd/gstmpegdemux.c @@ -28,7 +28,8 @@ #include "gstmpegdefs.h" #include "gstmpegdemux.h" -#define SEGMENT_THRESHOLD (GST_SECOND/2) +#define SEGMENT_THRESHOLD (300*GST_MSECOND) +#define VIDEO_SEGMENT_THRESHOLD (500*GST_MSECOND) /* The SCR_MUNGE value is used to offset the scr_adjust value, to avoid * ever generating a negative timestamp */ @@ -248,6 +249,7 @@ gst_flups_demux_create_stream (GstFluPSDemux * demux, gint id, gint stream_type) gchar *name; GstFluPSDemuxClass *klass = GST_FLUPS_DEMUX_GET_CLASS (demux); GstCaps *caps; + GstClockTime threshold = SEGMENT_THRESHOLD; name = NULL; template = NULL; @@ -277,6 +279,7 @@ gst_flups_demux_create_stream (GstFluPSDemux * demux, gint id, gint stream_type) caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, mpeg_version, "systemstream", G_TYPE_BOOLEAN, FALSE, NULL); + threshold = VIDEO_SEGMENT_THRESHOLD; break; } case ST_AUDIO_MPEG1: @@ -296,6 +299,7 @@ gst_flups_demux_create_stream (GstFluPSDemux * demux, gint id, gint stream_type) template = klass->video_template; name = g_strdup_printf ("video_%02x", id); caps = gst_caps_new_simple ("video/x-h264", NULL); + threshold = VIDEO_SEGMENT_THRESHOLD; break; case ST_PS_AUDIO_AC3: template = klass->audio_template; @@ -335,6 +339,7 @@ gst_flups_demux_create_stream (GstFluPSDemux * demux, gint id, gint stream_type) stream->notlinked = FALSE; stream->type = stream_type; stream->pad = gst_pad_new_from_template (template, name); + stream->segment_thresh = threshold; gst_pad_set_event_function (stream->pad, gst_flups_demux_src_event); gst_pad_set_query_function (stream->pad, gst_flups_demux_src_query); gst_pad_use_fixed_caps (stream->pad); @@ -487,11 +492,14 @@ gst_flups_demux_send_segment_updates (GstFluPSDemux * demux, if (stream->last_ts == GST_CLOCK_TIME_NONE || stream->last_ts < demux->src_segment.start) stream->last_ts = demux->src_segment.start; - if (stream->last_ts + SEGMENT_THRESHOLD < new_time) { + if (stream->last_ts + stream->segment_thresh < new_time) { #if 0 g_print ("Segment update to pad %s time %" GST_TIME_FORMAT "\n", GST_PAD_NAME (stream->pad), GST_TIME_ARGS (new_time)); #endif + GST_DEBUG_OBJECT (demux, + "Segment update to pad %s time %" GST_TIME_FORMAT, + GST_PAD_NAME (stream->pad), GST_TIME_ARGS (new_time)); if (event == NULL) { event = gst_event_new_new_segment_full (TRUE, demux->src_segment.rate, demux->src_segment.applied_rate, diff --git a/ext/resindvd/gstmpegdemux.h b/ext/resindvd/gstmpegdemux.h index 3f38b088..b7b2d9fc 100644 --- a/ext/resindvd/gstmpegdemux.h +++ b/ext/resindvd/gstmpegdemux.h @@ -64,6 +64,7 @@ struct _GstFluPSStream { gboolean need_segment; GstClockTime last_ts; + GstClockTime segment_thresh; }; struct _GstFluPSDemux { -- cgit v1.2.1 From b769f22404ca1d566b38b50854f184b5eda628fd Mon Sep 17 00:00:00 2001 From: Jan Schmidt Date: Wed, 13 May 2009 10:29:36 +0100 Subject: resindvd: Fix raciness in rsndvdbin when initially creating pads Protect pad exposure with a preroll lock to avoid situations where no-more-pads is fired more than once, or fired just before the last pad is actually added. --- ext/resindvd/resindvdbin.c | 28 ++++++++++++++++------------ ext/resindvd/resindvdbin.h | 1 + 2 files changed, 17 insertions(+), 12 deletions(-) (limited to 'ext') diff --git a/ext/resindvd/resindvdbin.c b/ext/resindvd/resindvdbin.c index 310fac7f..e5f28288 100644 --- a/ext/resindvd/resindvdbin.c +++ b/ext/resindvd/resindvdbin.c @@ -44,6 +44,9 @@ GST_DEBUG_CATEGORY_EXTERN (resindvd_debug); #define DVDBIN_LOCK(d) g_mutex_lock((d)->dvd_lock) #define DVDBIN_UNLOCK(d) g_mutex_unlock((d)->dvd_lock) +#define DVDBIN_PREROLL_LOCK(d) g_mutex_lock((d)->preroll_lock) +#define DVDBIN_PREROLL_UNLOCK(d) g_mutex_unlock((d)->preroll_lock) + #define DEFAULT_DEVICE "/dev/dvd" enum { @@ -159,6 +162,7 @@ static void rsn_dvdbin_init (RsnDvdBin * dvdbin, RsnDvdBinClass * gclass) { dvdbin->dvd_lock = g_mutex_new (); + dvdbin->preroll_lock = g_mutex_new (); } static void @@ -167,6 +171,7 @@ rsn_dvdbin_finalize (GObject * object) RsnDvdBin *dvdbin = RESINDVDBIN (object); g_mutex_free (dvdbin->dvd_lock); + g_mutex_free (dvdbin->preroll_lock); g_free (dvdbin->last_uri); g_free (dvdbin->device); @@ -741,58 +746,57 @@ failed: static void dvdbin_pad_blocked_cb (GstPad * pad, gboolean blocked, RsnDvdBin * dvdbin) { - gboolean changed = FALSE; + gboolean added_last_pad = FALSE; gboolean added = FALSE; if (!blocked) return; if (pad == dvdbin->subpicture_pad) { GST_DEBUG_OBJECT (dvdbin, "Pad block -> subpicture pad"); - GST_OBJECT_LOCK (dvdbin); + DVDBIN_PREROLL_LOCK (dvdbin); added = dvdbin->subpicture_added; dvdbin->subpicture_added = TRUE; - GST_OBJECT_UNLOCK (dvdbin); if (!added) { gst_element_add_pad (GST_ELEMENT (dvdbin), dvdbin->subpicture_pad); - changed = TRUE; + added_last_pad = (dvdbin->audio_added && dvdbin->video_added); } + DVDBIN_PREROLL_UNLOCK (dvdbin); gst_pad_set_blocked_async (pad, FALSE, (GstPadBlockCallback) dvdbin_pad_blocked_cb, dvdbin); } else if (pad == dvdbin->audio_pad) { GST_DEBUG_OBJECT (dvdbin, "Pad block -> audio pad"); - GST_OBJECT_LOCK (dvdbin); + DVDBIN_PREROLL_LOCK (dvdbin); added = dvdbin->audio_added; dvdbin->audio_added = TRUE; - GST_OBJECT_UNLOCK (dvdbin); if (!added) { gst_element_add_pad (GST_ELEMENT (dvdbin), dvdbin->audio_pad); - changed = TRUE; + added_last_pad = (dvdbin->subpicture_added && dvdbin->video_added); } + DVDBIN_PREROLL_UNLOCK (dvdbin); gst_pad_set_blocked_async (pad, FALSE, (GstPadBlockCallback) dvdbin_pad_blocked_cb, dvdbin); } else if (pad == dvdbin->video_pad) { GST_DEBUG_OBJECT (dvdbin, "Pad block -> video pad"); - GST_OBJECT_LOCK (dvdbin); + DVDBIN_PREROLL_LOCK (dvdbin); added = dvdbin->video_added; dvdbin->video_added = TRUE; - GST_OBJECT_UNLOCK (dvdbin); if (!added) { gst_element_add_pad (GST_ELEMENT (dvdbin), dvdbin->video_pad); - changed = TRUE; + added_last_pad = (dvdbin->subpicture_added && dvdbin->audio_added); } + DVDBIN_PREROLL_UNLOCK (dvdbin); gst_pad_set_blocked_async (pad, FALSE, (GstPadBlockCallback) dvdbin_pad_blocked_cb, dvdbin); } - if (changed && - dvdbin->video_added && dvdbin->audio_added && dvdbin->subpicture_added) { + if (added_last_pad) { GST_DEBUG_OBJECT (dvdbin, "Firing no more pads from pad-blocked cb"); gst_element_no_more_pads (GST_ELEMENT (dvdbin)); } diff --git a/ext/resindvd/resindvdbin.h b/ext/resindvd/resindvdbin.h index 5a063f4f..d9aa1078 100644 --- a/ext/resindvd/resindvdbin.h +++ b/ext/resindvd/resindvdbin.h @@ -58,6 +58,7 @@ struct _RsnDvdBin /* Protects pieces list and properties */ GMutex *dvd_lock; + GMutex *preroll_lock; gchar *device; gchar *last_uri; -- cgit v1.2.1 From d9fef92ea03961f2bf7a1fc75c99223ecf35f168 Mon Sep 17 00:00:00 2001 From: Jan Schmidt Date: Thu, 14 May 2009 08:42:24 +0100 Subject: resindvd: Fix a leak of the DVD title string --- ext/resindvd/resindvdsrc.c | 1 + 1 file changed, 1 insertion(+) (limited to 'ext') diff --git a/ext/resindvd/resindvdsrc.c b/ext/resindvd/resindvdsrc.c index 15a2408d..37fc9da9 100644 --- a/ext/resindvd/resindvdsrc.c +++ b/ext/resindvd/resindvdsrc.c @@ -842,6 +842,7 @@ update_title_info (resinDvdSrc * src) GstTagList *tags = gst_tag_list_new (); gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_TITLE, title_str, NULL); + g_free (title_str); gst_element_found_tags (GST_ELEMENT_CAST (src), tags); } } -- cgit v1.2.1 From 73f77c04aacd5e6ad97e34546a7a9517b430a901 Mon Sep 17 00:00:00 2001 From: Jan Schmidt Date: Tue, 12 May 2009 23:42:00 +0100 Subject: resindvd: Send commands-changed on button change and handle commands query Send the commands-changed navigation message when the set of available DVD menu button actions changes, and handle the commands navigation query so that (e.g.) Totem can know about the available navigation commands. --- ext/resindvd/resindvdsrc.c | 95 +++++++++++++++++++++++++++++++++++++++++++--- ext/resindvd/resindvdsrc.h | 2 + 2 files changed, 92 insertions(+), 5 deletions(-) (limited to 'ext') diff --git a/ext/resindvd/resindvdsrc.c b/ext/resindvd/resindvdsrc.c index 37fc9da9..3b635abc 100644 --- a/ext/resindvd/resindvdsrc.c +++ b/ext/resindvd/resindvdsrc.c @@ -53,6 +53,15 @@ typedef enum RSN_NAV_RESULT_BRANCH_AND_HIGHLIGHT } RsnNavResult; +typedef enum +{ + RSN_BTN_NONE = 0x00, + RSN_BTN_LEFT = 0x01, + RSN_BTN_RIGHT = 0x02, + RSN_BTN_UP = 0x04, + RSN_BTN_DOWN = 0x04 +} RsnBtnMask; + enum { /* FILL ME */ @@ -395,6 +404,7 @@ rsn_dvdsrc_start (RsnBaseSrc * bsrc) src->part_n = -1; src->active_button = -1; + src->cur_btn_mask = RSN_BTN_NONE; src->angles_changed = FALSE; src->n_angles = 0; @@ -583,6 +593,7 @@ rsn_dvdsrc_do_still (resinDvdSrc * src, int duration) { GstEvent *still_event; GstEvent *hl_event; + gboolean cmds_changed; GstStructure *s; GstEvent *seg_event; GstSegment *segment = &(GST_BASE_SRC (src)->segment); @@ -612,6 +623,8 @@ rsn_dvdsrc_do_still (resinDvdSrc * src, int duration) /* Grab any pending highlight event to send too */ hl_event = src->highlight_event; src->highlight_event = NULL; + cmds_changed = src->commands_changed; + src->commands_changed = FALSE; /* Now, send the events. We need to drop the dvd lock while doing so, * and then check after if we got flushed */ @@ -622,6 +635,9 @@ rsn_dvdsrc_do_still (resinDvdSrc * src, int duration) GST_LOG_OBJECT (src, "Sending highlight event before still"); gst_pad_push_event (GST_BASE_SRC_PAD (src), hl_event); } + if (cmds_changed) + rsn_dvdsrc_send_commands_changed (src); + g_mutex_lock (src->dvd_lock); g_mutex_lock (src->branch_lock); @@ -1106,7 +1122,46 @@ rsn_dvdsrc_send_commands_changed (resinDvdSrc * src) static gboolean rsn_dvdsrc_handle_cmds_query (resinDvdSrc * src, GstQuery * query) { - return FALSE; + /* Expand this array if we have more commands in the future: */ + GstNavigationCommand cmds[16]; + gint n_cmds = 0; + + /* Fill out the standard set of commands we support */ + cmds[n_cmds++] = GST_NAVIGATION_COMMAND_DVD_MENU; + cmds[n_cmds++] = GST_NAVIGATION_COMMAND_DVD_TITLE_MENU; + cmds[n_cmds++] = GST_NAVIGATION_COMMAND_DVD_ROOT_MENU; + cmds[n_cmds++] = GST_NAVIGATION_COMMAND_DVD_SUBPICTURE_MENU; + cmds[n_cmds++] = GST_NAVIGATION_COMMAND_DVD_AUDIO_MENU; + cmds[n_cmds++] = GST_NAVIGATION_COMMAND_DVD_ANGLE_MENU; + cmds[n_cmds++] = GST_NAVIGATION_COMMAND_DVD_CHAPTER_MENU; + + g_mutex_lock (src->dvd_lock); + + /* Multiple angles available? */ + if (src->n_angles > 1) { + cmds[n_cmds++] = GST_NAVIGATION_COMMAND_PREV_ANGLE; + cmds[n_cmds++] = GST_NAVIGATION_COMMAND_NEXT_ANGLE; + } + + /* Add button selection commands if we have them */ + if (src->active_button > 0) { + /* We have a valid current button */ + cmds[n_cmds++] = GST_NAVIGATION_COMMAND_ACTIVATE; + } + /* Check for buttons in each direction */ + if (src->cur_btn_mask & RSN_BTN_LEFT) + cmds[n_cmds++] = GST_NAVIGATION_COMMAND_LEFT; + if (src->cur_btn_mask & RSN_BTN_RIGHT) + cmds[n_cmds++] = GST_NAVIGATION_COMMAND_RIGHT; + if (src->cur_btn_mask & RSN_BTN_UP) + cmds[n_cmds++] = GST_NAVIGATION_COMMAND_UP; + if (src->cur_btn_mask & RSN_BTN_DOWN) + cmds[n_cmds++] = GST_NAVIGATION_COMMAND_DOWN; + g_mutex_unlock (src->dvd_lock); + + gst_navigation_query_set_commandsv (query, n_cmds, cmds); + + return TRUE; } static gboolean @@ -1131,6 +1186,9 @@ rsn_dvdsrc_handle_navigation_query (resinDvdSrc * src, GstNavigationQueryType nq_type, GstQuery * query) { gboolean res; + + GST_LOG_OBJECT (src, "Have Navigation query of type %d", nq_type); + switch (nq_type) { case GST_NAVIGATION_QUERY_COMMANDS: res = rsn_dvdsrc_handle_cmds_query (src, query); @@ -1211,10 +1269,8 @@ rsn_dvdsrc_create (RsnPushSrc * psrc, GstBuffer ** outbuf) src->angles_changed = FALSE; } - if (src->commands_changed) { - cmds_changed = TRUE; - src->commands_changed = FALSE; - } + cmds_changed = src->commands_changed; + src->commands_changed = FALSE; g_mutex_unlock (src->dvd_lock); @@ -1600,6 +1656,7 @@ rsn_dvdsrc_handle_navigation_event (resinDvdSrc * src, GstEvent * event) if (have_lock) { gboolean channel_hop = FALSE; + gboolean cmds_changed; if (nav_res != RSN_NAV_RESULT_NONE) { if (nav_res == RSN_NAV_RESULT_BRANCH) { @@ -1660,6 +1717,9 @@ rsn_dvdsrc_handle_navigation_event (resinDvdSrc * src, GstEvent * event) update_title_info (src); } + cmds_changed = src->commands_changed; + src->commands_changed = FALSE; + g_mutex_unlock (src->dvd_lock); if (hl_event) { @@ -1667,6 +1727,9 @@ rsn_dvdsrc_handle_navigation_event (resinDvdSrc * src, GstEvent * event) src->active_button); gst_pad_push_event (GST_BASE_SRC_PAD (src), hl_event); } + + if (cmds_changed) + rsn_dvdsrc_send_commands_changed (src); } if (mouse_over_msg) { @@ -1978,6 +2041,10 @@ rsn_dvdsrc_update_highlight (resinDvdSrc * src) if (src->highlight_event) gst_event_unref (src->highlight_event); src->highlight_event = event; + if (src->cur_btn_mask != RSN_BTN_NONE) { + src->cur_btn_mask = RSN_BTN_NONE; + src->commands_changed = TRUE; + } } return; } @@ -1996,6 +2063,8 @@ rsn_dvdsrc_update_highlight (resinDvdSrc * src) area.sx != src->area.sx || area.sy != src->area.sy || area.ex != src->area.ex || area.ey != src->area.ey || area.palette != src->area.palette) { + btni_t *btn_info = pci->hli.btnit + button - 1; + guint32 btn_mask; GST_DEBUG_OBJECT (src, "Setting highlight. Button %d @ %d,%d " "active %d palette 0x%x (from button %d @ %d,%d palette 0x%x)", @@ -2026,6 +2095,22 @@ rsn_dvdsrc_update_highlight (resinDvdSrc * src) if (src->highlight_event) gst_event_unref (src->highlight_event); src->highlight_event = event; + + /* Calculate whether the available set of button motions is changed */ + btn_mask = 0; + if (btn_info->left && btn_info->left != button) + btn_mask |= RSN_BTN_LEFT; + if (btn_info->right && btn_info->right != button) + btn_mask |= RSN_BTN_RIGHT; + if (btn_info->up && btn_info->up != button) + btn_mask |= RSN_BTN_UP; + if (btn_info->down && btn_info->down != button) + btn_mask |= RSN_BTN_DOWN; + + if (btn_mask != src->cur_btn_mask) { + src->cur_btn_mask = btn_mask; + src->commands_changed = TRUE; + } } } diff --git a/ext/resindvd/resindvdsrc.h b/ext/resindvd/resindvdsrc.h index d30140ea..263c7afb 100644 --- a/ext/resindvd/resindvdsrc.h +++ b/ext/resindvd/resindvdsrc.h @@ -141,6 +141,8 @@ struct _resinDvdSrc gint8 cur_spu_phys_stream; gboolean cur_spu_forced_only; guint32 cur_clut[16]; + + guint32 cur_btn_mask; }; struct _resinDvdSrcClass -- cgit v1.2.1 From cae9db0d8c4c3ff939ac6ac1d4d574b2c030b536 Mon Sep 17 00:00:00 2001 From: Jan Schmidt Date: Wed, 13 May 2009 12:47:43 +0100 Subject: resindvd: Rework button highlight calculation slightly When the current button number is higher than the number of available buttons, switch to the highest numbered button rather than the lowest. Also, don't throw errors when we fail to retrieve some button info from libdvdnav, just reset the highlight. --- ext/resindvd/resindvdsrc.c | 41 +++++++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 20 deletions(-) (limited to 'ext') diff --git a/ext/resindvd/resindvdsrc.c b/ext/resindvd/resindvdsrc.c index 3b635abc..bdf74ced 100644 --- a/ext/resindvd/resindvdsrc.c +++ b/ext/resindvd/resindvdsrc.c @@ -1069,6 +1069,9 @@ rsn_dvdsrc_step (resinDvdSrc * src, gboolean have_dvd_lock) break; } case DVDNAV_HIGHLIGHT:{ + dvdnav_highlight_event_t *event = (dvdnav_highlight_event_t *) data; + GST_DEBUG_OBJECT (src, "highlight change event, button %d", + event->buttonN); rsn_dvdsrc_update_highlight (src); break; } @@ -2011,21 +2014,26 @@ rsn_dvdsrc_update_highlight (resinDvdSrc * src) int button = 0; pci_t *pci = &src->cur_pci; dvdnav_highlight_area_t area; - int mode = 0; + int mode = src->active_highlight ? 1 : 0; GstEvent *event = NULL; GstStructure *s; if (src->have_pci) { - if (dvdnav_get_current_highlight (src->dvdnav, &button) != DVDNAV_STATUS_OK) { - GST_ELEMENT_ERROR (src, LIBRARY, FAILED, (NULL), - ("dvdnav_get_current_highlight: %s", - dvdnav_err_to_string (src->dvdnav))); - return; + if (dvdnav_get_current_highlight (src->dvdnav, &button) == DVDNAV_STATUS_OK) { + GST_LOG_OBJECT (src, "current dvdnav button is %d, we have %d", + button, src->active_button); } - if (pci->hli.hl_gi.hli_ss == 0 || (button > pci->hli.hl_gi.btn_ns) || - (button < 1)) { + if (pci->hli.hl_gi.hli_ss == 0 || button < 0) { + button = 0; + } else if (button > pci->hli.hl_gi.btn_ns) { /* button is out of the range of possible buttons. */ + button = pci->hli.hl_gi.btn_ns; + dvdnav_button_select (src->dvdnav, &src->cur_pci, button); + } + + if (button > 0 && dvdnav_get_highlight_area (pci, button, mode, + &area) != DVDNAV_STATUS_OK) { button = 0; } } @@ -2049,15 +2057,6 @@ rsn_dvdsrc_update_highlight (resinDvdSrc * src) return; } - if (src->active_highlight) - mode = 1; - - if (dvdnav_get_highlight_area (pci, button, mode, &area) != DVDNAV_STATUS_OK) { - GST_ELEMENT_ERROR (src, LIBRARY, FAILED, (NULL), - ("dvdnav_get_highlight_area: %s", dvdnav_err_to_string (src->dvdnav))); - return; - } - /* Check if we have a new button number, or a new highlight region. */ if (button != src->active_button || area.sx != src->area.sx || area.sy != src->area.sy || @@ -2149,12 +2148,14 @@ rsn_dvdsrc_activate_nav_block (resinDvdSrc * src, GstBuffer * nav_buf) src->have_pci = TRUE; forced_button = src->cur_pci.hli.hl_gi.fosl_btnn & 0x3f; - - if (forced_button != 0) + if (forced_button != 0) { + GST_DEBUG_OBJECT (src, "Selecting button %d based on nav packet command", + forced_button); dvdnav_button_select (src->dvdnav, &src->cur_pci, forced_button); - + } /* highlight might change, let's check */ rsn_dvdsrc_update_highlight (src); + if (src->highlight_event && src->in_still_state) { GST_LOG_OBJECT (src, "Signalling still condition due to highlight change"); g_cond_broadcast (src->still_cond); -- cgit v1.2.1 From 13694cd654cef130bd97d2498f5e65e8da525722 Mon Sep 17 00:00:00 2001 From: Jan Schmidt Date: Thu, 14 May 2009 09:53:25 +0100 Subject: resindvd: Make segment updates less aggressive. When updating a pad, send the update to half a second behind the SCR, which avoids ever updating the start time for a pad to beyond the end of the cell. Also, remember the last actual new-segment start time for each pad, and use it when closing the segment. --- ext/resindvd/gstmpegdemux.c | 38 +++++++++++++++++++++++++------------- ext/resindvd/gstmpegdemux.h | 1 + 2 files changed, 26 insertions(+), 13 deletions(-) (limited to 'ext') diff --git a/ext/resindvd/gstmpegdemux.c b/ext/resindvd/gstmpegdemux.c index ed4b3d93..b360bdcc 100644 --- a/ext/resindvd/gstmpegdemux.c +++ b/ext/resindvd/gstmpegdemux.c @@ -469,7 +469,7 @@ gst_flups_demux_clear_times (GstFluPSDemux * demux) GstFluPSStream *stream = demux->streams[id]; if (stream) { - stream->last_ts = GST_CLOCK_TIME_NONE; + stream->last_seg_start = stream->last_ts = GST_CLOCK_TIME_NONE; } } } @@ -494,8 +494,9 @@ gst_flups_demux_send_segment_updates (GstFluPSDemux * demux, stream->last_ts = demux->src_segment.start; if (stream->last_ts + stream->segment_thresh < new_time) { #if 0 - g_print ("Segment update to pad %s time %" GST_TIME_FORMAT "\n", - GST_PAD_NAME (stream->pad), GST_TIME_ARGS (new_time)); + g_print ("Segment update to pad %s time %" GST_TIME_FORMAT " stop now %" + GST_TIME_FORMAT "\n", GST_PAD_NAME (stream->pad), + GST_TIME_ARGS (new_time), GST_TIME_ARGS (demux->src_segment.stop)); #endif GST_DEBUG_OBJECT (demux, "Segment update to pad %s time %" GST_TIME_FORMAT, @@ -509,7 +510,7 @@ gst_flups_demux_send_segment_updates (GstFluPSDemux * demux, } gst_event_ref (event); gst_pad_push_event (stream->pad, event); - stream->last_ts = new_time; + stream->last_seg_start = stream->last_ts = new_time; } } } @@ -528,23 +529,30 @@ gst_flups_demux_send_segment_close (GstFluPSDemux * demux) GstFluPSStream *stream = demux->streams[id]; if (stream) { - if (stream->last_ts == GST_CLOCK_TIME_NONE || - stream->last_ts < demux->src_segment.start) - stream->last_ts = demux->src_segment.start; + GstClockTime start = demux->src_segment.start; + if (stream->last_seg_start != GST_CLOCK_TIME_NONE && + stream->last_seg_start > start) + start = stream->last_seg_start; #if 0 - g_print ("Segment update to pad %s start %" GST_TIME_FORMAT + g_print ("Segment close to pad %s start %" GST_TIME_FORMAT " stop %" GST_TIME_FORMAT "\n", - GST_PAD_NAME (stream->pad), GST_TIME_ARGS (stream->last_ts), + GST_PAD_NAME (stream->pad), GST_TIME_ARGS (start), GST_TIME_ARGS (demux->src_segment.stop)); #endif + if (start > demux->src_segment.stop) { + g_print ("Problem on pad %s with start %" GST_TIME_FORMAT " > stop %" + GST_TIME_FORMAT "\n", + gst_object_get_name (GST_OBJECT (stream->pad)), + GST_TIME_ARGS (start), GST_TIME_ARGS (demux->src_segment.stop)); + } event = gst_event_new_new_segment_full (TRUE, demux->src_segment.rate, demux->src_segment.applied_rate, - GST_FORMAT_TIME, stream->last_ts, + GST_FORMAT_TIME, start, demux->src_segment.stop, - demux->src_segment.time + - (stream->last_ts - demux->src_segment.start)); - gst_pad_push_event (stream->pad, event); + demux->src_segment.time + (start - demux->src_segment.start)); + if (event) + gst_pad_push_event (stream->pad, event); } } } @@ -1354,6 +1362,10 @@ gst_flups_demux_parse_pack_start (GstFluPSDemux * demux) new_time = MPEGTIME_TO_GSTTIME (scr_adjusted); if (new_time != GST_CLOCK_TIME_NONE) { // g_print ("SCR now %" GST_TIME_FORMAT "\n", GST_TIME_ARGS (new_time)); + if (new_time > GST_SECOND / 2) + new_time -= GST_SECOND / 2; + else + new_time = 0; gst_flups_demux_send_segment_updates (demux, new_time); demux->src_segment.last_stop = new_time; } diff --git a/ext/resindvd/gstmpegdemux.h b/ext/resindvd/gstmpegdemux.h index b7b2d9fc..683b7cde 100644 --- a/ext/resindvd/gstmpegdemux.h +++ b/ext/resindvd/gstmpegdemux.h @@ -63,6 +63,7 @@ struct _GstFluPSStream { gboolean notlinked; gboolean need_segment; + GstClockTime last_seg_start; GstClockTime last_ts; GstClockTime segment_thresh; }; -- cgit v1.2.1 From e62b64f1d34ec402f8fce4f91f174d40315576c9 Mon Sep 17 00:00:00 2001 From: Jan Schmidt Date: Thu, 14 May 2009 10:34:08 +0100 Subject: resindvd: Fix the argument order in a debug statement Make the debug statement correctly show the 'old' and 'new' button coordinates, instead of the wrong way around. --- ext/resindvd/resindvdsrc.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'ext') diff --git a/ext/resindvd/resindvdsrc.c b/ext/resindvd/resindvdsrc.c index bdf74ced..f24e45aa 100644 --- a/ext/resindvd/resindvdsrc.c +++ b/ext/resindvd/resindvdsrc.c @@ -2065,10 +2065,12 @@ rsn_dvdsrc_update_highlight (resinDvdSrc * src) btni_t *btn_info = pci->hli.btnit + button - 1; guint32 btn_mask; - GST_DEBUG_OBJECT (src, "Setting highlight. Button %d @ %d,%d " - "active %d palette 0x%x (from button %d @ %d,%d palette 0x%x)", - button, src->area.sx, src->area.sy, mode, src->area.palette, - src->active_button, area.sx, area.sy, area.palette); + GST_DEBUG_OBJECT (src, "Setting highlight. Button %d @ %d,%d,%d,%d " + "active %d palette 0x%x (from button %d @ %d,%d,%d,%d palette 0x%x)", + button, area.sx, area.sy, area.ex, area.ey, + mode, area.palette, + src->active_button, src->area.sx, src->area.sy, src->area.ex, + src->area.ey, src->area.palette); memcpy (&(src->area), &area, sizeof (dvdnav_highlight_area_t)); -- cgit v1.2.1 From b6e891bbdad221105daecdef83098a2585d0f039 Mon Sep 17 00:00:00 2001 From: Jan Schmidt Date: Mon, 18 May 2009 23:38:59 +0100 Subject: dtsdec: Reconcile element code with a52dec changes Re-work the dtsdec element code to unify it with changes made it a52dec, including support for reverse playback and dynamic channel negotiation on the source pad. --- ext/dts/gstdtsdec.c | 489 +++++++++++++++++++++++++++++++++++----------------- ext/dts/gstdtsdec.h | 32 ++-- 2 files changed, 348 insertions(+), 173 deletions(-) (limited to 'ext') diff --git a/ext/dts/gstdtsdec.c b/ext/dts/gstdtsdec.c index 5b85a803..08695936 100644 --- a/ext/dts/gstdtsdec.c +++ b/ext/dts/gstdtsdec.c @@ -1,5 +1,6 @@ /* GStreamer DTS decoder plugin based on libdtsdec * Copyright (C) 2004 Ronald Bultje + * Copyright (C) 2009 Jan Schmidt * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -84,43 +85,46 @@ typedef struct dts_state_s dca_state_t; #include #include -GST_DEBUG_CATEGORY_STATIC (dtsdec_debug); -#define GST_CAT_DEFAULT (dtsdec_debug) - static const GstElementDetails gst_dtsdec_details = GST_ELEMENT_DETAILS ("DTS audio decoder", "Codec/Decoder/Audio", "Decodes DTS audio streams", + "Jan Schmidt \n" "Ronald Bultje "); +#if defined(LIBDTS_FIXED) || defined(LIBDCA_FIXED) +#define SAMPLE_WIDTH 16 +#elif defined (LIBDTS_DOUBLE) || defined(LIBDCA_DOUBLE) +#define SAMPLE_WIDTH 64 +#else +#define SAMPLE_WIDTH 32 +#endif + +GST_DEBUG_CATEGORY_STATIC (dtsdec_debug); +#define GST_CAT_DEFAULT (dtsdec_debug) + enum { ARG_0, ARG_DRC }; + static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, - GST_STATIC_CAPS ("audio/x-dts;" "audio/x-private1-dts") + GST_STATIC_CAPS ("audio/x-dts; audio/x-private1-dts") ); #if defined(LIBDTS_FIXED) || defined(LIBDCA_FIXED) #define DTS_CAPS "audio/x-raw-int, " \ "endianness = (int) " G_STRINGIFY (G_BYTE_ORDER) ", " \ "signed = (boolean) true, " \ - "width = (int) 16, " \ + "width = (int) " G_STRINGIFY (SAMPLE_WIDTH) ", " \ "depth = (int) 16" -#define SAMPLE_WIDTH 16 -#elif defined(LIBDTS_DOUBLE) || defined(LIBDCA_DOUBLE) -#define DTS_CAPS "audio/x-raw-float, " \ - "endianness = (int) " G_STRINGIFY (G_BYTE_ORDER) ", " \ - "width = (int) 64" -#define SAMPLE_WIDTH 64 #else #define DTS_CAPS "audio/x-raw-float, " \ "endianness = (int) " G_STRINGIFY (G_BYTE_ORDER) ", " \ - "width = (int) 32" -#define SAMPLE_WIDTH 32 + "width = (int) " G_STRINGIFY (SAMPLE_WIDTH) #endif static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src", @@ -135,6 +139,7 @@ GST_BOILERPLATE (GstDtsDec, gst_dtsdec, GstElement, GST_TYPE_ELEMENT); static gboolean gst_dtsdec_sink_setcaps (GstPad * pad, GstCaps * caps); static gboolean gst_dtsdec_sink_event (GstPad * pad, GstEvent * event); static GstFlowReturn gst_dtsdec_chain (GstPad * pad, GstBuffer * buf); +static GstFlowReturn gst_dtsdec_chain_raw (GstPad * pad, GstBuffer * buf); static GstStateChangeReturn gst_dtsdec_change_state (GstElement * element, GstStateChange transition); @@ -155,7 +160,7 @@ gst_dtsdec_base_init (gpointer g_class) gst_static_pad_template_get (&src_factory)); gst_element_class_set_details (element_class, &gst_dtsdec_details); - GST_DEBUG_CATEGORY_INIT (dtsdec_debug, "dtsdec", 0, "DTS audio decoder"); + GST_DEBUG_CATEGORY_INIT (dtsdec_debug, "dtsdec", 0, "DTS/DCA audio decoder"); } static void @@ -202,6 +207,7 @@ gst_dtsdec_class_init (GstDtsDecClass * klass) static void gst_dtsdec_init (GstDtsDec * dtsdec, GstDtsDecClass * g_class) { + /* create the sink and src pads */ dtsdec->sinkpad = gst_pad_new_from_static_template (&sink_factory, "sink"); gst_pad_set_setcaps_function (dtsdec->sinkpad, GST_DEBUG_FUNCPTR (gst_dtsdec_sink_setcaps)); @@ -212,10 +218,12 @@ gst_dtsdec_init (GstDtsDec * dtsdec, GstDtsDecClass * g_class) gst_element_add_pad (GST_ELEMENT (dtsdec), dtsdec->sinkpad); dtsdec->srcpad = gst_pad_new_from_static_template (&src_factory, "src"); - gst_pad_use_fixed_caps (dtsdec->srcpad); gst_element_add_pad (GST_ELEMENT (dtsdec), dtsdec->srcpad); + dtsdec->request_channels = DCA_CHANNEL; dtsdec->dynamic_range_compression = FALSE; + + gst_segment_init (&dtsdec->segment, GST_FORMAT_UNDEFINED); } static gint @@ -317,6 +325,105 @@ gst_dtsdec_channels (uint32_t flags, GstAudioChannelPosition ** pos) return chans; } +static void +clear_queued (GstDtsDec * dec) +{ + g_list_foreach (dec->queued, (GFunc) gst_mini_object_unref, NULL); + g_list_free (dec->queued); + dec->queued = NULL; +} + +static GstFlowReturn +flush_queued (GstDtsDec * dec) +{ + GstFlowReturn ret = GST_FLOW_OK; + + while (dec->queued) { + GstBuffer *buf = GST_BUFFER_CAST (dec->queued->data); + + GST_LOG_OBJECT (dec, "pushing buffer %p, timestamp %" + GST_TIME_FORMAT ", duration %" GST_TIME_FORMAT, buf, + GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)), + GST_TIME_ARGS (GST_BUFFER_DURATION (buf))); + + /* iterate ouput queue an push downstream */ + ret = gst_pad_push (dec->srcpad, buf); + + dec->queued = g_list_delete_link (dec->queued, dec->queued); + } + return ret; +} + +static GstFlowReturn +gst_dtsdec_drain (GstDtsDec * dec) +{ + GstFlowReturn ret = GST_FLOW_OK; + + if (dec->segment.rate < 0.0) { + /* if we have some queued frames for reverse playback, flush + * them now */ + ret = flush_queued (dec); + } + return ret; +} + +static GstFlowReturn +gst_dtsdec_push (GstDtsDec * dtsdec, + GstPad * srcpad, int flags, sample_t * samples, GstClockTime timestamp) +{ + GstBuffer *buf; + int chans, n, c; + GstFlowReturn result; + + flags &= (DCA_CHANNEL_MASK | DCA_LFE); + chans = gst_dtsdec_channels (flags, NULL); + if (!chans) { + GST_ELEMENT_ERROR (GST_ELEMENT (dtsdec), STREAM, DECODE, (NULL), + ("Invalid channel flags: %d", flags)); + return GST_FLOW_ERROR; + } + + result = + gst_pad_alloc_buffer_and_set_caps (srcpad, 0, + 256 * chans * (SAMPLE_WIDTH / 8), GST_PAD_CAPS (srcpad), &buf); + if (result != GST_FLOW_OK) + return result; + + for (n = 0; n < 256; n++) { + for (c = 0; c < chans; c++) { + ((sample_t *) GST_BUFFER_DATA (buf))[n * chans + c] = + samples[c * 256 + n]; + } + } + GST_BUFFER_TIMESTAMP (buf) = timestamp; + GST_BUFFER_DURATION (buf) = 256 * GST_SECOND / dtsdec->sample_rate; + + result = GST_FLOW_OK; + if ((buf = gst_audio_buffer_clip (buf, &dtsdec->segment, + dtsdec->sample_rate, (SAMPLE_WIDTH / 8) * chans))) { + /* set discont when needed */ + if (dtsdec->discont) { + GST_LOG_OBJECT (dtsdec, "marking DISCONT"); + GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT); + dtsdec->discont = FALSE; + } + + if (dtsdec->segment.rate > 0.0) { + GST_DEBUG_OBJECT (dtsdec, + "Pushing buffer with ts %" GST_TIME_FORMAT " duration %" + GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)), + GST_TIME_ARGS (GST_BUFFER_DURATION (buf))); + + result = gst_pad_push (srcpad, buf); + } else { + /* reverse playback, queue frame till later when we get a discont. */ + GST_DEBUG_OBJECT (dtsdec, "queued frame"); + dtsdec->queued = g_list_prepend (dtsdec->queued, buf); + } + } + return result; +} + static gboolean gst_dtsdec_renegotiate (GstDtsDec * dts) { @@ -360,32 +467,57 @@ gst_dtsdec_sink_event (GstPad * pad, GstEvent * event) switch (GST_EVENT_TYPE (event)) { case GST_EVENT_NEWSEGMENT:{ GstFormat format; - gint64 val; - - gst_event_parse_new_segment (event, NULL, NULL, &format, &val, NULL, - NULL); - if (format != GST_FORMAT_TIME || !GST_CLOCK_TIME_IS_VALID (val)) { - GST_WARNING ("No time in newsegment event %p", event); + gboolean update; + gint64 start, end, pos; + gdouble rate; + + gst_event_parse_new_segment (event, &update, &rate, &format, &start, &end, + &pos); + + /* drain queued buffers before activating the segment so that we can clip + * against the old segment first */ + gst_dtsdec_drain (dtsdec); + + if (format != GST_FORMAT_TIME || !GST_CLOCK_TIME_IS_VALID (start)) { + GST_WARNING ("No time in newsegment event %p (format is %s)", + event, gst_format_get_name (format)); + gst_event_unref (event); + dtsdec->sent_segment = FALSE; + /* set some dummy values, FIXME: do proper conversion */ + dtsdec->time = start = pos = 0; + format = GST_FORMAT_TIME; + end = -1; } else { - dtsdec->current_ts = val; + dtsdec->time = start; + dtsdec->sent_segment = TRUE; + ret = gst_pad_push_event (dtsdec->srcpad, event); } - if (dtsdec->cache) { - gst_buffer_unref (dtsdec->cache); - dtsdec->cache = NULL; - } - ret = gst_pad_event_default (pad, event); + gst_segment_set_newsegment (&dtsdec->segment, update, rate, format, start, + end, pos); break; } + case GST_EVENT_TAG: + ret = gst_pad_push_event (dtsdec->srcpad, event); + break; + case GST_EVENT_EOS: + gst_dtsdec_drain (dtsdec); + ret = gst_pad_push_event (dtsdec->srcpad, event); + break; + case GST_EVENT_FLUSH_START: + ret = gst_pad_push_event (dtsdec->srcpad, event); + break; case GST_EVENT_FLUSH_STOP: if (dtsdec->cache) { gst_buffer_unref (dtsdec->cache); dtsdec->cache = NULL; } - ret = gst_pad_event_default (pad, event); + clear_queued (dtsdec); + gst_segment_init (&dtsdec->segment, GST_FORMAT_UNDEFINED); + ret = gst_pad_push_event (dtsdec->srcpad, event); break; default: - ret = gst_pad_event_default (pad, event); + ret = gst_pad_push_event (dtsdec->srcpad, event); break; } @@ -393,24 +525,6 @@ gst_dtsdec_sink_event (GstPad * pad, GstEvent * event) return ret; } -static gboolean -gst_dtsdec_sink_setcaps (GstPad * pad, GstCaps * caps) -{ - GstDtsDec *dts = GST_DTSDEC (gst_pad_get_parent (pad)); - GstStructure *structure; - - structure = gst_caps_get_structure (caps, 0); - - if (structure && gst_structure_has_name (structure, "audio/x-private1-dts")) - dts->dvdmode = TRUE; - else - dts->dvdmode = FALSE; - - gst_object_unref (dts); - - return TRUE; -} - static void gst_dtsdec_update_streaminfo (GstDtsDec * dts) { @@ -419,6 +533,7 @@ gst_dtsdec_update_streaminfo (GstDtsDec * dts) taglist = gst_tag_list_new (); gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND, + GST_TAG_AUDIO_CODEC, "DTS DCA", GST_TAG_BITRATE, (guint) dts->bit_rate, NULL); gst_element_found_tags_for_pad (GST_ELEMENT (dts), dts->srcpad, taglist); @@ -428,29 +543,37 @@ static GstFlowReturn gst_dtsdec_handle_frame (GstDtsDec * dts, guint8 * data, guint length, gint flags, gint sample_rate, gint bit_rate) { + gint channels, i, num_blocks; gboolean need_renegotiation = FALSE; - gint channels, num_blocks; - GstBuffer *out; - gint i, s, c, num_c; - sample_t *samples; - GstFlowReturn result = GST_FLOW_OK; - /* go over stream properties, update caps/streaminfo if needed */ + /* go over stream properties, renegotiate or update streaminfo if needed */ if (dts->sample_rate != sample_rate) { need_renegotiation = TRUE; dts->sample_rate = sample_rate; } - dts->stream_channels = flags; + if (flags) { + dts->stream_channels = flags & (DCA_CHANNEL_MASK | DCA_LFE); + } if (bit_rate != dts->bit_rate) { dts->bit_rate = bit_rate; gst_dtsdec_update_streaminfo (dts); } - if (dts->request_channels == DCA_CHANNEL) { + /* If we haven't had an explicit number of channels chosen through properties + * at this point, choose what to downmix to now, based on what the peer will + * accept - this allows a52dec to do downmixing in preference to a + * downstream element such as audioconvert. + * FIXME: Add the property back in for forcing output channels. + */ + if (dts->request_channels != DCA_CHANNEL) { + flags = dts->request_channels; + } else if (dts->flag_update) { GstCaps *caps; + dts->flag_update = FALSE; + caps = gst_pad_get_allowed_caps (dts->srcpad); if (caps && gst_caps_get_size (caps) > 0) { GstCaps *copy = gst_caps_copy_nth (caps, 0); @@ -472,38 +595,38 @@ gst_dtsdec_handle_frame (GstDtsDec * dts, guint8 * data, flags ? gst_dtsdec_channels (flags, NULL) : 6); gst_structure_get_int (structure, "channels", &channels); if (channels <= 6) - dts->request_channels = dts_channels[channels - 1]; + flags = dts_channels[channels - 1]; else - dts->request_channels = dts_channels[5]; + flags = dts_channels[5]; gst_caps_unref (copy); } else if (flags) { - dts->request_channels = dts->stream_channels; + flags = dts->stream_channels; } else { - dts->request_channels = DCA_3F2R | DCA_LFE; + flags = DCA_3F2R | DCA_LFE; } if (caps) gst_caps_unref (caps); + } else { + flags = dts->using_channels; } - /* process */ - flags = dts->request_channels | DCA_ADJUST_LEVEL; + flags |= DCA_ADJUST_LEVEL; dts->level = 1; - if (dca_frame (dts->state, data, &flags, &dts->level, dts->bias)) { - GST_WARNING ("dts_frame error"); + GST_WARNING_OBJECT (dts, "dts_frame error"); + dts->discont = TRUE; return GST_FLOW_OK; } - channels = flags & (DCA_CHANNEL_MASK | DCA_LFE); - if (dts->using_channels != channels) { need_renegotiation = TRUE; dts->using_channels = channels; } - if (need_renegotiation == TRUE) { + /* negotiate if required */ + if (need_renegotiation) { GST_DEBUG ("dtsdec: sample_rate:%d stream_chans:0x%x using_chans:0x%x", dts->sample_rate, dts->stream_channels, dts->using_channels); if (!gst_dtsdec_renegotiate (dts)) { @@ -520,107 +643,60 @@ gst_dtsdec_handle_frame (GstDtsDec * dts, guint8 * data, num_blocks = dca_blocks_num (dts->state); for (i = 0; i < num_blocks; i++) { if (dca_block (dts->state)) { - GST_WARNING ("dts_block error %d", i); - continue; - } - - samples = dca_samples (dts->state); - num_c = gst_dtsdec_channels (dts->using_channels, NULL); - - result = gst_pad_alloc_buffer_and_set_caps (dts->srcpad, 0, - (SAMPLE_WIDTH / 8) * 256 * num_c, GST_PAD_CAPS (dts->srcpad), &out); - - if (result != GST_FLOW_OK) - break; + /* Ignore errors, but mark a discont */ + GST_WARNING_OBJECT (dts, "dts_block error %d", i); + dts->discont = TRUE; + } else { + GstFlowReturn ret; - GST_BUFFER_TIMESTAMP (out) = dts->current_ts; - GST_BUFFER_DURATION (out) = GST_SECOND * 256 / dts->sample_rate; - dts->current_ts += GST_BUFFER_DURATION (out); - - /* libdts returns buffers in 256-sample-blocks per channel, - * we want interleaved. And we need to copy anyway... */ - data = GST_BUFFER_DATA (out); - for (s = 0; s < 256; s++) { - for (c = 0; c < num_c; c++) { - *(sample_t *) data = samples[s + c * 256]; - data += (SAMPLE_WIDTH / 8); - } + /* push on */ + ret = gst_dtsdec_push (dts, dts->srcpad, dts->using_channels, + dts->samples, dts->time); + if (ret != GST_FLOW_OK) + return ret; } - - /* push on */ - result = gst_pad_push (dts->srcpad, out); - - if (result != GST_FLOW_OK) - break; + dts->time += GST_SECOND * 256 / dts->sample_rate; } - return result; + return GST_FLOW_OK; } -static GstFlowReturn -gst_dtsdec_chain_raw (GstPad * pad, GstBuffer * buf) +static gboolean +gst_dtsdec_sink_setcaps (GstPad * pad, GstCaps * caps) { - GstDtsDec *dts; - guint8 *data; - gint size; - gint length, flags, sample_rate, bit_rate, frame_length; - GstFlowReturn result = GST_FLOW_OK; - - dts = GST_DTSDEC (GST_PAD_PARENT (pad)); - - if (dts->cache) { - buf = gst_buffer_join (dts->cache, buf); - dts->cache = NULL; - } + GstDtsDec *dts = GST_DTSDEC (gst_pad_get_parent (pad)); + GstStructure *structure; - data = GST_BUFFER_DATA (buf); - size = GST_BUFFER_SIZE (buf); - length = 0; - while (size >= 7) { - length = dca_syncinfo (dts->state, data, &flags, - &sample_rate, &bit_rate, &frame_length); - if (length == 0) { - /* shift window to re-find sync */ - data++; - size--; - } else if (length <= size) { - GST_DEBUG ("Sync: frame size %d", length); - result = gst_dtsdec_handle_frame (dts, data, length, - flags, sample_rate, bit_rate); - if (result != GST_FLOW_OK) { - size = 0; - break; - } - size -= length; - data += length; - } else { - GST_LOG ("Not enough data available (needed %d had %d)", length, size); - break; - } - } + structure = gst_caps_get_structure (caps, 0); - /* keep cache */ - if (length == 0) { - GST_LOG ("No sync found"); - } - if (size > 0) { - dts->cache = gst_buffer_create_sub (buf, - GST_BUFFER_SIZE (buf) - size, size); - } + if (structure && gst_structure_has_name (structure, "audio/x-private1-dts")) + dts->dvdmode = TRUE; + else + dts->dvdmode = FALSE; - gst_buffer_unref (buf); + gst_object_unref (dts); - return result; + return TRUE; } - static GstFlowReturn gst_dtsdec_chain (GstPad * pad, GstBuffer * buf) { - GstFlowReturn res = GST_FLOW_OK; + GstFlowReturn ret = GST_FLOW_OK; GstDtsDec *dts = GST_DTSDEC (GST_PAD_PARENT (pad)); gint first_access; + if (GST_BUFFER_IS_DISCONT (buf)) { + GST_LOG_OBJECT (dts, "received DISCONT"); + gst_dtsdec_drain (dts); + /* clear cache on discont and mark a discont in the element */ + if (dts->cache) { + gst_buffer_unref (dts->cache); + dts->cache = NULL; + } + dts->discont = TRUE; + } + if (dts->dvdmode) { gint size = GST_BUFFER_SIZE (buf); guint8 *data = GST_BUFFER_DATA (buf); @@ -644,8 +720,8 @@ gst_dtsdec_chain (GstPad * pad, GstBuffer * buf) subbuf = gst_buffer_create_sub (buf, offset, len); GST_BUFFER_TIMESTAMP (subbuf) = GST_CLOCK_TIME_NONE; - res = gst_dtsdec_chain_raw (pad, subbuf); - if (res != GST_FLOW_OK) + ret = gst_dtsdec_chain_raw (pad, subbuf); + if (ret != GST_FLOW_OK) goto done; offset += len; @@ -655,21 +731,20 @@ gst_dtsdec_chain (GstPad * pad, GstBuffer * buf) subbuf = gst_buffer_create_sub (buf, offset, len); GST_BUFFER_TIMESTAMP (subbuf) = GST_BUFFER_TIMESTAMP (buf); - res = gst_dtsdec_chain_raw (pad, subbuf); + ret = gst_dtsdec_chain_raw (pad, subbuf); } } else { - /* first_access = 0 or 1, so if there's a timestamp it applies - * to the first byte */ + /* first_access = 0 or 1, so if there's a timestamp it applies to the first byte */ subbuf = gst_buffer_create_sub (buf, offset, size - offset); GST_BUFFER_TIMESTAMP (subbuf) = GST_BUFFER_TIMESTAMP (buf); - res = gst_dtsdec_chain_raw (pad, subbuf); + ret = gst_dtsdec_chain_raw (pad, subbuf); } } else { - res = gst_dtsdec_chain_raw (pad, buf); + ret = gst_dtsdec_chain_raw (pad, buf); } done: - return res; + return ret; /* ERRORS */ not_enough_data: @@ -684,7 +759,97 @@ bad_first_access_parameter: ("Bad first_access parameter (%d) in buffer", first_access)); return GST_FLOW_ERROR; } +} + +static GstFlowReturn +gst_dtsdec_chain_raw (GstPad * pad, GstBuffer * buf) +{ + GstDtsDec *dts; + guint8 *data; + gint size; + gint length = 0, flags, sample_rate, bit_rate, frame_length; + GstFlowReturn result = GST_FLOW_OK; + + dts = GST_DTSDEC (GST_PAD_PARENT (pad)); + + if (!dts->sent_segment) { + GstSegment segment; + + /* Create a basic segment. Usually, we'll get a new-segment sent by + * another element that will know more information (a demuxer). If we're + * just looking at a raw AC3 stream, we won't - so we need to send one + * here, but we don't know much info, so just send a minimal TIME + * new-segment event + */ + gst_segment_init (&segment, GST_FORMAT_TIME); + gst_pad_push_event (dts->srcpad, gst_event_new_new_segment (FALSE, + segment.rate, segment.format, segment.start, + segment.duration, segment.start)); + dts->sent_segment = TRUE; + } + + /* merge with cache, if any. Also make sure timestamps match */ + if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)) { + dts->time = GST_BUFFER_TIMESTAMP (buf); + GST_DEBUG_OBJECT (dts, + "Received buffer with ts %" GST_TIME_FORMAT " duration %" + GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)), + GST_TIME_ARGS (GST_BUFFER_DURATION (buf))); + } + + if (dts->cache) { + buf = gst_buffer_join (dts->cache, buf); + dts->cache = NULL; + } + data = GST_BUFFER_DATA (buf); + size = GST_BUFFER_SIZE (buf); + + /* find and read header */ + bit_rate = dts->bit_rate; + sample_rate = dts->sample_rate; + flags = 0; + while (size >= 7) { + length = dca_syncinfo (dts->state, data, &flags, + &sample_rate, &bit_rate, &frame_length); + + if (length == 0) { + /* shift window to re-find sync */ + data++; + size--; + } else if (length <= size) { + GST_DEBUG ("Sync: frame size %d", length); + if (flags != dts->prev_flags) + dts->flag_update = TRUE; + dts->prev_flags = flags; + + result = gst_dtsdec_handle_frame (dts, data, length, + flags, sample_rate, bit_rate); + if (result != GST_FLOW_OK) { + size = 0; + break; + } + size -= length; + data += length; + } else { + GST_LOG ("Not enough data available (needed %d had %d)", length, size); + break; + } + } + + /* keep cache */ + if (length == 0) { + GST_LOG ("No sync found"); + } + + if (size > 0) { + dts->cache = gst_buffer_create_sub (buf, + GST_BUFFER_SIZE (buf) - size, size); + } + + gst_buffer_unref (buf); + + return result; } static GstStateChangeReturn @@ -705,13 +870,14 @@ gst_dtsdec_change_state (GstElement * element, GstStateChange transition) dts->samples = dca_samples (dts->state); dts->bit_rate = -1; dts->sample_rate = -1; - dts->stream_channels = 0; - /* FIXME force stereo for now */ - dts->request_channels = DCA_CHANNEL; - dts->using_channels = 0; + dts->stream_channels = DCA_CHANNEL; + dts->using_channels = DCA_CHANNEL; dts->level = 1; dts->bias = 0; - dts->current_ts = 0; + dts->time = 0; + dts->sent_segment = FALSE; + dts->flag_update = TRUE; + gst_segment_init (&dts->segment, GST_FORMAT_UNDEFINED); break; case GST_STATE_CHANGE_PAUSED_TO_PLAYING: break; @@ -730,6 +896,7 @@ gst_dtsdec_change_state (GstElement * element, GstStateChange transition) gst_buffer_unref (dts->cache); dts->cache = NULL; } + clear_queued (dts); break; case GST_STATE_CHANGE_READY_TO_NULL: dca_free (dts->state); diff --git a/ext/dts/gstdtsdec.h b/ext/dts/gstdtsdec.h index 5222c687..a7c8f718 100644 --- a/ext/dts/gstdtsdec.h +++ b/ext/dts/gstdtsdec.h @@ -43,15 +43,22 @@ struct _GstDtsDec { GstElement element; /* pads */ - GstPad *sinkpad; - GstPad *srcpad; + GstPad *sinkpad; + GstPad *srcpad; + GstSegment segment; + + gboolean dvdmode; + gboolean sent_segment; + gboolean discont; + gboolean flag_update; + gboolean prev_flags; /* stream properties */ - gint bit_rate; - gint sample_rate; - gint stream_channels; - gint request_channels; - gint using_channels; + gint bit_rate; + gint sample_rate; + gint stream_channels; + gint request_channels; + gint using_channels; /* decoding properties */ sample_t level; @@ -63,13 +70,14 @@ struct _GstDtsDec { #else dts_state_t *state; #endif - gboolean dvdmode; + /* Data left over from the previous buffer */ - GstBuffer *cache; - - /* keep track of time */ - GstClockTime current_ts; + GstBuffer *cache; + GstClockTime time; + + /* reverse playback */ + GList *queued; }; struct _GstDtsDecClass { -- cgit v1.2.1 From 43b755312bca15f74440bc1beba92c21f9ea3ccd Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 25 May 2009 11:18:57 +0200 Subject: x264enc: add multipass-cache-file property Fixes #583627 --- ext/x264/gstx264enc.c | 30 +++++++++++++++++++----------- ext/x264/gstx264enc.h | 2 +- 2 files changed, 20 insertions(+), 12 deletions(-) (limited to 'ext') diff --git a/ext/x264/gstx264enc.c b/ext/x264/gstx264enc.c index fcafdd3d..0bcd4434 100644 --- a/ext/x264/gstx264enc.c +++ b/ext/x264/gstx264enc.c @@ -76,6 +76,7 @@ enum ARG_PASS, ARG_QUANTIZER, ARG_STATS_FILE, + ARG_MULTIPASS_CACHE_FILE, ARG_BYTE_STREAM, ARG_BITRATE, ARG_VBV_BUF_CAPACITY, @@ -104,7 +105,8 @@ enum #define ARG_THREADS_DEFAULT 1 #define ARG_PASS_DEFAULT 0 #define ARG_QUANTIZER_DEFAULT 21 -#define ARG_STATS_FILE_DEFAULT "x264.log" +#define ARG_MULTIPASS_CACHE_FILE_DEFAULT "x264.log" +#define ARG_STATS_FILE_DEFAULT ARG_MULTIPASS_CACHE_FILE_DEFAULT #define ARG_BYTE_STREAM_DEFAULT FALSE #define ARG_BITRATE_DEFAULT (2 * 1024) #define ARG_VBV_BUF_CAPACITY_DEFAULT 600 @@ -300,8 +302,12 @@ gst_x264_enc_class_init (GstX264EncClass * klass) 1, 50, ARG_QUANTIZER_DEFAULT, G_PARAM_READWRITE)); g_object_class_install_property (gobject_class, ARG_STATS_FILE, g_param_spec_string ("stats-file", "Stats File", - "Filename for multipass statistics", + "Filename for multipass statistics (deprecated, use multipass-stats-file)", ARG_STATS_FILE_DEFAULT, G_PARAM_READWRITE)); + g_object_class_install_property (gobject_class, ARG_MULTIPASS_CACHE_FILE, + g_param_spec_string ("multipass-cache-file", "Multipass Cache File", + "Filename for multipass cache file", + ARG_MULTIPASS_CACHE_FILE_DEFAULT, G_PARAM_READWRITE)); g_object_class_install_property (gobject_class, ARG_BYTE_STREAM, g_param_spec_boolean ("byte-stream", "Byte Stream", "Generate byte stream format of NALU", @@ -448,7 +454,7 @@ gst_x264_enc_init (GstX264Enc * encoder, GstX264EncClass * klass) encoder->threads = ARG_THREADS_DEFAULT; encoder->pass = ARG_PASS_DEFAULT; encoder->quantizer = ARG_QUANTIZER_DEFAULT; - encoder->stats_file = g_strdup (ARG_STATS_FILE_DEFAULT); + encoder->mp_cache_file = g_strdup (ARG_MULTIPASS_CACHE_FILE_DEFAULT); encoder->byte_stream = ARG_BYTE_STREAM_DEFAULT; encoder->bitrate = ARG_BITRATE_DEFAULT; encoder->vbv_buf_capacity = ARG_VBV_BUF_CAPACITY_DEFAULT; @@ -502,8 +508,8 @@ gst_x264_enc_finalize (GObject * object) { GstX264Enc *encoder = GST_X264_ENC (object); - g_free (encoder->stats_file); - encoder->stats_file = NULL; + g_free (encoder->mp_cache_file); + encoder->mp_cache_file = NULL; g_free (encoder->buffer); encoder->buffer = NULL; g_queue_free (encoder->delay); @@ -637,8 +643,8 @@ gst_x264_enc_init_encoder (GstX264Enc * encoder) encoder->x264param.rc.b_stat_write = 1; break; } - encoder->x264param.rc.psz_stat_in = encoder->stats_file; - encoder->x264param.rc.psz_stat_out = encoder->stats_file; + encoder->x264param.rc.psz_stat_in = encoder->mp_cache_file; + encoder->x264param.rc.psz_stat_out = encoder->mp_cache_file; GST_OBJECT_UNLOCK (encoder); @@ -1110,9 +1116,10 @@ gst_x264_enc_set_property (GObject * object, guint prop_id, encoder->quantizer = g_value_get_uint (value); break; case ARG_STATS_FILE: - if (encoder->stats_file) - g_free (encoder->stats_file); - encoder->stats_file = g_value_dup_string (value); + case ARG_MULTIPASS_CACHE_FILE: + if (encoder->mp_cache_file) + g_free (encoder->mp_cache_file); + encoder->mp_cache_file = g_value_dup_string (value); break; case ARG_BYTE_STREAM: encoder->byte_stream = g_value_get_boolean (value); @@ -1218,7 +1225,8 @@ gst_x264_enc_get_property (GObject * object, guint prop_id, g_value_set_uint (value, encoder->quantizer); break; case ARG_STATS_FILE: - g_value_set_string (value, encoder->stats_file); + case ARG_MULTIPASS_CACHE_FILE: + g_value_set_string (value, encoder->mp_cache_file); break; case ARG_BYTE_STREAM: g_value_set_boolean (value, encoder->byte_stream); diff --git a/ext/x264/gstx264enc.h b/ext/x264/gstx264enc.h index 7cebf112..15ffe65e 100644 --- a/ext/x264/gstx264enc.h +++ b/ext/x264/gstx264enc.h @@ -57,7 +57,7 @@ struct _GstX264Enc guint threads; gint pass; guint quantizer; - gchar *stats_file; + gchar *mp_cache_file; gboolean byte_stream; guint bitrate; gint me; -- cgit v1.2.1 From 46b4d226ca6ed4efa7574ad7bae46af8c73fc7bd Mon Sep 17 00:00:00 2001 From: Mathias Hasselmann Date: Mon, 25 May 2009 17:24:32 +0200 Subject: neonhttp: add property to support SS cerificates Add a property to support self-signed certificates in neonhttpsrc. This property is FALSE by default. Fixes #511097 --- ext/neon/gstneonhttpsrc.c | 71 +++++++++++++++++++++++++++++++++++------------ ext/neon/gstneonhttpsrc.h | 3 ++ 2 files changed, 57 insertions(+), 17 deletions(-) (limited to 'ext') diff --git a/ext/neon/gstneonhttpsrc.c b/ext/neon/gstneonhttpsrc.c index 739b0132..1af733db 100644 --- a/ext/neon/gstneonhttpsrc.c +++ b/ext/neon/gstneonhttpsrc.c @@ -63,6 +63,7 @@ static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src", #define DEFAULT_IRADIO_GENRE NULL #define DEFAULT_IRADIO_URL NULL #define DEFAULT_AUTOMATIC_REDIRECT TRUE +#define DEFAULT_ACCEPT_SELF_SIGNED FALSE #define DEFAULT_NEON_HTTP_DEBUG FALSE enum @@ -76,6 +77,7 @@ enum PROP_IRADIO_GENRE, PROP_IRADIO_URL, PROP_AUTOMATIC_REDIRECT, + PROP_ACCEPT_SELF_SIGNED, #ifndef GST_DISABLE_GST_DEBUG PROP_NEON_HTTP_DEBUG #endif @@ -200,6 +202,12 @@ gst_neonhttp_src_class_init (GstNeonhttpSrcClass * klass) "Automatically follow HTTP redirects (HTTP Status Code 302/303)", TRUE, G_PARAM_READWRITE)); + g_object_class_install_property + (gobject_class, PROP_ACCEPT_SELF_SIGNED, + g_param_spec_boolean ("accept-self-signed", "accept-self-signed", + "Accept self-signed SSL/TLS certificates", + DEFAULT_ACCEPT_SELF_SIGNED, G_PARAM_READWRITE)); + #ifndef GST_DISABLE_GST_DEBUG g_object_class_install_property (gobject_class, PROP_NEON_HTTP_DEBUG, @@ -233,6 +241,7 @@ gst_neonhttp_src_init (GstNeonhttpSrc * src, GstNeonhttpSrcClass * g_class) src->iradio_url = DEFAULT_IRADIO_URL; src->user_agent = g_strdup (DEFAULT_USER_AGENT); src->automatic_redirect = DEFAULT_AUTOMATIC_REDIRECT; + src->accept_self_signed = DEFAULT_ACCEPT_SELF_SIGNED; src->session = NULL; src->request = NULL; @@ -332,28 +341,23 @@ gst_neonhttp_src_set_property (GObject * object, guint prop_id, break; } case PROP_USER_AGENT: - { if (src->user_agent) g_free (src->user_agent); src->user_agent = g_strdup (g_value_get_string (value)); break; - } case PROP_IRADIO_MODE: - { src->iradio_mode = g_value_get_boolean (value); break; - } case PROP_AUTOMATIC_REDIRECT: - { src->automatic_redirect = g_value_get_boolean (value); break; - } + case PROP_ACCEPT_SELF_SIGNED: + src->accept_self_signed = g_value_get_boolean (value); + break; #ifndef GST_DISABLE_GST_DEBUG case PROP_NEON_HTTP_DEBUG: - { src->neon_http_debug = g_value_get_boolean (value); break; - } #endif default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); @@ -401,10 +405,8 @@ gst_neonhttp_src_get_property (GObject * object, guint prop_id, break; } case PROP_USER_AGENT: - { g_value_set_string (value, neonhttpsrc->user_agent); break; - } case PROP_IRADIO_MODE: g_value_set_boolean (value, neonhttpsrc->iradio_mode); break; @@ -420,6 +422,9 @@ gst_neonhttp_src_get_property (GObject * object, guint prop_id, case PROP_AUTOMATIC_REDIRECT: g_value_set_boolean (value, neonhttpsrc->automatic_redirect); break; + case PROP_ACCEPT_SELF_SIGNED: + g_value_set_boolean (value, neonhttpsrc->accept_self_signed); + break; #ifndef GST_DISABLE_GST_DEBUG case PROP_NEON_HTTP_DEBUG: g_value_set_boolean (value, neonhttpsrc->neon_http_debug); @@ -431,6 +436,13 @@ gst_neonhttp_src_get_property (GObject * object, guint prop_id, } } +/* NEON CALLBACK */ +static void +oom_callback () +{ + GST_ERROR ("memory exeception in neon"); +} + static GstFlowReturn gst_neonhttp_src_create (GstPushSrc * psrc, GstBuffer ** outbuf) { @@ -772,6 +784,37 @@ error: } } +static int +ssl_verify_callback (void *data, int failures, const ne_ssl_certificate * cert) +{ + GstNeonhttpSrc *src = GST_NEONHTTP_SRC (data); + + if ((failures & NE_SSL_UNTRUSTED) && + src->accept_self_signed && !ne_ssl_cert_signedby (cert)) { + GST_ELEMENT_INFO (src, RESOURCE, READ, + (NULL), ("Accepting self-signed server certificate")); + + failures &= ~NE_SSL_UNTRUSTED; + } + + if (failures & NE_SSL_NOTYETVALID) + GST_ELEMENT_ERROR (src, RESOURCE, READ, + (NULL), ("Server certificate not valid yet")); + if (failures & NE_SSL_EXPIRED) + GST_ELEMENT_ERROR (src, RESOURCE, READ, + (NULL), ("Server certificate has expired")); + if (failures & NE_SSL_IDMISMATCH) + GST_ELEMENT_ERROR (src, RESOURCE, READ, + (NULL), ("Server certificate doesn't match hostname")); + if (failures & NE_SSL_UNTRUSTED) + GST_ELEMENT_ERROR (src, RESOURCE, READ, + (NULL), ("Server certificate signer not trusted")); + + GST_DEBUG_OBJECT (src, "failures: %d\n", failures); + + return failures; +} + /* Try to send the HTTP request to the Icecast server, and if possible deals with * all the probable redirections (HTTP status code == 302/303) */ @@ -799,6 +842,7 @@ gst_neonhttp_src_send_request_and_redirect (GstNeonhttpSrc * src, } ne_set_session_flag (session, NE_SESSFLAG_ICYPROTO, 1); + ne_ssl_set_verify (session, ssl_verify_callback, src); request = ne_request_create (session, "GET", src->query_string); @@ -1014,13 +1058,6 @@ gst_neonhttp_src_uri_handler_init (gpointer g_iface, gpointer iface_data) iface->set_uri = gst_neonhttp_src_uri_set_uri; } -/* NEON CALLBACK */ -static void -oom_callback () -{ - GST_ERROR ("memory exeception in neon"); -} - /* entry point to initialize the plug-in * initialize the plug-in itself * register the element factories and pad templates diff --git a/ext/neon/gstneonhttpsrc.h b/ext/neon/gstneonhttpsrc.h index 68383485..f88c964c 100644 --- a/ext/neon/gstneonhttpsrc.h +++ b/ext/neon/gstneonhttpsrc.h @@ -71,6 +71,9 @@ struct _GstNeonhttpSrc { /* enable Neon HTTP debug messages */ gboolean neon_http_debug; + /* accept self-signed certificates */ + gboolean accept_self_signed; + gint64 read_position; gboolean seekable; }; -- cgit v1.2.1