1 /*
2  * This program is free software; you can redistribute it and/or modify
3  * it under the terms of the GNU General Public License as published by
4  * the Free Software Foundation; either version 2 of the License, or
5  * (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License along
13  * with this program; if not, write to the Free Software Foundation, Inc.,
14  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
15  */
16 
17 #define SAVE_STREAMS
18 
19 // simple ASF header display program by A'rpi/ESP-team
20 // .asf fileformat docs from http://divx.euro.ru
21 
22 #include <stdio.h>
23 #include <stdlib.h>
24 
25 typedef struct __attribute__((packed))
26 {
27   long      biSize;          // sizeof(BITMAPINFOHEADER)
28   long      biWidth;
29   long      biHeight;
30   short     biPlanes;        // unused
31   short     biBitCount;
32   long      biCompression;   // fourcc of image
33   long      biSizeImage;     // size of image. For uncompressed images
34                              // ( biCompression 0 or 3 ) can be zero.
35 
36 
37   long      biXPelsPerMeter; // unused
38   long      biYPelsPerMeter; // unused
39   long      biClrUsed;       // valid only for palettized images.
40                              // Number of colors in palette.
41   long      biClrImportant;
42 } BITMAPINFOHEADER;
43 
44 typedef struct
45 {
46   short     wFormatTag;      // value that identifies compression format
47   short     nChannels;
48   long      nSamplesPerSec;
49   long      nAvgBytesPerSec;
50   short     nBlockAlign;     // size of a data sample
51   short     wBitsPerSample;
52   short     cbSize;          // size of format-specific data
53 } WAVEFORMATEX;
54 
55 typedef struct __attribute__((packed)) {
56   unsigned char      guid[16];
57   unsigned long long size;
58 } ASF_obj_header_t;
59 
60 typedef struct __attribute__((packed)) {
61   ASF_obj_header_t objh;
62   unsigned int     cno; // number of subchunks
63   unsigned char    v1; // unknown (0x01)
64   unsigned char    v2; // unknown (0x02)
65 } ASF_header_t;
66 
67 typedef struct __attribute__((packed)) {
68   unsigned char client[16]; // Client GUID
69   unsigned long long file_size;
70   unsigned long long creat_time; //File creation time FILETIME 8
71   unsigned long long packets;    //Number of packets UINT64 8
72   unsigned long long end_timestamp; //Timestamp of the end position UINT64 8
73   unsigned long long duration;  //Duration of the playback UINT64 8
74   unsigned long start_timestamp; //Timestamp of the start position UINT32 4
75   unsigned long unk1; //Unknown, maybe reserved ( usually contains 0 ) UINT32 4
76   unsigned long flags; //Unknown, maybe flags ( usually contains 2 ) UINT32 4
77   unsigned long packetsize; //Size of packet, in bytes UINT32 4
78   unsigned long packetsize2; //Size of packet ( confirm ) UINT32 4
79   unsigned long frame_size; //Size of uncompressed video frame UINT32 4
80 } ASF_file_header_t;
81 
82 typedef struct __attribute__((packed)) {
83   unsigned char type[16]; // Stream type (audio/video) GUID 16
84   unsigned char concealment[16]; // Audio error concealment type GUID 16
85   unsigned long long unk1; // Unknown, maybe reserved ( usually contains 0 ) UINT64 8
86   unsigned long type_size; //Total size of type-specific data UINT32 4
87   unsigned long stream_size; //Size of stream-specific data UINT32 4
88   unsigned short stream_no; //Stream number UINT16 2
89   unsigned long unk2; //Unknown UINT32 4
90 } ASF_stream_header_t;
91 
92 typedef struct __attribute__((packed)) {
93   unsigned char streamno;
94   unsigned char seq;
95   unsigned long x;
96   unsigned char flag;
97 } ASF_segmhdr_t;
98 
99 
100 ASF_header_t asfh;
101 ASF_obj_header_t objh;
102 ASF_file_header_t fileh;
103 ASF_stream_header_t streamh;
104 unsigned char buffer[8192];
105 
106 int i;
107 
chunk_type(unsigned char * guid)108 static char* chunk_type(unsigned char* guid){
109   switch(*((unsigned int*)guid)){
110     case 0xF8699E40: return "guid_audio_stream";
111     case 0xBC19EFC0: return "guid_video_stream";
112     case 0x49f1a440: return "guid_audio_conceal_none";
113     case 0xbfc3cd50: return "guid_audio_conceal_interleave";
114     case 0x75B22630: return "guid_header";
115     case 0x75b22636: return "guid_data_chunk";
116     case 0x33000890: return "guid_index_chunk";
117     case 0xB7DC0791: return "guid_stream_header";
118     case 0xD6E229D1: return "guid_header_2_0";
119     case 0x8CABDCA1: return "guid_file_header";
120   }
121   return NULL;
122 }
123 
print_wave_header(WAVEFORMATEX * h)124 static void print_wave_header(WAVEFORMATEX *h){
125   printf("======= WAVE Format =======\n");
126 
127   printf("Format Tag: %d (0x%X)\n", h->wFormatTag, h->wFormatTag);
128   printf("Channels: %d\n", h->nChannels);
129   printf("Samplerate: %ld\n", h->nSamplesPerSec);
130   printf("avg byte/sec: %ld\n", h->nAvgBytesPerSec);
131   printf("Block align: %d\n", h->nBlockAlign);
132   printf("bits/sample: %d\n", h->wBitsPerSample);
133   printf("cbSize: %d\n", h->cbSize);
134 
135   switch(h->wFormatTag){
136     case 0x01:        printf("Audio in PCM format\n"); break;
137     case 0x50:        printf("Audio in MPEG Layer 1/2 format\n"); break;
138     case 0x55:        printf("Audio in MPEG Layer-3 format\n"); break; // ACM
139     case 0x02:        printf("Audio in MS ADPCM format\n"); break;  // ACM
140     case 0x11:        printf("Audio in IMA ADPCM format\n"); break; // ACM
141     case 0x31:
142     case 0x32:        printf("Audio in MS GSM 6.10 format\n"); break; // ACM
143     case 0x160:
144     case 0x161:       printf("Audio in DivX WMA format\n"); break; // ACM
145     default:          printf("Audio in UNKNOWN (id=0x%X) format\n", h->wFormatTag);
146   }
147 
148   printf("===========================\n");
149 }
150 
print_video_header(BITMAPINFOHEADER * h)151 static void print_video_header(BITMAPINFOHEADER *h){
152   printf("======= VIDEO Format ======\n");
153   printf("  biSize %ld\n", h->biSize);
154   printf("  biWidth %ld\n", h->biWidth);
155   printf("  biHeight %ld\n", h->biHeight);
156   printf("  biPlanes %d\n", h->biPlanes);
157   printf("  biBitCount %d\n", h->biBitCount);
158   printf("  biCompression %ld='%.4s'\n", h->biCompression, (const char*)&h->biCompression);
159   printf("  biSizeImage %ld\n", h->biSizeImage);
160   printf("===========================\n");
161 }
162 
163 FILE* streams[128];
164 
main(int argc,char * argv[])165 int main(int argc, char* argv[]){
166   FILE *f = fopen(argc > 1 ? argv[1] : "Alice Deejay - Back In My Life.asf", "rb");
167 
168   if(!f){
169     printf("file not found\n");
170     exit(1);
171   }
172 
173   //printf("sizeof=%d\n", sizeof(objh));
174   //printf("sizeof=%d\n", sizeof(asfh));
175 
176   fread(&asfh, sizeof(asfh), 1, f); // header obj
177   //for(i = 0; i < 16; i++)
178   //  printf("%02X ", asfh.objh.guid[i]);
179   printf("[%s] %d  (subchunks: %d)\n", chunk_type(asfh.objh.guid),
180          (int) asfh.objh.size, asfh.cno);
181 
182   while(fread(&objh, sizeof(objh), 1, f) > 0){
183     int pos = ftell(f);
184     //for(i = 0; i < 16; i++)
185     //  printf("%02X ", objh.guid[i]);
186     printf("0x%08X  [%s] %d\n", pos-sizeof(objh), chunk_type(objh.guid),
187            (int) objh.size);
188     switch(*((unsigned int*)&objh.guid)){
189       case 0xB7DC0791: // guid_stream_header
190         fread(&streamh, sizeof(streamh), 1, f);
191         printf("stream type: %s\n", chunk_type(streamh.type));
192         printf("stream concealment: %s\n", chunk_type(streamh.concealment));
193         printf("type: %d bytes,  stream: %d bytes  ID: %d\n",
194                (int)streamh.type_size, (int)streamh.stream_size,
195                (int)streamh.stream_no);
196         printf("FILEPOS=0x%lX\n", ftell(f));
197         // type-specific data:
198         fread(buffer,streamh.type_size,1,f);
199         switch(*((unsigned int*)&streamh.type)){
200         case 0xF8699E40:  // guid_audio_stream
201           print_wave_header((WAVEFORMATEX*)buffer);
202           break;
203         case 0xBC19EFC0:  // guid_video_stream
204           print_video_header((BITMAPINFOHEADER*)&buffer[4 + 4 + 1 + 2]);
205           break;
206         }
207         // stream-specific data:
208         fread(buffer, streamh.stream_size, 1, f);
209         break;
210       //case 0xD6E229D1:
211       //  return "guid_header_2_0";
212       case 0x8CABDCA1: // guid_file_header
213         fread(&fileh, sizeof(fileh), 1, f);
214         printf("packets: %d  flags: %d  pack_size: %d  frame_size: %d\n",
215                (int)fileh.packets, (int)fileh.flags, (int)fileh.packetsize,
216                (int)fileh.frame_size);
217         break;
218       case 0x75b22636: // guid_data_chunk
219         { int endp = pos + objh.size - sizeof(objh);
220           unsigned char* packet = malloc((int)fileh.packetsize);
221           int fpos;
222           fseek(f, 26, SEEK_CUR);
223           while((fpos = ftell(f)) < endp){
224             fread(packet, (int)fileh.packetsize, 1, f);
225             if(packet[0] == 0x82){
226               unsigned char flags = packet[3];
227               unsigned char* p = &packet[5];
228               unsigned long time;
229               unsigned short duration;
230               int segs = 1;
231               int seg;
232               int padding=0;
233               if(flags & 8){
234                 padding = p[0];
235                 ++p;
236               } else
237               if(flags & 16){
238                 padding = p[0] | (p[1] << 8);
239                 p += 2;
240               }
241               time = *((unsigned long*)p);
242               p += 4;
243               duration = *((unsigned short*)p);
244               p += 2;
245               if(flags & 1){
246                 segs = p[0] - 0x80;
247                 ++p;
248               }
249               printf("%08X:  flag=%02X  segs=%d  pad=%d  time=%ld  dur=%d\n",
250                      fpos, flags, segs, padding, time, duration);
251               for(seg = 0; seg < segs; seg++){
252                 ASF_segmhdr_t* sh = (ASF_segmhdr_t*)p;
253                 int len = 0;
254                 p += sizeof(ASF_segmhdr_t);
255                 if(sh->flag & 8) p+=8;// else
256                 if(sh->flag & 1) ++p;
257                 if(flags & 1){
258                   len = *((unsigned short*)p);
259                   p += 2;
260                 }
261                 printf("  seg #%d: streamno=%d  seq=%d  flag=%02X  len=%d\n",
262                        seg, sh->streamno&0x7F, sh->seq, sh->flag, len);
263   #ifdef SAVE_STREAMS
264                 if(!streams[sh->streamno & 0x7F]){
265                   char name[256];
266                   snprintf(name, 256, "stream%02X.dat", sh->streamno & 0x7F);
267                   streams[sh->streamno & 0x7F] = fopen(name, "wb");
268                 }
269                 fwrite(p, len, 1, streams[sh->streamno & 0x7F]);
270   #endif
271                 p += len;
272               }
273             } else
274               printf("%08X:  UNKNOWN  %02X %02X %02X %02X %02X...\n", fpos,
275                      packet[0], packet[1], packet[2], packet[3], packet[4]);
276           }
277         }
278         break;
279 
280         //case 0x33000890:
281         //  return "guid_index_chunk";
282 
283     }
284     fseek(f, pos + objh.size - sizeof(objh), SEEK_SET);
285   }
286 
287   fclose(f);
288   return 0;
289 }
290