mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-24 09:10:36 +00:00
qtmux: Do timecode handling per track, not per muxer instance
There could be multiple video tracks with timecodes.
This commit is contained in:
parent
d76bd1913f
commit
cb6aab8685
2 changed files with 39 additions and 35 deletions
|
@ -541,6 +541,12 @@ gst_qt_mux_pad_reset (GstQTPad * qtpad)
|
||||||
|
|
||||||
/* reference owned elsewhere */
|
/* reference owned elsewhere */
|
||||||
qtpad->tfra = NULL;
|
qtpad->tfra = NULL;
|
||||||
|
|
||||||
|
qtpad->first_pts = GST_CLOCK_TIME_NONE;
|
||||||
|
qtpad->tc_pos = -1;
|
||||||
|
if (qtpad->first_tc)
|
||||||
|
gst_video_time_code_free (qtpad->first_tc);
|
||||||
|
qtpad->first_tc = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -622,11 +628,6 @@ gst_qt_mux_reset (GstQTMux * qtmux, gboolean alloc)
|
||||||
qtmux->last_moov_update = GST_CLOCK_TIME_NONE;
|
qtmux->last_moov_update = GST_CLOCK_TIME_NONE;
|
||||||
qtmux->muxed_since_last_update = 0;
|
qtmux->muxed_since_last_update = 0;
|
||||||
qtmux->reserved_duration_remaining = GST_CLOCK_TIME_NONE;
|
qtmux->reserved_duration_remaining = GST_CLOCK_TIME_NONE;
|
||||||
qtmux->first_pts = GST_CLOCK_TIME_NONE;
|
|
||||||
qtmux->tc_pos = -1;
|
|
||||||
if (qtmux->first_tc)
|
|
||||||
gst_video_time_code_free (qtmux->first_tc);
|
|
||||||
qtmux->first_tc = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -2595,14 +2596,14 @@ gst_qt_mux_update_edit_lists (GstQTMux * qtmux)
|
||||||
}
|
}
|
||||||
|
|
||||||
static GstFlowReturn
|
static GstFlowReturn
|
||||||
gst_qt_mux_update_timecode (GstQTMux * qtmux)
|
gst_qt_mux_update_timecode (GstQTMux * qtmux, GstQTPad * qtpad)
|
||||||
{
|
{
|
||||||
GstSegment segment;
|
GstSegment segment;
|
||||||
GstBuffer *buf;
|
GstBuffer *buf;
|
||||||
GstMapInfo map;
|
GstMapInfo map;
|
||||||
guint64 offset = qtmux->tc_pos;
|
guint64 offset = qtpad->tc_pos;
|
||||||
|
|
||||||
g_assert (qtmux->tc_pos != -1);
|
g_assert (qtpad->tc_pos != -1);
|
||||||
|
|
||||||
gst_segment_init (&segment, GST_FORMAT_BYTES);
|
gst_segment_init (&segment, GST_FORMAT_BYTES);
|
||||||
segment.start = offset;
|
segment.start = offset;
|
||||||
|
@ -2612,11 +2613,11 @@ gst_qt_mux_update_timecode (GstQTMux * qtmux)
|
||||||
gst_buffer_map (buf, &map, GST_MAP_WRITE);
|
gst_buffer_map (buf, &map, GST_MAP_WRITE);
|
||||||
|
|
||||||
GST_WRITE_UINT32_BE (map.data,
|
GST_WRITE_UINT32_BE (map.data,
|
||||||
gst_video_time_code_frames_since_daily_jam (qtmux->first_tc));
|
gst_video_time_code_frames_since_daily_jam (qtpad->first_tc));
|
||||||
gst_buffer_unmap (buf, &map);
|
gst_buffer_unmap (buf, &map);
|
||||||
|
|
||||||
/* Reset this value, so the timecode won't be re-rewritten */
|
/* Reset this value, so the timecode won't be re-rewritten */
|
||||||
qtmux->tc_pos = -1;
|
qtpad->tc_pos = -1;
|
||||||
|
|
||||||
return gst_qt_mux_send_buffer (qtmux, buf, &offset, FALSE);
|
return gst_qt_mux_send_buffer (qtmux, buf, &offset, FALSE);
|
||||||
}
|
}
|
||||||
|
@ -2627,6 +2628,7 @@ gst_qt_mux_stop_file (GstQTMux * qtmux)
|
||||||
gboolean ret = GST_FLOW_OK;
|
gboolean ret = GST_FLOW_OK;
|
||||||
guint64 offset = 0, size = 0;
|
guint64 offset = 0, size = 0;
|
||||||
gboolean large_file;
|
gboolean large_file;
|
||||||
|
GSList *walk;
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (qtmux, "Updating remaining values and sending last data");
|
GST_DEBUG_OBJECT (qtmux, "Updating remaining values and sending last data");
|
||||||
|
|
||||||
|
@ -2641,12 +2643,16 @@ gst_qt_mux_stop_file (GstQTMux * qtmux)
|
||||||
}
|
}
|
||||||
|
|
||||||
gst_qt_mux_update_global_statistics (qtmux);
|
gst_qt_mux_update_global_statistics (qtmux);
|
||||||
if (qtmux->tc_pos != -1) {
|
for (walk = qtmux->collect->data; walk; walk = walk->next) {
|
||||||
/* File is being stopped and timecode hasn't been updated. Update it now
|
GstQTPad *qtpad = (GstQTPad *) walk->data;
|
||||||
* with whatever we have */
|
|
||||||
ret = gst_qt_mux_update_timecode (qtmux);
|
if (qtpad->tc_pos != -1) {
|
||||||
if (ret != GST_FLOW_OK)
|
/* File is being stopped and timecode hasn't been updated. Update it now
|
||||||
return ret;
|
* with whatever we have */
|
||||||
|
ret = gst_qt_mux_update_timecode (qtmux, qtpad);
|
||||||
|
if (ret != GST_FLOW_OK)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (qtmux->mux_mode) {
|
switch (qtmux->mux_mode) {
|
||||||
|
@ -3104,7 +3110,7 @@ static GstFlowReturn
|
||||||
gst_qt_mux_check_and_update_timecode (GstQTMux * qtmux, GstQTPad * pad,
|
gst_qt_mux_check_and_update_timecode (GstQTMux * qtmux, GstQTPad * pad,
|
||||||
GstBuffer * buf, GstFlowReturn ret)
|
GstBuffer * buf, GstFlowReturn ret)
|
||||||
{
|
{
|
||||||
if (buf != NULL && (pad->tc_trak == NULL || qtmux->tc_pos != -1)) {
|
if (buf != NULL && (pad->tc_trak == NULL || pad->tc_pos != -1)) {
|
||||||
GstVideoTimeCodeMeta *tc_meta = gst_buffer_get_video_time_code_meta (buf);
|
GstVideoTimeCodeMeta *tc_meta = gst_buffer_get_video_time_code_meta (buf);
|
||||||
if (tc_meta) {
|
if (tc_meta) {
|
||||||
GstVideoTimeCode *tc = &tc_meta->tc;
|
GstVideoTimeCode *tc = &tc_meta->tc;
|
||||||
|
@ -3113,7 +3119,7 @@ gst_qt_mux_check_and_update_timecode (GstQTMux * qtmux, GstQTPad * pad,
|
||||||
guint32 frames_since_daily_jam;
|
guint32 frames_since_daily_jam;
|
||||||
|
|
||||||
/* This means we never got a timecode before */
|
/* This means we never got a timecode before */
|
||||||
if (qtmux->first_tc == NULL) {
|
if (pad->first_tc == NULL) {
|
||||||
#ifndef GST_DISABLE_GST_DEBUG
|
#ifndef GST_DISABLE_GST_DEBUG
|
||||||
gchar *tc_str = gst_video_time_code_to_string (tc);
|
gchar *tc_str = gst_video_time_code_to_string (tc);
|
||||||
GST_DEBUG_OBJECT (qtmux, "Found first timecode %s", tc_str);
|
GST_DEBUG_OBJECT (qtmux, "Found first timecode %s", tc_str);
|
||||||
|
@ -3121,18 +3127,18 @@ gst_qt_mux_check_and_update_timecode (GstQTMux * qtmux, GstQTPad * pad,
|
||||||
#endif
|
#endif
|
||||||
g_assert (pad->tc_trak == NULL);
|
g_assert (pad->tc_trak == NULL);
|
||||||
tc_buf = gst_buffer_new_allocate (NULL, 4, NULL);
|
tc_buf = gst_buffer_new_allocate (NULL, 4, NULL);
|
||||||
qtmux->first_tc = gst_video_time_code_copy (tc);
|
pad->first_tc = gst_video_time_code_copy (tc);
|
||||||
/* If frames are out of order, the frame we're currently getting might
|
/* If frames are out of order, the frame we're currently getting might
|
||||||
* not be the first one. Just write a 0 timecode for now and wait
|
* not be the first one. Just write a 0 timecode for now and wait
|
||||||
* until we receive a timecode that's lower than the current one */
|
* until we receive a timecode that's lower than the current one */
|
||||||
if (pad->is_out_of_order) {
|
if (pad->is_out_of_order) {
|
||||||
qtmux->first_pts = GST_BUFFER_PTS (buf);
|
pad->first_pts = GST_BUFFER_PTS (buf);
|
||||||
frames_since_daily_jam = 0;
|
frames_since_daily_jam = 0;
|
||||||
/* Position to rewrite */
|
/* Position to rewrite */
|
||||||
qtmux->tc_pos = qtmux->mdat_size;
|
pad->tc_pos = qtmux->mdat_size;
|
||||||
} else {
|
} else {
|
||||||
frames_since_daily_jam =
|
frames_since_daily_jam =
|
||||||
gst_video_time_code_frames_since_daily_jam (qtmux->first_tc);
|
gst_video_time_code_frames_since_daily_jam (pad->first_tc);
|
||||||
frames_since_daily_jam = GUINT32_TO_BE (frames_since_daily_jam);
|
frames_since_daily_jam = GUINT32_TO_BE (frames_since_daily_jam);
|
||||||
}
|
}
|
||||||
/* Write the timecode trak now */
|
/* Write the timecode trak now */
|
||||||
|
@ -3143,7 +3149,7 @@ gst_qt_mux_check_and_update_timecode (GstQTMux * qtmux, GstQTPad * pad,
|
||||||
atom_tref_add_entry (pad->trak->tref, pad->tc_trak->tkhd.track_ID);
|
atom_tref_add_entry (pad->trak->tref, pad->tc_trak->tkhd.track_ID);
|
||||||
|
|
||||||
atom_trak_set_timecode_type (pad->tc_trak, qtmux->context,
|
atom_trak_set_timecode_type (pad->tc_trak, qtmux->context,
|
||||||
qtmux->first_tc);
|
pad->first_tc);
|
||||||
|
|
||||||
szret = gst_buffer_fill (tc_buf, 0, &frames_since_daily_jam, 4);
|
szret = gst_buffer_fill (tc_buf, 0, &frames_since_daily_jam, 4);
|
||||||
g_assert (szret == 4);
|
g_assert (szret == 4);
|
||||||
|
@ -3154,10 +3160,10 @@ gst_qt_mux_check_and_update_timecode (GstQTMux * qtmux, GstQTPad * pad,
|
||||||
} else if (pad->is_out_of_order) {
|
} else if (pad->is_out_of_order) {
|
||||||
/* Check for a lower timecode than the one stored */
|
/* Check for a lower timecode than the one stored */
|
||||||
g_assert (pad->tc_trak != NULL);
|
g_assert (pad->tc_trak != NULL);
|
||||||
if (GST_BUFFER_DTS (buf) <= qtmux->first_pts) {
|
if (GST_BUFFER_DTS (buf) <= pad->first_pts) {
|
||||||
if (gst_video_time_code_compare (tc, qtmux->first_tc) == -1) {
|
if (gst_video_time_code_compare (tc, pad->first_tc) == -1) {
|
||||||
gst_video_time_code_free (qtmux->first_tc);
|
gst_video_time_code_free (pad->first_tc);
|
||||||
qtmux->first_tc = gst_video_time_code_copy (tc);
|
pad->first_tc = gst_video_time_code_copy (tc);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
guint64 bk_size = qtmux->mdat_size;
|
guint64 bk_size = qtmux->mdat_size;
|
||||||
|
@ -3165,7 +3171,7 @@ gst_qt_mux_check_and_update_timecode (GstQTMux * qtmux, GstQTPad * pad,
|
||||||
/* If this frame's DTS is after the first PTS received, it means
|
/* If this frame's DTS is after the first PTS received, it means
|
||||||
* we've already received the first frame to be presented. Otherwise
|
* we've already received the first frame to be presented. Otherwise
|
||||||
* the decoder would need to go back in time */
|
* the decoder would need to go back in time */
|
||||||
gst_qt_mux_update_timecode (qtmux);
|
gst_qt_mux_update_timecode (qtmux, pad);
|
||||||
|
|
||||||
/* Reset writing position */
|
/* Reset writing position */
|
||||||
gst_segment_init (&segment, GST_FORMAT_BYTES);
|
gst_segment_init (&segment, GST_FORMAT_BYTES);
|
||||||
|
@ -5031,8 +5037,6 @@ gst_qt_mux_change_state (GstElement * element, GstStateChange transition)
|
||||||
case GST_STATE_CHANGE_READY_TO_PAUSED:
|
case GST_STATE_CHANGE_READY_TO_PAUSED:
|
||||||
gst_collect_pads_start (qtmux->collect);
|
gst_collect_pads_start (qtmux->collect);
|
||||||
qtmux->state = GST_QT_MUX_STATE_STARTED;
|
qtmux->state = GST_QT_MUX_STATE_STARTED;
|
||||||
qtmux->first_tc = NULL;
|
|
||||||
qtmux->tc_pos = -1;
|
|
||||||
break;
|
break;
|
||||||
case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
|
case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -144,6 +144,11 @@ struct _GstQTPad
|
||||||
GstQTPadPrepareBufferFunc prepare_buf_func;
|
GstQTPadPrepareBufferFunc prepare_buf_func;
|
||||||
GstQTPadSetCapsFunc set_caps;
|
GstQTPadSetCapsFunc set_caps;
|
||||||
GstQTPadCreateEmptyBufferFunc create_empty_buffer;
|
GstQTPadCreateEmptyBufferFunc create_empty_buffer;
|
||||||
|
|
||||||
|
/* SMPTE timecode */
|
||||||
|
GstVideoTimeCode *first_tc;
|
||||||
|
GstClockTime first_pts;
|
||||||
|
guint64 tc_pos;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef enum _GstQTMuxState
|
typedef enum _GstQTMuxState
|
||||||
|
@ -212,11 +217,6 @@ struct _GstQTMux
|
||||||
/* Set when tags are received, cleared when written to moov */
|
/* Set when tags are received, cleared when written to moov */
|
||||||
gboolean tags_changed;
|
gboolean tags_changed;
|
||||||
|
|
||||||
/* SMPTE timecode */
|
|
||||||
GstVideoTimeCode *first_tc;
|
|
||||||
GstClockTime first_pts;
|
|
||||||
guint64 tc_pos;
|
|
||||||
|
|
||||||
/* fragmented file index */
|
/* fragmented file index */
|
||||||
AtomMFRA *mfra;
|
AtomMFRA *mfra;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue