[MPlayer-dev-eng] [PATCH] faster MPEG demuxing

Reimar Döffinger Reimar.Doeffinger at stud.uni-karlsruhe.de
Wed Aug 31 02:10:01 CEST 2005


Hi,
well, actually it is mostly a fix for my horribly gxf demuxer. But the
parse_es.c seem to be a bit faster like this, too.
What do you think about it? Especially the __builtin_expect macros can
make quite a difference in some cases, that's why this patch would
define them in config.h (I admit, probably not the best place,
suggestions as always welcome...)
Please comment and test (i.e. benchmark).

Greetings,
Reimar Döffinger
-------------- next part --------------
Index: libmpdemux/demux_mpg.c
===================================================================
RCS file: /cvsroot/mplayer/main/libmpdemux/demux_mpg.c,v
retrieving revision 1.61
diff -u -r1.61 demux_mpg.c
--- libmpdemux/demux_mpg.c	26 Aug 2005 17:40:01 -0000	1.61
+++ libmpdemux/demux_mpg.c	30 Aug 2005 23:06:24 -0000
@@ -506,33 +506,70 @@
   return 1;
 }
 
+/**
+ * \brief discard until 0x100 header and return a filled buffer
+ * \param b buffer-end pointer
+ * \param pos current pos in stream, negative since b points to end of buffer
+ * \param s stream to read from
+ * \return new position, differs from original pos when eof hit and thus
+ *             b was modified to point to the new end of buffer
+ */
+static int find_end(unsigned char **b, int pos, stream_t *s) {
+  register int state = 0xffffffff;
+  unsigned char *buf = *b;
+  int start = pos;
+  int read, unused;
+  // search already read part
+  while (state != 0x100 && pos) {
+    state = state << 8 | buf[pos++];
+  }
+  // continue search in stream
+  while (state != 0x100) {
+    register int c = stream_read_char(s);
+    if (c < 0) break;
+    state = state << 8 | c;
+  }
+  // modify previous header (from 0x1bc or 0x1bf to 0x100)
+  buf[start++] = 0;
+  // copy remaining buffer part to current pos
+  memmove(&buf[start], &buf[pos], -pos);
+  unused = start + -pos; // -unused bytes in buffer
+  read = stream_read(s, &buf[unused], -unused);
+  unused += read;
+  // fix buffer so it ends at pos == 0 (eof case)
+  *b = &buf[unused];
+  start -= unused;
+  return start;
+}
+
+/**
+ * This format usually uses an insane bitrate, which makes this function
+ * performance-critical!
+ * Be sure to benchmark any changes with different compiler versions.
+ */
 static int demux_mpg_gxf_fill_buffer(demuxer_t *demux, demux_stream_t *ds) {
   demux_packet_t *pack;
-  uint32_t state = (uint32_t)demux->priv;
-  int pos = 0;
-  int discard = 0;
-  unsigned char *buf;
-  if (demux->stream->eof)
-    return 0;
+  int len;
   demux->filepos = stream_tell(demux->stream);
   pack = new_demux_packet(STREAM_BUFFER_SIZE);
-  buf = pack->buffer;
-  while (pos < STREAM_BUFFER_SIZE) {
-    register int c = stream_read_char(demux->stream);
-    if (c < 0) { // EOF
-      resize_demux_packet(pack, pos);
-      break;
-    }
-    state = state << 8 | c;
-    if (state == 0x1bc || state == 0x1bf)
-      discard = 1;
-    else if (state == 0x100)
-      discard = 0;
-    if (!discard)
-      buf[pos++] = c;
+  len = stream_read(demux->stream, pack->buffer, STREAM_BUFFER_SIZE);
+  if (len <= 0)
+    return 0;
+  {
+    register uint32_t state = (uint32_t)demux->priv;
+    register int pos = -len;
+    unsigned char *buf = &pack->buffer[len];
+    do {
+      state = state << 8 | buf[pos];
+      if (unlikely((state | 3) == 0x1bf))
+        pos = find_end(&buf, pos, demux->stream);
+    } while (++pos);
+    demux->priv = (void *)state;
+    len = buf - pack->buffer;
   }
+  if (len < STREAM_BUFFER_SIZE)
+    resize_demux_packet(pack, len);
   ds_add_packet(ds, pack);
-  demux->priv = (void *)state;
   return 1;
 }
 
Index: libmpdemux/demuxer.h
===================================================================
RCS file: /cvsroot/mplayer/main/libmpdemux/demuxer.h,v
retrieving revision 1.80
diff -u -r1.80 demuxer.h
--- libmpdemux/demuxer.h	26 Aug 2005 17:40:02 -0000	1.80
+++ libmpdemux/demuxer.h	30 Aug 2005 23:06:27 -0000
@@ -259,8 +259,8 @@
 
 #if 1
 #define demux_getc(ds) (\
-     (ds->buffer_pos<ds->buffer_size) ? ds->buffer[ds->buffer_pos++] \
-     :((!ds_fill_buffer(ds))? (-1) : ds->buffer[ds->buffer_pos++] ) )
+     (likely(ds->buffer_pos<ds->buffer_size)) ? ds->buffer[ds->buffer_pos++] \
+     :((unlikely(!ds_fill_buffer(ds)))? (-1) : ds->buffer[ds->buffer_pos++] ) )
 #else
 inline static int demux_getc(demux_stream_t *ds){
   if(ds->buffer_pos>=ds->buffer_size){
Index: libmpdemux/parse_es.c
===================================================================
RCS file: /cvsroot/mplayer/main/libmpdemux/parse_es.c,v
retrieving revision 1.7
diff -u -r1.7 parse_es.c
--- libmpdemux/parse_es.c	30 Oct 2001 17:03:11 -0000	1.7
+++ libmpdemux/parse_es.c	30 Aug 2005 23:06:27 -0000
@@ -53,6 +53,8 @@
 int read_video_packet(demux_stream_t *ds){
 int packet_start;
   
+  if (VIDEOBUFFER_SIZE - videobuf_len < 5)
+    return 0;
   // SYNC STREAM
 //  if(!sync_video_packet(ds)) return 0; // cannot sync (EOF)
 
@@ -65,21 +67,20 @@
   videobuf_len+=4;
   
   // READ PACKET:
-  { unsigned int head=-1;
-    while(videobuf_len<VIDEOBUFFER_SIZE){
+  {
+    register uint32_t head = 0xffffffff;
+    register unsigned char *buf = &videobuffer[VIDEOBUFFER_SIZE];
+    register int pos = videobuf_len - VIDEOBUFFER_SIZE;
+    do {
       int c=demux_getc(ds);
       if(c<0) break; // EOF
-      videobuffer[videobuf_len++]=c;
-#if 1
+      buf[pos]=c;
       head<<=8;
       if(head==0x100) break; // synced
       head|=c;
-#else
-      if(videobuffer[videobuf_len-4]==0 &&
-         videobuffer[videobuf_len-3]==0 &&
-         videobuffer[videobuf_len-2]==1) break; // synced
-#endif
-    }
+    } while (++pos);
+    if (pos) pos++; // increment missed because of break
+    videobuf_len = &buf[pos] - videobuffer;
   }
   
   if(ds->eof){
Index: configure
===================================================================
RCS file: /cvsroot/mplayer/main/configure,v
retrieving revision 1.1045
diff -u -r1.1045 configure
--- configure	19 Aug 2005 19:24:30 -0000	1.1045
+++ configure	30 Aug 2005 23:06:54 -0000
@@ -7152,6 +7082,13 @@
 
 /* __builtin_expect branch prediction hint */
 $_def_builtin_expect
+#ifdef HAVE_BUILTIN_EXPECT
+#define likely(x) __builtin_expect ((x) != 0, 1)
+#define unlikely(x) __builtin_expect ((x) != 0, 0)
+#else
+#define likely(x) (x)
+#define unlikely(x) (x)
+#endif
 
 /* attribute(used) as needed by some compilers */
 #if (__GNUC__ * 100 + __GNUC_MINOR__ >= 300)


More information about the MPlayer-dev-eng mailing list