diff -r be87d28e8371 -r d2bfa2e06cfa gst-gpac/src/gpacmux.c --- a/gst-gpac/src/gpacmux.c Thu Feb 21 17:44:16 2008 +0000 +++ b/gst-gpac/src/gpacmux.c Mon Mar 03 13:50:41 2008 +0000 @@ -35,9 +35,14 @@ gint track_number; guint32 di; /* outDescriptionIndex */ + GstBuffer *buffer; + GstBuffer *next_buffer; + guint32 frame_count; gboolean is_video; + gboolean eos; + } GstGpacPad; struct _GstGpacMux @@ -46,6 +51,7 @@ GstPad *srcpad; GstCollectPads *collect; + gint active_pads; GF_ISOFile *file; @@ -109,6 +115,13 @@ static GstStateChangeReturn gst_gpac_mux_change_state (GstElement * element, GstStateChange transition); +static GstGpacPad* gst_gpac_mux_queue_pads (GstGpacMux * gpac_mux); +static GstFlowReturn gst_gpac_mux_process_pad (GstGpacMux * gpac_mux, GstGpacPad *pad); +static gboolean gst_gpac_mux_all_pads_eos (GstCollectPads * pads); +static gint gst_gpac_mux_compare_pads (GstGpacMux * ogg_mux, GstGpacPad *first, + GstGpacPad *second); + + static GstElementClass *parent_class = NULL; GType @@ -216,13 +229,6 @@ GstGpacPad *gpacpad = (GstGpacPad *) data; GstBuffer *buf; -/* if (gpacpad->pagebuffers) { - while ((buf = g_queue_pop_head (gpacpad->pagebuffers)) != NULL) { - gst_buffer_unref (buf); - } - g_queue_free (gpacpad->pagebuffers); - gpacpad->pagebuffers = NULL; - }*/ } static GstPadLinkReturn @@ -282,7 +288,7 @@ /* create new pad with the name */ GST_DEBUG_OBJECT (gpac_mux, "Creating new pad for serial %d", serial); - printf ("XXXX new pad from template\n"); + newpad = gst_pad_new_from_template (templ, padname); g_free (padname); @@ -294,6 +300,7 @@ gpacpad = (GstGpacPad *) gst_collect_pads_add_pad_full (gpac_mux->collect, newpad, sizeof (GstGpacPad), gst_gpac_mux_gpac_pad_destroy_notify); + gpac_mux->active_pads++; /* gpac new track */ gpacpad->is_video = is_video; @@ -411,92 +418,128 @@ return gst_pad_push (mux->srcpad, buffer); } +static GstFlowReturn +gst_gpac_mux_collected (GstCollectPads * pads, GstGpacMux * gpac_mux) +{ + GstFlowReturn ret = GST_FLOW_OK; + GstGpacPad *pad; + gint active_before; + + GST_LOG_OBJECT (gpac_mux, "collected"); + + active_before = gpac_mux->active_pads; + + pad = gst_gpac_mux_queue_pads (gpac_mux); + if (!pad) { + return GST_FLOW_WRONG_STATE; + } + + if (pad->buffer) { + ret = gst_gpac_mux_process_pad (gpac_mux, pad); + } + + if (gpac_mux->active_pads < active_before) { + /* If the active pad count went down, this mean at least one pad has gone + * EOS. Since CollectPads only calls _collected() once when all pads are + * EOS, and our code doesn't _pop() from all pads we need to check that by + * peeking on all pads, else we won't be called again and the muxing will + * not terminate (push out EOS). */ + printf ("XXXX um pad foi desativado %" GST_PTR_FORMAT "\n", pad); + + /* if all the pads have been removed, flush all pending data */ + if ((ret == GST_FLOW_OK) && gst_gpac_mux_all_pads_eos (pads)) { + GST_LOG_OBJECT (gpac_mux, "no pads remaining, flushing data"); + + do { + pad = gst_gpac_mux_queue_pads (gpac_mux); + if (pad) + ret = gst_gpac_mux_process_pad (gpac_mux, pad); + } while ((ret == GST_FLOW_OK) && (pad != NULL)); + + /* gpac file close (eos) */ + // Fixme: this should flush all data to src pad + // Fixme: where to release gpac_mux->file? + printf ("CCCCCCCCCCCCCCCCcclosing the file\n"); + gf_isom_close (gpac_mux->file); + + + GST_DEBUG_OBJECT (gpac_mux, "Pushing EOS"); + gst_pad_push_event (gpac_mux->srcpad, gst_event_new_eos ()); + } + } + + return ret; + +} + static gboolean -all_pads_eos (GstCollectPads * pads) +gst_gpac_mux_all_pads_eos (GstCollectPads * pads) { - GSList *iter; + GSList *walk; gboolean alleos = TRUE; - iter = pads->data; - while (iter) { + walk = pads->data; + while (walk) { GstBuffer *buf; - GstCollectData *data = (GstCollectData *) iter->data; + GstCollectData *data = (GstCollectData *) walk->data; buf = gst_collect_pads_peek (pads, data); if (buf) { alleos = FALSE; gst_buffer_unref (buf); - goto beach; + break; } - iter = iter->next; + walk = walk->next; } -beach: + return alleos; } - + + static GstFlowReturn -gst_gpac_mux_collected (GstCollectPads * pads, GstGpacMux * gpac_mux) +gst_gpac_mux_process_pad (GstGpacMux *gpac_mux, GstGpacPad *pad) { GstFlowReturn ret = GST_FLOW_OK; - GSList *iter; - GstBuffer *buf; - gint i = 0; + GF_ISOSample *sample; - GST_LOG_OBJECT (gpac_mux, "collected"); - - iter = gpac_mux->collect->data; - while (iter) { - GstCollectData *data = (GstCollectData *) iter->data; - GstGpacPad *pad = (GstGpacPad *) data; - - buf = gst_collect_pads_pop (gpac_mux->collect, data); - if (buf == NULL) { - iter = g_slist_next (iter); - continue; - } - GST_LOG_OBJECT (data->pad, "popped buffer %" GST_PTR_FORMAT, buf); - - /* gpac output */ - printf ("xxxxxx buffer size: %d\n", GST_BUFFER_SIZE(buf)); fflush (stdout); - if (pad->frame_count < 300) { - GF_ISOSample *sample = gf_isom_sample_new(); - - sample->dataLength = GST_BUFFER_SIZE(buf); - sample->data = GST_BUFFER_DATA(buf); - sample->CTS_Offset = 0; - - if (pad->is_video) { - sample->IsRAP = 0; - sample->DTS += 1000*pad->frame_count; - } else { - sample->IsRAP = 0; - sample->DTS = 2048*pad->frame_count; - } - - gf_isom_add_sample(gpac_mux->file, pad->track_number, - pad->di, sample); - sample->data = NULL; - - gf_isom_sample_del(&sample); - - printf ("xxxx frames %d\n", pad->frame_count); - - } else if (pad->frame_count == 300) { - printf ("XXX closing gpac output file\n"); fflush (stdout); - gf_isom_close (gpac_mux->file); - } - - /* gstreamer output (push) */ - if (gst_gpac_mux_push_buffer (gpac_mux, buf) != GST_FLOW_OK) { - printf ("EEEEEEEE push failed\n"); - } - - iter = g_slist_next (iter); - pad->frame_count++; - i++; + if (pad->buffer == NULL) { + printf ("Buffer is null, wrong state\n"); + return GST_FLOW_WRONG_STATE; } - /* fixme */ + /* gpac output */ + printf ("xxxxxx buffer size: %d\n", GST_BUFFER_SIZE(pad->buffer)); fflush (stdout); + printf ("xxxx frames %d\n", pad->frame_count); + + sample = gf_isom_sample_new(); + sample->dataLength = GST_BUFFER_SIZE(pad->buffer); + sample->data = GST_BUFFER_DATA(pad->buffer); + sample->CTS_Offset = 0; + + if (pad->is_video) { + sample->IsRAP = 0; + sample->DTS += 1000*pad->frame_count; + } else { + sample->IsRAP = 0; + sample->DTS = 2048*pad->frame_count; + } + + gf_isom_add_sample(gpac_mux->file, pad->track_number, + pad->di, sample); + sample->data = NULL; + + gf_isom_sample_del(&sample); + + + /* gstreamer output (push) */ + ret = gst_gpac_mux_push_buffer (gpac_mux, pad->buffer); + pad->buffer = NULL; + + if (ret != GST_FLOW_OK) { + } + + pad->frame_count++; + return ret; } @@ -504,13 +547,13 @@ static void gst_gpac_mux_init_collectpads (GstCollectPads * collect) { - GSList *walk; + GSList *iter; - walk = collect->data; - while (walk) { - GstGpacPad *gpacpad = (GstGpacPad *) walk->data; + iter = collect->data; + while (iter) { + GstGpacPad *gpacpad = (GstGpacPad *) iter->data; - //ogg_stream_init (&gpacpad->stream, gpacpad->serial); + //gpac_stream_init (&gpacpad->stream, gpacpad->serial); //gpacpad->packetno = 0; //gpacpad->pageno = 0; //gpacpad->eos = FALSE; @@ -521,7 +564,7 @@ //gpacpad->prev_delta = FALSE; //gpacpad->pagebuffers = g_queue_new (); - walk = g_slist_next (walk); + iter = g_slist_next (iter); } } @@ -529,10 +572,10 @@ static void gst_gpac_mux_clear_collectpads (GstCollectPads * collect) { - GSList *walk; + GSList *iter; - for (walk = collect->data; walk; walk = g_slist_next (walk)) { - GstGpacPad *gpacpad = (GstGpacPad *) walk->data; + for (iter = collect->data; iter; iter = g_slist_next (iter)) { + GstGpacPad *gpacpad = (GstGpacPad *) iter->data; GstBuffer *buf; //gpac_stream_clear (&gpacpad->stream); @@ -588,6 +631,97 @@ } +static GstGpacPad * +gst_gpac_mux_queue_pads (GstGpacMux * gpac_mux) +{ + GstGpacPad *bestpad = NULL;//, *still_hungry = NULL; + GSList *iter; + + /* try to make sure we have a buffer from each usable pad first */ + iter = gpac_mux->collect->data; + while (iter) { + GstGpacPad *pad; + GstCollectData *data; + + data = (GstCollectData *) iter->data; + pad = (GstGpacPad *) data; + + iter = g_slist_next (iter); + + GST_LOG_OBJECT (data->pad, "looking at pad for buffer"); + + /* try to get a new buffer for this pad if needed and possible */ + if (pad->buffer == NULL) { + GstBuffer *buf; + + buf = gst_collect_pads_pop (gpac_mux->collect, data); + GST_LOG_OBJECT (data->pad, "popped buffer %" GST_PTR_FORMAT, buf); + + /* On EOS we get a NULL buffer */ + if (buf == NULL) { + printf ("EENENENENENEND OF STREAM EOS\n"); + GST_DEBUG_OBJECT (data->pad, "EOS on pad"); + if (!pad->eos) { + /* it's no longer active */ + gpac_mux->active_pads--; + pad->eos = TRUE; + + } + } + + pad->buffer = buf; + } + + /* we should have a buffer now, see if it is the best pad to + * pull on */ + if (gst_gpac_mux_compare_pads (gpac_mux, bestpad, pad) > 0) { + GST_LOG_OBJECT (data->pad, + "new best pad, with buffers %" GST_PTR_FORMAT, pad->buffer); + bestpad = pad; + } + } + + return bestpad; +} + +static gint +gst_gpac_mux_compare_pads (GstGpacMux * ogg_mux, GstGpacPad *first, + GstGpacPad *second) +{ + guint64 firsttime, secondtime; + + /* if the first pad doesn't contain anything or is even NULL, return + * the second pad as best candidate and vice versa */ + if (first == NULL || (first->buffer == NULL)) + return 1; + if (second == NULL || (second->buffer == NULL)) + return -1; + + /* no timestamp on first buffer, it must go first */ + if (first->buffer) + firsttime = GST_BUFFER_TIMESTAMP (first->buffer); + if (firsttime == GST_CLOCK_TIME_NONE) + return -1; + + /* no timestamp on second buffer, it must go first */ + if (second->buffer) + secondtime = GST_BUFFER_TIMESTAMP (second->buffer); + if (secondtime == GST_CLOCK_TIME_NONE) + return 1; + + /* first buffer has higher timestamp, second one should go first */ + if (secondtime < firsttime) + return 1; + /* second buffer has higher timestamp, first one should go first */ + else if (secondtime > firsttime) + return -1; + + /* same priority if all of the above failed */ + return 0; +} + + + static gboolean gst_gpac_mux_plugin_init (GstPlugin * plugin) {