chiark / gitweb /
server/*.c: Don't try reading per-user configuration.
[disorder] / server / gstdecode.c
index 93cde8500d678da4755e7afb1f5487256d949195..6a288bc2ce79e3875da9a3b3981a84b998c5b43e 100644 (file)
 #include <gst/app/gstappsink.h>
 #include <gst/audio/audio.h>
 
-/* The only application we have for `attribute' is declaring function
+/* The only applications we have for `attribute' is declaring function
  * arguments as being unused, because we have a lot of callback functions
- * which are meant to comply with an externally defined interface.
+ * which are meant to comply with an externally defined interface; and
+ * marking `help' as not returning.
  */
 #ifdef __GNUC__
+#  define NORETURN __attribute__((noreturn))
 #  define UNUSED __attribute__((unused))
 #endif
 
@@ -91,17 +93,35 @@ static void report_element_pads(const char *what, GstElement *elt,
                                 GstIterator *it)
 {
   gchar *cs;
+#ifdef HAVE_GSTREAMER_0_10
   gpointer pad;
+#else
+  GValue gv;
+  GstPad *pad;
+  GstCaps *caps;
+#endif
 
   for(;;) {
+#ifdef HAVE_GSTREAMER_0_10
     switch(gst_iterator_next(it, &pad)) {
+#else
+    switch(gst_iterator_next(it, &gv)) {
+#endif
     case GST_ITERATOR_DONE:
       goto done;
     case GST_ITERATOR_OK:
-      cs = gst_caps_to_string(gst_pad_get_caps(pad));
+#ifdef HAVE_GSTREAMER_0_10
+      cs = gst_caps_to_string(GST_PAD_CAPS(pad));
+#else
+      assert(G_VALUE_HOLDS(&gv, GST_TYPE_PAD));
+      pad = g_value_get_object(&gv);
+      caps = gst_pad_query_caps(pad, 0);
+      cs = gst_caps_to_string(caps);
+      gst_caps_unref(caps);
+#endif
       disorder_error(0, "  `%s' %s pad: %s", GST_OBJECT_NAME(elt), what, cs);
       g_free(cs);
-      g_object_unref(pad);
+      gst_object_unref(pad);
       break;
     case GST_ITERATOR_RESYNC:
       gst_iterator_resync(it);
@@ -131,7 +151,7 @@ static void link_elements(GstElement *left, GstElement *right)
   disorder_error(0, "failed to link GStreamer elements `%s' and `%s'",
                  GST_OBJECT_NAME(left), GST_OBJECT_NAME(right));
   report_element_pads("source", left, gst_element_iterate_src_pads(left));
-  report_element_pads("source", right, gst_element_iterate_sink_pads(right));
+  report_element_pads("dest", right, gst_element_iterate_sink_pads(right));
   disorder_fatal(0, "can't decode `%s'", file);
 }
 
@@ -142,7 +162,11 @@ static void link_elements(GstElement *left, GstElement *right)
 static void decoder_pad_arrived(GstElement *decode, GstPad *pad, gpointer u)
 {
   GstElement *tail = u;
+#ifdef HAVE_GSTREAMER_0_10
   GstCaps *caps = gst_pad_get_caps(pad);
+#else
+  GstCaps *caps = gst_pad_get_current_caps(pad);
+#endif
   GstStructure *s;
   guint i, n;
   const gchar *name;
@@ -153,9 +177,14 @@ static void decoder_pad_arrived(GstElement *decode, GstPad *pad, gpointer u)
   for(i = 0, n = gst_caps_get_size(caps); i < n; i++) {
     s = gst_caps_get_structure(caps, i);
     name = gst_structure_get_name(s);
-    if(strncmp(name, "audio/x-raw-", 12) == 0) goto match;
+#ifdef HAVE_GSTREAMER_0_10
+    if(strncmp(name, "audio/x-raw-", 12) == 0)
+#else
+    if(strcmp(name, "audio/x-raw") == 0)
+#endif
+      goto match;
   }
-  return;
+  goto end;
 
 match:
   /* Yes, it's audio.  Link the two elements together. */
@@ -167,6 +196,9 @@ match:
   GST_DEBUG_BIN_TO_DOT_FILE(GST_BIN(pipeline),
                             GST_DEBUG_GRAPH_SHOW_ALL,
                             "disorder-gstdecode");
+
+end:
+  gst_caps_unref(caps);
 }
 
 /* Prepare the GStreamer pipeline, ready to decode the given FILE.  This sets
@@ -185,6 +217,25 @@ static void prepare_pipeline(void)
   GstCaps *caps;
   const struct stream_header *fmt = &config->sample_format;
 
+  if(!source || !decode || !resample || !convert || !sink)
+    disorder_fatal(0, "failed to create GStreamer elements: "
+                   "need base and good plugins");
+
+#ifndef HAVE_GSTREAMER_0_10
+  static const struct fmttab {
+    const char *fmt;
+    unsigned bits;
+    unsigned endian;
+  } fmttab[] = {
+    { "S8", 8, ENDIAN_BIG },
+    { "S8", 8, ENDIAN_LITTLE },
+    { "S16BE", 16, ENDIAN_BIG },
+    { "S16LE", 16, ENDIAN_LITTLE },
+    { 0 }
+  };
+  const struct fmttab *ft;
+#endif
+
   /* Set up the global variables. */
   pipeline = gst_pipeline_new("pipe");
   appsink = GST_APP_SINK(sink);
@@ -201,6 +252,7 @@ static void prepare_pipeline(void)
   if(shape >= 0) g_object_set(convert, "noise-shaping", shape, END);
 
   /* Set up the sink's capabilities from the configuration. */
+#ifdef HAVE_GSTREAMER_0_10
   caps = gst_caps_new_simple("audio/x-raw-int",
                              "width", G_TYPE_INT, fmt->bits,
                              "depth", G_TYPE_INT, fmt->bits,
@@ -211,7 +263,21 @@ static void prepare_pipeline(void)
                                fmt->endian == ENDIAN_BIG ?
                                  G_BIG_ENDIAN : G_LITTLE_ENDIAN,
                              END);
+#else
+  for (ft = fmttab; ft->fmt; ft++)
+    if (ft->bits == fmt->bits && ft->endian == fmt->endian) break;
+  if(!ft->fmt) {
+    disorder_fatal(0, "unsupported sample format: bits=%"PRIu32", endian=%u",
+                   fmt->bits, fmt->endian);
+  }
+  caps = gst_caps_new_simple("audio/x-raw",
+                             "format", G_TYPE_STRING, ft->fmt,
+                             "channels", G_TYPE_INT, fmt->channels,
+                             "rate", G_TYPE_INT, fmt->rate,
+                             END);
+#endif
   gst_app_sink_set_caps(appsink, caps);
+  gst_caps_unref(caps);
 
   /* Add the various elements into the pipeline.  We'll stitch them together
    * in pieces, because the pipeline is somewhat dynamic.
@@ -231,6 +297,9 @@ static void prepare_pipeline(void)
    */
   if(mode != OFF) {
     gain = gst_element_factory_make("rgvolume", "gain");
+    if(!gain)
+      disorder_fatal(0, "failed to create GStreamer elements: "
+                     "need base and good plugins");
     g_object_set(gain,
                  "album-mode", mode == ALBUM,
                  "fallback-gain", fallback,
@@ -254,10 +323,11 @@ static void prepare_pipeline(void)
 static void bus_message(GstBus UNUSED *bus, GstMessage *msg,
                         gpointer UNUSED u)
 {
-  switch(msg->type) {
+  switch(GST_MESSAGE_TYPE(msg)) {
   case GST_MESSAGE_ERROR:
     disorder_fatal(0, "%s",
-                   gst_structure_get_string(msg->structure, "debug"));
+                   gst_structure_get_string(gst_message_get_structure(msg),
+                                            "debug"));
   default:
     break;
   }
@@ -275,8 +345,13 @@ static void cb_eos(GstAppSink UNUSED *sink, gpointer UNUSED u)
  */
 static GstFlowReturn cb_preroll(GstAppSink *sink, gpointer UNUSED u)
 {
+#ifdef HAVE_GSTREAMER_0_10
   GstBuffer *buf = gst_app_sink_pull_preroll(sink);
   GstCaps *caps = GST_BUFFER_CAPS(buf);
+#else
+  GstSample *samp = gst_app_sink_pull_preroll(sink);
+  GstCaps *caps = gst_sample_get_caps(samp);
+#endif
 
 #ifdef HAVE_GST_AUDIO_INFO_FROM_CAPS
 
@@ -324,7 +399,11 @@ static GstFlowReturn cb_preroll(GstAppSink *sink, gpointer UNUSED u)
 
 #endif
 
+#ifdef HAVE_GSTREAMER_0_10
   gst_buffer_unref(buf);
+#else
+  gst_sample_unref(samp);
+#endif
   return GST_FLOW_OK;
 }
 
@@ -333,26 +412,55 @@ static GstFlowReturn cb_preroll(GstAppSink *sink, gpointer UNUSED u)
  */
 static GstFlowReturn cb_buffer(GstAppSink *sink, gpointer UNUSED u)
 {
+#ifdef HAVE_GSTREAMER_0_10
   GstBuffer *buf = gst_app_sink_pull_buffer(sink);
+#else
+  GstSample *samp = gst_app_sink_pull_sample(sink);
+  GstBuffer *buf = gst_sample_get_buffer(samp);
+  GstMemory *mem;
+  GstMapInfo map;
+  gint i, n;
+#endif
 
   /* Make sure we actually have a grip on the sample format here. */
   if(!hdr.rate) disorder_fatal(0, "format unset");
 
   /* Write out a frame of audio data. */
+#ifdef HAVE_GSTREAMER_0_10
   hdr.nbytes = GST_BUFFER_SIZE(buf);
   if((!(flags&f_stream) && fwrite(&hdr, sizeof(hdr), 1, fp) != 1) ||
      fwrite(GST_BUFFER_DATA(buf), 1, hdr.nbytes, fp) != hdr.nbytes)
     disorder_fatal(errno, "output");
+#else
+  for(i = 0, n = gst_buffer_n_memory(buf); i < n; i++) {
+    mem = gst_buffer_peek_memory(buf, i);
+    if(!gst_memory_map(mem, &map, GST_MAP_READ))
+      disorder_fatal(0, "failed to map sample buffer");
+    hdr.nbytes = map.size;
+    if((!(flags&f_stream) && fwrite(&hdr, sizeof(hdr), 1, fp) != 1) ||
+       fwrite(map.data, 1, map.size, fp) != map.size)
+      disorder_fatal(errno, "output");
+    gst_memory_unmap(mem, &map);
+  }
+#endif
 
   /* And we're done. */
+#ifdef HAVE_GSTREAMER_0_10
   gst_buffer_unref(buf);
+#else
+  gst_sample_unref(samp);
+#endif
   return GST_FLOW_OK;
 }
 
 static GstAppSinkCallbacks callbacks = {
   .eos = cb_eos,
   .new_preroll = cb_preroll,
+#ifdef HAVE_GSTREAMER_0_10
   .new_buffer = cb_buffer
+#else
+  .new_sample = cb_buffer
+#endif
 };
 
 /* Decode the audio file.  We're already set up for everything. */
@@ -366,10 +474,12 @@ static void decode(void)
   g_signal_connect(bus, "message", G_CALLBACK(bus_message), 0);
 
   /* Tell the sink to call us when interesting things happen. */
+  gst_app_sink_set_max_buffers(appsink, 16);
+  gst_app_sink_set_drop(appsink, FALSE);
   gst_app_sink_set_callbacks(appsink, &callbacks, 0, 0);
 
   /* Set the ball rolling. */
-  gst_element_set_state(GST_ELEMENT(pipeline), GST_STATE_PLAYING);
+  gst_element_set_state(pipeline, GST_STATE_PLAYING);
 
   /* And wait for the miracle to come. */
   g_main_loop_run(loop);
@@ -377,7 +487,7 @@ static void decode(void)
   /* Shut down the pipeline.  This isn't strictly necessary, since we're
    * about to exit very soon, but it's kind of polite.
    */
-  gst_element_set_state(GST_ELEMENT(pipeline), GST_STATE_NULL);
+  gst_element_set_state(pipeline, GST_STATE_NULL);
 }
 
 static int getenum(const char *what, const char *s, const char *const *tags)
@@ -425,7 +535,7 @@ static const struct option options[] = {
   { 0, 0, 0, 0 }
 };
 
-static void help(void)
+static void NORETURN help(void)
 {
   xprintf("Usage:\n"
           "  disorder-gstdecode [OPTIONS] PATH\n"
@@ -476,6 +586,7 @@ int main(int argc, char *argv[])
   if(optind >= argc) disorder_fatal(0, "missing filename");
   file = argv[optind++];
   if(optind < argc) disorder_fatal(0, "excess arguments");
+  config_per_user = 0;
   if(config_read(1, 0)) disorder_fatal(0, "cannot read configuration");
 
   /* Set up the GStreamer machinery. */