configure.ac: use AC_C_INLINE
authorBenjamin Otte <otte@gnome.org>
Fri, 30 Jan 2004 20:23:24 +0000 (20:23 +0000)
committerBenjamin Otte <otte@gnome.org>
Fri, 30 Jan 2004 20:23:24 +0000 (20:23 +0000)
Original commit message from CVS:
2004-01-30  Benjamin Otte  <in7y118@public.uni-hamburg.de>

* configure.ac:
use AC_C_INLINE
* configure.ac:
* ext/Makefile.am:
* ext/theora/Makefile.am:
* ext/theora/theoradec.c:
add theora video decoder. Does just do simple decoding for now and
has been tested against Theora cvs only.
* ext/vorbis/vorbisdec.c: (vorbis_dec_event):
always reset packetno on DISCONT

ChangeLog
common
configure.ac
ext/Makefile.am
ext/theora/Makefile.am [new file with mode: 0644]
ext/theora/theoradec.c [new file with mode: 0644]
ext/vorbis/vorbisdec.c

index edfd98b95a392a3f9eb424bf14dfc5ec18a7b537..d1892422ac61b0847be34701ae417b9d9e2e930a 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,16 @@
+2004-01-30  Benjamin Otte  <in7y118@public.uni-hamburg.de>
+
+       * configure.ac:
+         use AC_C_INLINE
+       * configure.ac:
+       * ext/Makefile.am:
+       * ext/theora/Makefile.am:
+       * ext/theora/theoradec.c: 
+         add theora video decoder. Does just do simple decoding for now and
+         has been tested against Theora cvs only.
+       * ext/vorbis/vorbisdec.c: (vorbis_dec_event):
+         always reset packetno on DISCONT
+
 2004-01-30  Ronald Bultje  <rbultje@ronald.bitfreak.net>
 
        * gst/mpegstream/gstmpegdemux.c: (gst_mpeg_demux_parse_syshead):
diff --git a/common b/common
index 5da247bb6f217c5c32e5ebab0d3a2014dfa452c3..508678c12ea745e207eb8bb3be12c156e3bb698c 160000 (submodule)
--- a/common
+++ b/common
@@ -1 +1 @@
-Subproject commit 5da247bb6f217c5c32e5ebab0d3a2014dfa452c3
+Subproject commit 508678c12ea745e207eb8bb3be12c156e3bb698c
index 0fa8bc55e8ac264fcd3dac6b2295593dd04a49ca..25a828ed84db0391668337557d3fc8e20b38418b 100644 (file)
@@ -81,6 +81,7 @@ AC_PROG_CXXCPP
 AC_ISC_POSIX
 
 AC_HEADER_STDC([])
+AC_C_INLINE
 
 dnl Check for a way to display the function name in debug output
 GST_CHECK_FUNCTION()
@@ -1333,6 +1334,14 @@ GST_CHECK_FEATURE(OGG, [ogg de/encoder], oggdemux oggmux, [
   AS_SCRUB_INCLUDE(OGG_CFLAGS)
 ])
 
+dnl *** theora ***
+dnl FIXME: theora doesn't have proper pc/m4 files yet, change this when this happens
+translit(dnm, m, l) AM_CONDITIONAL(USE_THEORA, true)
+GST_CHECK_FEATURE(THEORA, [ogg theora codec], theoradec, [
+  GST_CHECK_LIBHEADER(THEORA, theora, theora_version_string, , theora/theora.h, THEORA_LIBS="-ltheora")
+  AC_SUBST(THEORA_LIBS)
+])
+
 dnl *** vorbis ***
 dnl AM_PATH_VORBIS only takes two options
 translit(dnm, m, l) AM_CONDITIONAL(USE_VORBIS, true)
@@ -1687,8 +1696,9 @@ ext/snapshot/Makefile
 ext/speex/Makefile
 ext/sndfile/Makefile
 ext/swfdec/Makefile
-ext/vorbis/Makefile
 ext/tarkin/Makefile
+ext/theora/Makefile
+ext/vorbis/Makefile
 ext/xvid/Makefile
 gst-libs/Makefile
 gst-libs/gst/Makefile
index 0e091de57c9dac680d5dc3243042602feecbfd3f..182ac56a7102717b357d181bc2e5b75bcd99f88b 100644 (file)
@@ -298,6 +298,12 @@ else
 VORBIS_DIR=
 endif
 
+if USE_THEORA
+THEORA_DIR=theora
+else
+THEORA_DIR=
+endif
+
 if USE_XVID
 XVID_DIR=xvid
 else
@@ -366,6 +372,7 @@ SUBDIRS=\
        $(SPEEX_DIR) \
        $(SWFDEC_DIR) \
        $(TARKIN_DIR) \
+       $(THEORA_DIR) \
        $(IVORBIS_DIR) \
        $(VORBIS_DIR) \
        $(XVID_DIR)
@@ -422,5 +429,6 @@ DIST_SUBDIRS=\
        speex \
        swfdec \
        tarkin \
+       theora \
        vorbis \
        xvid
diff --git a/ext/theora/Makefile.am b/ext/theora/Makefile.am
new file mode 100644 (file)
index 0000000..0fda115
--- /dev/null
@@ -0,0 +1,9 @@
+plugindir = $(libdir)/gstreamer-@GST_MAJORMINOR@
+
+plugin_LTLIBRARIES = libgsttheora.la
+
+libgsttheora_la_SOURCES = theoradec.c
+libgsttheora_la_CFLAGS = $(GST_CFLAGS) $(THEORA_CFLAGS)
+libgsttheora_la_LIBADD = $(THEORA_LIBS)
+libgsttheora_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+
diff --git a/ext/theora/theoradec.c b/ext/theora/theoradec.c
new file mode 100644 (file)
index 0000000..04bef04
--- /dev/null
@@ -0,0 +1,364 @@
+/* GStreamer
+ * Copyright (C) 2004 Benjamin Otte <in7y118@public.uni-hamburg.de>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include <gst/gst.h>
+#include <theora/theora.h>
+#include <string.h>
+#include <gst/tag/tag.h>
+
+
+#define GST_TYPE_THEORA_DEC \
+  (gst_theora_dec_get_type())
+#define GST_THEORA_DEC(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_THEORA_DEC,GstTheoraDec))
+#define GST_THEORA_DEC_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_THEORA_DEC,GstTheoraDec))
+#define GST_IS_THEORA_DEC(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_THEORA_DEC))
+#define GST_IS_THEORA_DEC_CLASS(obj) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_THEORA_DEC))
+
+typedef struct _GstTheoraDec GstTheoraDec;
+typedef struct _GstTheoraDecClass GstTheoraDecClass;
+
+struct _GstTheoraDec {
+  GstElement           element;
+
+  GstPad *             sinkpad;
+  GstPad *             srcpad;
+
+  theora_state         state;
+  theora_info          info;
+  theora_comment       comment;
+  
+  guint                        packetno;
+  guint64              granulepos;
+};
+
+struct _GstTheoraDecClass {
+  GstElementClass parent_class;
+};
+
+static GstElementDetails theora_dec_details = {
+  "TheoraDec",
+  "Filter/Decoder/Video",
+  "decode raw theora streams to raw YUV video",
+  "Benjamin Otte <in7y118@public.uni-hamburg.de>",
+};
+
+static GstStaticPadTemplate theora_dec_src_factory =
+GST_STATIC_PAD_TEMPLATE (
+  "src",
+  GST_PAD_SRC,
+  GST_PAD_ALWAYS,
+  GST_STATIC_CAPS (
+    "video/x-raw-yuv, "
+      "format = (fourcc) I420, "
+      "framerate = (double) [0, MAX], "
+      "width = (int) [ 1, MAX ], "
+      "height = (int) [ 1, MAX ]"
+  )
+);
+
+static GstStaticPadTemplate theora_dec_sink_factory =
+GST_STATIC_PAD_TEMPLATE (
+  "sink",
+  GST_PAD_SINK,
+  GST_PAD_ALWAYS,
+  GST_STATIC_CAPS (
+    "video/x-theora"
+  )
+);
+
+GST_BOILERPLATE (GstTheoraDec, gst_theora_dec, GstElement, GST_TYPE_ELEMENT);
+  
+static void            theora_dec_chain                (GstPad *               pad,
+                                                        GstData *              data);
+static GstElementStateReturn 
+                       theora_dec_change_state         (GstElement *           element);
+static gboolean                theora_dec_src_event            (GstPad *               pad,
+                                                        GstEvent *             event);
+
+
+static void
+gst_theora_dec_base_init (gpointer g_class)
+{
+  GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
+  
+  gst_element_class_add_pad_template (element_class, 
+      gst_static_pad_template_get (&theora_dec_src_factory));
+  gst_element_class_add_pad_template (element_class,
+      gst_static_pad_template_get (&theora_dec_sink_factory));
+  gst_element_class_set_details (element_class, &theora_dec_details);
+}
+
+static void
+gst_theora_dec_class_init (GstTheoraDecClass *klass)
+{
+  GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
+
+  gstelement_class->change_state = theora_dec_change_state;
+}
+
+static void
+gst_theora_dec_init (GstTheoraDec *dec)
+{
+  dec->sinkpad = gst_pad_new_from_template(
+      gst_static_pad_template_get (&theora_dec_sink_factory), "sink");
+  gst_pad_set_chain_function (dec->sinkpad, theora_dec_chain);
+  gst_element_add_pad (GST_ELEMENT (dec), dec->sinkpad);
+
+  dec->srcpad = gst_pad_new_from_template(
+      gst_static_pad_template_get (&theora_dec_src_factory), "src");
+  gst_pad_use_explicit_caps (dec->srcpad);
+  gst_pad_set_event_function (dec->srcpad, theora_dec_src_event);
+  gst_element_add_pad (GST_ELEMENT (dec), dec->srcpad);
+
+  GST_FLAG_SET (dec, GST_ELEMENT_EVENT_AWARE);
+}
+#if 0
+static gboolean
+theora_dec_to_granulepos (GstTheoraDec *dec, GstFormat format, guint64 from, guint64 *to)
+{
+  guint64 framecount;
+  
+  if (dec->packetno < 1) return FALSE;
+  
+  switch (format) {
+    case GST_FORMAT_TIME:
+      framecount = from * dec->vi.rate / GST_SECOND;
+      return TRUE;
+    case GST_FORMAT_DEFAULT:
+      framecount = from;
+      return TRUE;
+    case GST_FORMAT_BYTES:
+      framecount = from / sizeof (float) / dec->vi.channels;
+      return TRUE;
+    default:
+      return FALSE;
+  }
+}
+#endif
+static gboolean
+theora_dec_src_event (GstPad *pad, GstEvent *event)
+{
+  gboolean res = TRUE;
+  GstTheoraDec *dec;
+
+  dec = GST_THEORA_DEC (gst_pad_get_parent (pad));
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_SEEK: {
+#if 0
+      guint64 value;
+      
+      res = theora_dec_to_granulepos (dec, GST_EVENT_SEEK_FORMAT (event), 
+         GST_EVENT_SEEK_OFFSET (event), &value); 
+      if (res) {
+       GstEvent *real_seek = gst_event_new_seek (
+           (GST_EVENT_SEEK_TYPE (event) & ~GST_SEEK_FORMAT_MASK) | GST_FORMAT_DEFAULT,
+           value);
+       res = gst_pad_send_event (GST_PAD_PEER (dec->sinkpad), real_seek);
+      }
+#else
+      gst_event_unref (event);
+      res = FALSE;
+#endif
+      break;
+    }
+    default:
+      res = gst_pad_event_default (pad, event);
+      break;
+  }
+
+  return res;
+}
+
+static void
+theora_dec_event (GstTheoraDec *dec, GstEvent *event)
+{
+  guint64 value;
+  
+  GST_LOG_OBJECT (dec, "handling event");
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_DISCONTINUOUS:
+      if (gst_event_discont_get_value (event, GST_FORMAT_DEFAULT, &value)) {
+       dec->granulepos = value;
+       GST_DEBUG_OBJECT (dec, "setting granuleposition to %"G_GUINT64_FORMAT" after discont\n", value);
+      } else {
+       GST_WARNING_OBJECT (dec, 
+           "discont event didn't include offset, we might set it wrong now");
+      }
+      dec->packetno = 3;
+      break;
+    default:
+      break;
+  }
+  gst_pad_event_default (dec->sinkpad, event);
+}
+
+static void
+theora_dec_chain (GstPad *pad, GstData *data)
+{
+  GstBuffer *buf;
+  GstTheoraDec *dec;
+  ogg_packet packet;
+
+  dec = GST_THEORA_DEC (gst_pad_get_parent (pad));
+  if (GST_IS_EVENT (data)) {
+    theora_dec_event (dec, GST_EVENT (data));
+    return;
+  }
+
+  buf = GST_BUFFER (data);
+  /* make ogg_packet out of the buffer */
+  packet.packet = GST_BUFFER_DATA (buf);
+  packet.bytes = GST_BUFFER_SIZE (buf);
+  packet.granulepos = GST_BUFFER_OFFSET_END (buf);
+  packet.packetno = dec->packetno ++;
+  if (packet.packetno == 0)
+    packet.b_o_s = 1;
+  /* switch depending on packet type */
+  if (packet.packet[0] & 0x80) {
+    /* header packet */
+    if (theora_decode_header (&dec->info, &dec->comment, &packet)) {
+      GST_ELEMENT_ERROR (GST_ELEMENT (dec), STREAM, DECODE, 
+         (NULL), ("couldn't read header packet"));
+      gst_data_unref (data);
+      return;
+    }
+    if (packet.packetno == 1) {
+      GstTagList *list = gst_tag_list_from_vorbiscomment_buffer (buf, "\101theora", 7, NULL);
+      gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
+         GST_TAG_ENCODER_VERSION, dec->info.version_major, NULL);
+      gst_element_found_tags_for_pad (GST_ELEMENT (dec), dec->srcpad, 0, list);
+    } else if (packet.packetno == 2) {
+      GstCaps *caps;
+      /* done */
+      theora_decode_init (&dec->state, &dec->info);
+      caps = gst_caps_new_simple ("video/x-raw-yuv",
+         "format",     GST_TYPE_FOURCC,  GST_MAKE_FOURCC ('I', '4', '2', '0'),
+         "framerate",  G_TYPE_DOUBLE,    ((gdouble) dec->info.fps_numerator) / dec->info.fps_denominator,
+         "width",      G_TYPE_INT,       dec->info.width,
+         "height",     G_TYPE_INT,       dec->info.height,
+         NULL);
+      g_print ("%s\n", gst_caps_to_string (caps));
+      gst_pad_set_explicit_caps (dec->srcpad, caps);
+      gst_caps_free (caps);
+    }
+  } else {
+    yuv_buffer yuv;
+    GstBuffer *out;
+    guint8 *y, *v, *u;
+    guint i;
+    /* normal data packet */
+    if (theora_decode_packetin (&dec->state, &packet)) {
+      GST_ELEMENT_ERROR (GST_ELEMENT (dec), STREAM, DECODE, 
+         (NULL), ("theora decoder did not read data packet"));
+      gst_data_unref (data);
+      return;
+    }
+    if (theora_decode_YUVout (&dec->state, &yuv) < 0) {
+      GST_ELEMENT_ERROR (GST_ELEMENT (dec), STREAM, DECODE,
+         (NULL), ("couldn't read out YUV image"));
+      gst_data_unref (data);
+      return;
+    }
+    g_return_if_fail (yuv.y_width == dec->info.width);
+    g_return_if_fail (yuv.y_height == dec->info.height);
+    out = gst_pad_alloc_buffer (dec->srcpad, GST_BUFFER_OFFSET_NONE, 
+       yuv.y_width * yuv.y_height * 12 / 8);
+    y = GST_BUFFER_DATA (out);
+    u = y + yuv.y_width * yuv.y_height;
+    v = u + yuv.y_width * yuv.y_height / 4;
+    for (i = 0; i < yuv.y_height; i++) {
+      memcpy (y + i * yuv.y_width, yuv.y + i * yuv.y_stride, yuv.y_width);
+    }
+    for (i = 0; i < yuv.y_height / 2; i++) {
+      memcpy (u + i * yuv.uv_width, yuv.u + i * yuv.uv_stride, yuv.uv_width);
+      memcpy (v + i * yuv.uv_width, yuv.v + i * yuv.uv_stride, yuv.uv_width);
+    }
+    GST_BUFFER_OFFSET (out) = dec->packetno - 4;
+    GST_BUFFER_OFFSET_END (out) = dec->packetno - 3;
+    GST_BUFFER_DURATION (out) = GST_SECOND * ((gdouble) dec->info.fps_denominator) / dec->info.fps_numerator;
+    GST_BUFFER_TIMESTAMP (out) = GST_BUFFER_OFFSET (out) * GST_BUFFER_DURATION (out);
+    gst_pad_push (dec->srcpad, GST_DATA (out));
+  }
+  gst_data_unref (data);
+}
+
+static GstElementStateReturn
+theora_dec_change_state (GstElement *element)
+{
+  GstTheoraDec *dec = GST_THEORA_DEC (element);
+
+  switch (GST_STATE_TRANSITION (element)) {
+    case GST_STATE_NULL_TO_READY:
+      break;
+    case GST_STATE_READY_TO_PAUSED:
+      theora_info_init (&dec->info);
+      theora_comment_init (&dec->comment);
+      break;
+    case GST_STATE_PAUSED_TO_PLAYING:
+      break;
+    case GST_STATE_PLAYING_TO_PAUSED:
+      break;
+    case GST_STATE_PAUSED_TO_READY:
+      theora_clear (&dec->state);
+      theora_comment_clear (&dec->comment);
+      theora_info_clear (&dec->info);
+      dec->packetno = 0;
+      dec->granulepos = 0;
+      break;
+    case GST_STATE_READY_TO_NULL:
+      break;
+    default:
+      g_assert_not_reached ();
+      break;
+  }
+
+  return parent_class->change_state (element);
+}
+
+static gboolean
+plugin_init (GstPlugin *plugin)
+{
+  if (!gst_library_load ("gsttags"))
+    return FALSE;
+
+  if (!gst_element_register (plugin, "theoradec", GST_RANK_SECONDARY, gst_theora_dec_get_type ()))
+    return FALSE;
+
+  return TRUE;
+}
+
+GST_PLUGIN_DEFINE (
+  GST_VERSION_MAJOR,
+  GST_VERSION_MINOR,
+  "gsttheora",
+  "Theora plugin library",
+  plugin_init,
+  VERSION,
+  "LGPL",
+  GST_PACKAGE,
+  GST_ORIGIN)
index 133451f8a9358e49e989f128e457bc2baa5b6901..4209d5aae53e6da52a7c76228dfea358a484ec01 100644 (file)
@@ -253,12 +253,12 @@ vorbis_dec_event (GstVorbisDec *dec, GstEvent *event)
     case GST_EVENT_DISCONTINUOUS:
       if (gst_event_discont_get_value (event, GST_FORMAT_DEFAULT, &value)) {
        dec->granulepos = value;
-       dec->packetno = 3;
        GST_DEBUG_OBJECT (dec, "setting granuleposition to %"G_GUINT64_FORMAT" after discont\n", value);
       } else {
        GST_WARNING_OBJECT (dec, 
            "discont event didn't include offset, we might set it wrong now");
       }
+      dec->packetno = 3;
       break;
     default:
       break;