gst/matroska/matroska-mux.c: Fix possible deadlock in matroska muxer (#327825).

Original commit message from CVS:
Reviewed by: Tim-Philipp Müller  <tim at centricular dot net>
* gst/matroska/matroska-mux.c: (gst_matroska_mux_best_pad),
(gst_matroska_mux_write_data), (gst_matroska_mux_collected):
Fix possible deadlock in matroska muxer (#327825).
This commit is contained in:
Tim-Philipp Müller 2006-01-23 10:44:03 +00:00
parent f42029d79f
commit 00c44209d8
2 changed files with 50 additions and 29 deletions

View file

@ -1,3 +1,11 @@
2006-01-23 Michal Benes <michal dot benes at xeris dot cz>
Reviewed by: Tim-Philipp Müller <tim at centricular dot net>
* gst/matroska/matroska-mux.c: (gst_matroska_mux_best_pad),
(gst_matroska_mux_write_data), (gst_matroska_mux_collected):
Fix possible deadlock in matroska muxer (#327825).
2006-01-23 Tim-Philipp Müller <tim at centricular dot net> 2006-01-23 Tim-Philipp Müller <tim at centricular dot net>
* ext/libpng/gstpngenc.c: (gst_pngenc_chain): * ext/libpng/gstpngenc.c: (gst_pngenc_chain):

View file

@ -1244,6 +1244,7 @@ gst_matroska_mux_finish (GstMatroskaMux * mux)
/** /**
* gst_matroska_mux_best_pad: * gst_matroska_mux_best_pad:
* @mux: #GstMatroskaMux * @mux: #GstMatroskaMux
* @popped: True if at least one buffer was popped from #GstCollectPads
* *
* Find a pad with the oldest data * Find a pad with the oldest data
* (data from this pad should be written first). * (data from this pad should be written first).
@ -1251,11 +1252,12 @@ gst_matroska_mux_finish (GstMatroskaMux * mux)
* Returns: Selected pad. * Returns: Selected pad.
*/ */
static GstMatroskaPad * static GstMatroskaPad *
gst_matroska_mux_best_pad (GstMatroskaMux * mux) gst_matroska_mux_best_pad (GstMatroskaMux * mux, gboolean * popped)
{ {
GSList *collected; GSList *collected;
GstMatroskaPad *best = NULL; GstMatroskaPad *best = NULL;
*popped = FALSE;
for (collected = mux->collect->data; collected; for (collected = mux->collect->data; collected;
collected = g_slist_next (collected)) { collected = g_slist_next (collected)) {
GstMatroskaPad *collect_pad; GstMatroskaPad *collect_pad;
@ -1265,6 +1267,9 @@ gst_matroska_mux_best_pad (GstMatroskaMux * mux)
if (collect_pad->buffer == NULL) { if (collect_pad->buffer == NULL) {
collect_pad->buffer = gst_collect_pads_pop (mux->collect, collect_pad->buffer = gst_collect_pads_pop (mux->collect,
(GstCollectData *) collect_pad); (GstCollectData *) collect_pad);
if (collect_pad->buffer != NULL)
*popped = TRUE;
} }
/* if we have a buffer check if it is better then the current best one */ /* if we have a buffer check if it is better then the current best one */
@ -1312,15 +1317,15 @@ gst_matroska_mux_create_buffer_header (GstMatroskaTrackContext * track,
/** /**
* gst_matroska_mux_write_data: * gst_matroska_mux_write_data:
* @mux: #GstMatroskaMux * @mux: #GstMatroskaMux
* @collect_pad: #GstMatroskaPad with the data
* *
* Write collected data (called from gst_matroska_mux_collected). * Write collected data (called from gst_matroska_mux_collected).
* *
* Returns: Result of the gst_pad_push issued to write the data. * Returns: Result of the gst_pad_push issued to write the data.
*/ */
static GstFlowReturn static GstFlowReturn
gst_matroska_mux_write_data (GstMatroskaMux * mux) gst_matroska_mux_write_data (GstMatroskaMux * mux, GstMatroskaPad * collect_pad)
{ {
GstMatroskaPad *best;
GstEbmlWrite *ebml = mux->ebml_write; GstEbmlWrite *ebml = mux->ebml_write;
GstBuffer *buf, *hdr; GstBuffer *buf, *hdr;
guint64 cluster, blockgroup; guint64 cluster, blockgroup;
@ -1328,21 +1333,9 @@ gst_matroska_mux_write_data (GstMatroskaMux * mux)
guint16 relative_timestamp; guint16 relative_timestamp;
guint64 block_duration; guint64 block_duration;
/* which stream to write from? */
best = gst_matroska_mux_best_pad (mux);
/* if there is no best pad, we have reached EOS */
if (best == NULL) {
GST_DEBUG_OBJECT (mux, "No best pad finishing...");
gst_matroska_mux_finish (mux);
gst_pad_push_event (mux->srcpad, gst_event_new_eos ());
return GST_FLOW_WRONG_STATE;
}
GST_DEBUG_OBJECT (best->collect.pad, "best pad");
/* write data */ /* write data */
buf = best->buffer; buf = collect_pad->buffer;
best->buffer = NULL; collect_pad->buffer = NULL;
/* set the timestamp for outgoing buffers */ /* set the timestamp for outgoing buffers */
ebml->timestamp = GST_BUFFER_TIMESTAMP (buf); ebml->timestamp = GST_BUFFER_TIMESTAMP (buf);
@ -1390,14 +1383,14 @@ gst_matroska_mux_write_data (GstMatroskaMux * mux)
/* update duration of this track */ /* update duration of this track */
if (GST_BUFFER_DURATION_IS_VALID (buf)) if (GST_BUFFER_DURATION_IS_VALID (buf))
best->duration += GST_BUFFER_DURATION (buf); collect_pad->duration += GST_BUFFER_DURATION (buf);
/* We currently write an index entry for each keyframe in a /* We currently write an index entry for each keyframe in a
* video track or one entry for each cluster in an audio track * video track or one entry for each cluster in an audio track
* for audio only files. This can be largely improved, such as doing * for audio only files. This can be largely improved, such as doing
* one for each keyframe or each second (for all-keyframe * one for each keyframe or each second (for all-keyframe
* streams), only the *first* video track. But that'll come later... */ * streams), only the *first* video track. But that'll come later... */
if (best->track->type == GST_MATROSKA_TRACK_TYPE_VIDEO && if (collect_pad->track->type == GST_MATROSKA_TRACK_TYPE_VIDEO &&
!GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT)) { !GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT)) {
GstMatroskaIndex *idx; GstMatroskaIndex *idx;
@ -1409,8 +1402,8 @@ gst_matroska_mux_write_data (GstMatroskaMux * mux)
idx->pos = mux->cluster_pos; idx->pos = mux->cluster_pos;
idx->time = GST_BUFFER_TIMESTAMP (buf); idx->time = GST_BUFFER_TIMESTAMP (buf);
idx->track = best->track->num; idx->track = collect_pad->track->num;
} else if ((best->track->type == GST_MATROSKA_TRACK_TYPE_AUDIO) && } else if ((collect_pad->track->type == GST_MATROSKA_TRACK_TYPE_AUDIO) &&
(mux->num_streams == 1)) { (mux->num_streams == 1)) {
GstMatroskaIndex *idx; GstMatroskaIndex *idx;
@ -1422,14 +1415,14 @@ gst_matroska_mux_write_data (GstMatroskaMux * mux)
idx->pos = mux->cluster_pos; idx->pos = mux->cluster_pos;
idx->time = GST_BUFFER_TIMESTAMP (buf); idx->time = GST_BUFFER_TIMESTAMP (buf);
idx->track = best->track->num; idx->track = collect_pad->track->num;
} }
/* Check if the duration differs from the default duration. */ /* Check if the duration differs from the default duration. */
write_duration = FALSE; write_duration = FALSE;
block_duration = GST_BUFFER_DURATION (buf); block_duration = GST_BUFFER_DURATION (buf);
if (GST_BUFFER_DURATION_IS_VALID (buf)) { if (GST_BUFFER_DURATION_IS_VALID (buf)) {
if (block_duration != best->track->default_duration) { if (block_duration != collect_pad->track->default_duration) {
write_duration = TRUE; write_duration = TRUE;
} }
} }
@ -1444,8 +1437,8 @@ gst_matroska_mux_write_data (GstMatroskaMux * mux)
GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT) ? 0 : 0x80; GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT) ? 0 : 0x80;
hdr = hdr =
gst_matroska_mux_create_buffer_header (best->track, relative_timestamp, gst_matroska_mux_create_buffer_header (collect_pad->track,
flags); relative_timestamp, flags);
gst_ebml_write_buffer_header (ebml, GST_MATROSKA_ID_SIMPLEBLOCK, gst_ebml_write_buffer_header (ebml, GST_MATROSKA_ID_SIMPLEBLOCK,
GST_BUFFER_SIZE (buf) + GST_BUFFER_SIZE (hdr)); GST_BUFFER_SIZE (buf) + GST_BUFFER_SIZE (hdr));
gst_ebml_write_buffer (ebml, hdr); gst_ebml_write_buffer (ebml, hdr);
@ -1455,8 +1448,8 @@ gst_matroska_mux_write_data (GstMatroskaMux * mux)
} else { } else {
blockgroup = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_BLOCKGROUP); blockgroup = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_BLOCKGROUP);
hdr = hdr =
gst_matroska_mux_create_buffer_header (best->track, relative_timestamp, gst_matroska_mux_create_buffer_header (collect_pad->track,
0); relative_timestamp, 0);
gst_ebml_write_buffer_header (ebml, GST_MATROSKA_ID_BLOCK, gst_ebml_write_buffer_header (ebml, GST_MATROSKA_ID_BLOCK,
GST_BUFFER_SIZE (buf) + GST_BUFFER_SIZE (hdr)); GST_BUFFER_SIZE (buf) + GST_BUFFER_SIZE (hdr));
gst_ebml_write_buffer (ebml, hdr); gst_ebml_write_buffer (ebml, hdr);
@ -1484,6 +1477,9 @@ static GstFlowReturn
gst_matroska_mux_collected (GstCollectPads * pads, gpointer user_data) gst_matroska_mux_collected (GstCollectPads * pads, gpointer user_data)
{ {
GstMatroskaMux *mux = GST_MATROSKA_MUX (user_data); GstMatroskaMux *mux = GST_MATROSKA_MUX (user_data);
GstMatroskaPad *best;
gboolean popped;
GstFlowReturn ret;
GST_DEBUG_OBJECT (mux, "Collected pads"); GST_DEBUG_OBJECT (mux, "Collected pads");
@ -1499,8 +1495,25 @@ gst_matroska_mux_collected (GstCollectPads * pads, gpointer user_data)
mux->state = GST_MATROSKA_MUX_STATE_DATA; mux->state = GST_MATROSKA_MUX_STATE_DATA;
} }
/* do one single buffer */ do {
return gst_matroska_mux_write_data (mux); /* which stream to write from? */
best = gst_matroska_mux_best_pad (mux, &popped);
/* if there is no best pad, we have reached EOS */
if (best == NULL) {
GST_DEBUG_OBJECT (mux, "No best pad finishing...");
gst_matroska_mux_finish (mux);
gst_pad_push_event (mux->srcpad, gst_event_new_eos ());
ret = GST_FLOW_UNEXPECTED;
break;
}
GST_DEBUG_OBJECT (best->collect.pad, "best pad");
/* write one buffer */
ret = gst_matroska_mux_write_data (mux, best);
} while (ret == GST_FLOW_OK && !popped);
return ret;
} }