QtDemuxStream * stream, guint32 n);
static GstFlowReturn qtdemux_expose_streams (GstQTDemux * qtdemux);
-
static void
gst_qtdemux_base_init (gpointer klass)
{
qtdemux->posted_redirect = FALSE;
qtdemux->offset = 0;
qtdemux->first_mdat = -1;
+ qtdemux->header_size = 0;
qtdemux->got_moov = FALSE;
qtdemux->mdatoffset = GST_CLOCK_TIME_NONE;
if (qtdemux->mdatbuffer)
static void
qtdemux_parse_ftyp (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
{
+ /* counts as header data */
+ qtdemux->header_size += length;
+
/* only consider at least a sufficiently complete ftyp atom */
if (length >= 20) {
GstBuffer *buf;
};
guint offset;
+ /* counts as header data */
+ qtdemux->header_size += length;
+
offset = (QT_UINT32 (buffer) == 0) ? 16 : 8;
if (length <= offset + 16) {
qtdemux->moov_node = g_node_new ((guint8 *) buffer);
+ /* counts as header data */
+ qtdemux->header_size += length;
+
GST_DEBUG_OBJECT (qtdemux, "parsing 'moov' atom");
qtdemux_parse_node (qtdemux, qtdemux->moov_node, buffer, length);
}
}
+/* If we can estimate the overall bitrate, and don't have information about the
+ * stream bitrate for exactly one stream, this guesses the stream bitrate as
+ * the overall bitrate minus the sum of the bitrates of all other streams. This
+ * should be useful for the common case where we have one audio and one video
+ * stream and can estimate the bitrate of one, but not the other. */
+static void
+gst_qtdemux_guess_bitrate (GstQTDemux * qtdemux)
+{
+ GstFormat format = GST_FORMAT_BYTES;
+ QtDemuxStream *stream = NULL;
+ gint64 size, duration, sys_bitrate, sum_bitrate = 0;
+ gint i;
+ guint bitrate;
+
+ if (qtdemux->fragmented)
+ return;
+
+ GST_DEBUG_OBJECT (qtdemux, "Looking for streams with unknown bitrate");
+
+ if (!gst_pad_query_peer_duration (qtdemux->sinkpad, &format, &size) ||
+ format != GST_FORMAT_BYTES) {
+ GST_DEBUG_OBJECT (qtdemux,
+ "Size in bytes of the stream not known - bailing");
+ return;
+ }
+
+ /* Subtract the header size */
+ GST_DEBUG_OBJECT (qtdemux, "Total size %" G_GINT64_FORMAT ", header size %u",
+ size, qtdemux->header_size);
+ g_assert (size > qtdemux->header_size);
+ size = size - qtdemux->header_size;
+
+ if (!gst_qtdemux_get_duration (qtdemux, &duration) ||
+ duration == GST_CLOCK_TIME_NONE) {
+ GST_DEBUG_OBJECT (qtdemux, "Stream duration not known - bailing");
+ return;
+ }
+
+ for (i = 0; i < qtdemux->n_streams; i++) {
+ switch (qtdemux->streams[i]->subtype) {
+ case FOURCC_soun:
+ case FOURCC_vide:
+ /* retrieve bitrate, prefer avg then max */
+ if (qtdemux->streams[i]->pending_tags) {
+ gst_tag_list_get_uint (qtdemux->streams[i]->pending_tags,
+ GST_TAG_MAXIMUM_BITRATE, &bitrate);
+ gst_tag_list_get_uint (qtdemux->streams[i]->pending_tags,
+ GST_TAG_BITRATE, &bitrate);
+ }
+ if (bitrate)
+ sum_bitrate += bitrate;
+ else {
+ if (stream) {
+ GST_DEBUG_OBJECT (qtdemux,
+ ">1 stream with unknown bitrate - bailing");
+ return;
+ } else
+ stream = qtdemux->streams[i];
+ }
+
+ default:
+ /* For other subtypes, we assume no significant impact on bitrate */
+ break;
+ }
+ }
+
+ if (!stream) {
+ GST_DEBUG_OBJECT (qtdemux, "All stream bitrates are known");
+ return;
+ }
+
+ sys_bitrate = gst_util_uint64_scale (size, GST_SECOND * 8, duration);
+
+ if (sys_bitrate < sum_bitrate) {
+ /* This can happen, since sum_bitrate might be derived from maximum
+ * bitrates and not average bitrates */
+ GST_DEBUG_OBJECT (qtdemux,
+ "System bitrate less than sum bitrate - bailing");
+ return;
+ }
+
+ bitrate = sys_bitrate - sum_bitrate;
+ GST_DEBUG_OBJECT (qtdemux, "System bitrate = %" G_GINT64_FORMAT
+ ", Stream bitrate = %u", sys_bitrate, bitrate);
+
+ if (!stream->pending_tags)
+ stream->pending_tags = gst_tag_list_new ();
+
+ gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
+ GST_TAG_BITRATE, bitrate, NULL);
+}
+
static GstFlowReturn
qtdemux_expose_streams (GstQTDemux * qtdemux)
{
gst_qtdemux_add_stream (qtdemux, stream, list);
}
+ gst_qtdemux_guess_bitrate (qtdemux);
+
gst_element_no_more_pads (GST_ELEMENT_CAST (qtdemux));
/* check if we should post a redirect in case there is a single trak