mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-05-18 00:12:46 +00:00
Merge branch 'asfdemux-scan-duration' into 'main'
Draft: asfdemux: scan last packet to determine duration for files saved from broadcasts Closes #2633 See merge request gstreamer/gstreamer!1778
This commit is contained in:
commit
d605330bd5
|
@ -27,6 +27,7 @@
|
|||
|
||||
#include <gst/gstutils.h>
|
||||
#include <gst/gstinfo.h>
|
||||
#include <gst/base/gstbytereader.h>
|
||||
#include <string.h>
|
||||
|
||||
#define GST_ASF_PAYLOAD_KF_COMPLETE(stream, payload) (stream->is_video && payload->keyframe && payload->buf_filled >= payload->mo_size)
|
||||
|
@ -806,3 +807,61 @@ done:
|
|||
gst_buffer_unmap (buf, &map);
|
||||
return ret;
|
||||
}
|
||||
|
||||
gboolean
|
||||
gst_asf_packet_get_packet_times (GstASFDemux * demux, GstBuffer * buf,
|
||||
GstClockTime * send_time, GstClockTime * duration)
|
||||
{
|
||||
static const guint lens[4] = { 0, 1, 2, 4 };
|
||||
GstByteReader br;
|
||||
GstMapInfo map;
|
||||
gboolean ret = FALSE;
|
||||
guint8 ec_flags, flags1, len;
|
||||
|
||||
gst_buffer_map (buf, &map, GST_MAP_READ);
|
||||
|
||||
gst_byte_reader_init (&br, map.data, map.size);
|
||||
|
||||
/* need at least two payload flag bytes, send time, and duration */
|
||||
if (gst_byte_reader_get_remaining (&br) < 1 + 1 + 4 + 2)
|
||||
goto done;
|
||||
|
||||
ec_flags = gst_byte_reader_get_uint8_unchecked (&br);
|
||||
|
||||
/* skip optional error correction stuff */
|
||||
if ((ec_flags & 0x80) != 0) {
|
||||
guint ec_len_type, ec_len;
|
||||
|
||||
ec_len_type = (ec_flags & 0x60) >> 5;
|
||||
if (ec_len_type == 0) {
|
||||
ec_len = ec_flags & 0x0f;
|
||||
} else {
|
||||
ec_len = 2;
|
||||
}
|
||||
if (!gst_byte_reader_skip (&br, ec_len))
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* parse payload info */
|
||||
if (!gst_byte_reader_get_uint8 (&br, &flags1) ||
|
||||
!gst_byte_reader_skip (&br, 1))
|
||||
goto done;
|
||||
|
||||
len = lens[(flags1 >> 1) & 0x03]; /* sequence len */
|
||||
len += lens[(flags1 >> 3) & 0x03]; /* padding len */
|
||||
len += lens[(flags1 >> 5) & 0x03]; /* length len */
|
||||
|
||||
if (!gst_byte_reader_skip (&br, len))
|
||||
goto done;
|
||||
|
||||
if (gst_byte_reader_get_remaining (&br) < 4 + 2)
|
||||
goto done;
|
||||
|
||||
*send_time = gst_byte_reader_get_uint32_le_unchecked (&br) * GST_MSECOND;
|
||||
*duration = gst_byte_reader_get_uint16_le_unchecked (&br) * GST_MSECOND;
|
||||
ret = TRUE;
|
||||
|
||||
done:
|
||||
gst_buffer_unmap (buf, &map);
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -65,6 +65,11 @@ typedef enum {
|
|||
|
||||
GstAsfDemuxParsePacketError gst_asf_demux_parse_packet (GstASFDemux * demux, GstBuffer * buf);
|
||||
|
||||
gboolean gst_asf_packet_get_packet_times (GstASFDemux * demux,
|
||||
GstBuffer * buf,
|
||||
GstClockTime * send_time,
|
||||
GstClockTime * duration);
|
||||
|
||||
#define gst_asf_payload_is_complete(payload) \
|
||||
((payload)->buf_filled >= (payload)->mo_size)
|
||||
|
||||
|
|
|
@ -1150,6 +1150,73 @@ gst_asf_demux_pull_indices (GstASFDemux * demux)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_asf_demux_scan_peek_packet_times (GstASFDemux * demux, guint n,
|
||||
GstClockTime * send_time, GstClockTime * duration)
|
||||
{
|
||||
GstBuffer *buf = NULL;
|
||||
|
||||
if (!gst_asf_demux_pull_data (demux,
|
||||
demux->data_offset + (n * demux->packet_size), demux->packet_size,
|
||||
&buf, NULL))
|
||||
return FALSE;
|
||||
|
||||
if (!gst_asf_packet_get_packet_times (demux, buf, send_time, duration)) {
|
||||
GST_WARNING_OBJECT (demux, "Couldn't extract send time from packet %u", n);
|
||||
gst_buffer_unref (buf);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
GST_INFO_OBJECT (demux, "packet %u: send time %" GST_TIME_FORMAT
|
||||
", duration %" GST_TIME_FORMAT, n, GST_TIME_ARGS (*send_time),
|
||||
GST_TIME_ARGS (*duration));
|
||||
|
||||
gst_buffer_unref (buf);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_asf_demux_scan_for_duration (GstASFDemux * demux)
|
||||
{
|
||||
GstClockTime start, stop, duration;
|
||||
gint64 size = 0;
|
||||
guint num_packets, last;
|
||||
|
||||
if (!gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &size))
|
||||
return FALSE;
|
||||
|
||||
GST_INFO_OBJECT (demux, "file size %" G_GINT64_FORMAT, size);
|
||||
GST_INFO_OBJECT (demux, "data offset %" G_GUINT64_FORMAT, demux->data_offset);
|
||||
GST_INFO_OBJECT (demux, "packet size %u", demux->packet_size);
|
||||
|
||||
if (size <= demux->data_offset)
|
||||
return FALSE;
|
||||
|
||||
num_packets = (size - demux->data_offset) / demux->packet_size;
|
||||
GST_INFO_OBJECT (demux, "num_packets = %u (calculated)", num_packets);
|
||||
|
||||
if (num_packets < 10) /* arbitrary value */
|
||||
return FALSE;
|
||||
|
||||
if (!gst_asf_demux_scan_peek_packet_times (demux, 0, &start, &duration))
|
||||
return FALSE;
|
||||
|
||||
last = num_packets - 1;
|
||||
if (!gst_asf_demux_scan_peek_packet_times (demux, last, &stop, &duration))
|
||||
return FALSE;
|
||||
|
||||
if (GST_CLOCK_TIME_IS_VALID (duration))
|
||||
stop += duration;
|
||||
|
||||
demux->num_packets = num_packets;
|
||||
demux->play_time = stop - start;
|
||||
demux->segment.duration = stop - start;
|
||||
GST_INFO_OBJECT (demux, "scanned duration: %" GST_TIME_FORMAT,
|
||||
GST_TIME_ARGS (demux->play_time));
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
static gboolean
|
||||
gst_asf_demux_parse_data_object_start (GstASFDemux * demux, guint8 * data)
|
||||
{
|
||||
|
@ -1182,6 +1249,11 @@ gst_asf_demux_parse_data_object_start (GstASFDemux * demux, guint8 * data)
|
|||
demux->num_packets = GST_READ_UINT64_LE (data + (16 + 8) + 16);
|
||||
} else {
|
||||
demux->num_packets = 0;
|
||||
|
||||
if (!demux->streaming) {
|
||||
if (!gst_asf_demux_scan_for_duration (demux))
|
||||
GST_WARNING_OBJECT (demux, "couldn't determine duration");
|
||||
}
|
||||
}
|
||||
|
||||
if (demux->num_packets == 0)
|
||||
|
|
Loading…
Reference in a new issue