gst-gpac/src/gpacmux.c
author melunko
Thu Feb 21 22:49:45 2008 +0000 (2008-02-21)
branchtrunk
changeset 920 e3e434d3ed83
parent 917 be87d28e8371
permissions -rw-r--r--
[svn r929] Fixed eos problems and more than one track limitation
melunko@917
     1
melunko@917
     2
#ifdef HAVE_CONFIG_H
melunko@917
     3
#include "config.h"
melunko@917
     4
#endif
melunko@917
     5
melunko@917
     6
#include <gst/gst.h>
melunko@917
     7
#include <gst/base/gstcollectpads.h>
melunko@917
     8
melunko@917
     9
#include <stdlib.h> 
melunko@917
    10
#include <string.h>
melunko@917
    11
melunko@917
    12
/* gpac includes */
melunko@917
    13
#include <gpac/isomedia.h>
melunko@917
    14
melunko@917
    15
#define GST_TYPE_GPAC_MUX (gst_gpac_mux_get_type())
melunko@917
    16
#define GST_GPAC_MUX(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_GPAC_MUX, GstGpacMux))
melunko@917
    17
#define GST_GPAC_MUX_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_GPAC_MUX, GstGpacMux))
melunko@917
    18
#define GST_IS_GPAC_MUX(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_GPAC_MUX))
melunko@917
    19
#define GST_IS_GPAC_MUX_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_GPAC_MUX))
melunko@917
    20
melunko@917
    21
typedef struct _GstGpacMux GstGpacMux;
melunko@917
    22
typedef struct _GstGpacMuxClass GstGpacMuxClass;
melunko@917
    23
melunko@917
    24
typedef enum
melunko@917
    25
{
melunko@917
    26
  GST_GPAC_PAD_STATE_CONTROL = 0,
melunko@917
    27
  GST_GPAC_PAD_STATE_DATA = 1
melunko@917
    28
}
melunko@917
    29
GstGpacPadState;
melunko@917
    30
melunko@917
    31
typedef struct
melunko@917
    32
{
melunko@917
    33
  GstCollectData collect;       /* we extend the CollectData */
melunko@917
    34
melunko@917
    35
  gint track_number;
melunko@917
    36
  guint32 di; /* outDescriptionIndex */
melunko@917
    37
melunko@920
    38
  GstBuffer *buffer;
melunko@920
    39
  GstBuffer *next_buffer;
melunko@920
    40
melunko@917
    41
  guint32 frame_count;
melunko@917
    42
  gboolean is_video;
melunko@917
    43
melunko@920
    44
  gboolean eos;
melunko@920
    45
melunko@917
    46
} GstGpacPad;
melunko@917
    47
melunko@917
    48
struct _GstGpacMux
melunko@917
    49
{
melunko@917
    50
  GstElement element;
melunko@917
    51
melunko@917
    52
  GstPad *srcpad;
melunko@917
    53
  GstCollectPads *collect;
melunko@920
    54
  gint active_pads;
melunko@917
    55
melunko@917
    56
  GF_ISOFile *file;
melunko@917
    57
melunko@917
    58
};
melunko@917
    59
melunko@917
    60
struct _GstGpacMuxClass
melunko@917
    61
{
melunko@917
    62
  GstElementClass parent_class;
melunko@917
    63
};
melunko@917
    64
melunko@917
    65
/* elementfactory information */
melunko@917
    66
static const GstElementDetails gst_gpac_mux_details =
melunko@917
    67
GST_ELEMENT_DETAILS ("Gpac muxer",
melunko@917
    68
    "Codec/Muxer",
melunko@917
    69
    "mux mp4 streams",
melunko@917
    70
    "Hallyson Melo <hallyson.melo@indt.org.br");
melunko@917
    71
melunko@917
    72
/* GpacMux signals and args */
melunko@917
    73
enum
melunko@917
    74
{
melunko@917
    75
  /* FILL ME */
melunko@917
    76
  LAST_SIGNAL
melunko@917
    77
};
melunko@917
    78
melunko@917
    79
static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
melunko@917
    80
    GST_PAD_SRC,
melunko@917
    81
    GST_PAD_ALWAYS,
melunko@917
    82
    GST_STATIC_CAPS ("video/quicktime")
melunko@917
    83
    );
melunko@917
    84
melunko@917
    85
static GstStaticPadTemplate audio_sink_factory = GST_STATIC_PAD_TEMPLATE ("audio_%d",
melunko@917
    86
    GST_PAD_SINK,
melunko@917
    87
    GST_PAD_REQUEST,
melunko@917
    88
    GST_STATIC_CAPS (
melunko@917
    89
        "audio/mpeg, " 
melunko@917
    90
        "mpegversion = (int) 4, " 
melunko@917
    91
        "channels = (int) { 1, 2 }, " 
melunko@917
    92
        "rate = (int) [ 8000, 96000 ]")
melunko@917
    93
    );
melunko@917
    94
    //GST_STATIC_CAPS ("audio/mpeg, mpegversion = 1, layer = 3")
melunko@917
    95
melunko@917
    96
static GstStaticPadTemplate video_sink_factory = GST_STATIC_PAD_TEMPLATE ("video_%d",
melunko@917
    97
    GST_PAD_SINK,
melunko@917
    98
    GST_PAD_REQUEST,
melunko@917
    99
    GST_STATIC_CAPS ("video/mpeg, mpegversion = 4")
melunko@917
   100
   );
melunko@917
   101
melunko@917
   102
static void gst_gpac_mux_base_init (gpointer g_class);
melunko@917
   103
static void gst_gpac_mux_class_init (GstGpacMuxClass * klass);
melunko@917
   104
static void gst_gpac_mux_init (GstGpacMux * gpac_mux);
melunko@917
   105
static void gst_gpac_mux_finalize (GObject * object);
melunko@917
   106
melunko@917
   107
static GstFlowReturn
melunko@917
   108
gst_gpac_mux_collected (GstCollectPads * pads, GstGpacMux * gpac_mux);
melunko@917
   109
melunko@917
   110
static gboolean gst_gpac_mux_handle_src_event (GstPad * pad, GstEvent * event);
melunko@917
   111
static GstPad *gst_gpac_mux_request_new_pad (GstElement * element,
melunko@917
   112
    GstPadTemplate * templ, const gchar * name);
melunko@917
   113
static void gst_gpac_mux_release_pad (GstElement * element, GstPad * pad);
melunko@917
   114
melunko@917
   115
static GstStateChangeReturn gst_gpac_mux_change_state (GstElement * element,
melunko@917
   116
    GstStateChange transition);
melunko@917
   117
melunko@920
   118
static GstGpacPad* gst_gpac_mux_queue_pads (GstGpacMux * gpac_mux);
melunko@920
   119
static GstFlowReturn gst_gpac_mux_process_pad (GstGpacMux * gpac_mux, GstGpacPad *pad);
melunko@920
   120
static gboolean gst_gpac_mux_all_pads_eos (GstCollectPads * pads);
melunko@920
   121
static gint gst_gpac_mux_compare_pads (GstGpacMux * ogg_mux, GstGpacPad *first,
melunko@920
   122
    GstGpacPad *second);
melunko@920
   123
melunko@920
   124
melunko@917
   125
static GstElementClass *parent_class = NULL;
melunko@917
   126
melunko@917
   127
GType
melunko@917
   128
gst_gpac_mux_get_type (void)
melunko@917
   129
{
melunko@917
   130
  static GType gpac_mux_type = 0;
melunko@917
   131
melunko@917
   132
  if (G_UNLIKELY (gpac_mux_type == 0)) {
melunko@917
   133
    static const GTypeInfo gpac_mux_info = {
melunko@917
   134
      sizeof (GstGpacMuxClass),
melunko@917
   135
      gst_gpac_mux_base_init,
melunko@917
   136
      NULL,
melunko@917
   137
      (GClassInitFunc) gst_gpac_mux_class_init,
melunko@917
   138
      NULL,
melunko@917
   139
      NULL,
melunko@917
   140
      sizeof (GstGpacMux),
melunko@917
   141
      0,
melunko@917
   142
      (GInstanceInitFunc) gst_gpac_mux_init,
melunko@917
   143
    };
melunko@917
   144
melunko@917
   145
    gpac_mux_type =
melunko@917
   146
        g_type_register_static (GST_TYPE_ELEMENT, "GstGpacMux", &gpac_mux_info,
melunko@917
   147
        0);
melunko@917
   148
  }
melunko@917
   149
  return gpac_mux_type;
melunko@917
   150
}
melunko@917
   151
melunko@917
   152
static void
melunko@917
   153
gst_gpac_mux_base_init (gpointer g_class)
melunko@917
   154
{
melunko@917
   155
  GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
melunko@917
   156
melunko@917
   157
  gst_element_class_add_pad_template (element_class,
melunko@917
   158
      gst_static_pad_template_get (&src_factory));
melunko@917
   159
  gst_element_class_add_pad_template (element_class,
melunko@917
   160
      gst_static_pad_template_get (&audio_sink_factory));
melunko@917
   161
  gst_element_class_add_pad_template (element_class,
melunko@917
   162
      gst_static_pad_template_get (&video_sink_factory));
melunko@917
   163
melunko@917
   164
  gst_element_class_set_details (element_class, &gst_gpac_mux_details);
melunko@917
   165
}
melunko@917
   166
melunko@917
   167
static void
melunko@917
   168
gst_gpac_mux_class_init (GstGpacMuxClass * klass)
melunko@917
   169
{
melunko@917
   170
  GObjectClass *gobject_class;
melunko@917
   171
  GstElementClass *gstelement_class;
melunko@917
   172
melunko@917
   173
  gobject_class = (GObjectClass *) klass;
melunko@917
   174
  gstelement_class = (GstElementClass *) klass;
melunko@917
   175
melunko@917
   176
  parent_class = g_type_class_peek_parent (klass);
melunko@917
   177
melunko@917
   178
  gobject_class->finalize = gst_gpac_mux_finalize;
melunko@917
   179
melunko@917
   180
  gstelement_class->request_new_pad = gst_gpac_mux_request_new_pad;
melunko@917
   181
  gstelement_class->release_pad = gst_gpac_mux_release_pad;
melunko@917
   182
melunko@917
   183
  gstelement_class->change_state = gst_gpac_mux_change_state;
melunko@917
   184
melunko@917
   185
}
melunko@917
   186
melunko@917
   187
static void
melunko@917
   188
gst_gpac_mux_init (GstGpacMux * gpac_mux)
melunko@917
   189
{
melunko@917
   190
  GstElementClass *klass = GST_ELEMENT_GET_CLASS (gpac_mux);
melunko@917
   191
melunko@917
   192
  gpac_mux->srcpad =
melunko@917
   193
      gst_pad_new_from_template (gst_element_class_get_pad_template (klass,
melunko@917
   194
          "src"), "src");
melunko@917
   195
  gst_pad_set_event_function (gpac_mux->srcpad, gst_gpac_mux_handle_src_event);
melunko@917
   196
  gst_element_add_pad (GST_ELEMENT (gpac_mux), gpac_mux->srcpad);
melunko@917
   197
melunko@917
   198
  gpac_mux->collect = gst_collect_pads_new ();
melunko@917
   199
  gst_collect_pads_set_function (gpac_mux->collect,
melunko@917
   200
      (GstCollectPadsFunction) GST_DEBUG_FUNCPTR (gst_gpac_mux_collected),
melunko@917
   201
      gpac_mux);
melunko@917
   202
melunko@917
   203
  /* Opens gpac library */
melunko@917
   204
  /* FIXME */
melunko@917
   205
  gpac_mux->file = gf_isom_open("/tmp/gpac.mp4", GF_ISOM_OPEN_WRITE, NULL);
melunko@917
   206
  gf_isom_set_storage_mode(gpac_mux->file, GF_ISOM_STORE_FLAT /*STREAMABLE*/);
melunko@917
   207
melunko@917
   208
  //gst_gpac_mux_clear (gpac_mux);
melunko@917
   209
}
melunko@917
   210
melunko@917
   211
static void
melunko@917
   212
gst_gpac_mux_finalize (GObject * object)
melunko@917
   213
{
melunko@917
   214
  GstGpacMux *gpac_mux;
melunko@917
   215
melunko@917
   216
  gpac_mux = GST_GPAC_MUX (object);
melunko@917
   217
melunko@917
   218
  if (gpac_mux->collect) {
melunko@917
   219
    gst_object_unref (gpac_mux->collect);
melunko@917
   220
    gpac_mux->collect = NULL;
melunko@917
   221
  }
melunko@917
   222
melunko@917
   223
  G_OBJECT_CLASS (parent_class)->finalize (object);
melunko@917
   224
}
melunko@917
   225
melunko@917
   226
static void
melunko@917
   227
gst_gpac_mux_gpac_pad_destroy_notify (GstCollectData * data)
melunko@917
   228
{
melunko@917
   229
  GstGpacPad *gpacpad = (GstGpacPad *) data;
melunko@917
   230
  GstBuffer *buf;
melunko@917
   231
melunko@917
   232
}
melunko@917
   233
melunko@917
   234
static GstPadLinkReturn
melunko@917
   235
gst_gpac_mux_sinkconnect (GstPad * pad, GstPad * peer)
melunko@917
   236
{
melunko@917
   237
  GstGpacMux *gpac_mux;
melunko@917
   238
melunko@917
   239
  gpac_mux = GST_GPAC_MUX (gst_pad_get_parent (pad));
melunko@917
   240
melunko@917
   241
  GST_DEBUG_OBJECT (gpac_mux, "sinkconnect triggered on %s", GST_PAD_NAME (pad));
melunko@917
   242
melunko@917
   243
  gst_object_unref (gpac_mux);
melunko@917
   244
melunko@917
   245
  return GST_PAD_LINK_OK;
melunko@917
   246
}
melunko@917
   247
melunko@917
   248
static GstPad *
melunko@917
   249
gst_gpac_mux_request_new_pad (GstElement * element,
melunko@917
   250
    GstPadTemplate * templ, const gchar * req_name)
melunko@917
   251
{
melunko@917
   252
  GstGpacMux *gpac_mux;
melunko@917
   253
  GstPad *newpad;
melunko@917
   254
  GstElementClass *klass;
melunko@917
   255
  gchar *padname = NULL;
melunko@917
   256
  gint serial;
melunko@917
   257
  gboolean is_video = FALSE;
melunko@917
   258
melunko@917
   259
  g_return_val_if_fail (templ != NULL, NULL);
melunko@917
   260
melunko@917
   261
  if (templ->direction != GST_PAD_SINK)
melunko@917
   262
    goto wrong_direction;
melunko@917
   263
melunko@917
   264
  g_return_val_if_fail (GST_IS_GPAC_MUX (element), NULL);
melunko@917
   265
  gpac_mux = GST_GPAC_MUX (element);
melunko@917
   266
melunko@917
   267
  klass = GST_ELEMENT_GET_CLASS (element);
melunko@917
   268
melunko@917
   269
    if (req_name == NULL || strlen (req_name) < 6) {
melunko@917
   270
      /* no name given when requesting the pad, use random serial number */
melunko@917
   271
      serial = rand ();
melunko@917
   272
    } else {
melunko@917
   273
      /* parse serial number from requested padname */
melunko@917
   274
      serial = atoi (&req_name[5]);
melunko@917
   275
    }
melunko@917
   276
melunko@917
   277
  if (templ == gst_element_class_get_pad_template (klass, "video_%d")) {
melunko@917
   278
    is_video = TRUE;      
melunko@917
   279
    padname = g_strdup_printf ("video_%d", serial);
melunko@917
   280
  } else if (templ != gst_element_class_get_pad_template (klass, "audio_%d")) {
melunko@917
   281
    goto wrong_template;
melunko@917
   282
  } else {
melunko@917
   283
    padname = g_strdup_printf ("audio_%d", serial);
melunko@917
   284
  }
melunko@917
   285
melunko@917
   286
melunko@917
   287
  {
melunko@917
   288
    
melunko@917
   289
    /* create new pad with the name */
melunko@917
   290
    GST_DEBUG_OBJECT (gpac_mux, "Creating new pad for serial %d", serial);
melunko@920
   291
melunko@917
   292
    newpad = gst_pad_new_from_template (templ, padname);
melunko@917
   293
    g_free (padname);
melunko@917
   294
melunko@917
   295
    /* construct our own wrapper data structure for the pad to
melunko@917
   296
     * keep track of its status */
melunko@917
   297
    {
melunko@917
   298
      GstGpacPad *gpacpad;
melunko@917
   299
melunko@917
   300
      gpacpad = (GstGpacPad *)
melunko@917
   301
          gst_collect_pads_add_pad_full (gpac_mux->collect, newpad,
melunko@917
   302
          sizeof (GstGpacPad), gst_gpac_mux_gpac_pad_destroy_notify);
melunko@920
   303
      gpac_mux->active_pads++;
melunko@917
   304
melunko@917
   305
      /* gpac new track */
melunko@917
   306
      gpacpad->is_video = is_video;
melunko@917
   307
      if (gpacpad->is_video) {
melunko@917
   308
        gpacpad->track_number = gf_isom_new_track(gpac_mux->file, 0, 
melunko@917
   309
          GF_ISOM_MEDIA_VISUAL, 10 * 1000 /* time scale */);
melunko@917
   310
      } else {
melunko@917
   311
        gpacpad->track_number = gf_isom_new_track(gpac_mux->file, 0, 
melunko@917
   312
          GF_ISOM_MEDIA_AUDIO, 48000 /*time scale */);
melunko@917
   313
        
melunko@917
   314
      }
melunko@917
   315
      if (gpacpad->track_number == 0) {
melunko@917
   316
        g_warning ("Error while adding the new gpac track");
melunko@917
   317
      } else {
melunko@917
   318
        gf_isom_set_track_enabled(gpac_mux->file, gpacpad->track_number, 1);
melunko@917
   319
        if (is_video) {
melunko@917
   320
          GF_ESD *esd = gf_odf_desc_esd_new (0);
melunko@917
   321
          esd->ESID = gf_isom_get_track_id(gpac_mux->file, gpacpad->track_number);
melunko@917
   322
melunko@917
   323
          gf_isom_new_mpeg4_description( gpac_mux->file, gpacpad->track_number,
melunko@917
   324
                        esd, NULL, NULL, &(gpacpad->di));
melunko@917
   325
melunko@917
   326
           gf_isom_set_visual_info (gpac_mux->file, gpacpad->track_number, gpacpad->di, 320, 240);//fixme
melunko@917
   327
          //gf_isom_set_cts_packing (gpac_mux->file, gpacpad->track_number, 0);
melunko@917
   328
        } else {
melunko@917
   329
          GF_ESD *esd = gf_odf_desc_esd_new (2);
melunko@917
   330
          esd->ESID = gf_isom_get_track_id(gpac_mux->file, gpacpad->track_number);
melunko@917
   331
melunko@917
   332
          gf_isom_new_mpeg4_description(gpac_mux->file, gpacpad->track_number,
melunko@917
   333
                         esd, NULL, NULL, &(gpacpad->di));
melunko@917
   334
melunko@917
   335
          gf_isom_set_audio_info(gpac_mux->file, gpacpad->track_number, 
melunko@917
   336
                          gpacpad->di, 48000, 2 /*num channels */, 16);
melunko@917
   337
        }
melunko@917
   338
      }
melunko@917
   339
    }
melunko@917
   340
  }
melunko@917
   341
melunko@917
   342
  /* setup some pad functions */
melunko@917
   343
  gst_pad_set_link_function (newpad, gst_gpac_mux_sinkconnect);
melunko@917
   344
  /* dd the pad to the element */
melunko@917
   345
  gst_element_add_pad (element, newpad);
melunko@917
   346
melunko@917
   347
  return newpad;
melunko@917
   348
melunko@917
   349
  /* ERRORS */
melunko@917
   350
wrong_direction:
melunko@917
   351
  {
melunko@917
   352
    g_warning ("gpac_mux: request pad that is not a SINK pad\n");
melunko@917
   353
    return NULL;
melunko@917
   354
  }
melunko@917
   355
wrong_template:
melunko@917
   356
  {
melunko@917
   357
    g_warning ("gpac_mux: this is not our template!\n");
melunko@917
   358
    return NULL;
melunko@917
   359
  }
melunko@917
   360
}
melunko@917
   361
melunko@917
   362
static void
melunko@917
   363
gst_gpac_mux_release_pad (GstElement * element, GstPad * pad)
melunko@917
   364
{
melunko@917
   365
  GstGpacMux *gpac_mux;
melunko@917
   366
melunko@917
   367
  gpac_mux = GST_GPAC_MUX (gst_pad_get_parent (pad));
melunko@917
   368
melunko@917
   369
  gst_collect_pads_remove_pad (gpac_mux->collect, pad);
melunko@917
   370
  gst_element_remove_pad (element, pad);
melunko@917
   371
}
melunko@917
   372
melunko@917
   373
/* handle events */
melunko@917
   374
static gboolean
melunko@917
   375
gst_gpac_mux_handle_src_event (GstPad * pad, GstEvent * event)
melunko@917
   376
{
melunko@917
   377
  GstEventType type;
melunko@917
   378
melunko@917
   379
  type = event ? GST_EVENT_TYPE (event) : GST_EVENT_UNKNOWN;
melunko@917
   380
melunko@917
   381
  switch (type) {
melunko@917
   382
    case GST_EVENT_SEEK:
melunko@917
   383
      /* disable seeking for now */
melunko@917
   384
      return FALSE;
melunko@917
   385
    default:
melunko@917
   386
      break;
melunko@917
   387
  }
melunko@917
   388
melunko@917
   389
  return gst_pad_event_default (pad, event);
melunko@917
   390
}
melunko@917
   391
melunko@917
   392
static GstFlowReturn
melunko@917
   393
gst_gpac_mux_push_buffer (GstGpacMux * mux, GstBuffer * buffer)
melunko@917
   394
{
melunko@917
   395
  GstCaps *caps;
melunko@917
   396
#if 0
melunko@917
   397
  /* fix up OFFSET and OFFSET_END again */
melunko@917
   398
  GST_BUFFER_OFFSET (buffer) = mux->offset;
melunko@917
   399
  mux->offset += GST_BUFFER_SIZE (buffer);
melunko@917
   400
  GST_BUFFER_OFFSET_END (buffer) = mux->offset;
melunko@917
   401
melunko@917
   402
  /* Ensure we have monotonically increasing timestamps in the output. */
melunko@917
   403
  if (GST_BUFFER_TIMESTAMP_IS_VALID (buffer)) {
melunko@917
   404
    if (mux->last_ts != GST_CLOCK_TIME_NONE &&
melunko@917
   405
        GST_BUFFER_TIMESTAMP (buffer) < mux->last_ts)
melunko@917
   406
      GST_BUFFER_TIMESTAMP (buffer) = mux->last_ts;
melunko@917
   407
    else
melunko@917
   408
      mux->last_ts = GST_BUFFER_TIMESTAMP (buffer);
melunko@917
   409
  }
melunko@917
   410
#endif
melunko@917
   411
  
melunko@917
   412
  caps = gst_pad_get_negotiated_caps (mux->srcpad);
melunko@917
   413
  gst_buffer_set_caps (buffer, caps);
melunko@917
   414
  if (caps != NULL) {
melunko@917
   415
    gst_caps_unref (caps);
melunko@917
   416
  }
melunko@917
   417
melunko@917
   418
  return gst_pad_push (mux->srcpad, buffer);
melunko@917
   419
}
melunko@917
   420
melunko@920
   421
static GstFlowReturn
melunko@920
   422
gst_gpac_mux_collected (GstCollectPads * pads, GstGpacMux * gpac_mux)
melunko@920
   423
{
melunko@920
   424
  GstFlowReturn ret = GST_FLOW_OK;
melunko@920
   425
  GstGpacPad *pad;
melunko@920
   426
  gint active_before;
melunko@920
   427
melunko@920
   428
  GST_LOG_OBJECT (gpac_mux, "collected");
melunko@920
   429
melunko@920
   430
  active_before = gpac_mux->active_pads;
melunko@920
   431
melunko@920
   432
  pad = gst_gpac_mux_queue_pads (gpac_mux);
melunko@920
   433
  if (!pad) {
melunko@920
   434
    return GST_FLOW_WRONG_STATE;
melunko@920
   435
  }
melunko@920
   436
melunko@920
   437
  if (pad->buffer) {
melunko@920
   438
    ret = gst_gpac_mux_process_pad (gpac_mux, pad);
melunko@920
   439
  }
melunko@920
   440
melunko@920
   441
  if (gpac_mux->active_pads < active_before) {
melunko@920
   442
    /* If the active pad count went down, this mean at least one pad has gone
melunko@920
   443
     * EOS. Since CollectPads only calls _collected() once when all pads are
melunko@920
   444
     * EOS, and our code doesn't _pop() from all pads we need to check that by
melunko@920
   445
     * peeking on all pads, else we won't be called again and the muxing will
melunko@920
   446
     * not terminate (push out EOS). */
melunko@920
   447
          printf ("XXXX um pad foi desativado %" GST_PTR_FORMAT "\n", pad);
melunko@920
   448
melunko@920
   449
    /* if all the pads have been removed, flush all pending data */
melunko@920
   450
    if ((ret == GST_FLOW_OK) && gst_gpac_mux_all_pads_eos (pads)) {
melunko@920
   451
      GST_LOG_OBJECT (gpac_mux, "no pads remaining, flushing data");
melunko@920
   452
melunko@920
   453
      do {
melunko@920
   454
        pad = gst_gpac_mux_queue_pads (gpac_mux);
melunko@920
   455
        if (pad)
melunko@920
   456
          ret = gst_gpac_mux_process_pad (gpac_mux, pad);
melunko@920
   457
      } while ((ret == GST_FLOW_OK) && (pad != NULL));
melunko@920
   458
melunko@920
   459
      /* gpac file close (eos) */
melunko@920
   460
      // Fixme: this should flush all data to src pad
melunko@920
   461
      // Fixme: where to release gpac_mux->file?
melunko@920
   462
      printf ("CCCCCCCCCCCCCCCCcclosing the file\n");
melunko@920
   463
      gf_isom_close (gpac_mux->file);
melunko@920
   464
melunko@920
   465
melunko@920
   466
      GST_DEBUG_OBJECT (gpac_mux, "Pushing EOS");
melunko@920
   467
      gst_pad_push_event (gpac_mux->srcpad, gst_event_new_eos ());
melunko@920
   468
    }
melunko@920
   469
  }
melunko@920
   470
melunko@920
   471
  return ret;
melunko@920
   472
melunko@920
   473
}
melunko@920
   474
melunko@917
   475
static gboolean
melunko@920
   476
gst_gpac_mux_all_pads_eos (GstCollectPads * pads)
melunko@917
   477
{
melunko@920
   478
  GSList *walk;
melunko@917
   479
  gboolean alleos = TRUE;
melunko@917
   480
melunko@920
   481
  walk = pads->data;
melunko@920
   482
  while (walk) {
melunko@917
   483
    GstBuffer *buf;
melunko@920
   484
    GstCollectData *data = (GstCollectData *) walk->data;
melunko@917
   485
melunko@917
   486
    buf = gst_collect_pads_peek (pads, data);
melunko@917
   487
    if (buf) {
melunko@917
   488
      alleos = FALSE;
melunko@917
   489
      gst_buffer_unref (buf);
melunko@920
   490
      break;
melunko@917
   491
    }
melunko@920
   492
    walk = walk->next;
melunko@917
   493
  }
melunko@920
   494
melunko@917
   495
  return alleos;
melunko@917
   496
}
melunko@920
   497
melunko@920
   498
melunko@917
   499
static GstFlowReturn
melunko@920
   500
gst_gpac_mux_process_pad (GstGpacMux *gpac_mux, GstGpacPad *pad)
melunko@917
   501
{
melunko@917
   502
  GstFlowReturn ret = GST_FLOW_OK;
melunko@920
   503
  GF_ISOSample *sample;
melunko@917
   504
melunko@920
   505
  if (pad->buffer == NULL) {
melunko@920
   506
          printf ("Buffer is null, wrong state\n");
melunko@920
   507
      return GST_FLOW_WRONG_STATE;
melunko@917
   508
  }
melunko@917
   509
melunko@920
   510
  /* gpac output */
melunko@920
   511
  printf ("xxxxxx buffer size: %d\n", GST_BUFFER_SIZE(pad->buffer)); fflush (stdout);
melunko@920
   512
  printf ("xxxx frames %d\n", pad->frame_count);
melunko@920
   513
melunko@920
   514
  sample = gf_isom_sample_new();
melunko@920
   515
  sample->dataLength = GST_BUFFER_SIZE(pad->buffer);
melunko@920
   516
  sample->data = GST_BUFFER_DATA(pad->buffer);
melunko@920
   517
  sample->CTS_Offset = 0;
melunko@920
   518
melunko@920
   519
  if (pad->is_video) {
melunko@920
   520
    sample->IsRAP = 0;
melunko@920
   521
    sample->DTS += 1000*pad->frame_count;
melunko@920
   522
  } else {
melunko@920
   523
    sample->IsRAP = 0;
melunko@920
   524
    sample->DTS = 2048*pad->frame_count;
melunko@920
   525
  }
melunko@920
   526
melunko@920
   527
  gf_isom_add_sample(gpac_mux->file, pad->track_number, 
melunko@920
   528
                     pad->di, sample);
melunko@920
   529
  sample->data = NULL;
melunko@920
   530
melunko@920
   531
  gf_isom_sample_del(&sample);
melunko@920
   532
melunko@920
   533
melunko@920
   534
  /* gstreamer output (push) */
melunko@920
   535
  ret = gst_gpac_mux_push_buffer (gpac_mux, pad->buffer);
melunko@920
   536
  pad->buffer = NULL;
melunko@920
   537
melunko@920
   538
  if (ret != GST_FLOW_OK) {
melunko@920
   539
  }
melunko@920
   540
melunko@920
   541
  pad->frame_count++;
melunko@920
   542
 
melunko@917
   543
  return ret;
melunko@917
   544
}
melunko@917
   545
melunko@917
   546
/* reset all variables in the gpac pads. */
melunko@917
   547
static void
melunko@917
   548
gst_gpac_mux_init_collectpads (GstCollectPads * collect)
melunko@917
   549
{
melunko@920
   550
  GSList *iter;
melunko@917
   551
melunko@920
   552
  iter = collect->data;
melunko@920
   553
  while (iter) {
melunko@920
   554
    GstGpacPad *gpacpad = (GstGpacPad *) iter->data;
melunko@917
   555
melunko@920
   556
    //gpac_stream_init (&gpacpad->stream, gpacpad->serial);
melunko@917
   557
    //gpacpad->packetno = 0;
melunko@917
   558
    //gpacpad->pageno = 0;
melunko@917
   559
    //gpacpad->eos = FALSE;
melunko@917
   560
    /* we assume there will be some control data first for this pad */
melunko@917
   561
    //gpacpad->state = GST_GPAC_PAD_STATE_CONTROL;
melunko@917
   562
    //gpacpad->new_page = TRUE;
melunko@917
   563
    //gpacpad->first_delta = FALSE;
melunko@917
   564
    //gpacpad->prev_delta = FALSE;
melunko@917
   565
    //gpacpad->pagebuffers = g_queue_new ();
melunko@917
   566
melunko@920
   567
    iter = g_slist_next (iter);
melunko@917
   568
  }
melunko@917
   569
}
melunko@917
   570
melunko@917
   571
/* Clear all buffers from the collectpads object */
melunko@917
   572
static void
melunko@917
   573
gst_gpac_mux_clear_collectpads (GstCollectPads * collect)
melunko@917
   574
{
melunko@920
   575
  GSList *iter;
melunko@917
   576
melunko@920
   577
  for (iter = collect->data; iter; iter = g_slist_next (iter)) {
melunko@920
   578
    GstGpacPad *gpacpad = (GstGpacPad *) iter->data;
melunko@917
   579
    GstBuffer *buf;
melunko@917
   580
melunko@917
   581
    //gpac_stream_clear (&gpacpad->stream);
melunko@917
   582
/*
melunko@917
   583
    while ((buf = g_queue_pop_head (gpacpad->pagebuffers)) != NULL) {
melunko@917
   584
      gst_buffer_unref (buf);
melunko@917
   585
    }
melunko@917
   586
    g_queue_free (gpacpad->pagebuffers);
melunko@917
   587
    gpacpad->pagebuffers = NULL;*/
melunko@917
   588
  }
melunko@917
   589
}
melunko@917
   590
melunko@917
   591
static GstStateChangeReturn
melunko@917
   592
gst_gpac_mux_change_state (GstElement * element, GstStateChange transition)
melunko@917
   593
{
melunko@917
   594
  GstGpacMux *gpac_mux;
melunko@917
   595
  GstStateChangeReturn ret;
melunko@917
   596
melunko@917
   597
  gpac_mux = GST_GPAC_MUX (element);
melunko@917
   598
melunko@917
   599
  switch (transition) {
melunko@917
   600
    case GST_STATE_CHANGE_NULL_TO_READY:
melunko@917
   601
      break;
melunko@917
   602
    case GST_STATE_CHANGE_READY_TO_PAUSED:
melunko@917
   603
      //gst_gpac_mux_clear (gpac_mux);
melunko@917
   604
      //gst_gpac_mux_init_collectpads (gpac_mux->collect);
melunko@917
   605
      gst_collect_pads_start (gpac_mux->collect);
melunko@917
   606
      break;
melunko@917
   607
    case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
melunko@917
   608
      break;
melunko@917
   609
    case GST_STATE_CHANGE_PAUSED_TO_READY:
melunko@917
   610
      gst_collect_pads_stop (gpac_mux->collect);
melunko@917
   611
      break;
melunko@917
   612
    default:
melunko@917
   613
      break;
melunko@917
   614
  }
melunko@917
   615
melunko@917
   616
  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
melunko@917
   617
melunko@917
   618
  switch (transition) {
melunko@917
   619
    case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
melunko@917
   620
      break;
melunko@917
   621
    case GST_STATE_CHANGE_PAUSED_TO_READY:
melunko@917
   622
      gst_gpac_mux_clear_collectpads (gpac_mux->collect);
melunko@917
   623
      break;
melunko@917
   624
    case GST_STATE_CHANGE_READY_TO_NULL:
melunko@917
   625
      break;
melunko@917
   626
    default:
melunko@917
   627
      break;
melunko@917
   628
  }
melunko@917
   629
melunko@917
   630
  return ret;
melunko@917
   631
melunko@917
   632
}
melunko@917
   633
melunko@920
   634
static GstGpacPad *
melunko@920
   635
gst_gpac_mux_queue_pads (GstGpacMux * gpac_mux)
melunko@920
   636
{
melunko@920
   637
  GstGpacPad *bestpad = NULL;//, *still_hungry = NULL;
melunko@920
   638
  GSList *iter;
melunko@920
   639
melunko@920
   640
  /* try to make sure we have a buffer from each usable pad first */
melunko@920
   641
  iter = gpac_mux->collect->data;
melunko@920
   642
  while (iter) {
melunko@920
   643
    GstGpacPad *pad;
melunko@920
   644
    GstCollectData *data;
melunko@920
   645
melunko@920
   646
    data = (GstCollectData *) iter->data;
melunko@920
   647
    pad = (GstGpacPad *) data;
melunko@920
   648
melunko@920
   649
    iter = g_slist_next (iter);
melunko@920
   650
melunko@920
   651
    GST_LOG_OBJECT (data->pad, "looking at pad for buffer");
melunko@920
   652
melunko@920
   653
    /* try to get a new buffer for this pad if needed and possible */
melunko@920
   654
    if (pad->buffer == NULL) {
melunko@920
   655
      GstBuffer *buf;
melunko@920
   656
melunko@920
   657
      buf = gst_collect_pads_pop (gpac_mux->collect, data);
melunko@920
   658
      GST_LOG_OBJECT (data->pad, "popped buffer %" GST_PTR_FORMAT, buf);
melunko@920
   659
melunko@920
   660
      /* On EOS we get a NULL buffer */
melunko@920
   661
      if (buf == NULL) {
melunko@920
   662
              printf ("EENENENENENEND OF STREAM EOS\n");
melunko@920
   663
        GST_DEBUG_OBJECT (data->pad, "EOS on pad");
melunko@920
   664
        if (!pad->eos) {
melunko@920
   665
          /* it's no longer active */
melunko@920
   666
          gpac_mux->active_pads--;
melunko@920
   667
          pad->eos = TRUE;
melunko@920
   668
melunko@920
   669
        }
melunko@920
   670
      }
melunko@920
   671
melunko@920
   672
      pad->buffer = buf;
melunko@920
   673
    } 
melunko@920
   674
melunko@920
   675
    /* we should have a buffer now, see if it is the best pad to
melunko@920
   676
     * pull on */
melunko@920
   677
      if (gst_gpac_mux_compare_pads (gpac_mux, bestpad, pad) > 0) {
melunko@920
   678
        GST_LOG_OBJECT (data->pad,
melunko@920
   679
            "new best pad, with buffers %" GST_PTR_FORMAT, pad->buffer);
melunko@920
   680
        bestpad = pad;
melunko@920
   681
      }
melunko@920
   682
  }
melunko@920
   683
 
melunko@920
   684
  return bestpad;
melunko@920
   685
}
melunko@920
   686
melunko@920
   687
static gint
melunko@920
   688
gst_gpac_mux_compare_pads (GstGpacMux * ogg_mux, GstGpacPad *first,
melunko@920
   689
    GstGpacPad *second)
melunko@920
   690
{
melunko@920
   691
  guint64 firsttime, secondtime;
melunko@920
   692
melunko@920
   693
  /* if the first pad doesn't contain anything or is even NULL, return
melunko@920
   694
   * the second pad as best candidate and vice versa */
melunko@920
   695
  if (first == NULL || (first->buffer == NULL))
melunko@920
   696
    return 1;
melunko@920
   697
  if (second == NULL || (second->buffer == NULL))
melunko@920
   698
    return -1;
melunko@920
   699
melunko@920
   700
  /* no timestamp on first buffer, it must go first */
melunko@920
   701
  if (first->buffer)
melunko@920
   702
    firsttime = GST_BUFFER_TIMESTAMP (first->buffer);
melunko@920
   703
  if (firsttime == GST_CLOCK_TIME_NONE)
melunko@920
   704
    return -1;
melunko@920
   705
melunko@920
   706
  /* no timestamp on second buffer, it must go first */
melunko@920
   707
  if (second->buffer)
melunko@920
   708
    secondtime = GST_BUFFER_TIMESTAMP (second->buffer);
melunko@920
   709
  if (secondtime == GST_CLOCK_TIME_NONE)
melunko@920
   710
    return 1;
melunko@920
   711
melunko@920
   712
  /* first buffer has higher timestamp, second one should go first */
melunko@920
   713
  if (secondtime < firsttime)
melunko@920
   714
    return 1;
melunko@920
   715
  /* second buffer has higher timestamp, first one should go first */
melunko@920
   716
  else if (secondtime > firsttime)
melunko@920
   717
    return -1;
melunko@920
   718
melunko@920
   719
  /* same priority if all of the above failed */
melunko@920
   720
  return 0;
melunko@920
   721
}
melunko@920
   722
melunko@920
   723
melunko@920
   724
melunko@917
   725
static gboolean
melunko@917
   726
gst_gpac_mux_plugin_init (GstPlugin * plugin)
melunko@917
   727
{
melunko@917
   728
  return gst_element_register (plugin, "gpacmux", GST_RANK_NONE,
melunko@917
   729
      GST_TYPE_GPAC_MUX);
melunko@917
   730
}
melunko@917
   731
melunko@917
   732
GST_PLUGIN_DEFINE(GST_VERSION_MAJOR,
melunko@917
   733
                  GST_VERSION_MINOR,
melunko@917
   734
                  "gpacmux",
melunko@917
   735
                  "Muxes audio and video",
melunko@917
   736
                  gst_gpac_mux_plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME,
melunko@917
   737
                  GST_PACKAGE_ORIGIN)
melunko@917
   738