GST_OBJECT_LOCK (qtmux);
gst_tag_setter_reset_tags (GST_TAG_SETTER (qtmux));
- GST_OBJECT_UNLOCK (qtmux);
/* reset pad data */
for (l = GST_ELEMENT_CAST (qtmux)->sinkpads; l; l = l->next) {
atom_moov_add_trak (qtmux->moov, qtpad->trak);
}
}
+ GST_OBJECT_UNLOCK (qtmux);
qtmux->current_pad = NULL;
qtmux->current_chunk_size = 0;
GST_DEBUG_OBJECT (qtmux, "No new tags received");
}
+ GST_OBJECT_LOCK (qtmux);
for (l = GST_ELEMENT (qtmux)->sinkpads; l; l = l->next) {
GstQTMuxPad *qpad = GST_QT_MUX_PAD (l->data);
GST_DEBUG_OBJECT (qpad, "No new tags received");
}
}
+ GST_OBJECT_UNLOCK (qtmux);
}
static inline GstBuffer *
/* update modification times */
qtmux->moov->mvhd.time_info.modification_time = current_time;
+
+ GST_OBJECT_LOCK (qtmux);
for (l = GST_ELEMENT_CAST (qtmux)->sinkpads; l; l = l->next) {
GstQTMuxPad *qtpad = (GstQTMuxPad *) l->data;
qtpad->trak->mdia.mdhd.time_info.modification_time = current_time;
qtpad->trak->tkhd.modification_time = current_time;
}
+ GST_OBJECT_UNLOCK (qtmux);
/* serialize moov */
offset = size = 0;
gst_qt_mux_prepare_ftyp (qtmux, &ftyp, &prefix);
+ GST_OBJECT_LOCK (qtmux);
if (!atoms_recov_write_headers (qtmux->moov_recov_file, ftyp, prefix,
qtmux->moov, qtmux->timescale,
g_list_length (GST_ELEMENT (qtmux)->sinkpads))) {
GST_WARNING_OBJECT (qtmux, "Failed to write moov recovery file " "headers");
+ GST_OBJECT_UNLOCK (qtmux);
goto fail;
}
+ GST_OBJECT_UNLOCK (qtmux);
atom_ftyp_free (ftyp);
if (prefix)
gst_buffer_unref (prefix);
+ GST_OBJECT_LOCK (qtmux);
for (l = GST_ELEMENT_CAST (qtmux)->sinkpads; l; l = l->next) {
GstQTMuxPad *qpad = (GstQTMuxPad *) l->data;
/* write info for each stream */
break;
}
}
+ GST_OBJECT_UNLOCK (qtmux);
return;
/* Find the (first) video track and assume that we have to output
* in that size */
+ GST_OBJECT_LOCK (qtmux);
for (l = GST_ELEMENT_CAST (qtmux)->sinkpads; l; l = l->next) {
GstQTMuxPad *tmp_qpad = (GstQTMuxPad *) l->data;
break;
}
}
+ GST_OBJECT_UNLOCK (qtmux);
if (l == NULL) {
GST_INFO_OBJECT (qtmux,
/* If interleave limits have been specified and the current pad is within
* those interleave limits, pick that one, otherwise let's try to figure out
* the next best one. */
+
if (qtmux->current_pad &&
(qtmux->interleave_bytes != 0 || qtmux->interleave_time != 0) &&
(qtmux->interleave_bytes == 0
if (qtmux->current_pad->total_duration < qtmux->reserved_max_duration) {
best_pad = qtmux->current_pad;
}
- } else if (GST_ELEMENT_CAST (qtmux)->sinkpads->next) {
- /* Attempt to try another pad if we have one. Otherwise use the only pad
- * present */
- best_pad = qtmux->current_pad = NULL;
+ } else {
+ GST_OBJECT_LOCK (qtmux);
+ if (GST_ELEMENT_CAST (qtmux)->sinkpads->next) {
+ /* Attempt to try another pad if we have one. Otherwise use the only pad
+ * present */
+ best_pad = qtmux->current_pad = NULL;
+ }
+ GST_OBJECT_UNLOCK (qtmux);
}
/* The next best pad is the one which has the lowest timestamp and hasn't
GList *l;
GstClockTime best_time = GST_CLOCK_TIME_NONE;
+ GST_OBJECT_LOCK (qtmux);
for (l = GST_ELEMENT_CAST (qtmux)->sinkpads; l; l = l->next) {
GstQTMuxPad *qtpad = (GstQTMuxPad *) l->data;
GstClockTime timestamp;
best_time = timestamp;
}
}
+ GST_OBJECT_UNLOCK (qtmux);
}
return best_pad;
/* Update expected sample sizes/durations as needed, this is for raw
* audio where samples are actual audio samples. */
+ GST_OBJECT_LOCK (qtmux);
for (l = GST_ELEMENT_CAST (qtmux)->sinkpads; l; l = l->next) {
GstQTMuxPad *qpad = (GstQTMuxPad *) l->data;
- if (!prefill_update_sample_size (qtmux, qpad))
+ if (!prefill_update_sample_size (qtmux, qpad)) {
+ GST_OBJECT_UNLOCK (qtmux);
return FALSE;
+ }
}
+ GST_OBJECT_UNLOCK (qtmux);
if (qtmux_klass->format == GST_QT_MUX_FORMAT_QT) {
/* For the first sample check/update timecode as needed. We do that before
* all actual samples as the code in gst_qt_mux_add_buffer() does it with
* initial buffer directly, not with last_buf */
+ GST_OBJECT_LOCK (qtmux);
for (l = GST_ELEMENT_CAST (qtmux)->sinkpads; l; l = l->next) {
GstQTMuxPad *qpad = (GstQTMuxPad *) l->data;
GstBuffer *buffer =
if (buffer)
gst_buffer_unref (buffer);
}
+ GST_OBJECT_UNLOCK (qtmux);
}
while ((qpad = find_best_pad_prefill_start (qtmux))) {
FALSE);
break;
case GST_QT_MUX_MODE_ROBUST_RECORDING_PREFILL:
+ {
+ guint32 atom_size;
+
ret = gst_qt_mux_prepare_and_send_ftyp (qtmux);
if (ret != GST_FLOW_OK)
break;
if (ret != GST_FLOW_OK)
return ret;
+ GST_OBJECT_LOCK (qtmux);
+ atom_size = 12 * g_list_length (GST_ELEMENT (qtmux)->sinkpads) + 8;
+ GST_OBJECT_UNLOCK (qtmux);
+
/* last_moov_size now contains the full size of the moov, moov_pos the
* position. This allows us to rewrite it in the very end as needed */
- qtmux->reserved_moov_size =
- qtmux->last_moov_size +
- 12 * g_list_length (GST_ELEMENT (qtmux)->sinkpads) + 8;
+ qtmux->reserved_moov_size = qtmux->last_moov_size + atom_size;
/* Send an additional free atom at the end so we definitely have space
* to rewrite the moov header at the end and remove the samples that
* were not actually written */
ret =
- gst_qt_mux_send_free_atom (qtmux, &qtmux->header_size,
- 12 * g_list_length (GST_ELEMENT (qtmux)->sinkpads) + 8, FALSE);
+ gst_qt_mux_send_free_atom (qtmux, &qtmux->header_size, atom_size,
+ FALSE);
if (ret != GST_FLOW_OK)
return ret;
qtmux->current_pad = NULL;
qtmux->longest_chunk = GST_CLOCK_TIME_NONE;
+ GST_OBJECT_LOCK (qtmux);
for (l = GST_ELEMENT_CAST (qtmux)->sinkpads; l; l = l->next) {
GstQTMuxPad *qtpad = (GstQTMuxPad *) l->data;
qtpad->last_dts = GST_CLOCK_TIME_NONE;
qtpad->sample_offset = 0;
}
+ GST_OBJECT_UNLOCK (qtmux);
break;
+ }
case GST_QT_MUX_MODE_FAST_START:
GST_OBJECT_LOCK (qtmux);
qtmux->fast_start_file = g_fopen (qtmux->fast_start_file_path, "wb+");
gst_qt_mux_send_last_buffers (GstQTMux * qtmux)
{
GstFlowReturn ret = GST_FLOW_OK;
- GList *l;
+ GList *sinkpads, *l;
- for (l = GST_ELEMENT_CAST (qtmux)->sinkpads; l; l = l->next) {
+ GST_OBJECT_LOCK (qtmux);
+ sinkpads = g_list_copy_deep (GST_ELEMENT_CAST (qtmux)->sinkpads,
+ (GCopyFunc) gst_object_ref, NULL);
+ GST_OBJECT_UNLOCK (qtmux);
+
+ for (l = sinkpads; l; l = l->next) {
GstQTMuxPad *qtpad = (GstQTMuxPad *) l->data;
/* avoid add_buffer complaining if not negotiated
}
}
+ g_list_free_full (sinkpads, gst_object_unref);
+
return ret;
}
qtmux->first_ts = qtmux->last_dts = GST_CLOCK_TIME_NONE;
+ GST_OBJECT_LOCK (qtmux);
for (l = GST_ELEMENT_CAST (qtmux)->sinkpads; l; l = l->next) {
GstQTMuxPad *qtpad = (GstQTMuxPad *) l->data;
atom_trak_update_bitrates (qtpad->trak, avgbitrate, maxbitrate);
}
}
+ GST_OBJECT_UNLOCK (qtmux);
/* need to update values on subtitle traks now that we know the
* max width and height */
+ GST_OBJECT_LOCK (qtmux);
for (l = GST_ELEMENT_CAST (qtmux)->sinkpads; l; l = l->next) {
GstQTMuxPad *qtpad = (GstQTMuxPad *) l->data;
atom_trak_tx3g_update_dimension (qtpad->trak, max_width, max_height);
}
}
+ GST_OBJECT_UNLOCK (qtmux);
}
/* Called after gst_qt_mux_update_global_statistics() updates the
/* add/update EDTSs for late streams. configure_moov will have
* set the trak durations above by summing the sample tables,
* here we extend that if needing to insert an empty segment */
+ GST_OBJECT_LOCK (qtmux);
for (l = GST_ELEMENT_CAST (qtmux)->sinkpads; l; l = l->next) {
GstQTMuxPad *qtpad = (GstQTMuxPad *) l->data;
}
}
}
+ GST_OBJECT_UNLOCK (qtmux);
}
static GstFlowReturn
gboolean ret = GST_FLOW_OK;
guint64 offset = 0, size = 0;
gboolean large_file;
- GList *l;
+ GList *sinkpads, *l;
GST_DEBUG_OBJECT (qtmux, "Updating remaining values and sending last data");
}
gst_qt_mux_update_global_statistics (qtmux);
- for (l = GST_ELEMENT_CAST (qtmux)->sinkpads; l; l = l->next) {
+
+ GST_OBJECT_LOCK (qtmux);
+ sinkpads = g_list_copy_deep (GST_ELEMENT_CAST (qtmux)->sinkpads,
+ (GCopyFunc) gst_object_ref, NULL);
+ GST_OBJECT_UNLOCK (qtmux);
+
+ for (l = sinkpads; l; l = l->next) {
GstQTMuxPad *qtpad = (GstQTMuxPad *) l->data;
if (qtpad->tc_pos != -1) {
/* File is being stopped and timecode hasn't been updated. Update it now
* with whatever we have */
ret = gst_qt_mux_update_timecode (qtmux, qtpad);
- if (ret != GST_FLOW_OK)
+ if (ret != GST_FLOW_OK) {
+ g_list_free_full (sinkpads, gst_object_unref);
return ret;
+ }
}
}
+ g_list_free_full (sinkpads, gst_object_unref);
+
switch (qtmux->mux_mode) {
case GST_QT_MUX_MODE_FRAGMENTED:{
GstSegment segment;
GList *l;
guint32 next_track_id = qtmux->moov->mvhd.next_track_id;
+ GST_OBJECT_LOCK (qtmux);
for (l = GST_ELEMENT_CAST (qtmux)->sinkpads; l; l = l->next) {
GstQTMuxPad *qpad = (GstQTMuxPad *) l->data;
guint64 block_idx;
qpad->trak->tkhd.track_ID = next_track_id++;
}
}
+ GST_OBJECT_UNLOCK (qtmux);
+
qtmux->moov->mvhd.next_track_id = next_track_id;
gst_qt_mux_update_global_statistics (qtmux);
* reserved for this in the moov and the pre-finalized moov would have
* broken A/V synchronization. Error out here now
*/
+ GST_OBJECT_LOCK (qtmux);
for (l = GST_ELEMENT_CAST (qtmux)->sinkpads; l; l = l->next) {
GstQTMuxPad *qpad = (GstQTMuxPad *) l->data;
GST_ELEMENT_ERROR (qtmux, STREAM, MUX, (NULL),
("Can't support gaps in prefill mode"));
+ GST_OBJECT_UNLOCK (qtmux);
+
return GST_FLOW_ERROR;
}
}
+ GST_OBJECT_UNLOCK (qtmux);
gst_qt_mux_setup_metadata (qtmux);
atom_moov_chunks_set_offset (qtmux->moov, qtmux->header_size);
guint64 smallest_offset = G_MAXUINT64;
guint64 chunk_offset = 0;
+ GST_OBJECT_LOCK (qtmux);
for (l = GST_ELEMENT_CAST (qtmux)->sinkpads; l; l = l->next) {
GstQTMuxPad *qtpad = (GstQTMuxPad *) l->data;
const TrakBufferEntryInfo *sample_entry;
chunk_offset = sample_entry->chunk_offset;
}
}
+ GST_OBJECT_UNLOCK (qtmux);
if (chunk_offset != qtmux->current_chunk_offset) {
qtmux->current_pad = NULL;
GST_DEBUG_OBJECT (qtmux, "Reusing pad %s:%s",
GST_DEBUG_PAD_NAME (best_pad));
}
- } else if (GST_ELEMENT (qtmux)->sinkpads->next) {
- /* Only switch pads if we have more than one, otherwise
- * we can just put everything into a single chunk and save
- * a few bytes of offsets
- */
- if (qtmux->current_pad)
- GST_DEBUG_OBJECT (qtmux, "Switching from pad %s:%s",
- GST_DEBUG_PAD_NAME (qtmux->current_pad));
- best_pad = qtmux->current_pad = NULL;
+ } else {
+ GST_OBJECT_LOCK (qtmux);
+ if (GST_ELEMENT (qtmux)->sinkpads->next) {
+ /* Only switch pads if we have more than one, otherwise
+ * we can just put everything into a single chunk and save
+ * a few bytes of offsets
+ */
+ if (qtmux->current_pad)
+ GST_DEBUG_OBJECT (qtmux, "Switching from pad %s:%s",
+ GST_DEBUG_PAD_NAME (qtmux->current_pad));
+ best_pad = qtmux->current_pad = NULL;
+ }
+ GST_OBJECT_UNLOCK (qtmux);
}
if (!best_pad) {
GstClockTime best_time = GST_CLOCK_TIME_NONE;
+ GST_OBJECT_LOCK (qtmux);
for (l = GST_ELEMENT_CAST (qtmux)->sinkpads; l; l = l->next) {
GstQTMuxPad *qtpad = (GstQTMuxPad *) l->data;
GstBuffer *tmp_buf;
if (tmp_buf)
gst_buffer_unref (tmp_buf);
}
+ GST_OBJECT_UNLOCK (qtmux);
if (best_pad) {
GST_DEBUG_OBJECT (qtmux, "Choosing pad %s:%s",
gst_qt_mux_are_all_pads_eos (GstQTMux * mux)
{
GList *l;
+ gboolean ret = TRUE;
+ GST_OBJECT_LOCK (mux);
for (l = GST_ELEMENT_CAST (mux)->sinkpads; l; l = l->next) {
- if (!gst_aggregator_pad_is_eos (GST_AGGREGATOR_PAD (l->data)))
- return FALSE;
+ if (!gst_aggregator_pad_is_eos (GST_AGGREGATOR_PAD (l->data))) {
+ ret = FALSE;
+ break;
+ }
}
- return TRUE;
+ GST_OBJECT_UNLOCK (mux);
+
+ return ret;
}
static GstFlowReturn
mux->current_chunk_duration = 0;
}
+ GST_OBJECT_LOCK (mux);
if (GST_ELEMENT (mux)->sinkpads == NULL) {
/* No more outstanding request pads, reset our counters */
mux->video_pads = 0;
mux->audio_pads = 0;
mux->subtitle_pads = 0;
}
+ GST_OBJECT_UNLOCK (mux);
}
static GstAggregatorPad *