[MPlayer-dev-eng] [PATCH] Support asf aspect ratio

Zuxy Meng zuxy.meng at gmail.com
Sun Dec 3 14:58:28 CET 2006


Hi,

Attached patch reads and applies aspect ratio information in asf/wmv
files. Code follows the style of get_ext_stream_properties. A sample
file can be found at
http://download.microsoft.com/download/a/9/3/a9327df4-aeb5-46de-b438-d0f60da6fb54/Coral_Reef_Adventure_1080.exe
(It's a self-extracting cabinet file containing a wmv and can be
opened with 7-zip).

BTW: The patch currently only supports stream-wide aspect.
Packet-level aspect is, er, too complex and I haven't seen any sample
that really makes use of it!
-- 
Zuxy
Beauty is truth,
While truth is beauty.
PGP KeyID: E8555ED6
-------------- next part --------------
Index: libmpdemux/asf.h
===================================================================
--- libmpdemux/asf.h	???????? 21461??
+++ libmpdemux/asf.h	????????????
@@ -84,6 +84,20 @@
 } ASF_content_description_t;
 
 ////////////////////////
+// ASF Metadata Record
+////////////////////////
+typedef struct __attribute__((packed)) {
+  // must be 0 for metadata record, might be non-zero for metadata lib record
+  uint16_t lang_list_index;
+  uint16_t stream_num;
+  uint16_t name_length;
+  uint16_t data_type;
+  uint32_t data_length;
+  uint16_t name[0];
+  // Followed by data
+} ASF_meta_record_t;
+
+////////////////////////
 // ASF Segment Header 
 ////////////////////////
 typedef struct __attribute__((packed)) {
@@ -127,6 +141,17 @@
 	ASF_Authenticate_e
 } ASF_StreamType_e;
 
+// Data types are usually represented by a uint16_t of following values
+typedef enum {
+	ASF_UCS16LEs_e,	// Unicode string encoded as UCS16LE
+	ASF_Bytes_e,	// Array of bytes
+	ASF_Bool_e,	// BOOL represented by a uint32_t
+	ASF_DWORD_e,
+	ASF_QWORD_e,
+	ASF_WORD_e,
+	ASF_GUID_e
+} ASF_DataType_e;
+
 typedef struct {
 	ASF_StreamType_e streaming_type;
 	int request;
@@ -174,6 +199,13 @@
     (h)->comment_size = le2me_16((h)->comment_size);			\
     (h)->rating_size = le2me_16((h)->rating_size);			\
 }
+#define le2me_ASF_meta_record_t(h) {					\
+    (h)->lang_list_index = le2me_16((h)->lang_list_index);		\
+    (h)->stream_no = le2me_16((h)->stream_no);				\
+    (h)->name_length = le2me_16((h)->name_length);			\
+    (h)->data_type = le2me_16((h)->data_type);				\
+    (h)->data_length = le2me_16((h)->data_length);			\
+}
 #define le2me_BITMAPINFOHEADER(h) {					\
     (h)->biSize = le2me_32((h)->biSize);				\
     (h)->biWidth = le2me_32((h)->biWidth);				\
@@ -208,6 +240,7 @@
 #define le2me_ASF_stream_header_t(h)	/**/
 #define le2me_ASF_file_header_t(h)	/**/
 #define le2me_ASF_content_description_t(h) /**/
+#define le2me_ASF_meta_record_t(h)  /**/
 #define le2me_BITMAPINFOHEADER(h)   /**/
 #define le2me_WAVEFORMATEX(h)	    /**/
 #define le2me_ASF_stream_chunck_t(h) /**/
Index: libmpdemux/asfheader.c
===================================================================
--- libmpdemux/asfheader.c	???????? 21461??
+++ libmpdemux/asfheader.c	????????????
@@ -60,6 +60,8 @@
   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};
+const char asf_metadata_header[16] = {0xea, 0xcb, 0xf8, 0xc5,
+  0xaf, 0x5b, 0x77, 0x48, 0x84, 0x67, 0xaa, 0x8c, 0x44, 0xfa, 0x4c, 0xca};
 
 static char* get_ucs2str(const uint16_t* inbuf, uint16_t inlen)
 {
@@ -205,6 +207,72 @@
   return 0;
 }
 
+static int get_meta(char *buf, int buf_len, int this_stream_num,
+    float* asp_ratio)
+{
+  int pos = 0;
+  uint64_t object_size;
+  uint16_t records_count, i;
+  uint32_t x = 0, y = 0;
+
+  if ((pos = find_asf_guid(buf, asf_metadata_header, pos, buf_len)) < 0)
+    return 0;
+
+  buf += pos;
+  object_size = *(uint64_t*)(buf - sizeof(uint64_t));
+  records_count = *(uint16_t*)buf;
+  buf += sizeof(uint16_t);
+
+  for (i = 0; i < records_count; i++) {
+    ASF_meta_record_t* record_entry = (ASF_meta_record_t*)buf;
+    uint32_t data;
+    uint16_t name_len;
+    char* name;
+
+    buf = (char*)&record_entry->name + record_entry->name_length +
+      record_entry->data_length;
+    le2me_ASF_meta_record_t(record_entry);
+    /* reserved, must be zero */
+    if (record_entry->lang_list_index)
+      continue;
+    /* match stream number: 0 to match all */
+    if (record_entry->stream_num && record_entry->stream_num != this_stream_num)
+      continue;
+    /* match name length */
+    if ((name_len = record_entry->name_length) !=
+        2 * strlen("AspectRatioX") + 2)
+      continue;
+    if (!(name = get_ucs2str(record_entry->name, name_len))) {
+      mp_msg(MSGT_HEADER, MSGL_ERR, MSGTR_MemAllocFailed);
+      continue;
+    }
+    if (strncmp(name, "AspectRatio", strlen("AspectRatio")) == 0) {
+      char* pdata = (char*)record_entry->name + name_len;
+      switch (record_entry->data_type) {
+      case ASF_DWORD_e:
+        data = le2me_32(*(uint32_t*)pdata);
+        break;
+      case ASF_WORD_e:
+        data = le2me_16(*(uint16_t*)pdata);
+        break;
+      default:
+        free(name);
+        continue;
+      }
+    }
+    if (name[strlen("AspectRatio")] == 'X')
+      x = data;
+    else if (name[strlen("AspectRatio")] == 'Y')
+      y = data;
+    free(name);
+    if (x && y) {
+      *asp_ratio = (float)x / (float)y;
+      return 1;
+    }
+  }
+  return 0;
+}
+
 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;
@@ -336,6 +404,7 @@
       case ASF_GUID_PREFIX_video_stream: {
         sh_video_t* sh_video=new_sh_video(demuxer,streamh->stream_no & 0x7F);
         unsigned int len=streamh->type_size-(4+4+1+2);
+        float asp_ratio;
 	++video_streams;
 //        sh_video->bih=malloc(chunksize); memset(sh_video->bih,0,chunksize);
         sh_video->bih=calloc((len<sizeof(BITMAPINFOHEADER))?sizeof(BITMAPINFOHEADER):len,1);
@@ -358,6 +427,10 @@
 	  sh_video->fps=1000.0f;
 	  sh_video->frametime=0.001f;
         }
+        if (get_meta(hdr, hdr_len, streamh->stream_no, &asp_ratio)) {
+          sh_video->aspect = asp_ratio * sh_video->bih->biWidth /
+            sh_video->bih->biHeight;
+        }
 
         if( mp_msg_test(MSGT_DEMUX,MSGL_V) ) print_video_header(sh_video->bih, MSGL_V);
         //asf_video_id=streamh.stream_no & 0x7F;


More information about the MPlayer-dev-eng mailing list