static GstFlowReturn gst_compare_collect_pads (GstCollectPads * cpads, GstCompare * comp) { GstBuffer *buf1, *buf2; buf1 = gst_collect_pads_pop (comp->cpads, gst_pad_get_element_private (comp->sinkpad)); buf2 = gst_collect_pads_pop (comp->cpads, gst_pad_get_element_private (comp->checkpad)); if (!buf1 && !buf2) { gst_pad_push_event (comp->srcpad, gst_event_new_eos ()); return GST_FLOW_UNEXPECTED; } else if (buf1 && buf2) { gst_compare_buffers (comp, buf1, buf2); } else { GST_WARNING_OBJECT (comp, "buffer %p != NULL", buf1 ? buf1 : buf2); comp->count++; gst_element_post_message (GST_ELEMENT (comp), gst_message_new_element (GST_OBJECT (comp), gst_structure_new ("delta", "count", G_TYPE_INT, comp->count, NULL))); } if (buf1) gst_pad_push (comp->srcpad, buf1); if (buf2) gst_buffer_unref (buf2); return GST_FLOW_OK; }
/* pop and unref the currently queued buffer, should e called with the LOCK * helt. */ static void gst_collect_pads_clear (GstCollectPads * pads, GstCollectData * data) { GstBuffer *buf; if ((buf = gst_collect_pads_pop (pads, data))) gst_buffer_unref (buf); }
static MpegPsPadData * mpegpsmux_choose_best_stream (MpegPsMux * mux) { /* Choose from which stream to mux with */ MpegPsPadData *best = NULL; GstCollectData *c_best = NULL; GSList *walk; for (walk = mux->collect->data; walk != NULL; walk = g_slist_next (walk)) { GstCollectData *c_data = (GstCollectData *) walk->data; MpegPsPadData *ps_data = (MpegPsPadData *) walk->data; if (ps_data->eos == FALSE) { if (ps_data->queued.buf == NULL) { GstBuffer *buf; buf = mpegpsmux_queue_buffer_for_stream (mux, ps_data); if (buf == NULL) { ps_data->eos = TRUE; continue; } /* Choose a stream we've never seen a timestamp for to ensure * we push enough buffers from it to reach a timestamp */ if (ps_data->last_ts == GST_CLOCK_TIME_NONE) { best = ps_data; c_best = c_data; } } /* If we don't yet have a best pad, take this one, otherwise take * whichever has the oldest timestamp */ if (best != NULL) { if (ps_data->last_ts != GST_CLOCK_TIME_NONE && best->last_ts != GST_CLOCK_TIME_NONE && ps_data->last_ts < best->last_ts) { best = ps_data; c_best = c_data; } } else { best = ps_data; c_best = c_data; } } } if (c_best) { gst_buffer_unref (gst_collect_pads_pop (mux->collect, c_best)); } return best; }
/* Function for sent each encoder instance to be process after collect the buffers in the sink pads */ GstFlowReturn gst_tidmai_base_video_dualencoder_entry_buffers_collected (GstCollectPads * pads, GstTIDmaiBaseVideoDualEncoder * video_dualencoder) { GST_DEBUG_OBJECT (video_dualencoder, "Entry gst_tidmai_base_video_dualencoder_entry_buffers_collected"); GstTIDmaiBaseDualEncoder *base_dualencoder = GST_TI_DMAI_BASE_DUALENCODER(video_dualencoder); GstFlowReturn ret; GstBuffer *low_res_buffer; GstBuffer *high_res_buffer; /* Obtain the buffers */ low_res_buffer = gst_collect_pads_pop (base_dualencoder->collect_sink_pads, base_dualencoder->low_resolution_encoder->collect); high_res_buffer = gst_collect_pads_pop (base_dualencoder->collect_sink_pads, base_dualencoder->high_resolution_encoder->collect); /* Process for the low resolution instance */ GST_DEBUG_OBJECT (video_dualencoder, "Process low resolution instance"); ret = gst_tidmai_base_video_dualencoder_realize_instance(video_dualencoder, base_dualencoder->low_resolution_encoder, low_res_buffer); /* Process for the high resolution instance */ GST_DEBUG_OBJECT (video_dualencoder, "Process high resolution instance"); ret = gst_tidmai_base_video_dualencoder_realize_instance(video_dualencoder, base_dualencoder->high_resolution_encoder, high_res_buffer); /* unref the buffer with the high-resolution for being reuse for the driver */ gst_buffer_unref(high_res_buffer); if(1 == GST_MINI_OBJECT_REFCOUNT(high_res_buffer)) { gst_buffer_unref(high_res_buffer); } GST_DEBUG_OBJECT (video_dualencoder, "Leave gst_tidmai_base_video_dualencoder_entry_buffers_collected"); return ret; }
static MpegTsPadData * mpegtsmux_choose_best_stream (MpegTsMux * mux) { MpegTsPadData *best = NULL; GstCollectData *c_best = NULL; GSList *walk; for (walk = mux->collect->data; walk != NULL; walk = g_slist_next (walk)) { GstCollectData *c_data = (GstCollectData *) walk->data; MpegTsPadData *ts_data = (MpegTsPadData *) walk->data; if (ts_data->eos == FALSE) { if (ts_data->queued_buf == NULL) { GstBuffer *buf; ts_data->queued_buf = buf = gst_collect_pads_peek (mux->collect, c_data); if (buf != NULL) { if (ts_data->prepare_func) { buf = ts_data->prepare_func (buf, ts_data, mux); if (buf) { /* Take the prepared buffer instead */ gst_buffer_unref (ts_data->queued_buf); ts_data->queued_buf = buf; } else { /* If data preparation returned NULL, use unprepared one */ buf = ts_data->queued_buf; } } if (GST_BUFFER_TIMESTAMP (buf) != GST_CLOCK_TIME_NONE) { /* Ignore timestamps that go backward for now. FIXME: Handle all * incoming PTS */ if (ts_data->last_ts == GST_CLOCK_TIME_NONE || ts_data->last_ts < GST_BUFFER_TIMESTAMP (buf)) { ts_data->cur_ts = ts_data->last_ts = gst_segment_to_running_time (&c_data->segment, GST_FORMAT_TIME, GST_BUFFER_TIMESTAMP (buf)); } else { GST_DEBUG_OBJECT (mux, "Ignoring PTS that has gone backward"); } } else ts_data->cur_ts = GST_CLOCK_TIME_NONE; GST_DEBUG_OBJECT (mux, "Pulled buffer with ts %" GST_TIME_FORMAT " (uncorrected ts %" GST_TIME_FORMAT " %" G_GUINT64_FORMAT ") for PID 0x%04x", GST_TIME_ARGS (ts_data->cur_ts), GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)), GST_BUFFER_TIMESTAMP (buf), ts_data->pid); /* Choose a stream we've never seen a timestamp for to ensure * we push enough buffers from it to reach a timestamp */ if (ts_data->last_ts == GST_CLOCK_TIME_NONE) { best = ts_data; c_best = c_data; } } else { ts_data->eos = TRUE; continue; } } /* If we don't yet have a best pad, take this one, otherwise take * whichever has the oldest timestamp */ if (best != NULL) { if (ts_data->last_ts != GST_CLOCK_TIME_NONE && best->last_ts != GST_CLOCK_TIME_NONE && ts_data->last_ts < best->last_ts) { best = ts_data; c_best = c_data; } } else { best = ts_data; c_best = c_data; } } } if (c_best) { gst_buffer_unref (gst_collect_pads_pop (mux->collect, c_best)); } return best; }
static GstFlowReturn gst_frei0r_mixer_collected (GstCollectPads * pads, GstFrei0rMixer * self) { GstBuffer *inbuf0 = NULL, *inbuf1 = NULL, *inbuf2 = NULL; GstBuffer *outbuf = NULL; GstFlowReturn ret = GST_FLOW_OK; GSList *l; GstFrei0rMixerClass *klass = GST_FREI0R_MIXER_GET_CLASS (self); GstClockTime timestamp; gdouble time; GstSegment *segment = NULL; GstAllocationParams alloc_params = { 0, 31, 0, 0 }; GstMapInfo outmap, inmap0, inmap1, inmap2; if (G_UNLIKELY (self->info.width <= 0 || self->info.height <= 0)) return GST_FLOW_NOT_NEGOTIATED; if (G_UNLIKELY (!self->f0r_instance)) { self->f0r_instance = gst_frei0r_instance_construct (klass->ftable, klass->properties, klass->n_properties, self->property_cache, self->info.width, self->info.height); if (G_UNLIKELY (!self->f0r_instance)) return GST_FLOW_ERROR; } if (self->segment_event) { gst_pad_push_event (self->src, self->segment_event); self->segment_event = NULL; } /* FIXME Request an allocator and/or pool */ outbuf = gst_buffer_new_allocate (NULL, self->info.size, &alloc_params); for (l = pads->data; l; l = l->next) { GstCollectData *cdata = l->data; if (cdata->pad == self->sink0) { inbuf0 = gst_collect_pads_pop (pads, cdata); segment = &cdata->segment; } else if (cdata->pad == self->sink1) { inbuf1 = gst_collect_pads_pop (pads, cdata); } else if (cdata->pad == self->sink2) { inbuf2 = gst_collect_pads_pop (pads, cdata); } } if (!inbuf0 || !inbuf1 || (!inbuf2 && self->sink2)) goto eos; gst_buffer_map (outbuf, &outmap, GST_MAP_READWRITE); gst_buffer_map (inbuf0, &inmap0, GST_MAP_READ); gst_buffer_map (inbuf1, &inmap1, GST_MAP_READ); if (inbuf2) gst_buffer_map (inbuf2, &inmap2, GST_MAP_READ); g_assert (segment != NULL); timestamp = GST_BUFFER_PTS (inbuf0); timestamp = gst_segment_to_stream_time (segment, GST_FORMAT_TIME, timestamp); GST_DEBUG_OBJECT (self, "sync to %" GST_TIME_FORMAT, GST_TIME_ARGS (timestamp)); if (GST_CLOCK_TIME_IS_VALID (timestamp)) gst_object_sync_values (GST_OBJECT (self), timestamp); gst_buffer_copy_into (outbuf, inbuf0, GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS, 0, -1); time = ((gdouble) GST_BUFFER_PTS (outbuf)) / GST_SECOND; GST_OBJECT_LOCK (self); klass->ftable->update2 (self->f0r_instance, time, (const guint32 *) inmap0.data, (const guint32 *) inmap1.data, (inbuf2) ? (const guint32 *) inmap2.data : NULL, (guint32 *) outmap.data); GST_OBJECT_UNLOCK (self); gst_buffer_unmap (outbuf, &outmap); gst_buffer_unref (inbuf0); gst_buffer_unmap (inbuf0, &inmap0); gst_buffer_unref (inbuf1); gst_buffer_unmap (inbuf1, &inmap1); if (inbuf2) { gst_buffer_unmap (inbuf2, &inmap2); gst_buffer_unref (inbuf2); } ret = gst_pad_push (self->src, outbuf); return ret; eos: { GST_DEBUG_OBJECT (self, "no data available, must be EOS"); gst_buffer_unref (outbuf); if (inbuf0) gst_buffer_unref (inbuf0); if (inbuf1) gst_buffer_unref (inbuf1); if (inbuf2) gst_buffer_unref (inbuf2); gst_pad_push_event (self->src, gst_event_new_eos ()); return GST_FLOW_EOS; } }
static GstFlowReturn gst_ffmpegmux_collected (GstCollectPads * pads, gpointer user_data) { GstFFMpegMux *ffmpegmux = (GstFFMpegMux *) user_data; GSList *collected; GstFFMpegMuxPad *best_pad; GstClockTime best_time; const GstTagList *tags; /* open "file" (gstreamer protocol to next element) */ if (!ffmpegmux->opened) { int open_flags = URL_WRONLY; /* we do need all streams to have started capsnego, * or things will go horribly wrong */ for (collected = ffmpegmux->collect->data; collected; collected = g_slist_next (collected)) { GstFFMpegMuxPad *collect_pad = (GstFFMpegMuxPad *) collected->data; AVStream *st = ffmpegmux->context->streams[collect_pad->padnum]; /* check whether the pad has successfully completed capsnego */ if (st->codec->codec_id == CODEC_ID_NONE) { GST_ELEMENT_ERROR (ffmpegmux, CORE, NEGOTIATION, (NULL), ("no caps set on stream %d (%s)", collect_pad->padnum, (st->codec->codec_type == CODEC_TYPE_VIDEO) ? "video" : "audio")); return GST_FLOW_ERROR; } /* set framerate for audio */ if (st->codec->codec_type == CODEC_TYPE_AUDIO) { switch (st->codec->codec_id) { case CODEC_ID_PCM_S16LE: case CODEC_ID_PCM_S16BE: case CODEC_ID_PCM_U16LE: case CODEC_ID_PCM_U16BE: case CODEC_ID_PCM_S8: case CODEC_ID_PCM_U8: st->codec->frame_size = 1; break; default: { GstBuffer *buffer; /* FIXME : This doesn't work for RAW AUDIO... * in fact I'm wondering if it even works for any kind of audio... */ buffer = gst_collect_pads_peek (ffmpegmux->collect, (GstCollectData *) collect_pad); if (buffer) { st->codec->frame_size = st->codec->sample_rate * GST_BUFFER_DURATION (buffer) / GST_SECOND; gst_buffer_unref (buffer); } } } } } /* tags */ tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (ffmpegmux)); if (tags) { gint i; gchar *s; /* get the interesting ones */ if (gst_tag_list_get_string (tags, GST_TAG_TITLE, &s)) { strncpy (ffmpegmux->context->title, s, sizeof (ffmpegmux->context->title)); } if (gst_tag_list_get_string (tags, GST_TAG_ARTIST, &s)) { strncpy (ffmpegmux->context->author, s, sizeof (ffmpegmux->context->author)); } if (gst_tag_list_get_string (tags, GST_TAG_COPYRIGHT, &s)) { strncpy (ffmpegmux->context->copyright, s, sizeof (ffmpegmux->context->copyright)); } if (gst_tag_list_get_string (tags, GST_TAG_COMMENT, &s)) { strncpy (ffmpegmux->context->comment, s, sizeof (ffmpegmux->context->comment)); } if (gst_tag_list_get_string (tags, GST_TAG_ALBUM, &s)) { strncpy (ffmpegmux->context->album, s, sizeof (ffmpegmux->context->album)); } if (gst_tag_list_get_string (tags, GST_TAG_GENRE, &s)) { strncpy (ffmpegmux->context->genre, s, sizeof (ffmpegmux->context->genre)); } if (gst_tag_list_get_int (tags, GST_TAG_TRACK_NUMBER, &i)) { ffmpegmux->context->track = i; } } /* set the streamheader flag for gstffmpegprotocol if codec supports it */ if (!strcmp (ffmpegmux->context->oformat->name, "flv")) { open_flags |= GST_FFMPEG_URL_STREAMHEADER; } if (url_fopen (&ffmpegmux->context->pb, ffmpegmux->context->filename, open_flags) < 0) { GST_ELEMENT_ERROR (ffmpegmux, LIBRARY, TOO_LAZY, (NULL), ("Failed to open stream context in ffmux")); return GST_FLOW_ERROR; } if (av_set_parameters (ffmpegmux->context, NULL) < 0) { GST_ELEMENT_ERROR (ffmpegmux, LIBRARY, INIT, (NULL), ("Failed to initialize muxer")); return GST_FLOW_ERROR; } /* now open the mux format */ if (av_write_header (ffmpegmux->context) < 0) { GST_ELEMENT_ERROR (ffmpegmux, LIBRARY, SETTINGS, (NULL), ("Failed to write file header - check codec settings")); return GST_FLOW_ERROR; } /* we're now opened */ ffmpegmux->opened = TRUE; /* flush the header so it will be used as streamheader */ put_flush_packet (ffmpegmux->context->pb); } /* take the one with earliest timestamp, * and push it forward */ best_pad = NULL; best_time = GST_CLOCK_TIME_NONE; for (collected = ffmpegmux->collect->data; collected; collected = g_slist_next (collected)) { GstFFMpegMuxPad *collect_pad = (GstFFMpegMuxPad *) collected->data; GstBuffer *buffer = gst_collect_pads_peek (ffmpegmux->collect, (GstCollectData *) collect_pad); /* if there's no buffer, just continue */ if (buffer == NULL) { continue; } /* if we have no buffer yet, just use the first one */ if (best_pad == NULL) { best_pad = collect_pad; best_time = GST_BUFFER_TIMESTAMP (buffer); goto next_pad; } /* if we do have one, only use this one if it's older */ if (GST_BUFFER_TIMESTAMP (buffer) < best_time) { best_time = GST_BUFFER_TIMESTAMP (buffer); best_pad = collect_pad; } next_pad: gst_buffer_unref (buffer); /* Mux buffers with invalid timestamp first */ if (!GST_CLOCK_TIME_IS_VALID (best_time)) break; } /* now handle the buffer, or signal EOS if we have * no buffers left */ if (best_pad != NULL) { GstBuffer *buf; AVPacket pkt; gboolean need_free = FALSE; /* push out current buffer */ buf = gst_collect_pads_pop (ffmpegmux->collect, (GstCollectData *) best_pad); ffmpegmux->context->streams[best_pad->padnum]->codec->frame_number++; /* set time */ pkt.pts = gst_ffmpeg_time_gst_to_ff (GST_BUFFER_TIMESTAMP (buf), ffmpegmux->context->streams[best_pad->padnum]->time_base); pkt.dts = pkt.pts; if (strcmp (ffmpegmux->context->oformat->name, "gif") == 0) { AVStream *st = ffmpegmux->context->streams[best_pad->padnum]; AVPicture src, dst; need_free = TRUE; pkt.size = st->codec->width * st->codec->height * 3; pkt.data = g_malloc (pkt.size); dst.data[0] = pkt.data; dst.data[1] = NULL; dst.data[2] = NULL; dst.linesize[0] = st->codec->width * 3; gst_ffmpeg_avpicture_fill (&src, GST_BUFFER_DATA (buf), PIX_FMT_RGB24, st->codec->width, st->codec->height); av_picture_copy (&dst, &src, PIX_FMT_RGB24, st->codec->width, st->codec->height); } else { pkt.data = GST_BUFFER_DATA (buf); pkt.size = GST_BUFFER_SIZE (buf); } pkt.stream_index = best_pad->padnum; pkt.flags = 0; if (!GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT)) pkt.flags |= PKT_FLAG_KEY; if (GST_BUFFER_DURATION_IS_VALID (buf)) pkt.duration = gst_ffmpeg_time_gst_to_ff (GST_BUFFER_DURATION (buf), ffmpegmux->context->streams[best_pad->padnum]->time_base); else pkt.duration = 0; av_write_frame (ffmpegmux->context, &pkt); gst_buffer_unref (buf); if (need_free) g_free (pkt.data); } else { /* close down */ av_write_trailer (ffmpegmux->context); ffmpegmux->opened = FALSE; put_flush_packet (ffmpegmux->context->pb); url_fclose (ffmpegmux->context->pb); gst_pad_push_event (ffmpegmux->srcpad, gst_event_new_eos ()); return GST_FLOW_UNEXPECTED; } return GST_FLOW_OK; }
static GstFlowReturn gst_frei0r_mixer_collected (GstCollectPads * pads, GstFrei0rMixer * self) { GstBuffer *inbuf0 = NULL, *inbuf1 = NULL, *inbuf2 = NULL; GstBuffer *outbuf = NULL; GstFlowReturn ret = GST_FLOW_OK; GSList *l; GstFrei0rMixerClass *klass = GST_FREI0R_MIXER_GET_CLASS (self); GstClockTime timestamp; gdouble time; GstSegment *segment = NULL; if (G_UNLIKELY (self->width <= 0 || self->height <= 0)) return GST_FLOW_NOT_NEGOTIATED; if (G_UNLIKELY (!self->f0r_instance)) { self->f0r_instance = gst_frei0r_instance_construct (klass->ftable, klass->properties, klass->n_properties, self->property_cache, self->width, self->height); if (G_UNLIKELY (!self->f0r_instance)) return GST_FLOW_ERROR; } if (self->newseg_event) { gst_pad_push_event (self->src, self->newseg_event); self->newseg_event = NULL; } if ((ret = gst_pad_alloc_buffer_and_set_caps (self->src, GST_BUFFER_OFFSET_NONE, gst_video_format_get_size (self->fmt, self->width, self->height), GST_PAD_CAPS (self->src), &outbuf)) != GST_FLOW_OK) return ret; for (l = pads->data; l; l = l->next) { GstCollectData *cdata = l->data; if (cdata->pad == self->sink0) { inbuf0 = gst_collect_pads_pop (pads, cdata); segment = &cdata->segment; } else if (cdata->pad == self->sink1) { inbuf1 = gst_collect_pads_pop (pads, cdata); } else if (cdata->pad == self->sink2) { inbuf2 = gst_collect_pads_pop (pads, cdata); } } if (!inbuf0 || !inbuf1 || (!inbuf2 && self->sink2)) goto eos; g_assert (segment != NULL); timestamp = GST_BUFFER_TIMESTAMP (inbuf0); timestamp = gst_segment_to_stream_time (segment, GST_FORMAT_TIME, timestamp); GST_DEBUG_OBJECT (self, "sync to %" GST_TIME_FORMAT, GST_TIME_ARGS (timestamp)); if (GST_CLOCK_TIME_IS_VALID (timestamp)) gst_object_sync_values (G_OBJECT (self), timestamp); gst_buffer_copy_metadata (outbuf, inbuf0, GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS); time = ((gdouble) GST_BUFFER_TIMESTAMP (outbuf)) / GST_SECOND; GST_OBJECT_LOCK (self); klass->ftable->update2 (self->f0r_instance, time, (const guint32 *) GST_BUFFER_DATA (inbuf0), (const guint32 *) GST_BUFFER_DATA (inbuf1), (inbuf2) ? (const guint32 *) GST_BUFFER_DATA (inbuf2) : NULL, (guint32 *) GST_BUFFER_DATA (outbuf)); GST_OBJECT_UNLOCK (self); gst_buffer_unref (inbuf0); gst_buffer_unref (inbuf1); if (inbuf2) gst_buffer_unref (inbuf2); ret = gst_pad_push (self->src, outbuf); return ret; eos: { GST_DEBUG_OBJECT (self, "no data available, must be EOS"); gst_buffer_unref (outbuf); if (inbuf0) gst_buffer_unref (inbuf0); if (inbuf1) gst_buffer_unref (inbuf1); if (inbuf2) gst_buffer_unref (inbuf2); gst_pad_push_event (self->src, gst_event_new_eos ()); return GST_FLOW_UNEXPECTED; } }
static GstFlowReturn collected_pads(GstCollectPads *pads, GstOmxBaseFilter21 *self) { GSList *item; GstCollectData *collectdata; GstFlowReturn ret = GST_FLOW_OK; GOmxCore *gomx = self->gomx; gint sink_number; GstBuffer *buffers[2]; gboolean eos = FALSE; GST_DEBUG_OBJECT(self, "Collected pads !"); // Collect buffers for( item = pads->data ; item != NULL ; item = item->next ) { collectdata = (GstCollectData *) item->data; //FIXME Use collect data if(strcmp(GST_PAD_NAME(collectdata->pad), "sink_00") == 0){ sink_number=0; } else{ sink_number=1; } buffers[sink_number] = gst_collect_pads_pop(pads, collectdata); if( buffers[sink_number] == NULL ) { eos = TRUE; } } // Detect EOS if( eos == TRUE ) { GST_INFO_OBJECT(self, "EOS"); for( sink_number=0 ; sink_number<2 ; sink_number++ ) { if( buffers[sink_number] ) { gst_buffer_unref(buffers[sink_number]); } } gst_pad_push_event(self->srcpad, gst_event_new_eos()); return GST_FLOW_UNEXPECTED; } // Setup input ports if not done yet if (G_LIKELY (gomx->omx_state != OMX_StateExecuting)) { for( sink_number=0 ; sink_number<2 ; sink_number++ ) { GST_INFO_OBJECT(self, "Setup port %d", sink_number); setup_input_buffer (self, buffers[sink_number], sink_number); } } // Call chain foreach buffer for( sink_number=0 ; sink_number<2 ; sink_number++ ) { ret = pad_chain(self->sinkpad[sink_number], buffers[sink_number]); } // Call output_loop after pad_chain output_loop(self->srcpad); return ret; }