[gst-cvs] CVS: gstreamer/plugins/mpeg2/parse mpeg2parse.c,1.32.4.3,1.32.4.4

Wim Taymans wtay at users.sourceforge.net
Sun Sep 23 16:24:02 PDT 2001


Update of /cvsroot/gstreamer/gstreamer/plugins/mpeg2/parse
In directory usw-pr-cvs1:/tmp/cvs-serv12524

Modified Files:
      Tag: BRANCH-EVENTS1
	mpeg2parse.c 
Log Message:
Added parsing of mpeg1 systems streams using bytestreams


Index: mpeg2parse.c
===================================================================
RCS file: /cvsroot/gstreamer/gstreamer/plugins/mpeg2/parse/mpeg2parse.c,v
retrieving revision 1.32.4.3
retrieving revision 1.32.4.4
diff -u -d -r1.32.4.3 -r1.32.4.4
--- mpeg2parse.c	2001/09/23 04:56:02	1.32.4.3
+++ mpeg2parse.c	2001/09/23 23:23:53	1.32.4.4
@@ -248,18 +248,18 @@
 }
 
 static inline gboolean
-parse_syshead (Mpeg2Parse *mpeg2parse)
+parse_syshead (Mpeg2Parse * mpeg2parse)
 {
   guint16 header_length;
   GstByteStream *bs = mpeg2parse->bs;
   guchar *buf;
 
-  GST_DEBUG (0,"mpeg2parse: in parse_syshead\n");
+  GST_DEBUG (0, "mpeg2parse: in parse_syshead\n");
 
   buf = gst_bytestream_peek_bytes (bs, 2);
 
-  header_length = GUINT16_FROM_BE (*(guint16*)buf);
-  GST_DEBUG (0,"mpeg2parse: header_length %d\n", header_length);
+  header_length = GUINT16_FROM_BE (*(guint16 *) buf);
+  GST_DEBUG (0, "mpeg2parse: header_length %d\n", header_length);
   buf = gst_bytestream_peek_bytes (bs, 2 + header_length);
   buf += 2;
 
@@ -268,18 +268,297 @@
 
   // audio_bound:6==1 ! fixed:1 | constrained:1
   buf += 1;
-  
+
   // audio_lock:1 | video_lock:1 | marker:1==1 | video_bound:5
   buf += 1;
 
   // apacket_rate_restriction:1 | reserved:7==0x7F
   buf += 1;
 
+  if (!mpeg2parse->MPEG2) {
+    gint stream_count = (header_length - 6) / 3;
+    gint i, j=0;
+
+    GST_DEBUG (0, "mpeg2parse::parse_syshead: number of streams=%d \n",
+	       stream_count);
+
+    for (i = 0; i < stream_count; i++) {
+      gint stream_num;
+      guint8 stream_id;
+      gboolean STD_buffer_bound_scale;
+      guint16 STD_buffer_size_bound;
+      guint32 buf_byte_size_bound;
+      gchar *name = NULL;
+      GstPad **outpad = NULL;
+      GstPadTemplate *newtemp = NULL;
+
+      stream_id = *buf++;
+      if (!(stream_id & 0x80)) {
+	GST_DEBUG (0, "mpeg2parse::parse_syshead: error in system header length\n");
+	return FALSE;
+      }
+
+      // check marker bits
+      if ((*buf & 0xC0) != 0xC0) {
+	GST_DEBUG (0,
+		   "mpeg2parse::parse_syshead: expecting placeholder bit values '11' after stream id\n");
+	return FALSE;
+      }
+
+      STD_buffer_bound_scale = *buf & 0x20;
+      STD_buffer_size_bound = (*buf++ & 0x1F) << 8;
+      STD_buffer_size_bound |= *buf++;
+
+      if (STD_buffer_bound_scale == 0) {
+	buf_byte_size_bound = STD_buffer_size_bound * 128;
+      }
+      else {
+	buf_byte_size_bound = STD_buffer_size_bound * 1024;
+      }
+
+      // private_stream_1
+      if (stream_id == 0xBD) {
+      }
+      // private_stream_2
+      else if (stream_id == 0xBF) {
+	name = g_strdup_printf ("private_stream_2");
+	stream_num = 0;
+	outpad = &mpeg2parse->private_2_pad;
+	newtemp = GST_PADTEMPLATE_GET (private2_factory);
+      }
+      // Audio
+      else if ((stream_id >= 0xC0) && (stream_id <= 0xDF)) {
+	name = g_strdup_printf ("audio_%02d", stream_id & 0x1F);
+	stream_num = stream_id & 0x1F;
+	outpad = &mpeg2parse->audio_pad[stream_num];
+	newtemp = GST_PADTEMPLATE_GET (audio_factory);
+      }
+      // Video
+      else if ((stream_id >= 0xE0) && (stream_id <= 0xEF)) {
+	name = g_strdup_printf ("video_%02d", stream_id & 0x0F);
+	stream_num = stream_id & 0x0F;
+	outpad = &mpeg2parse->video_pad[stream_num];
+	newtemp = GST_PADTEMPLATE_GET (video_factory);
+      }
+
+      GST_DEBUG (0, "mpeg2parse::parse_syshead: stream ID 0x%02X (%s)\n", stream_id, name);
+      GST_DEBUG (0, "mpeg2parse::parse_syshead: STD_buffer_bound_scale %d\n", STD_buffer_bound_scale);
+      GST_DEBUG (0, "mpeg2parse::parse_syshead: STD_buffer_size_bound %d or %d bytes\n",
+		 STD_buffer_size_bound, buf_byte_size_bound);
+
+      // create the pad and add it to self if it does not yet exist
+      // this should trigger the NEW_PAD signal, which should be caught by
+      // the app and used to attach to desired streams.
+      if (*outpad == NULL) {
+	(*outpad) = gst_pad_new_from_template (newtemp, name);
+	gst_pad_set_caps (*outpad, gst_pad_get_padtemplate_caps (*outpad));
+	gst_element_add_pad (GST_ELEMENT (mpeg2parse), (*outpad));
+      }
+      else {
+	// we won't be needing this.
+	if (name)
+	  g_free (name);
+      }
+
+      mpeg2parse->STD_buffer_info[j].stream_id = stream_id;
+      mpeg2parse->STD_buffer_info[j].STD_buffer_bound_scale =
+	STD_buffer_bound_scale;
+      mpeg2parse->STD_buffer_info[j].STD_buffer_size_bound =
+	STD_buffer_size_bound;
+
+      j++;
+    }
+  }
+
+  // return total number of bytes used in this chunk
   gst_bytestream_flush (bs, 2 + header_length);
 
   return TRUE;
 }
 
+static gboolean
+parse_packet (Mpeg2Parse *mpeg2parse)
+{
+  guint8 id = mpeg2parse->id;
+  guint16 headerlen;
+  gboolean *need_flush = NULL;
+
+  guint16 packet_length;
+  gboolean std_buffer_scale;
+  guint16 std_buffer_size;
+  guint64 dts;
+
+  guint16 datalen;
+  gulong outoffset = 0;
+  guint8 ac3_track_code;
+
+  GstPad **outpad = NULL;
+  GstBuffer *outbuf;
+  guchar *buf;
+  GstByteStream *bs = mpeg2parse->bs;
+
+  GST_DEBUG (0,"mpeg2parse::parse_packet: in parse_packet\n");
+
+
+  buf = gst_bytestream_peek_bytes (bs, 2);
+
+  // start parsing
+  packet_length = GUINT16_FROM_BE (*((guint16 *)buf));
+
+  GST_DEBUG (0,"mpeg2parse: got packet_length %d\n",packet_length);
+  buf = gst_bytestream_peek_bytes (bs, 2 + packet_length);
+  buf += 2;
+  headerlen = 2;
+
+  // loop through looping for stuffing bits, STD, PTS, DTS, etc
+  do {
+    guint8 bits = *buf++;
+
+    // stuffing bytes
+    switch (bits & 0xC0) {
+      case 0xC0:
+        if (bits == 0xff) {
+          GST_DEBUG (0,"mpeg2parse::parse_packet: have stuffing byte\n");
+        } else {
+          GST_DEBUG (0,"mpeg2parse::parse_packet: expected stuffing byte\n");
+        }
+        headerlen++;
+	break;
+      case 0x40:
+        GST_DEBUG (0,"mpeg2parse::parse_packet: have STD\n");
+	buf++;
+        //std_buffer_scale = gst_getbits1(&mpeg2parse->gb);
+        //std_buffer_size = gst_getbits13(&mpeg2parse->gb);
+        headerlen += 2;
+	break;
+      case 0x00:
+        switch (bits & 0x30) {
+	  case 0x20:
+	    buf += 4;
+	    // timestamp:36
+            //calc_time_stamp(&mpeg2parse->gb, mpeg2parse->last_pts);
+            GST_DEBUG (0,"mpeg2parse::parse_packet: PTS = %llu\n", mpeg2parse->last_pts);
+            headerlen += 5;
+	    goto done;
+	  case 0x30:
+	    // timestamp:36
+	    buf += 4;
+            //calc_time_stamp(&mpeg2parse->gb, mpeg2parse->last_pts);
+	    // sync:4==1
+	    buf++;
+	    // timestamp:36
+	    buf += 4;
+            //calc_time_stamp(&mpeg2parse->gb, dts);
+            GST_DEBUG (0,"mpeg2parse::parse_packet: PTS = %llu, DTS = %llu\n", mpeg2parse->last_pts, dts);
+            headerlen += 10;
+	    goto done;
+	  case 0x00:
+            GST_DEBUG (0,"mpeg2parse::parse_packet: have no pts/dts\n");
+            GST_DEBUG (0,"mpeg2parse::parse_packet: got trailer bits %x\n", (bits & 0x0f));
+            if ((bits & 0x0f) != 0xf) {
+              GST_DEBUG (0,"mpeg2parse::parse_packet: not a valid packet time sequence\n");
+    	      goto error;
+            }
+            headerlen++;
+          default:
+	    goto done;
+	}
+      default:
+	goto done;
+    } 
+  } while (1);
+  GST_DEBUG (0,"mpeg2parse::parse_packet: done with header loop\n");
+
+done:
+  // calculate the amount of real data in this packet
+  datalen = packet_length - headerlen+2;
+  GST_DEBUG (0,"mpeg2parse::parse_packet: headerlen is %d, datalen is %d\n",
+        headerlen,datalen);
+
+  // private_stream_1
+  if (id == 0xBD) {
+    // first find the track code
+    //ac3_track_code = *(guint8 *)(data+headerlen);
+    // make sure it's valid
+    //if ((ac3_track_code >= 0x80) && (ac3_track_code <= 0x87)) {
+    //  GST_DEBUG (0,"mpeg2parse::parse_packet: 0x%02X: we have a private_stream_1 (AC3) packet, track %d\n",
+    //        id, ac3_track_code - 0x80);
+    //  outpad = &mpeg2parse->private_1_pad[ac3_track_code - 0x80];
+      // scrap first 4 bytes (so-called "mystery AC3 tag")
+      headerlen += 4;
+      datalen -= 4;
+    //}
+  // private_stream_1
+  } else if (id == 0xBF) {
+    GST_DEBUG (0,"mpeg2parse::parse_packet: 0x%02X: we have a private_stream_2 packet\n", id);
+    outpad = &mpeg2parse->private_2_pad;
+  // audio
+  } else if ((id >= 0xC0) && (id <= 0xDF)) {
+    GST_DEBUG (0,"mpeg2parse::parse_packet: 0x%02X: we have an audio packet\n", id);
+    outpad = &mpeg2parse->audio_pad[id & 0x1F];
+    outoffset = mpeg2parse->audio_offset[id & 0x1F];
+    mpeg2parse->audio_offset[id & 0x1F] += datalen;
+    need_flush = &mpeg2parse->audio_need_flush[id & 0x1F];
+  // video
+  } else if ((id >= 0xE0) && (id <= 0xEF)) {
+    GST_DEBUG (0,"mpeg2parse::parse_packet: 0x%02X: we have a video packet\n", id);
+    outpad = &mpeg2parse->video_pad[id & 0x0F];
+    outoffset = mpeg2parse->video_offset[id & 0x1F];
+    mpeg2parse->video_offset[id & 0x1F] += datalen;
+    need_flush = &mpeg2parse->video_need_flush[id & 0x1F];
+  }
+
+  // if we don't know what it is, bail
+  if (outpad == NULL) {
+    GST_DEBUG (0,"mpeg2parse::parse_packet: unknown packet id 0x%02X !!\n", id);
+    // return total number of bytes
+    goto error;
+  }
+
+  // FIXME, this should be done in parse_syshead
+  if ((*outpad) == NULL) {
+    GST_DEBUG (0,"mpeg2parse::parse_packet: unexpected packet id 0x%02X!!\n", id);
+    // return total number of bytes
+    goto error;
+  }
+
+  //if (!GST_STATE_IS_SET(mpeg2parse, GST_STATE_COMPLETE)) {
+  //  gst_element_set_state(GST_ELEMENT(mpeg2parse), GST_STATE_COMPLETE);
+  //}
+
+  // create the buffer and send it off to the Other Side
+  if (GST_PAD_CONNECTED(*outpad) && datalen > 0) {
+    // if this is part of the buffer, create a subbuffer
+    GST_DEBUG (0,"mpeg2parse::parse_packet: creating subbuffer len %d\n", datalen);
+    gst_bytestream_flush (bs, headerlen);
+
+    outbuf = gst_bytestream_read (bs, datalen);
+
+    GST_DEBUG (0,"mpeg2parse::parse_packet: pushing buffer of len %d id %d\n", datalen, id);
+    GST_BUFFER_OFFSET(outbuf) = outoffset;
+    if (need_flush && *need_flush) {
+      GST_BUFFER_FLAG_SET(outbuf, GST_BUFFER_FLUSH);
+      *need_flush = FALSE;
+    }
+    else {
+      GST_BUFFER_FLAG_UNSET(outbuf, GST_BUFFER_FLUSH);
+    }
+    GST_BUFFER_TIMESTAMP(outbuf) = (mpeg2parse->last_pts*1000000LL)/90000LL;
+    gst_pad_push((*outpad),outbuf);
+
+    return TRUE;
+  }
+  else {
+    gst_bytestream_flush (bs, 2 + packet_length);
+    return TRUE;
+  }
+
+error:
+  gst_bytestream_flush (bs, 2 + packet_length);
+
+  return FALSE;
+}
+
 static inline gboolean
 parse_pes (Mpeg2Parse *mpeg2parse)
 {
@@ -554,7 +833,10 @@
           printf("mpeg2parse: ******** unknown id 0x%02X\n",mpeg2parse->id);
 	}
 	else {
-          parse_pes (mpeg2parse);
+	  if (mpeg2parse->MPEG2) 
+            parse_pes (mpeg2parse);
+	  else
+            parse_packet (mpeg2parse);
         }
     }
   } while (!GST_ELEMENT_IS_COTHREAD_STOPPING(element));





More information about the Gstreamer-commits mailing list