mixer.c 8.35 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11
/*
 * mixer.c - stereo audio mixer - thomas@apestaart.org
 * example based on helloworld by
 * demonstrates the adder plugin and the volume envelope plugin 
 * work in progress but do try it out 
 * 
 * Latest change : 	16/04/2001
 * 					mixer & adder plugin now work with variable-size input buffers 
 * Version :		0.2
 */

Wim Taymans's avatar
Wim Taymans committed
12 13
#include <stdlib.h>
#include <gst/gst.h>
14
#include "mixer.h"
15
#include <unistd.h>
16

17
//#define DEBUG
18 19 20

/* function prototypes */

21 22
input_channel_t*	create_input_channel (int id, char* location);
void				destroy_input_channel (input_channel_t *pipe);
23

Wim Taymans's avatar
Wim Taymans committed
24 25 26 27 28 29 30

gboolean playing;


/* eos will be called when the src element has an end of stream */
void eos(GstElement *element) 
{
31
  g_print("have eos, quitting ?\n");
Wim Taymans's avatar
Wim Taymans committed
32

33
//  playing = FALSE;
Wim Taymans's avatar
Wim Taymans committed
34 35
}

36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
static void
gst_play_have_type (GstElement *sink, GstElement *sink2, gpointer data)
{
  GST_DEBUG (0,"GstPipeline: play have type %p\n", (gboolean *)data);
 
  *(gboolean *)data = TRUE;
}

static GstCaps*
gst_play_typefind (GstBin *bin, GstElement *element)
{
  gboolean found = FALSE;
  GstElement *typefind;
  GstCaps *caps = NULL;

  GST_DEBUG (0,"GstPipeline: typefind for element \"%s\" %p\n",
             GST_ELEMENT_NAME(element), &found);
 
  typefind = gst_elementfactory_make ("typefind", "typefind");
  g_return_val_if_fail (typefind != NULL, FALSE);

  gtk_signal_connect (GTK_OBJECT (typefind), "have_type",  
                      GTK_SIGNAL_FUNC (gst_play_have_type), &found);
 
  gst_pad_connect (gst_element_get_pad (element, "src"),
                   gst_element_get_pad (typefind, "sink"));
  gst_bin_add (bin, typefind);
  
  gst_element_set_state (GST_ELEMENT (bin), GST_STATE_PLAYING);
  
  // push a buffer... the have_type signal handler will set the found flag
  gst_bin_iterate (bin);
  
  gst_element_set_state (GST_ELEMENT (bin), GST_STATE_NULL);

  caps = gst_pad_get_caps (gst_element_get_pad (element, "src"));

  gst_pad_disconnect (gst_element_get_pad (element, "src"),
                      gst_element_get_pad (typefind, "sink"));
  gst_bin_remove (bin, typefind);
  gst_object_unref (GST_OBJECT (typefind));
                   
  return caps;
}

Wim Taymans's avatar
Wim Taymans committed
81 82
int main(int argc,char *argv[]) 
{
83 84
  input_channel_t *channel_in1;
  input_channel_t *channel_in2;
85 86
  
  GstElement *main_bin;
Wim Taymans's avatar
Wim Taymans committed
87 88 89 90 91 92 93 94 95 96 97 98
  GstElement *adder;
  GstElement *audiosink;

  GstPad *pad; /* to request pads for the adder */

  gst_init(&argc,&argv);

  if (argc != 3) {
    g_print("usage: %s <filename1> <filename2>\n", argv[0]);
    exit(-1);
  }

99
  /* create input channels */
Wim Taymans's avatar
Wim Taymans committed
100

101 102
  channel_in1 = create_input_channel (1, argv[1]);
  channel_in2 = create_input_channel (2, argv[2]);
Wim Taymans's avatar
Wim Taymans committed
103 104 105 106 107 108 109 110 111 112 113


  /* create adder */
  adder = gst_elementfactory_make("adder", "adderel");

  /* create an audio sink */
  audiosink = gst_elementfactory_make("esdsink", "play_audio");

  /* now create main bin */
  main_bin = gst_bin_new("bin");

114 115
  gst_bin_add(GST_BIN(main_bin), channel_in1->pipe);
  gst_bin_add(GST_BIN(main_bin), channel_in2->pipe);
Wim Taymans's avatar
Wim Taymans committed
116 117 118 119 120 121 122
  gst_bin_add(GST_BIN(main_bin), adder);
  gst_bin_add(GST_BIN(main_bin), audiosink);

  /* request pads and connect to adder */

  pad = gst_element_request_pad_by_name (adder, "sink%d");
  g_print ("new pad %s\n", gst_pad_get_name (pad));
123
  gst_pad_connect (gst_element_get_pad (channel_in1->pipe, "channel1"), pad);
Wim Taymans's avatar
Wim Taymans committed
124 125
  pad = gst_element_request_pad_by_name (adder, "sink%d");
  g_print ("new pad %s\n", gst_pad_get_name (pad));
126
  gst_pad_connect (gst_element_get_pad (channel_in2->pipe, "channel2"), pad);
Wim Taymans's avatar
Wim Taymans committed
127 128 129 130 131 132 133 134

  /* connect adder and audiosink */

  gst_pad_connect(gst_element_get_pad(adder,"src"),
                  gst_element_get_pad(audiosink,"sink"));

  /* register the volume envelope */

135 136 137 138 139
  gtk_object_set(GTK_OBJECT(channel_in1->volenv), "controlpoint", "0:0.000001", NULL);
  gtk_object_set(GTK_OBJECT(channel_in1->volenv), "controlpoint", "5:0.000001", NULL);
  gtk_object_set(GTK_OBJECT(channel_in1->volenv), "controlpoint", "10:1", NULL);
  gtk_object_set(GTK_OBJECT(channel_in1->volenv), "controlpoint", "15:1", NULL);
  gtk_object_set(GTK_OBJECT(channel_in1->volenv), "controlpoint", "20:0.000001", NULL);
140 141
  gtk_object_set(GTK_OBJECT(channel_in1->volenv), "controlpoint", "40:0.000001", NULL);
  gtk_object_set(GTK_OBJECT(channel_in1->volenv), "controlpoint", "45:0.5", NULL);
142

143 144 145 146 147
  gtk_object_set(GTK_OBJECT(channel_in2->volenv), "controlpoint", "0:1", NULL);
  gtk_object_set(GTK_OBJECT(channel_in2->volenv), "controlpoint", "5:1", NULL);
  gtk_object_set(GTK_OBJECT(channel_in2->volenv), "controlpoint", "10:0.000001", NULL);
  gtk_object_set(GTK_OBJECT(channel_in2->volenv), "controlpoint", "15:0.000001", NULL);
  gtk_object_set(GTK_OBJECT(channel_in2->volenv), "controlpoint", "20:1", NULL);
148 149 150 151
  gtk_object_set(GTK_OBJECT(channel_in2->volenv), "controlpoint", "40:1", NULL);
  gtk_object_set(GTK_OBJECT(channel_in2->volenv), "controlpoint", "45:0.5", NULL);

  /* sleep a few seconds */
Wim Taymans's avatar
Wim Taymans committed
152

153 154 155 156
  printf ("Sleeping a few seconds ...\n");
  sleep (2);
  printf ("Waking up ...\n");
  
Wim Taymans's avatar
Wim Taymans committed
157 158 159 160 161 162 163 164 165 166 167 168
  /* start playing */
  gst_element_set_state(main_bin, GST_STATE_PLAYING);

  playing = TRUE;

  while (playing) {
    gst_bin_iterate(GST_BIN(main_bin));
  }

  /* stop the bin */
  gst_element_set_state(main_bin, GST_STATE_NULL);

169 170
  destroy_input_channel (channel_in1);
  destroy_input_channel (channel_in2);
171
  
Wim Taymans's avatar
Wim Taymans committed
172 173 174 175 176 177 178
  gst_object_destroy(GST_OBJECT(audiosink));

  gst_object_destroy(GST_OBJECT(main_bin));

  exit(0);
}

179 180
input_channel_t*
create_input_channel (int id, char* location)
181
{
182 183
  /* create an input channel, reading from location
   * return a pointer to the channel
184 185 186
   * return NULL if failed
   */

187 188
  input_channel_t *channel;
  
189 190
  char buffer[20]; 		/* hold the names */

191 192 193
  GstAutoplug *autoplug;
  GstCaps *srccaps;
  GstElement *new_element;  
194 195

#ifdef DEBUG
196
  printf ("DEBUG : c_i_p : creating channel with id %d for file %s\n",
197 198 199
  		  id, location);
#endif
  
200
  /* allocate channel */
201

202 203
  channel = (input_channel_t *) malloc (sizeof (input_channel_t));
  if (channel == NULL)
204
  {
205
    printf ("create_input_channel : could not allocate memory for channel !\n");
206 207 208
    return NULL;
  }

209 210 211 212 213
  /* create channel */

#ifdef DEBUG
  printf ("DEBUG : c_i_p : creating pipeline\n");
#endif
214

215 216 217
  channel->pipe = gst_bin_new ("pipeline");
  g_assert(channel->pipe != NULL);    
    
218 219
  /* create elements */

220 221 222 223
#ifdef DEBUG
  printf ("DEBUG : c_i_p : creating disksrc\n");
#endif

224
  sprintf (buffer, "disksrc%d", id);
225 226 227 228 229 230 231 232
  channel->disksrc = gst_elementfactory_make ("disksrc", buffer);
  g_assert(channel->disksrc != NULL);    
  
  gtk_object_set(GTK_OBJECT(channel->disksrc),"location", location, NULL);

  /* add disksrc to the bin before autoplug */
  gst_bin_add(GST_BIN(channel->pipe), channel->disksrc);

233 234
  /* connect signal to eos of disksrc */
  gtk_signal_connect(GTK_OBJECT(channel->disksrc),"eos",
235
                     GTK_SIGNAL_FUNC(eos),NULL);
236

237

238 239 240 241 242 243 244 245 246 247 248 249 250
#ifdef DEBUG
  printf ("DEBUG : c_i_p : creating volume envelope\n");
#endif

  sprintf (buffer, "volenv%d", id);
  channel->volenv = gst_elementfactory_make ("volenv", buffer);
  g_assert(channel->volenv != NULL);    

  /* autoplug the pipe */

#ifdef DEBUG
  printf ("DEBUG : c_i_p : getting srccaps\n");
#endif
251

252 253 254 255 256 257 258 259 260 261
  srccaps = gst_play_typefind (GST_BIN (channel->pipe), channel->disksrc);

  if (!srccaps) {
    g_print ("could not autoplug, unknown media type...\n");
    exit (-1);
  }

#ifdef DEBUG
  printf ("DEBUG : c_i_p : creating autoplug\n");
#endif
262

263 264
  autoplug = gst_autoplugfactory_make ("static");
  g_assert (autoplug != NULL);
265

266 267 268 269 270 271 272 273 274 275 276 277
#ifdef DEBUG
  printf ("DEBUG : c_i_p : autoplugging\n");
#endif
 
  new_element = gst_autoplug_to_caps (autoplug, srccaps, 
  					gst_caps_new ("audio", "audio/raw", NULL), NULL);
 
  if (!new_element) {
    g_print ("could not autoplug, no suitable codecs found...\n");
    exit (-1);
  }
  
278
  gst_bin_add (GST_BIN(channel->pipe), channel->volenv);
279 280 281 282 283
  gst_bin_add (GST_BIN (channel->pipe), new_element);
  
  gst_element_connect (channel->disksrc, "src", new_element, "sink");
  gst_element_connect (new_element, "src_00", channel->volenv, "sink");
  
284 285
  /* add a ghost pad */
  sprintf (buffer, "channel%d", id);
286 287
  gst_element_add_ghost_pad (channel->pipe,
                             gst_element_get_pad (channel->volenv, "src"), buffer);
288

289
   
290 291 292 293
#ifdef DEBUG
  printf ("DEBUG : c_i_p : end function\n");
#endif

294
  return channel;
295 296 297
}

void
298
destroy_input_channel (input_channel_t *channel)
299 300
{
  /* 
301
   * destroy an input channel
302 303 304 305 306 307
   */
   
#ifdef DEBUG
  printf ("DEBUG : d_i_p : start\n");
#endif

308
  /* destroy elements */
309

310
  gst_object_destroy (GST_OBJECT (channel->pipe));
311

312
  free (channel);
313 314 315 316 317
}