[MPlayer-dev-eng] [PATCH] - fix for audio and video in dvr-ms asf

John Donaghy johnfdonaghy at gmail.com
Sun Apr 30 00:45:44 CEST 2006


> > >
> > > +#if defined(ARCH_X86) || defined(ARCH_X86_64)
> > > +#    define unaligned32(a) (*(const uint32_t*)(a))
> > > +#else
> > > +#    ifdef __GNUC__
> > > +static inline uint32_t unaligned32(const void *v) {
> > > +    struct Unaligned {
> > > +        uint32_t i;
> > > +    } __attribute__((packed));
> > > +
> > > +    return ((const struct Unaligned *) v)->i;
> > > +}
> > > +#    elif defined(__DECC)
> > > +static inline uint32_t unaligned32(const void *v) {
> > > +    return *(const __unaligned uint32_t *) v;
> > > +}
> > > +#    else
> > > +static inline uint32_t unaligned32(const void *v) {
> > > +    return *(const uint32_t *) v;
> > > +}
> > > +#    endif
> > > +#endif //!ARCH_X86
> > > +
> >
> > Ugh. Scary. Why can't you use the LOAD_LE32 macros? Or alternatively
> > make similar LOAD_BE32 macros? This at least looks like both a
> > portability and maintainability macros - at best acceptable in highly
> > performance-critical code (if it makes a performance difference at all).
> >
>

I've replaced this in the attached version with a LOAD_BE32 macro
which I think is what you're suggesting but I'm not sure. It appears
to work on x86 but I'm not very knowlegable in this area. Can you
review and let me know if this is a correct and acceptable approach.

Thanks,

John
-------------- next part --------------
Index: asf.h
===================================================================
RCS file: /cvsroot/mplayer/main/libmpdemux/asf.h,v
retrieving revision 1.20
diff -u -r1.20 asf.h
--- asf.h	30 Mar 2006 23:06:18 -0000	1.20
+++ asf.h	29 Apr 2006 22:38:12 -0000
@@ -222,6 +222,9 @@
     unsigned packetsize;
     double   packetrate;
     unsigned movielength;
+    int asf_is_dvr_ms;
+    uint32_t asf_frame_state;
+    int asf_frame_start_found;
 };
 
 #endif
Index: asfheader.c
===================================================================
RCS file: /cvsroot/mplayer/main/libmpdemux/asfheader.c,v
retrieving revision 1.50
diff -u -r1.50 asfheader.c
--- asfheader.c	1 Apr 2006 23:50:30 -0000	1.50
+++ asfheader.c	29 Apr 2006 22:38:12 -0000
@@ -34,6 +34,8 @@
 #define ASF_GUID_PREFIX_file_header	0x8CABDCA1
 #define	ASF_GUID_PREFIX_content_desc	0x75b22633
 #define	ASF_GUID_PREFIX_stream_group	0x7bf875ce
+#define ASF_GUID_PREFIX_ext_audio_stream	0x31178C9D
+#define ASF_GUID_PREFIX_ext_stream_embed_stream_header	0x3AFB65E2
 
 /*
 const char asf_audio_stream_guid[16] = {0x40, 0x9e, 0x69, 0xf8,
@@ -51,6 +53,12 @@
   0x8d, 0x46, 0xd1, 0x11, 0x8d, 0x82, 0x00, 0x60, 0x97, 0xc9, 0xa2, 0xb2};
 const char asf_data_chunk_guid[16] = {0x36, 0x26, 0xb2, 0x75,
   0x8e, 0x66, 0xcf, 0x11, 0xa6, 0xd9, 0x00, 0xaa, 0x00, 0x62, 0xce, 0x6c};
+const char asf_ext_stream_embed_stream_header[16] = {0xe2, 0x65, 0xfb, 0x3a,
+  0xef, 0x47, 0xf2, 0x40, 0xac, 0x2c, 0x70, 0xa9, 0x0d, 0x71, 0xd3, 0x43};
+const char asf_ext_stream_audio[16] = {0x9d, 0x8c, 0x17, 0x31,
+  0xe1, 0x03, 0x28, 0x45, 0xb5, 0x82, 0x3d, 0xf9, 0xdb, 0x22, 0xf5, 0x03};
+const char asf_ext_stream_header[16] = {0xCB, 0xA5, 0xE6, 0x14,
+  0x72, 0xC6, 0x32, 0x43, 0x83, 0x99, 0xA9, 0x69, 0x52, 0x06, 0x5B, 0x5A};
 
 
 // the variable string is modify in this function
@@ -77,6 +85,10 @@
   switch(ASF_LOAD_GUID_PREFIX(guid)){
     case ASF_GUID_PREFIX_audio_stream:
       return "guid_audio_stream";
+    case ASF_GUID_PREFIX_ext_audio_stream:
+      return "guid_ext_audio_stream";
+    case ASF_GUID_PREFIX_ext_stream_embed_stream_header:
+      return "guid_ext_stream_embed_stream_header";
     case ASF_GUID_PREFIX_video_stream: 
       return "guid_video_stream";
     case ASF_GUID_PREFIX_audio_conceal_none:
@@ -144,6 +156,42 @@
   return -1;
 }
 
+static int find_backwards_asf_guid(char *buf, const char *guid, int cur_pos)
+{
+  int i;
+  for (i=cur_pos-16; i>0; i--) {
+    if (memcmp(&buf[i], guid, 16) == 0)
+      return i + 16 + 8; // point after guid + length
+  }
+  return -1;
+}
+
+static int asf_init_audio_stream(demuxer_t *demuxer,struct asf_priv* asf, sh_audio_t* sh_audio, ASF_stream_header_t *streamh, int *ppos, uint8_t** buf, char *hdr, unsigned int hdr_len)
+{
+  uint8_t *buffer = *buf;
+  int pos = *ppos;
+
+  sh_audio->wf=calloc((streamh->type_size<sizeof(WAVEFORMATEX))?sizeof(WAVEFORMATEX):streamh->type_size,1);
+  memcpy(sh_audio->wf,buffer,streamh->type_size);
+  le2me_WAVEFORMATEX(sh_audio->wf);
+  if( mp_msg_test(MSGT_HEADER,MSGL_V) ) print_wave_header(sh_audio->wf,MSGL_V);
+  if(ASF_LOAD_GUID_PREFIX(streamh->concealment)==ASF_GUID_PREFIX_audio_conceal_interleave){
+    buffer = &hdr[pos];
+    pos += streamh->stream_size;
+    if (pos > hdr_len) return 0;
+    asf->scrambling_h=buffer[0];
+    asf->scrambling_w=(buffer[2]<<8)|buffer[1];
+    asf->scrambling_b=(buffer[4]<<8)|buffer[3];
+    if(asf->scrambling_b>0){
+      asf->scrambling_w/=asf->scrambling_b;
+    }
+  } else {
+    asf->scrambling_b=asf->scrambling_h=asf->scrambling_w=1;
+  }
+  mp_msg(MSGT_HEADER,MSGL_V,"ASF: audio scrambling: %d x %d x %d\n",asf->scrambling_h,asf->scrambling_w,asf->scrambling_b);
+  return 1;
+}
+
 int read_asf_header(demuxer_t *demuxer,struct asf_priv* asf){
   int hdr_len = asf->header.objh.size - sizeof(asf->header);
   char *hdr = NULL;
@@ -156,6 +204,9 @@
   int best_video = -1;
   int best_audio = -1;
   uint64_t data_len;
+  ASF_stream_header_t *streamh;
+  uint8_t *buffer;
+  int audio_pos=0;
 
   if(hdr_len < 0) {
     mp_msg(MSGT_HEADER, MSGL_FATAL, "Header size is too small.\n");
@@ -179,12 +230,39 @@
     goto err_out;
   }
 
+  pos=0;
+  if ((pos = find_asf_guid(hdr, asf_ext_stream_audio, pos, hdr_len)) >= 0)
+  {
+    // Special case: found GUID for dvr-ms audio.
+    // Now skip back to associated stream header.
+    int sh_pos=0;
+
+    sh_pos = find_backwards_asf_guid(hdr, asf_stream_header_guid, pos);
+ 
+    if (sh_pos > 0) {
+       mp_msg(MSGT_HEADER, MSGL_V, "read_asf_header found dvr-ms audio stream header pos=%d\n", sh_pos);
+      // found audio stream header - following code reads header and
+      // initializes audio stream.
+      audio_pos = pos - 16 - 8;
+      streamh = (ASF_stream_header_t *)&hdr[sh_pos];
+      le2me_ASF_stream_header_t(streamh);
+      audio_pos += 64; //16+16+4+4+4+16+4;
+      buffer = &hdr[audio_pos];
+      sh_audio_t* sh_audio=new_sh_audio(demuxer,streamh->stream_no & 0x7F);
+      ++audio_streams;
+      if (!asf_init_audio_stream(demuxer, asf, sh_audio, streamh, &audio_pos, &buffer, hdr, hdr_len))
+        goto len_err_out;
+    }
+  }
   // find stream headers
-  pos = 0;
+  // only reset pos if we didnt find dvr_ms audio stream
+  // if we did find it then we want to avoid reading its header twice
+  if (audio_pos == 0) 
+    pos = 0;
+
   while ((pos = find_asf_guid(hdr, asf_stream_header_guid, pos, hdr_len)) >= 0)
   {
-    ASF_stream_header_t *streamh = (ASF_stream_header_t *)&hdr[pos];
-    uint8_t *buffer;
+    streamh = (ASF_stream_header_t *)&hdr[pos];
     pos += sizeof(ASF_stream_header_t);
     if (pos > hdr_len) goto len_err_out;
     le2me_ASF_stream_header_t(streamh);
@@ -206,24 +284,8 @@
       case ASF_GUID_PREFIX_audio_stream: {
         sh_audio_t* sh_audio=new_sh_audio(demuxer,streamh->stream_no & 0x7F);
         ++audio_streams;
-        sh_audio->wf=calloc((streamh->type_size<sizeof(WAVEFORMATEX))?sizeof(WAVEFORMATEX):streamh->type_size,1);
-        memcpy(sh_audio->wf,buffer,streamh->type_size);
-	le2me_WAVEFORMATEX(sh_audio->wf);
-        if( mp_msg_test(MSGT_HEADER,MSGL_V) ) print_wave_header(sh_audio->wf,MSGL_V);
-	if(ASF_LOAD_GUID_PREFIX(streamh->concealment)==ASF_GUID_PREFIX_audio_conceal_interleave){
-          buffer = &hdr[pos];
-          pos += streamh->stream_size;
-          if (pos > hdr_len) goto len_err_out;
-          asf->scrambling_h=buffer[0];
-          asf->scrambling_w=(buffer[2]<<8)|buffer[1];
-          asf->scrambling_b=(buffer[4]<<8)|buffer[3];
-          if(asf->scrambling_b>0){
-            asf->scrambling_w/=asf->scrambling_b;
-          }
-	} else {
-	  asf->scrambling_b=asf->scrambling_h=asf->scrambling_w=1;
-	}
-	mp_msg(MSGT_HEADER,MSGL_V,"ASF: audio scrambling: %d x %d x %d\n",asf->scrambling_h,asf->scrambling_w,asf->scrambling_b);
+        if (!asf_init_audio_stream(demuxer, asf, sh_audio, streamh, &pos, &buffer, hdr, hdr_len))
+          goto len_err_out;
 	//if(demuxer->audio->id==-1) demuxer->audio->id=streamh.stream_no & 0x7F;
         break;
         }
@@ -235,10 +297,14 @@
         sh_video->bih=calloc((len<sizeof(BITMAPINFOHEADER))?sizeof(BITMAPINFOHEADER):len,1);
         memcpy(sh_video->bih,&buffer[4+4+1+2],len);
 	le2me_BITMAPINFOHEADER(sh_video->bih);
-	if (sh_video->bih->biCompression == mmioFOURCC('D', 'V', 'R', ' '))
-	  mp_msg(MSGT_DEMUXER, MSGL_WARN, MSGTR_MPDEMUX_ASFHDR_DVRWantsLibavformat);
-        //sh_video->fps=(float)sh_video->video.dwRate/(float)sh_video->video.dwScale;
-        //sh_video->frametime=(float)sh_video->video.dwScale/(float)sh_video->video.dwRate;
+        if (sh_video->bih->biCompression == mmioFOURCC('D', 'V', 'R', ' ')) {
+          //mp_msg(MSGT_DEMUXER, MSGL_WARN, MSGTR_MPDEMUX_ASFHDR_DVRWantsLibavformat);
+          //sh_video->fps=(float)sh_video->video.dwRate/(float)sh_video->video.dwScale;
+          //sh_video->frametime=(float)sh_video->video.dwScale/(float)sh_video->video.dwRate;
+          asf->asf_frame_state=-1;
+          asf->asf_frame_start_found=0;
+          asf->asf_is_dvr_ms=1;
+        } else asf->asf_is_dvr_ms=0;
         if( mp_msg_test(MSGT_DEMUX,MSGL_V) ) print_video_header(sh_video->bih, MSGL_V);
         //asf_video_id=streamh.stream_no & 0x7F;
 	//if(demuxer->video->id==-1) demuxer->video->id=streamh.stream_no & 0x7F;
Index: demux_asf.c
===================================================================
RCS file: /cvsroot/mplayer/main/libmpdemux/demux_asf.c,v
retrieving revision 1.47
diff -u -r1.47 demux_asf.c
--- demux_asf.c	30 Mar 2006 23:06:18 -0000	1.47
+++ demux_asf.c	29 Apr 2006 22:38:13 -0000
@@ -14,6 +14,11 @@
 
 #include "libvo/fastmemcpy.h"
 
+#define ASFMIN(a,b) ((a) > (b) ? (b) : (a))
+#define SLICE_MIN_START_CODE    0x00000101
+#define SLICE_MAX_START_CODE    0x000001af
+#define END_NOT_FOUND -100
+
 /*
  * Load 16/32-bit values in little endian byte order
  * from an unaligned address
@@ -21,6 +26,10 @@
 #ifdef ARCH_X86
 #define	LOAD_LE32(p)	(*(unsigned int*)(p))
 #define	LOAD_LE16(p)	(*(unsigned short*)(p))
+#define	LOAD_BE32(p)	(((unsigned char*)(p))[3]     | \
+ 			 ((unsigned char*)(p))[2]<< 8 | \
+ 			 ((unsigned char*)(p))[1]<<16 | \
+ 			 ((unsigned char*)(p))[0]<<24 )
 #else
 #define	LOAD_LE32(p)	(((unsigned char*)(p))[0]     | \
  			 ((unsigned char*)(p))[1]<< 8 | \
@@ -28,6 +37,7 @@
  			 ((unsigned char*)(p))[3]<<24 )
 #define	LOAD_LE16(p)	(((unsigned char*)(p))[0]     | \
 			 ((unsigned char*)(p))[1]<<8)
+#define	LOAD_BE32(p)	(*(unsigned int*)(p))
 #endif
 
 // defined at asfheader.c:
@@ -64,9 +74,86 @@
 #define FF_INPUT_BUFFER_PADDING_SIZE 8
 #endif
 
+static const uint8_t *find_start_code(const uint8_t * restrict p, const uint8_t *end, uint32_t * restrict state){
+  int i;
+  if(p>=end)
+    return end;
+
+  for(i=0; i<3; i++){
+    uint32_t tmp= *state << 8;
+    *state= tmp + *(p++);
+    if(tmp == 0x100 || p==end)
+      return p;
+  }
+
+  while(p<end){
+    if     (p[-1] > 1      ) p+= 3;
+    else if(p[-2]          ) p+= 2;
+    else if(p[-3]|(p[-1]-1)) p++;
+    else{
+      p++;
+      break;
+    }
+  }
+
+  p= ASFMIN(p, end)-4;
+  *state=  LOAD_BE32(p);
+
+  return p+4;
+}
+
+static int mpeg1_find_frame_end(demuxer_t *demux, const uint8_t *buf, int buf_size)
+{
+  int i;
+  struct asf_priv* asf = demux->priv;
+
+  i=0;
+   if(!asf->asf_frame_start_found){
+    for(i=0; i<buf_size; i++){
+      i= find_start_code(buf+i, buf+buf_size, &asf->asf_frame_state) - buf - 1;
+      if(asf->asf_frame_state >= SLICE_MIN_START_CODE && asf->asf_frame_state <= SLICE_MAX_START_CODE){
+        i++;
+        asf->asf_frame_start_found=1;
+        break;
+      }
+    }
+  }
+
+  if(asf->asf_frame_start_found){
+    /* EOF considered as end of frame */
+      if (buf_size == 0)
+          return 0;
+            
+    for(; i<buf_size; i++){
+      i= find_start_code(buf+i, buf+buf_size, &asf->asf_frame_state) - buf - 1;
+      if((asf->asf_frame_state&0xFFFFFF00) == 0x100){
+        //if NOT in range 257 - 431
+        if(asf->asf_frame_state < SLICE_MIN_START_CODE || asf->asf_frame_state > SLICE_MAX_START_CODE){
+          asf->asf_frame_start_found=0;
+          asf->asf_frame_state=-1;
+          return i-3;
+        }
+      }
+    }
+  }
+  return END_NOT_FOUND;
+}
+
+static void demux_asf_append_to_packet(demux_packet_t* dp,unsigned char *data,int len,int offs)
+{
+  if(dp->len!=offs && offs!=-1) mp_msg(MSGT_DEMUX,MSGL_V,"warning! fragment.len=%d BUT next fragment offset=%d  \n",dp->len,offs);
+  dp->buffer=realloc(dp->buffer,dp->len+len+FF_INPUT_BUFFER_PADDING_SIZE);
+  memcpy(dp->buffer+dp->len,data,len);
+  memset(dp->buffer+dp->len+len, 0, FF_INPUT_BUFFER_PADDING_SIZE);
+  mp_dbg(MSGT_DEMUX,MSGL_DBG4,"data appended! %d+%d\n",dp->len,len);
+  dp->len+=len;
+}
+
 static int demux_asf_read_packet(demuxer_t *demux,unsigned char *data,int len,int id,int seq,unsigned long time,unsigned short dur,int offs,int keyframe){
   struct asf_priv* asf = demux->priv;
   demux_stream_t *ds=NULL;
+  int close_seg=0;
+  int frame_end_pos=END_NOT_FOUND;
   
   mp_dbg(MSGT_DEMUX,MSGL_DBG4,"demux_asf.read_packet: id=%d seq=%d len=%d\n",id,seq,len);
   
@@ -97,7 +184,23 @@
   
   if(ds){
     if(ds->asf_packet){
-      if(ds->asf_seq!=seq){
+      demux_packet_t* dp=ds->asf_packet;
+
+      if (ds==demux->video && asf->asf_is_dvr_ms) {
+        frame_end_pos=mpeg1_find_frame_end(demux, data, len);
+
+        if (frame_end_pos != END_NOT_FOUND) {
+          dp->pos=demux->filepos;
+          if (frame_end_pos > 0) {
+            demux_asf_append_to_packet(dp,data,frame_end_pos,offs);
+            data += frame_end_pos;
+            len -= frame_end_pos;
+          }
+          close_seg = 1;
+        } else seq = ds->asf_seq;
+      } else close_seg = ds->asf_seq!=seq;
+
+      if(close_seg){
         // closed segment, finalize packet:
 		if(ds==demux->audio)
 		  if(asf->scrambling_h>1 && asf->scrambling_w>1 && asf->scrambling_b>0)
@@ -106,13 +209,7 @@
         ds->asf_packet=NULL;
       } else {
         // append data to it!
-        demux_packet_t* dp=ds->asf_packet;
-        if(dp->len!=offs && offs!=-1) mp_msg(MSGT_DEMUX,MSGL_V,"warning! fragment.len=%d BUT next fragment offset=%d  \n",dp->len,offs);
-        dp->buffer=realloc(dp->buffer,dp->len+len+FF_INPUT_BUFFER_PADDING_SIZE);
-        memcpy(dp->buffer+dp->len,data,len);
-        memset(dp->buffer+dp->len+len, 0, FF_INPUT_BUFFER_PADDING_SIZE);
-        mp_dbg(MSGT_DEMUX,MSGL_DBG4,"data appended! %d+%d\n",dp->len,len);
-        dp->len+=len;
+        demux_asf_append_to_packet(dp,data,len,offs);
         // we are ready now.
         return 1;
       }





More information about the MPlayer-dev-eng mailing list