asfmux: Compatibility with WMSP in WMP
authorHåkon Skjelten <skjelten@pvv.org>
Thu, 21 Jan 2010 13:51:16 +0000 (10:51 -0300)
committerThiago Santos <thiago.sousa.santos@collabora.co.uk>
Mon, 25 Jan 2010 22:32:15 +0000 (19:32 -0300)
Makes the asfmux content compatible with WMSP and does
some hacks to make it playable in WMP, it doesn't accept
data objects with 0 size indicating that we don't know
its size, though the spec says it should be possible.

Fixes #607555

gst/asfmux/gstasfmux.c
gst/asfmux/gstasfmux.h
gst/asfmux/gstasfobjects.h

index 521e0543276a94ba67862a720cf96fca0a2298e7..31325670d6ee9a8dfcba48d3db0d4423f333df83 100644 (file)
@@ -1208,13 +1208,40 @@ static void
 gst_asf_mux_write_data_object (GstAsfMux * asfmux, guint8 ** buf)
 {
   gst_asf_put_guid (*buf, guids[ASF_DATA_OBJECT_INDEX]);
-  GST_WRITE_UINT64_LE (*buf + 16, 0);   /* object size - needs updating */
+
+  /* Data object size. This is always >= ASF_DATA_OBJECT_SIZE. The standard
+   * specifically accepts the value 0 in live streams, but WMP is not accepting
+   * this while streaming using WMSP, so we default to minimum size also for
+   * live streams. Otherwise this field must be updated later on when we know 
+   * the complete stream size.
+   */
+  GST_WRITE_UINT64_LE (*buf + 16, ASF_DATA_OBJECT_SIZE);
+
   gst_asf_put_guid (*buf + 24, asfmux->file_id);
   GST_WRITE_UINT64_LE (*buf + 40, 0);   /* total data packets */
   GST_WRITE_UINT16_LE (*buf + 48, 0x0101);      /* reserved */
   *buf += ASF_DATA_OBJECT_SIZE;
 }
 
+guint
+gst_asf_mux_find_payload_parsing_info_size (GstAsfMux * asfmux)
+{
+  /* Minimum payload parsing information size is 8 bytes */
+  guint size = 8;
+
+  if (asfmux->prop_packet_size > 65535)
+    size += 4;
+  else
+    size += 2;
+
+  if (asfmux->prop_padding > 65535)
+    size += 4;
+  else
+    size += 2;
+
+  return size;
+}
+
 /**
  * gst_asf_mux_start_file:
  * @asfmux: #GstAsfMux
@@ -1387,6 +1414,7 @@ gst_asf_mux_flush_payloads (GstAsfMux * asfmux)
   gboolean has_keyframe;
   AsfPayload *payload;
   guint32 payload_size;
+  guint offset;
 
   if (asfmux->payloads == NULL)
     return GST_FLOW_OK;         /* nothing to send is ok */
@@ -1397,8 +1425,8 @@ gst_asf_mux_flush_payloads (GstAsfMux * asfmux)
   memset (GST_BUFFER_DATA (buf), 0, asfmux->packet_size);
 
   /* 1 for the multiple payload flags */
-  data = GST_BUFFER_DATA (buf) + ASF_PAYLOAD_PARSING_INFO_SIZE + 1;
-  size_left = asfmux->packet_size - ASF_PAYLOAD_PARSING_INFO_SIZE - 1;
+  data = GST_BUFFER_DATA (buf) + asfmux->payload_parsing_info_size + 1;
+  size_left = asfmux->packet_size - asfmux->payload_parsing_info_size - 1;
 
   has_keyframe = FALSE;
   walk = asfmux->payloads;
@@ -1523,27 +1551,50 @@ gst_asf_mux_flush_payloads (GstAsfMux * asfmux)
       (ASF_FIELD_TYPE_DWORD << 3) |     /* padding length type */
       (ASF_FIELD_TYPE_NONE << 1) |      /* sequence type type */
       0x1);                     /* multiple payloads */
+  offset = 1;
 
   /* property flags - according to the spec, this should not change */
-  GST_WRITE_UINT8 (data + 1, (ASF_FIELD_TYPE_BYTE << 6) |       /* stream number length type */
+  GST_WRITE_UINT8 (data + offset, (ASF_FIELD_TYPE_BYTE << 6) |  /* stream number length type */
       (ASF_FIELD_TYPE_BYTE << 4) |      /* media obj number length type */
       (ASF_FIELD_TYPE_DWORD << 2) |     /* offset info media object length type */
       (ASF_FIELD_TYPE_BYTE));   /* replicated data length type */
+  offset++;
 
-  GST_WRITE_UINT32_LE (data + 2, asfmux->packet_size);
-  GST_WRITE_UINT32_LE (data + 6, size_left);    /* padding size */
+  /* Due to a limitation in WMP while streaming through WMSP we reduce the
+   * packet & padding size to 16bit if theay are <= 65535 bytes 
+   */
+  if (asfmux->packet_size > 65535) {
+    GST_WRITE_UINT32_LE (data + offset, asfmux->packet_size - size_left);
+    offset += 4;
+  } else {
+    *data &= ~(ASF_FIELD_TYPE_MASK << 5);
+    *data |= ASF_FIELD_TYPE_WORD << 5;
+    GST_WRITE_UINT16_LE (data + offset, asfmux->packet_size - size_left);
+    offset += 2;
+  }
+  if (asfmux->prop_padding > 65535) {
+    GST_WRITE_UINT32_LE (data + offset, size_left);
+    offset += 4;
+  } else {
+    *data &= ~(ASF_FIELD_TYPE_MASK << 3);
+    *data |= ASF_FIELD_TYPE_WORD << 3;
+    GST_WRITE_UINT16_LE (data + offset, size_left);
+    offset += 2;
+  }
 
   /* packet send time */
   if (GST_CLOCK_TIME_IS_VALID (send_ts)) {
-    GST_WRITE_UINT32_LE (data + 10, (send_ts / GST_MSECOND));
+    GST_WRITE_UINT32_LE (data + offset, (send_ts / GST_MSECOND));
     GST_BUFFER_TIMESTAMP (buf) = send_ts;
   }
+  offset += 4;
 
   /* packet duration */
-  GST_WRITE_UINT16_LE (data + 14, 0);   /* FIXME send duration needs to be estimated */
+  GST_WRITE_UINT16_LE (data + offset, 0);       /* FIXME send duration needs to be estimated */
+  offset += 2;
 
   /* multiple payloads flags */
-  GST_WRITE_UINT8 (data + 16, 0x2 << 6 | payloads_count);
+  GST_WRITE_UINT8 (data + offset, 0x2 << 6 | payloads_count);
 
   if (payloads_count == 0) {
     GST_WARNING_OBJECT (asfmux, "Sending packet without any payload");
@@ -1799,7 +1850,7 @@ gst_asf_mux_process_buffer (GstAsfMux * asfmux, GstAsfPad * pad,
   GST_LOG_OBJECT (asfmux, "Payload data size: %" G_GUINT32_FORMAT,
       asfmux->payload_data_size);
 
-  while (asfmux->payload_data_size + ASF_PAYLOAD_PARSING_INFO_SIZE >=
+  while (asfmux->payload_data_size + asfmux->payload_parsing_info_size >=
       asfmux->packet_size) {
     GstFlowReturn ret = gst_asf_mux_flush_payloads (asfmux);
     if (ret != GST_FLOW_OK)
@@ -2276,6 +2327,8 @@ gst_asf_mux_change_state (GstElement * element, GstStateChange transition)
     case GST_STATE_CHANGE_READY_TO_PAUSED:
       /* TODO - check if it is possible to mux 2 files without going
        * through here */
+      asfmux->payload_parsing_info_size =
+          gst_asf_mux_find_payload_parsing_info_size (asfmux);
       asfmux->packet_size = asfmux->prop_packet_size;
       asfmux->preroll = asfmux->prop_preroll;
       asfmux->merge_stream_tags = asfmux->prop_merge_stream_tags;
index 015c8b9abff19051416ca32ef563d170612691f0..dd157c566fec4aafc850216539a62850f0b78b83 100644 (file)
@@ -120,6 +120,7 @@ struct _GstAsfMux
 
   /* payloads still to be sent in a packet */
   guint32 payload_data_size;
+  guint32 payload_parsing_info_size;
   GSList *payloads;
 
   Guid file_id;
index a608dcee0b7f3ea063785ae6cf17d33b52a1bc43..affde86b623f18ed58b9de7589e68198c3a3bb20 100644 (file)
@@ -147,7 +147,6 @@ gboolean gst_asf_tag_present_in_content_description (const gchar * tag);
 #define ASF_AUDIO_SPECIFIC_DATA_SIZE 18
 #define ASF_VIDEO_SPECIFIC_DATA_SIZE 51
 #define ASF_DATA_OBJECT_SIZE 50
-#define ASF_PAYLOAD_PARSING_INFO_SIZE 16
 #define ASF_SINGLE_PAYLOAD_HEADER_SIZE 15
 #define ASF_MULTIPLE_PAYLOAD_HEADER_SIZE 17
 #define ASF_EXTENDED_STREAM_PROPERTIES_OBJECT_SIZE 88
@@ -163,6 +162,7 @@ gboolean gst_asf_tag_present_in_content_description (const gchar * tag);
 #define ASF_FIELD_TYPE_BYTE 1
 #define ASF_FIELD_TYPE_WORD 2
 #define ASF_FIELD_TYPE_DWORD 3
+#define ASF_FIELD_TYPE_MASK 3
 
 /* tag types */
 #define ASF_TAG_TYPE_UNICODE_STR 0