~fta/+junk/mediadb

« back to all changes in this revision

Viewing changes to asf.c

  • Committer: Fabien Tassin
  • Date: 2008-08-14 19:36:43 UTC
  • Revision ID: fta@sofaraway.org-20080814193643-pop12h3olx7azk41
* Initial revision, just the C code leading to identcd. The full PHP mediadb
  is not included, nor are all the data test files.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* asf.c */
 
2
/* Identify an ASF file and its parameters */
 
3
 
 
4
#include <stdio.h>
 
5
#include <string.h>
 
6
#include <stdlib.h>
 
7
#include <sys/stat.h>
 
8
#include "mediadb.h"
 
9
 
 
10
/* ASF GUIDs (Only the 1st 32bits out of 128 (MSB), enough for our needs). */
 
11
#define ASF_GUID_SIMPLE_INDEX   0x33000890 /* Simple Index */
 
12
#define ASF_GUID_HEADER_EXT     0x5fbf03b5 /* Header Extention */
 
13
#define ASF_GUID_HEADER         0x75b22630 /* Header */
 
14
#define ASF_GUID_CONTENT_DESC   0x75b22633 /* Content Description */
 
15
#define ASF_GUID_DATA           0x75b22636 /* Data */
 
16
#define ASF_GUID_STREAM_BR_PROP 0x7bf875ce /* Stream Bitrate Properties */
 
17
#define ASF_GUID_CODEC_LIST     0x86d15240 /* Codec List */
 
18
#define ASF_GUID_FILE_PROP      0x8cabdca1 /* File Properties */
 
19
#define ASF_GUID_RESERVED1      0xabd3d211 /* Reserved */
 
20
#define ASF_GUID_STREAM_PROP    0xb7dc0791 /* Stream Properties */
 
21
#define ASF_GUID_VIDEO_MEDIA    0xbc19efc0 /* Video Media */
 
22
#define ASF_GUID_EXT_CONT_DESC  0xd2d0a440 /* Extended Content Description */
 
23
#define ASF_GUID_AUDIO_MEDIA    0xf8699e40 /* Audio Media */
 
24
 
 
25
typedef struct __attribute__ ((packed)) {
 
26
  unsigned char guid[16];
 
27
  unsigned long long size;
 
28
} asf_obj_header_t;
 
29
 
 
30
typedef struct __attribute__ ((packed)) {
 
31
  asf_obj_header_t objh;
 
32
  unsigned int nho; /* number of header objects */
 
33
  unsigned char reserved1; /* Must be 0x01 and ignored */
 
34
  unsigned char reserved2; /* Must be 0x02 or fail */
 
35
} asf_header_t;
 
36
 
 
37
typedef struct __attribute__ ((packed)) {
 
38
  unsigned char reserved1[16];
 
39
  unsigned short reserved2;
 
40
  unsigned int data_size;
 
41
} asf_header_ext_t;
 
42
 
 
43
typedef struct __attribute__ ((packed)) {
 
44
  unsigned char fileid[16];         /* file ID */
 
45
  unsigned long long file_size;     /* entire file size in bytes */
 
46
  unsigned long long creat_date;    /* creation date and time */
 
47
  unsigned long long packets;       /* number of packets in the data object */
 
48
  unsigned long long play_duration; /* time needed to play file */
 
49
  unsigned long long send_duration; /* time needed to send file */
 
50
  unsigned long long preroll;       /* time to buffer data before play */
 
51
  unsigned long flags;              /* Flags (Broadcast/Seekable/Reserved) */
 
52
  unsigned long min_packetsize;     /* Minimum packet Size in bytes */
 
53
  unsigned long max_packetsize;     /* Maximum packet Size in bytes */
 
54
  unsigned long max_bitrate;        /* Maximum bitrate */
 
55
} asf_file_prop_t;
 
56
 
 
57
typedef struct __attribute__ ((packed)) {
 
58
  unsigned char stream_type[16];  /* stream type (GUID) */
 
59
  unsigned char errcorr_type[16]; /* error correction type (GUID) */
 
60
  unsigned long long time_offset; /* time offset */
 
61
  unsigned long type_data_len;    /* type specific data len */
 
62
  unsigned long errcorr_data_len; /* error correction specific data len */
 
63
  unsigned short flags;           /* flags (stream num/reserved/encrypt) */
 
64
  unsigned long reserved;
 
65
} asf_stream_prop_t;
 
66
 
 
67
typedef struct __attribute__ ((packed)) {
 
68
  unsigned char reserved[16];  /* reserved (GUID) */
 
69
  unsigned long num_codec;     /* number of codec entries in the list */
 
70
} asf_codec_list_t;
 
71
 
 
72
typedef enum {
 
73
  ASF_AUDIO_VOXWARE     = 0x0075,
 
74
  ASF_AUDIO_WMA         = 0x0160,
 
75
  ASF_AUDIO_WMA2        = 0x0161, /* Version 7 & 8 */
 
76
  ASF_AUDIO_GMS_AMR_CBR = 0x7A21, /* Fixed bitrate, no SID */
 
77
  ASF_AUDIO_GMS_AMR_VBR = 0x7A22  /* Variable bitrate, including SID */
 
78
} asf_audio_codecs;
 
79
 
 
80
typedef struct __attribute__ ((packed)) {
 
81
  unsigned short codec;
 
82
  unsigned short channels;
 
83
  unsigned long  srate;      /* in Hertz */
 
84
  unsigned long  bitrate;    /* in bytes per second of audio stream */
 
85
  unsigned short block_size; /* in bytes */
 
86
  unsigned short bit_per_sample;
 
87
  unsigned short size;       /* size of codec specific data */
 
88
} asf_audio_type_t;
 
89
 
 
90
typedef struct __attribute__ ((packed)) {
 
91
  unsigned long  data_size;
 
92
  unsigned long  width;     /* in pixels */
 
93
  unsigned long  height;    /* in pixels */
 
94
  unsigned short planes;    /* reserved, always 1 */
 
95
  unsigned short depth;     /* bits per pixel */
 
96
  unsigned long  codec;
 
97
  unsigned long  size;
 
98
  unsigned long  hppm;      /* horizontal pixels per meter */
 
99
  unsigned long  vppm;      /* vertical pixels per meter */
 
100
  unsigned long  colors;
 
101
  unsigned long  imp_colors;
 
102
} asf_video_format_t;
 
103
 
 
104
typedef struct __attribute__ ((packed)) {
 
105
  unsigned long      width;     /* in pixels */
 
106
  unsigned long      height;    /* in pixels */
 
107
  char               flags;     /* = 2 */
 
108
  unsigned short     data_size;
 
109
  asf_video_format_t data;
 
110
} asf_video_type_t;
 
111
 
 
112
int MEDIA_expectguid(char *expect, char *read) {
 
113
  char buf[5];
 
114
  if (strncmp(expect, read, 4) != 0) {
 
115
    strncpy(buf, read, 4);
 
116
    buf[4] = '\0';
 
117
    printf("*ERR* Read '%s' but '%s' was expected\n", buf, expect);
 
118
    return -1;
 
119
  }
 
120
  return 0;
 
121
}
 
122
 
 
123
int MEDIA_isguid(ulong expect, ulong read) {
 
124
  //printf("except 0x%08lx, read 0x%08lx\n", expect, read);
 
125
  return (expect == read);
 
126
}
 
127
 
 
128
int MEDIA_identify_asf(FILE *fd) {
 
129
  asf_header_t      asfh;
 
130
  asf_obj_header_t  objh;
 
131
  asf_file_prop_t   asffp;
 
132
  asf_stream_prop_t strp;
 
133
  asf_codec_list_t  codecs;
 
134
  asf_header_ext_t  exth;
 
135
  int stop, ttime, i, j;
 
136
  long opos, pos;
 
137
  ulong guid;
 
138
  struct stat fs;
 
139
  uchar *buf, *p;
 
140
 
 
141
  opos = ftell(fd);
 
142
  /* Read header object */
 
143
  fread(&asfh, sizeof(asfh), 1, fd);
 
144
  if (MEDIA_isguid(ASF_GUID_HEADER, *((ulong *) asfh.objh.guid)) == 0) {
 
145
    fseek(fd, opos, SEEK_SET);
 
146
    return 0;
 
147
  }
 
148
  printf("Format: ASF\n");
 
149
  //printf("Header Size: 0x%x\n", (int) asfh.objh.size);
 
150
  stop = 0;
 
151
  pos = ftell(fd);
 
152
  while (fread(&objh, sizeof(objh), 1, fd) > 0) {
 
153
    pos = ftell(fd);
 
154
    //fprintf(stderr, "[0x%08lx] size: %lld bytes\n",
 
155
    //   (ulong) pos - sizeof(objh), objh.size);
 
156
    // dump_hex(stderr, (uchar *)&objh, sizeof(objh), opos);
 
157
    guid = *((ulong *) &objh.guid);
 
158
    switch (guid) {
 
159
    case ASF_GUID_FILE_PROP:
 
160
      if (fread(&asffp, sizeof(asffp), 1, fd) < 0) {
 
161
        stop = 1;
 
162
        break;
 
163
      }
 
164
      fstat(fileno(fd), &fs);
 
165
      if (fs.st_size == asffp.file_size)
 
166
        printf("Size: %llu bytes (%.1f MB)\n", asffp.file_size,
 
167
               asffp.file_size / 1048576.);
 
168
      else {
 
169
        double d = (double) asffp.file_size;
 
170
        printf("*WARN* Expected size: %llu bytes (%.1f MB)\n"
 
171
               "             Missing: %ld bytes (%.1f MB - %.1f%%)\n",
 
172
               asffp.file_size, d / 1048576.,
 
173
               (ulong) asffp.file_size - (ulong) fs.st_size,
 
174
               ((ulong) asffp.file_size - (ulong) fs.st_size) / 1048576.,
 
175
               (double) ((ulong) asffp.file_size - fs.st_size) /
 
176
               (double) asffp.file_size * 100.);
 
177
      }
 
178
      ttime = asffp.play_duration / 10000000; /* 100 nano-seconds */
 
179
      printf("Length: %d:%02d:%02d\n", ttime / 3600, (ttime / 60) % 60,
 
180
             ttime % 60);
 
181
      /* printf("packets: %d, flags: %d, pack_size: %d, max_bitrate: %d\n",
 
182
             (int) asffp.packets, (int) asffp.flags,
 
183
             (int) asffp.min_packetsize, (int) asffp.max_bitrate); */
 
184
      printf("ASF flags:%s%s\n", asffp.flags & 0x01 ? " BROADCAST" : "",
 
185
             asffp.flags & 0x02 ? " SEEKABLE" : "");
 
186
      break;
 
187
    case ASF_GUID_HEADER_EXT:
 
188
      if (fread(&exth, sizeof(exth), 1, fd) < 0) {
 
189
        stop = 1;
 
190
        break;
 
191
      }
 
192
      if (exth.data_size > 0) {
 
193
        printf("Extention header data: %d bytes\n", exth.data_size);
 
194
        buf = (uchar *) malloc(exth.data_size);
 
195
        if (fread(buf, 1, exth.data_size, fd) < 0) {
 
196
          stop = 1;
 
197
          break;
 
198
        }
 
199
        dump_hex(stderr, buf, exth.data_size, opos);
 
200
      }
 
201
      break;
 
202
    case ASF_GUID_CONTENT_DESC:
 
203
      printf("GUID content description\n");
 
204
      break;
 
205
    case ASF_GUID_CODEC_LIST:
 
206
      // printf("GUID codec list\n");
 
207
      if (fread(&codecs, sizeof(codecs), 1, fd) < 0) {
 
208
        stop = 1;
 
209
        break;
 
210
      }
 
211
      buf = (uchar *) malloc(objh.size);
 
212
      if (fread(buf, 1, objh.size, fd) < 0) {
 
213
        stop = 1;
 
214
        break;
 
215
      }
 
216
      // dump_hex(stderr, buf, objh.size, opos);
 
217
      // printf("number of codecs: %ld\n", codecs.num_codec);
 
218
      p = buf;
 
219
      for (i = 1; i <= codecs.num_codec; i++) {
 
220
        ushort type, lname, ldesc, linfo;
 
221
        char *name, *desc, *info, *q;
 
222
        type = *((ushort *) p);
 
223
        p += 2;
 
224
        lname = *((ushort *) p);
 
225
        p += 2;
 
226
        name = (char *) malloc(lname + 1);
 
227
        for (q = name, j = 0; j < lname; j++, p += 2)
 
228
          q += sprintf(q, "%c", *(ushort *) p);
 
229
        *q = '\0';
 
230
        ldesc = *((ushort *) p);
 
231
        p += 2;
 
232
        desc = (char *) malloc(ldesc + 1);
 
233
        for (q = desc, j = 0; j < ldesc; j++, p += 2)
 
234
          q += sprintf(q, "%c", *(ushort *) p);
 
235
        *q = '\0';
 
236
        linfo = *((ushort *) p);
 
237
        p += 2;
 
238
        if (type == 0x0002) {
 
239
          switch(*((ushort *) p)) {
 
240
          case ASF_AUDIO_WMA:
 
241
            info = strdup("WMA");
 
242
            break;
 
243
          case ASF_AUDIO_WMA2:
 
244
            info = strdup("WMA2");
 
245
            break;
 
246
          case ASF_AUDIO_GMS_AMR_CBR:
 
247
            info = strdup("GSM_AMR_CBR");
 
248
            break;
 
249
          case ASF_AUDIO_GMS_AMR_VBR:
 
250
            info = strdup("GMS_AMR_VBR");
 
251
            break;
 
252
          case ASF_AUDIO_VOXWARE:
 
253
            info = strdup("VOXWARE");
 
254
            break;
 
255
          default:
 
256
            info = (char *) malloc(7);
 
257
            sprintf(info, "0x%04x", *((ushort *) p));
 
258
          }
 
259
          p += 2;
 
260
        }
 
261
        else {
 
262
          info = (char *) malloc(5 * linfo + 1);
 
263
          q = info; /* + sprintf(info, "0x"); */
 
264
          for (j = 0; j < linfo; j++, p++)
 
265
            if (*p >= 32 && *p < 127)
 
266
              q += sprintf(q, "%c", *p);
 
267
            else
 
268
              q += sprintf(q, "%02x", *p);
 
269
          *q = '\0';
 
270
        }
 
271
        if (0)
 
272
          printf("codec #%d: [%s] %s, '%s' '%s'\n",
 
273
                 i, type == 0x0001 ? "VIDEO" : type == 0x0002 ? "AUDIO" : "?",
 
274
                 info, name, desc);
 
275
        free(name);
 
276
        free(desc);
 
277
        free(info);
 
278
      }
 
279
      free(buf);
 
280
      break;
 
281
    case ASF_GUID_STREAM_PROP:
 
282
      // printf("GUID stream properties\n");
 
283
      if (fread(&strp, sizeof(strp), 1, fd) < 0) {
 
284
        stop = 1;
 
285
        break;
 
286
      }
 
287
      if (strp.type_data_len > 0) {
 
288
        asf_audio_type_t *auds;
 
289
        asf_video_type_t *vids;
 
290
        char *info;
 
291
 
 
292
        // printf("Type specific data: %lu bytes\n", strp.type_data_len);
 
293
        buf = (uchar *) malloc(strp.type_data_len);
 
294
        if (fread(buf, 1, strp.type_data_len, fd) < 0) {
 
295
          stop = 1;
 
296
          break;
 
297
        }
 
298
        switch (*((ulong *) &strp.stream_type)) {
 
299
          case ASF_GUID_AUDIO_MEDIA:
 
300
            auds = (asf_audio_type_t *) buf;
 
301
            switch(auds->codec) {
 
302
            case ASF_AUDIO_WMA:
 
303
              info = strdup("WMA");
 
304
              break;
 
305
            case ASF_AUDIO_WMA2:
 
306
              info = strdup("WMA2");
 
307
              break;
 
308
            case ASF_AUDIO_GMS_AMR_CBR:
 
309
              info = strdup("GSM_AMR_CBR");
 
310
              break;
 
311
            case ASF_AUDIO_GMS_AMR_VBR:
 
312
              info = strdup("GMS_AMR_VBR");
 
313
              break;
 
314
            case ASF_AUDIO_VOXWARE:
 
315
              info = strdup("VOXWARE");
 
316
              break;
 
317
            default:
 
318
              info = (char *) malloc(7);
 
319
              sprintf(info, "0x%04x", *((ushort *) buf));
 
320
            }
 
321
            printf("[AUDIO] %s, %lu Hz, %.1f kbps, %s\n",
 
322
                   info, auds->srate, (double) auds->bitrate * 8. / 1000.,
 
323
                   auds->channels == 2 ? "Stereo" :
 
324
                   auds->channels == 1 ? "Mono" : "FIXME");
 
325
            if (0 && auds->size != 0)
 
326
              dump_hex(stderr, buf + sizeof(asf_audio_type_t),
 
327
                       auds->size, opos);
 
328
            free(info);
 
329
            break;
 
330
        case ASF_GUID_VIDEO_MEDIA:
 
331
          vids = (asf_video_type_t *) buf;
 
332
          printf("[VIDEO] %c%c%c%c, %lux%lu, %u bpp, %u plane\n",
 
333
                 (char) (vids->data.codec & 0xFF),
 
334
                 (char) ((vids->data.codec >> 8) & 0xFF),
 
335
                 (char) ((vids->data.codec >> 16) & 0xFF),
 
336
                 (char) (vids->data.codec >> 24),
 
337
                 vids->data.width, vids->data.height,
 
338
                 vids->data.depth, vids->data.planes);
 
339
          break;
 
340
        default:
 
341
          printf("Stream #%d unrecognized\n", strp.flags & 0x003F);
 
342
          dump_hex(stderr, buf, strp.type_data_len, opos);
 
343
        }
 
344
      }
 
345
      if (0 && strp.errcorr_data_len > 0) {
 
346
        printf("Error correction specific data: %lu bytes\n",
 
347
               strp.errcorr_data_len);
 
348
        buf = (uchar *) malloc(strp.errcorr_data_len);
 
349
        if (fread(buf, 1, strp.errcorr_data_len, fd) < 0) {
 
350
          stop = 1;
 
351
          break;
 
352
        }
 
353
        dump_hex(stderr, buf, strp.errcorr_data_len, opos);
 
354
      }
 
355
      break;
 
356
    case ASF_GUID_EXT_CONT_DESC:
 
357
      printf("GUID Extended Content Description\n");
 
358
      break;
 
359
    case ASF_GUID_STREAM_BR_PROP:
 
360
      printf("GUID stream bitrate properties\n");
 
361
      break;
 
362
    case ASF_GUID_AUDIO_MEDIA:
 
363
      printf("GUID audio stream\n");
 
364
      break;
 
365
    case ASF_GUID_SIMPLE_INDEX:
 
366
      //printf("GUID simple index\n");
 
367
      break;
 
368
    case ASF_GUID_DATA:
 
369
      //printf("GUID data\n");
 
370
      //stop = 1;
 
371
      break;
 
372
    default:
 
373
      printf("GUID 0x%08lx unknown\n", guid);
 
374
    }
 
375
    if (stop)
 
376
      break;
 
377
    fseek(fd, pos + objh.size - sizeof(objh), SEEK_SET);
 
378
  }
 
379
  return 1;
 
380
}