/*
 * test metadata filtering
 *
 * gcc `pkg-config --cflags --libs gstreamer-0.10` tagfilter3.c -o tagfilter3
 *
 * run this first to create a test file:
 * gst-launch-0.10 audiotestsrc num-buffers=10 samplesperbuffer=160 ! taginject tags="keywords=\"testone,audio\",title=\"audio testtone\"" ! amrnbenc ! mp4mux ! filesink location=test_tags1.mp4
 * gst-launch-0.10 audiotestsrc num-buffers=10 samplesperbuffer=160 ! taginject tags="keywords=\"testone,audio\",title=\"audio testtone\"" ! lame ! avimux ! filesink location=test_tags1.avi
 */

#include <stdlib.h>
#include <string.h>
#include <glib.h>
#include <gst/gst.h>

static GMainLoop *loop = NULL;
static GstTagSetter *setter = NULL;
static GstTagList *tag_list = NULL;

const gchar *filter_tags[] = {
  GST_TAG_TITLE,
  GST_TAG_KEYWORDS,
  GST_TAG_DESCRIPTION,
  NULL
};

static void
msg_state_changed (GstBus * bus, GstMessage * message, GstElement * pipeline)
{
  const GstStructure *s = gst_message_get_structure (message);

  /* We only care about state changed on the pipeline */
  if (s && GST_MESSAGE_SRC (message) == GST_OBJECT_CAST (pipeline)) {
    GstState old, new, pending;

    gst_message_parse_state_changed (message, &old, &new, &pending);

    /* we send our tags, when we are going to paused */
    switch(GST_STATE_TRANSITION(old,new)) {
      case GST_STATE_CHANGE_READY_TO_PAUSED: {
        if (tag_list) {
          const gchar *tag = *filter_tags;
          
          GST_INFO("before filtering %" GST_PTR_FORMAT, tag_list);
          /* filter tag_list */
          while(tag) {
            gst_tag_list_remove_tag(tag_list,tag);
            tag++;
          }
          GST_INFO("after  filtering %" GST_PTR_FORMAT, tag_list);
        }
        else {
          tag_list = gst_tag_list_new ();
        }
        /* set tags */
        GST_INFO("setting tags on %s", GST_OBJECT_NAME(GST_OBJECT(setter)));
        gst_tag_setter_merge_tags (setter, tag_list, GST_TAG_MERGE_REPLACE_ALL);
        gst_tag_list_free (tag_list);
        tag_list = NULL;

        /* start playing */
        gst_element_set_state (pipeline, GST_STATE_PLAYING);
        break;
      }
      default:
        break;
    }
  }
}

static void
msg_eos (GstBus * bus, GstMessage * message, GstElement * pipeline)
{
  if(GST_MESSAGE_SRC(message) == GST_OBJECT(pipeline)) {
    GST_INFO("received EOS bus message from: %s", 
      GST_OBJECT_NAME (GST_MESSAGE_SRC (message)));

    g_main_loop_quit(loop);
  }
}

static void
msg_tag (GstBus * bus, GstMessage * message, GstElement * pipeline) {
  GstTagList *tags;
  
  gst_message_parse_tag (message, &tags);
  GST_INFO("received tags from %s", 
    GST_OBJECT_NAME (GST_MESSAGE_SRC (message)));
  
  gst_tag_list_merge (tag_list, tags, GST_TAG_MERGE_APPEND);
  gst_tag_list_free (tags);
}

static void
msg_error (GstBus * bus, GstMessage *message, GstElement * pipeline)
{
  GError *err = NULL;
  gchar *dbg = NULL;
  
  gst_message_parse_error(message, &err, &dbg);
  GST_ERROR ("%s (%s)", err->message, (dbg) ? dbg : "no details");
  g_error_free (err);
  g_free (dbg);
}

static void
msg_warning (GstBus * bus, GstMessage *message, GstElement * pipeline)
{
  GError *err = NULL;
  gchar *dbg = NULL;
  
  gst_message_parse_warning(message, &err, &dbg);
  GST_WARNING ("%s (%s)", err->message, (dbg) ? dbg : "no details");
  g_error_free (err);
  g_free (dbg);
}


static void
run_pipeline(GstElement *pipeline)
{
   /* prepare playing */
  gst_element_set_state (pipeline, GST_STATE_PLAYING);
}

int
main (int argc, char **argv)
{
  GstElement *pipeline;
  GstBus *bus;

  if (!g_thread_supported ())
    g_thread_init (NULL);
  gst_init (&argc,&argv);

  //pipeline = gst_parse_launch ("filesrc location=test_tags1.mp4 ! qtdemux ! queue ! mp4mux ! filesink location=test_tags2.mp4", NULL);
  pipeline = gst_parse_launch ("filesrc location=test_tags1.avi ! avidemux ! queue ! avimux ! filesink location=test_tags2.avi", NULL);
  if (!pipeline) {
    g_printerr("Can't create pipeline\n");
    return -1;
  }
  
  bus = gst_pipeline_get_bus(GST_PIPELINE(pipeline));
  gst_bus_add_signal_watch_full (bus, G_PRIORITY_HIGH);
  g_signal_connect (bus, "message::state-changed", G_CALLBACK (msg_state_changed), pipeline);
  g_signal_connect (bus, "message::eos", G_CALLBACK(msg_eos), pipeline);
  g_signal_connect (bus, "message::tag", G_CALLBACK(msg_tag), pipeline);
  g_signal_connect (bus, "message::error", G_CALLBACK(msg_error), pipeline);
  g_signal_connect (bus, "message::warning", G_CALLBACK(msg_warning), pipeline);
  gst_object_unref (bus);
  
  setter = GST_TAG_SETTER (gst_bin_get_by_interface (GST_BIN (pipeline), GST_TYPE_TAG_SETTER));
  if (!setter) {
    g_printerr("No tag setter in pipeline\n");
    return -1;
  }
  gst_tag_setter_set_tag_merge_mode (setter, GST_TAG_MERGE_KEEP_ALL);
  
  loop = g_main_loop_new(NULL, FALSE);
  g_idle_add((GSourceFunc)run_pipeline,(gpointer)pipeline);
  /* Run event loop listening for bus messages until EOS or ERROR */
  g_main_loop_run(loop);

  /* stop & unref */
  gst_element_set_state (pipeline, GST_STATE_NULL);
  gst_object_unref (pipeline);
  
  return 0;
}
