melunko@917: melunko@917: #ifdef HAVE_CONFIG_H melunko@917: #include "config.h" melunko@917: #endif melunko@917: melunko@917: #include melunko@917: #include melunko@917: melunko@917: #include melunko@917: #include melunko@917: melunko@917: /* gpac includes */ melunko@917: #include melunko@917: melunko@917: #define GST_TYPE_GPAC_MUX (gst_gpac_mux_get_type()) melunko@917: #define GST_GPAC_MUX(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_GPAC_MUX, GstGpacMux)) melunko@917: #define GST_GPAC_MUX_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_GPAC_MUX, GstGpacMux)) melunko@917: #define GST_IS_GPAC_MUX(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_GPAC_MUX)) melunko@917: #define GST_IS_GPAC_MUX_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_GPAC_MUX)) melunko@917: melunko@917: typedef struct _GstGpacMux GstGpacMux; melunko@917: typedef struct _GstGpacMuxClass GstGpacMuxClass; melunko@917: melunko@917: typedef enum melunko@917: { melunko@917: GST_GPAC_PAD_STATE_CONTROL = 0, melunko@917: GST_GPAC_PAD_STATE_DATA = 1 melunko@917: } melunko@917: GstGpacPadState; melunko@917: melunko@917: typedef struct melunko@917: { melunko@917: GstCollectData collect; /* we extend the CollectData */ melunko@917: melunko@917: gint track_number; melunko@917: guint32 di; /* outDescriptionIndex */ melunko@917: melunko@920: GstBuffer *buffer; melunko@920: GstBuffer *next_buffer; melunko@920: melunko@917: guint32 frame_count; melunko@917: gboolean is_video; melunko@917: melunko@920: gboolean eos; melunko@920: melunko@917: } GstGpacPad; melunko@917: melunko@917: struct _GstGpacMux melunko@917: { melunko@917: GstElement element; melunko@917: melunko@917: GstPad *srcpad; melunko@917: GstCollectPads *collect; melunko@920: gint active_pads; melunko@917: melunko@917: GF_ISOFile *file; melunko@917: melunko@917: }; melunko@917: melunko@917: struct _GstGpacMuxClass melunko@917: { melunko@917: GstElementClass parent_class; melunko@917: }; melunko@917: melunko@917: /* elementfactory information */ melunko@917: static const GstElementDetails gst_gpac_mux_details = melunko@917: GST_ELEMENT_DETAILS ("Gpac muxer", melunko@917: "Codec/Muxer", melunko@917: "mux mp4 streams", melunko@917: "Hallyson Melo finalize = gst_gpac_mux_finalize; melunko@917: melunko@917: gstelement_class->request_new_pad = gst_gpac_mux_request_new_pad; melunko@917: gstelement_class->release_pad = gst_gpac_mux_release_pad; melunko@917: melunko@917: gstelement_class->change_state = gst_gpac_mux_change_state; melunko@917: melunko@917: } melunko@917: melunko@917: static void melunko@917: gst_gpac_mux_init (GstGpacMux * gpac_mux) melunko@917: { melunko@917: GstElementClass *klass = GST_ELEMENT_GET_CLASS (gpac_mux); melunko@917: melunko@917: gpac_mux->srcpad = melunko@917: gst_pad_new_from_template (gst_element_class_get_pad_template (klass, melunko@917: "src"), "src"); melunko@917: gst_pad_set_event_function (gpac_mux->srcpad, gst_gpac_mux_handle_src_event); melunko@917: gst_element_add_pad (GST_ELEMENT (gpac_mux), gpac_mux->srcpad); melunko@917: melunko@917: gpac_mux->collect = gst_collect_pads_new (); melunko@917: gst_collect_pads_set_function (gpac_mux->collect, melunko@917: (GstCollectPadsFunction) GST_DEBUG_FUNCPTR (gst_gpac_mux_collected), melunko@917: gpac_mux); melunko@917: melunko@917: /* Opens gpac library */ melunko@917: /* FIXME */ melunko@917: gpac_mux->file = gf_isom_open("/tmp/gpac.mp4", GF_ISOM_OPEN_WRITE, NULL); melunko@917: gf_isom_set_storage_mode(gpac_mux->file, GF_ISOM_STORE_FLAT /*STREAMABLE*/); melunko@917: melunko@917: //gst_gpac_mux_clear (gpac_mux); melunko@917: } melunko@917: melunko@917: static void melunko@917: gst_gpac_mux_finalize (GObject * object) melunko@917: { melunko@917: GstGpacMux *gpac_mux; melunko@917: melunko@917: gpac_mux = GST_GPAC_MUX (object); melunko@917: melunko@917: if (gpac_mux->collect) { melunko@917: gst_object_unref (gpac_mux->collect); melunko@917: gpac_mux->collect = NULL; melunko@917: } melunko@917: melunko@917: G_OBJECT_CLASS (parent_class)->finalize (object); melunko@917: } melunko@917: melunko@917: static void melunko@917: gst_gpac_mux_gpac_pad_destroy_notify (GstCollectData * data) melunko@917: { melunko@917: GstGpacPad *gpacpad = (GstGpacPad *) data; melunko@917: GstBuffer *buf; melunko@917: melunko@917: } melunko@917: melunko@917: static GstPadLinkReturn melunko@917: gst_gpac_mux_sinkconnect (GstPad * pad, GstPad * peer) melunko@917: { melunko@917: GstGpacMux *gpac_mux; melunko@917: melunko@917: gpac_mux = GST_GPAC_MUX (gst_pad_get_parent (pad)); melunko@917: melunko@917: GST_DEBUG_OBJECT (gpac_mux, "sinkconnect triggered on %s", GST_PAD_NAME (pad)); melunko@917: melunko@917: gst_object_unref (gpac_mux); melunko@917: melunko@917: return GST_PAD_LINK_OK; melunko@917: } melunko@917: melunko@917: static GstPad * melunko@917: gst_gpac_mux_request_new_pad (GstElement * element, melunko@917: GstPadTemplate * templ, const gchar * req_name) melunko@917: { melunko@917: GstGpacMux *gpac_mux; melunko@917: GstPad *newpad; melunko@917: GstElementClass *klass; melunko@917: gchar *padname = NULL; melunko@917: gint serial; melunko@917: gboolean is_video = FALSE; melunko@917: melunko@917: g_return_val_if_fail (templ != NULL, NULL); melunko@917: melunko@917: if (templ->direction != GST_PAD_SINK) melunko@917: goto wrong_direction; melunko@917: melunko@917: g_return_val_if_fail (GST_IS_GPAC_MUX (element), NULL); melunko@917: gpac_mux = GST_GPAC_MUX (element); melunko@917: melunko@917: klass = GST_ELEMENT_GET_CLASS (element); melunko@917: melunko@917: if (req_name == NULL || strlen (req_name) < 6) { melunko@917: /* no name given when requesting the pad, use random serial number */ melunko@917: serial = rand (); melunko@917: } else { melunko@917: /* parse serial number from requested padname */ melunko@917: serial = atoi (&req_name[5]); melunko@917: } melunko@917: melunko@917: if (templ == gst_element_class_get_pad_template (klass, "video_%d")) { melunko@917: is_video = TRUE; melunko@917: padname = g_strdup_printf ("video_%d", serial); melunko@917: } else if (templ != gst_element_class_get_pad_template (klass, "audio_%d")) { melunko@917: goto wrong_template; melunko@917: } else { melunko@917: padname = g_strdup_printf ("audio_%d", serial); melunko@917: } melunko@917: melunko@917: melunko@917: { melunko@917: melunko@917: /* create new pad with the name */ melunko@917: GST_DEBUG_OBJECT (gpac_mux, "Creating new pad for serial %d", serial); melunko@920: melunko@917: newpad = gst_pad_new_from_template (templ, padname); melunko@917: g_free (padname); melunko@917: melunko@917: /* construct our own wrapper data structure for the pad to melunko@917: * keep track of its status */ melunko@917: { melunko@917: GstGpacPad *gpacpad; melunko@917: melunko@917: gpacpad = (GstGpacPad *) melunko@917: gst_collect_pads_add_pad_full (gpac_mux->collect, newpad, melunko@917: sizeof (GstGpacPad), gst_gpac_mux_gpac_pad_destroy_notify); melunko@920: gpac_mux->active_pads++; melunko@917: melunko@917: /* gpac new track */ melunko@917: gpacpad->is_video = is_video; melunko@917: if (gpacpad->is_video) { melunko@917: gpacpad->track_number = gf_isom_new_track(gpac_mux->file, 0, melunko@917: GF_ISOM_MEDIA_VISUAL, 10 * 1000 /* time scale */); melunko@917: } else { melunko@917: gpacpad->track_number = gf_isom_new_track(gpac_mux->file, 0, melunko@917: GF_ISOM_MEDIA_AUDIO, 48000 /*time scale */); melunko@917: melunko@917: } melunko@917: if (gpacpad->track_number == 0) { melunko@917: g_warning ("Error while adding the new gpac track"); melunko@917: } else { melunko@917: gf_isom_set_track_enabled(gpac_mux->file, gpacpad->track_number, 1); melunko@917: if (is_video) { melunko@917: GF_ESD *esd = gf_odf_desc_esd_new (0); melunko@917: esd->ESID = gf_isom_get_track_id(gpac_mux->file, gpacpad->track_number); melunko@917: melunko@917: gf_isom_new_mpeg4_description( gpac_mux->file, gpacpad->track_number, melunko@917: esd, NULL, NULL, &(gpacpad->di)); melunko@917: melunko@917: gf_isom_set_visual_info (gpac_mux->file, gpacpad->track_number, gpacpad->di, 320, 240);//fixme melunko@917: //gf_isom_set_cts_packing (gpac_mux->file, gpacpad->track_number, 0); melunko@917: } else { melunko@917: GF_ESD *esd = gf_odf_desc_esd_new (2); melunko@917: esd->ESID = gf_isom_get_track_id(gpac_mux->file, gpacpad->track_number); melunko@917: melunko@917: gf_isom_new_mpeg4_description(gpac_mux->file, gpacpad->track_number, melunko@917: esd, NULL, NULL, &(gpacpad->di)); melunko@917: melunko@917: gf_isom_set_audio_info(gpac_mux->file, gpacpad->track_number, melunko@917: gpacpad->di, 48000, 2 /*num channels */, 16); melunko@917: } melunko@917: } melunko@917: } melunko@917: } melunko@917: melunko@917: /* setup some pad functions */ melunko@917: gst_pad_set_link_function (newpad, gst_gpac_mux_sinkconnect); melunko@917: /* dd the pad to the element */ melunko@917: gst_element_add_pad (element, newpad); melunko@917: melunko@917: return newpad; melunko@917: melunko@917: /* ERRORS */ melunko@917: wrong_direction: melunko@917: { melunko@917: g_warning ("gpac_mux: request pad that is not a SINK pad\n"); melunko@917: return NULL; melunko@917: } melunko@917: wrong_template: melunko@917: { melunko@917: g_warning ("gpac_mux: this is not our template!\n"); melunko@917: return NULL; melunko@917: } melunko@917: } melunko@917: melunko@917: static void melunko@917: gst_gpac_mux_release_pad (GstElement * element, GstPad * pad) melunko@917: { melunko@917: GstGpacMux *gpac_mux; melunko@917: melunko@917: gpac_mux = GST_GPAC_MUX (gst_pad_get_parent (pad)); melunko@917: melunko@917: gst_collect_pads_remove_pad (gpac_mux->collect, pad); melunko@917: gst_element_remove_pad (element, pad); melunko@917: } melunko@917: melunko@917: /* handle events */ melunko@917: static gboolean melunko@917: gst_gpac_mux_handle_src_event (GstPad * pad, GstEvent * event) melunko@917: { melunko@917: GstEventType type; melunko@917: melunko@917: type = event ? GST_EVENT_TYPE (event) : GST_EVENT_UNKNOWN; melunko@917: melunko@917: switch (type) { melunko@917: case GST_EVENT_SEEK: melunko@917: /* disable seeking for now */ melunko@917: return FALSE; melunko@917: default: melunko@917: break; melunko@917: } melunko@917: melunko@917: return gst_pad_event_default (pad, event); melunko@917: } melunko@917: melunko@917: static GstFlowReturn melunko@917: gst_gpac_mux_push_buffer (GstGpacMux * mux, GstBuffer * buffer) melunko@917: { melunko@917: GstCaps *caps; melunko@917: #if 0 melunko@917: /* fix up OFFSET and OFFSET_END again */ melunko@917: GST_BUFFER_OFFSET (buffer) = mux->offset; melunko@917: mux->offset += GST_BUFFER_SIZE (buffer); melunko@917: GST_BUFFER_OFFSET_END (buffer) = mux->offset; melunko@917: melunko@917: /* Ensure we have monotonically increasing timestamps in the output. */ melunko@917: if (GST_BUFFER_TIMESTAMP_IS_VALID (buffer)) { melunko@917: if (mux->last_ts != GST_CLOCK_TIME_NONE && melunko@917: GST_BUFFER_TIMESTAMP (buffer) < mux->last_ts) melunko@917: GST_BUFFER_TIMESTAMP (buffer) = mux->last_ts; melunko@917: else melunko@917: mux->last_ts = GST_BUFFER_TIMESTAMP (buffer); melunko@917: } melunko@917: #endif melunko@917: melunko@917: caps = gst_pad_get_negotiated_caps (mux->srcpad); melunko@917: gst_buffer_set_caps (buffer, caps); melunko@917: if (caps != NULL) { melunko@917: gst_caps_unref (caps); melunko@917: } melunko@917: melunko@917: return gst_pad_push (mux->srcpad, buffer); melunko@917: } melunko@917: melunko@920: static GstFlowReturn melunko@920: gst_gpac_mux_collected (GstCollectPads * pads, GstGpacMux * gpac_mux) melunko@920: { melunko@920: GstFlowReturn ret = GST_FLOW_OK; melunko@920: GstGpacPad *pad; melunko@920: gint active_before; melunko@920: melunko@920: GST_LOG_OBJECT (gpac_mux, "collected"); melunko@920: melunko@920: active_before = gpac_mux->active_pads; melunko@920: melunko@920: pad = gst_gpac_mux_queue_pads (gpac_mux); melunko@920: if (!pad) { melunko@920: return GST_FLOW_WRONG_STATE; melunko@920: } melunko@920: melunko@920: if (pad->buffer) { melunko@920: ret = gst_gpac_mux_process_pad (gpac_mux, pad); melunko@920: } melunko@920: melunko@920: if (gpac_mux->active_pads < active_before) { melunko@920: /* If the active pad count went down, this mean at least one pad has gone melunko@920: * EOS. Since CollectPads only calls _collected() once when all pads are melunko@920: * EOS, and our code doesn't _pop() from all pads we need to check that by melunko@920: * peeking on all pads, else we won't be called again and the muxing will melunko@920: * not terminate (push out EOS). */ melunko@920: printf ("XXXX um pad foi desativado %" GST_PTR_FORMAT "\n", pad); melunko@920: melunko@920: /* if all the pads have been removed, flush all pending data */ melunko@920: if ((ret == GST_FLOW_OK) && gst_gpac_mux_all_pads_eos (pads)) { melunko@920: GST_LOG_OBJECT (gpac_mux, "no pads remaining, flushing data"); melunko@920: melunko@920: do { melunko@920: pad = gst_gpac_mux_queue_pads (gpac_mux); melunko@920: if (pad) melunko@920: ret = gst_gpac_mux_process_pad (gpac_mux, pad); melunko@920: } while ((ret == GST_FLOW_OK) && (pad != NULL)); melunko@920: melunko@920: /* gpac file close (eos) */ melunko@920: // Fixme: this should flush all data to src pad melunko@920: // Fixme: where to release gpac_mux->file? melunko@920: printf ("CCCCCCCCCCCCCCCCcclosing the file\n"); melunko@920: gf_isom_close (gpac_mux->file); melunko@920: melunko@920: melunko@920: GST_DEBUG_OBJECT (gpac_mux, "Pushing EOS"); melunko@920: gst_pad_push_event (gpac_mux->srcpad, gst_event_new_eos ()); melunko@920: } melunko@920: } melunko@920: melunko@920: return ret; melunko@920: melunko@920: } melunko@920: melunko@917: static gboolean melunko@920: gst_gpac_mux_all_pads_eos (GstCollectPads * pads) melunko@917: { melunko@920: GSList *walk; melunko@917: gboolean alleos = TRUE; melunko@917: melunko@920: walk = pads->data; melunko@920: while (walk) { melunko@917: GstBuffer *buf; melunko@920: GstCollectData *data = (GstCollectData *) walk->data; melunko@917: melunko@917: buf = gst_collect_pads_peek (pads, data); melunko@917: if (buf) { melunko@917: alleos = FALSE; melunko@917: gst_buffer_unref (buf); melunko@920: break; melunko@917: } melunko@920: walk = walk->next; melunko@917: } melunko@920: melunko@917: return alleos; melunko@917: } melunko@920: melunko@920: melunko@917: static GstFlowReturn melunko@920: gst_gpac_mux_process_pad (GstGpacMux *gpac_mux, GstGpacPad *pad) melunko@917: { melunko@917: GstFlowReturn ret = GST_FLOW_OK; melunko@920: GF_ISOSample *sample; melunko@917: melunko@920: if (pad->buffer == NULL) { melunko@920: printf ("Buffer is null, wrong state\n"); melunko@920: return GST_FLOW_WRONG_STATE; melunko@917: } melunko@917: melunko@920: /* gpac output */ melunko@920: printf ("xxxxxx buffer size: %d\n", GST_BUFFER_SIZE(pad->buffer)); fflush (stdout); melunko@920: printf ("xxxx frames %d\n", pad->frame_count); melunko@920: melunko@920: sample = gf_isom_sample_new(); melunko@920: sample->dataLength = GST_BUFFER_SIZE(pad->buffer); melunko@920: sample->data = GST_BUFFER_DATA(pad->buffer); melunko@920: sample->CTS_Offset = 0; melunko@920: melunko@920: if (pad->is_video) { melunko@920: sample->IsRAP = 0; melunko@920: sample->DTS += 1000*pad->frame_count; melunko@920: } else { melunko@920: sample->IsRAP = 0; melunko@920: sample->DTS = 2048*pad->frame_count; melunko@920: } melunko@920: melunko@920: gf_isom_add_sample(gpac_mux->file, pad->track_number, melunko@920: pad->di, sample); melunko@920: sample->data = NULL; melunko@920: melunko@920: gf_isom_sample_del(&sample); melunko@920: melunko@920: melunko@920: /* gstreamer output (push) */ melunko@920: ret = gst_gpac_mux_push_buffer (gpac_mux, pad->buffer); melunko@920: pad->buffer = NULL; melunko@920: melunko@920: if (ret != GST_FLOW_OK) { melunko@920: } melunko@920: melunko@920: pad->frame_count++; melunko@920: melunko@917: return ret; melunko@917: } melunko@917: melunko@917: /* reset all variables in the gpac pads. */ melunko@917: static void melunko@917: gst_gpac_mux_init_collectpads (GstCollectPads * collect) melunko@917: { melunko@920: GSList *iter; melunko@917: melunko@920: iter = collect->data; melunko@920: while (iter) { melunko@920: GstGpacPad *gpacpad = (GstGpacPad *) iter->data; melunko@917: melunko@920: //gpac_stream_init (&gpacpad->stream, gpacpad->serial); melunko@917: //gpacpad->packetno = 0; melunko@917: //gpacpad->pageno = 0; melunko@917: //gpacpad->eos = FALSE; melunko@917: /* we assume there will be some control data first for this pad */ melunko@917: //gpacpad->state = GST_GPAC_PAD_STATE_CONTROL; melunko@917: //gpacpad->new_page = TRUE; melunko@917: //gpacpad->first_delta = FALSE; melunko@917: //gpacpad->prev_delta = FALSE; melunko@917: //gpacpad->pagebuffers = g_queue_new (); melunko@917: melunko@920: iter = g_slist_next (iter); melunko@917: } melunko@917: } melunko@917: melunko@917: /* Clear all buffers from the collectpads object */ melunko@917: static void melunko@917: gst_gpac_mux_clear_collectpads (GstCollectPads * collect) melunko@917: { melunko@920: GSList *iter; melunko@917: melunko@920: for (iter = collect->data; iter; iter = g_slist_next (iter)) { melunko@920: GstGpacPad *gpacpad = (GstGpacPad *) iter->data; melunko@917: GstBuffer *buf; melunko@917: melunko@917: //gpac_stream_clear (&gpacpad->stream); melunko@917: /* melunko@917: while ((buf = g_queue_pop_head (gpacpad->pagebuffers)) != NULL) { melunko@917: gst_buffer_unref (buf); melunko@917: } melunko@917: g_queue_free (gpacpad->pagebuffers); melunko@917: gpacpad->pagebuffers = NULL;*/ melunko@917: } melunko@917: } melunko@917: melunko@917: static GstStateChangeReturn melunko@917: gst_gpac_mux_change_state (GstElement * element, GstStateChange transition) melunko@917: { melunko@917: GstGpacMux *gpac_mux; melunko@917: GstStateChangeReturn ret; melunko@917: melunko@917: gpac_mux = GST_GPAC_MUX (element); melunko@917: melunko@917: switch (transition) { melunko@917: case GST_STATE_CHANGE_NULL_TO_READY: melunko@917: break; melunko@917: case GST_STATE_CHANGE_READY_TO_PAUSED: melunko@917: //gst_gpac_mux_clear (gpac_mux); melunko@917: //gst_gpac_mux_init_collectpads (gpac_mux->collect); melunko@917: gst_collect_pads_start (gpac_mux->collect); melunko@917: break; melunko@917: case GST_STATE_CHANGE_PAUSED_TO_PLAYING: melunko@917: break; melunko@917: case GST_STATE_CHANGE_PAUSED_TO_READY: melunko@917: gst_collect_pads_stop (gpac_mux->collect); melunko@917: break; melunko@917: default: melunko@917: break; melunko@917: } melunko@917: melunko@917: ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); melunko@917: melunko@917: switch (transition) { melunko@917: case GST_STATE_CHANGE_PLAYING_TO_PAUSED: melunko@917: break; melunko@917: case GST_STATE_CHANGE_PAUSED_TO_READY: melunko@917: gst_gpac_mux_clear_collectpads (gpac_mux->collect); melunko@917: break; melunko@917: case GST_STATE_CHANGE_READY_TO_NULL: melunko@917: break; melunko@917: default: melunko@917: break; melunko@917: } melunko@917: melunko@917: return ret; melunko@917: melunko@917: } melunko@917: melunko@920: static GstGpacPad * melunko@920: gst_gpac_mux_queue_pads (GstGpacMux * gpac_mux) melunko@920: { melunko@920: GstGpacPad *bestpad = NULL;//, *still_hungry = NULL; melunko@920: GSList *iter; melunko@920: melunko@920: /* try to make sure we have a buffer from each usable pad first */ melunko@920: iter = gpac_mux->collect->data; melunko@920: while (iter) { melunko@920: GstGpacPad *pad; melunko@920: GstCollectData *data; melunko@920: melunko@920: data = (GstCollectData *) iter->data; melunko@920: pad = (GstGpacPad *) data; melunko@920: melunko@920: iter = g_slist_next (iter); melunko@920: melunko@920: GST_LOG_OBJECT (data->pad, "looking at pad for buffer"); melunko@920: melunko@920: /* try to get a new buffer for this pad if needed and possible */ melunko@920: if (pad->buffer == NULL) { melunko@920: GstBuffer *buf; melunko@920: melunko@920: buf = gst_collect_pads_pop (gpac_mux->collect, data); melunko@920: GST_LOG_OBJECT (data->pad, "popped buffer %" GST_PTR_FORMAT, buf); melunko@920: melunko@920: /* On EOS we get a NULL buffer */ melunko@920: if (buf == NULL) { melunko@920: printf ("EENENENENENEND OF STREAM EOS\n"); melunko@920: GST_DEBUG_OBJECT (data->pad, "EOS on pad"); melunko@920: if (!pad->eos) { melunko@920: /* it's no longer active */ melunko@920: gpac_mux->active_pads--; melunko@920: pad->eos = TRUE; melunko@920: melunko@920: } melunko@920: } melunko@920: melunko@920: pad->buffer = buf; melunko@920: } melunko@920: melunko@920: /* we should have a buffer now, see if it is the best pad to melunko@920: * pull on */ melunko@920: if (gst_gpac_mux_compare_pads (gpac_mux, bestpad, pad) > 0) { melunko@920: GST_LOG_OBJECT (data->pad, melunko@920: "new best pad, with buffers %" GST_PTR_FORMAT, pad->buffer); melunko@920: bestpad = pad; melunko@920: } melunko@920: } melunko@920: melunko@920: return bestpad; melunko@920: } melunko@920: melunko@920: static gint melunko@920: gst_gpac_mux_compare_pads (GstGpacMux * ogg_mux, GstGpacPad *first, melunko@920: GstGpacPad *second) melunko@920: { melunko@920: guint64 firsttime, secondtime; melunko@920: melunko@920: /* if the first pad doesn't contain anything or is even NULL, return melunko@920: * the second pad as best candidate and vice versa */ melunko@920: if (first == NULL || (first->buffer == NULL)) melunko@920: return 1; melunko@920: if (second == NULL || (second->buffer == NULL)) melunko@920: return -1; melunko@920: melunko@920: /* no timestamp on first buffer, it must go first */ melunko@920: if (first->buffer) melunko@920: firsttime = GST_BUFFER_TIMESTAMP (first->buffer); melunko@920: if (firsttime == GST_CLOCK_TIME_NONE) melunko@920: return -1; melunko@920: melunko@920: /* no timestamp on second buffer, it must go first */ melunko@920: if (second->buffer) melunko@920: secondtime = GST_BUFFER_TIMESTAMP (second->buffer); melunko@920: if (secondtime == GST_CLOCK_TIME_NONE) melunko@920: return 1; melunko@920: melunko@920: /* first buffer has higher timestamp, second one should go first */ melunko@920: if (secondtime < firsttime) melunko@920: return 1; melunko@920: /* second buffer has higher timestamp, first one should go first */ melunko@920: else if (secondtime > firsttime) melunko@920: return -1; melunko@920: melunko@920: /* same priority if all of the above failed */ melunko@920: return 0; melunko@920: } melunko@920: melunko@920: melunko@920: melunko@917: static gboolean melunko@917: gst_gpac_mux_plugin_init (GstPlugin * plugin) melunko@917: { melunko@917: return gst_element_register (plugin, "gpacmux", GST_RANK_NONE, melunko@917: GST_TYPE_GPAC_MUX); melunko@917: } melunko@917: melunko@917: GST_PLUGIN_DEFINE(GST_VERSION_MAJOR, melunko@917: GST_VERSION_MINOR, melunko@917: "gpacmux", melunko@917: "Muxes audio and video", melunko@917: gst_gpac_mux_plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, melunko@917: GST_PACKAGE_ORIGIN) melunko@917: