diff options
author | Dave Robillard <dave@drobilla.net> | 2009-05-25 22:23:04 -0400 |
---|---|---|
committer | Dave Robillard <dave@drobilla.net> | 2009-05-25 22:23:04 -0400 |
commit | e9f9ffa0e5ca0844a499a106963888176b6a7372 (patch) | |
tree | b86653bbb9f9f19c5d6adf29198bf2b168813cfe /ext | |
parent | 9e306663812d0af7d6889c1c314f2148e2dd40cf (diff) | |
parent | 023af351fba4b22db782b39f4aa8ae75b70cc10f (diff) | |
download | gst-plugins-bad-e9f9ffa0e5ca0844a499a106963888176b6a7372.tar.gz gst-plugins-bad-e9f9ffa0e5ca0844a499a106963888176b6a7372.tar.bz2 gst-plugins-bad-e9f9ffa0e5ca0844a499a106963888176b6a7372.zip |
Merge git://anongit.freedesktop.org/gstreamer/gst-plugins-bad into lv2
Diffstat (limited to 'ext')
-rw-r--r-- | ext/celt/gstceltenc.c | 7 | ||||
-rw-r--r-- | ext/dirac/gstdiracenc.cc | 16 | ||||
-rw-r--r-- | ext/dts/gstdtsdec.c | 489 | ||||
-rw-r--r-- | ext/dts/gstdtsdec.h | 32 | ||||
-rw-r--r-- | ext/faac/gstfaac.c | 11 | ||||
-rw-r--r-- | ext/jp2k/gstjasperenc.c | 16 | ||||
-rw-r--r-- | ext/mpeg2enc/gstmpeg2enc.cc | 18 | ||||
-rw-r--r-- | ext/neon/gstneonhttpsrc.c | 71 | ||||
-rw-r--r-- | ext/neon/gstneonhttpsrc.h | 3 | ||||
-rw-r--r-- | ext/resindvd/gstmpegdemux.c | 50 | ||||
-rw-r--r-- | ext/resindvd/gstmpegdemux.h | 2 | ||||
-rw-r--r-- | ext/resindvd/resindvdbin.c | 28 | ||||
-rw-r--r-- | ext/resindvd/resindvdbin.h | 1 | ||||
-rw-r--r-- | ext/resindvd/resindvdsrc.c | 495 | ||||
-rw-r--r-- | ext/resindvd/resindvdsrc.h | 14 | ||||
-rw-r--r-- | ext/resindvd/rsnaudiomunge.c | 55 | ||||
-rw-r--r-- | ext/x264/GstX264Enc.prs | 47 | ||||
-rw-r--r-- | ext/x264/gstx264enc.c | 32 | ||||
-rw-r--r-- | ext/x264/gstx264enc.h | 2 | ||||
-rw-r--r-- | ext/xvid/gstxvidenc.c | 8 |
20 files changed, 1048 insertions, 349 deletions
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"); } 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) 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 <rbultje@ronald.bitfreak.net> + * Copyright (C) 2009 Jan Schmidt <thaytan@noraisin.net> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -84,43 +85,46 @@ typedef struct dts_state_s dca_state_t; #include <liboil/liboilcpu.h> #include <liboil/liboilfunction.h> -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 <thaytan@noraisin.net>\n" "Ronald Bultje <rbultje@ronald.bitfreak.net>"); +#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 { diff --git a/ext/faac/gstfaac.c b/ext/faac/gstfaac.c index 22484ffb..0dc8a42a 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; @@ -798,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/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) diff --git a/ext/mpeg2enc/gstmpeg2enc.cc b/ext/mpeg2enc/gstmpeg2enc.cc index e96e8124..64008b16 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) @@ -703,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/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; }; diff --git a/ext/resindvd/gstmpegdemux.c b/ext/resindvd/gstmpegdemux.c index d41ded0b..b360bdcc 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); @@ -464,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; } } } @@ -487,11 +492,15 @@ 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)); + 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, + 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, @@ -501,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; } } } @@ -520,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); } } } @@ -1346,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 3f38b088..683b7cde 100644 --- a/ext/resindvd/gstmpegdemux.h +++ b/ext/resindvd/gstmpegdemux.h @@ -63,7 +63,9 @@ struct _GstFluPSStream { gboolean notlinked; gboolean need_segment; + GstClockTime last_seg_start; GstClockTime last_ts; + GstClockTime segment_thresh; }; struct _GstFluPSDemux { 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; diff --git a/ext/resindvd/resindvdsrc.c b/ext/resindvd/resindvdsrc.c index a2f31610..f24e45aa 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 */ @@ -134,6 +143,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) @@ -374,6 +384,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,8 +400,17 @@ 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; + src->cur_btn_mask = RSN_BTN_NONE; + + src->angles_changed = FALSE; + src->n_angles = 0; + src->cur_angle = 0; + + src->commands_changed = TRUE; src->cur_spu_phys_stream = -1; src->cur_spu_forced_only = FALSE; @@ -414,7 +435,6 @@ fail: static gboolean read_vts_info (resinDvdSrc * src) { - gint i; gint n_vts; if (src->vts_attrs) { @@ -443,28 +463,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 @@ -516,6 +556,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), @@ -551,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); @@ -558,6 +601,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", @@ -574,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 */ @@ -584,13 +635,18 @@ 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); 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); } @@ -627,26 +683,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"); - 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 */ @@ -658,12 +730,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); @@ -722,6 +799,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) { + /* Make sure we send an angles-changed message soon */ + src->angles_changed = TRUE; + } + + if (dvdnav_current_title_info (src->dvdnav, &title_n, + &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); + } + } + + 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); + g_free (title_str); + gst_element_found_tags (GST_ELEMENT_CAST (src), tags); + } + } +} + static GstFlowReturn rsn_dvdsrc_step (resinDvdSrc * src, gboolean have_dvd_lock) { @@ -821,7 +963,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: @@ -874,6 +1015,8 @@ rsn_dvdsrc_step (resinDvdSrc * src, gboolean have_dvd_lock) rsn_dvdsrc_prepare_streamsinfo_event (src); + update_title_info (src); + break; } case DVDNAV_SPU_CLUT_CHANGE: @@ -926,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; } @@ -967,6 +1113,99 @@ 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) +{ + /* 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 +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; + + 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); + 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) { @@ -998,6 +1237,8 @@ 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; + gboolean cmds_changed = FALSE; *outbuf = NULL; @@ -1020,6 +1261,20 @@ 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->angles_changed = FALSE; + } + + cmds_changed = src->commands_changed; + src->commands_changed = FALSE; + g_mutex_unlock (src->dvd_lock); /* Push in-band events now that we've dropped the dvd_lock, before @@ -1089,6 +1344,13 @@ 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); + } + + if (cmds_changed) + rsn_dvdsrc_send_commands_changed (src); + return ret; } @@ -1212,19 +1474,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 */ + 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) { + 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 */ + 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; - 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 */ + 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) { + 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 */ + if (new_angle) { + src->angles_changed = TRUE; + GST_INFO_OBJECT (src, "Switched to angle %d", new_angle); + } + } break; } default: @@ -1242,6 +1525,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:{ @@ -1375,6 +1659,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) { @@ -1422,6 +1707,22 @@ 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->angles_changed = FALSE; + + update_title_info (src); + } + + cmds_changed = src->commands_changed; + src->commands_changed = FALSE; + g_mutex_unlock (src->dvd_lock); if (hl_event) { @@ -1429,12 +1730,19 @@ 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) { 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) @@ -1515,15 +1823,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; @@ -1534,7 +1833,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; @@ -1542,7 +1841,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; @@ -1550,6 +1849,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); @@ -1712,28 +2014,33 @@ 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; } } 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", @@ -1742,29 +2049,28 @@ 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; } - 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 || 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)", - 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)); @@ -1790,6 +2096,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; + } } } @@ -1828,14 +2150,18 @@ 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) + + 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 @@ -1908,19 +2234,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; @@ -1943,6 +2269,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) { @@ -1953,9 +2280,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; @@ -1963,8 +2291,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) { @@ -2117,6 +2443,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 61fa5d19..263c7afb 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,10 @@ 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 */ + gint n_angles; /* number of angles */ + gint cur_angle; /* current angle */ gboolean running; gboolean discont; @@ -84,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 */ @@ -114,6 +123,9 @@ struct _resinDvdSrc GstEvent *audio_select_event; GstEvent *highlight_event; + gboolean angles_changed; + gboolean commands_changed; + /* GList of NAV packets awaiting activation, and the * running times to activate them. */ GSList *pending_nav_blocks; @@ -129,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 diff --git a/ext/resindvd/rsnaudiomunge.c b/ext/resindvd/rsnaudiomunge.c index fc7e552f..50d33be7 100644 --- a/ext/resindvd/rsnaudiomunge.c +++ b/ext/resindvd/rsnaudiomunge.c @@ -86,8 +86,8 @@ rsn_audiomunge_class_init (RsnAudioMungeClass * klass) "Jan Schmidt <thaytan@noraisin.net>" }; - 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)); @@ -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 200ms silence buffer for now. FIXME: Fill the gap */ + if (rsn_audiomunge_make_audio (munge, segment->start, + GST_SECOND / 5) == 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)); diff --git a/ext/x264/GstX264Enc.prs b/ext/x264/GstX264Enc.prs index daf60a77..84c76a94 100644 --- a/ext/x264/GstX264Enc.prs +++ b/ext/x264/GstX264Enc.prs @@ -2,12 +2,43 @@ 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 +[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 diff --git a/ext/x264/gstx264enc.c b/ext/x264/gstx264enc.c index 37f53cce..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); @@ -1303,7 +1311,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, 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; 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; } |