merge
[youtube-dl] / a.c
1 #include <stdio.h> 
2 #include <string.h> 
3 #include <assert.h> 
4 #include <stdint.h> 
5  
6 #define FLVF_HEADER 1 
7 #define FLVF_SCRIPT 2 
8  
9 struct flvhdr 
10
11     char fh_magic[3]; 
12     char fh_version; 
13     char fh_flags; 
14     char fh_hlen[4]; 
15     char fh_pads[4]; 
16 }__attribute__((packed)); 
17  
18 struct taghdr 
19
20     uint8_t th_type; 
21     uint8_t th_dlen[3]; 
22     uint8_t th_tstamp[3]; 
23     uint8_t th_xstamp; 
24     uint8_t th_streamid[3]; 
25 }__attribute__((packed)); 
26  
27 struct flvcombine 
28
29     FILE * fc_file; 
30     uint32_t fc_flags; 
31     uint32_t fc_timestamp; 
32     uint32_t fc_filesize; 
33     double fc_duration; 
34     int fc_filesize_offset; 
35     int fc_duration_offset; 
36 }; 
37  
38 /* duration, filesize */ 
39  
40 uint32_t buftoint(const void *buf, size_t len) 
41
42     uint32_t bufint = 0; 
43     const uint8_t *pval = (const uint8_t *)buf; 
44     while (len-- > 0) 
45         bufint = (bufint << 8) + *pval++; 
46     return bufint; 
47
48  
49 int dd_copy(FILE * dst_fp, FILE * src_fp, size_t dlen) 
50
51     size_t len; 
52     char buf[64 * 1024]; 
53     while (dlen > 0 && !feof(src_fp)) { 
54          len = fread(buf, 1, dlen < sizeof(buf)? dlen: sizeof(buf), src_fp); 
55         if (fwrite(buf, 1, len, dst_fp) != len) 
56             break; 
57         dlen -= len; 
58     } 
59     return dlen; 
60
61  
62 void adjtimestamp(struct taghdr *header, uint32_t stampbase) 
63
64     uint32_t netval = 0; 
65     uint32_t adjtime = stampbase; 
66     adjtime += buftoint(&header->th_tstamp, sizeof(header->th_tstamp)); 
67     adjtime += (header->th_xstamp << 24); 
68     header->th_xstamp = (adjtime >> 24); 
69     header->th_tstamp[0] = (adjtime >> 16); 
70     header->th_tstamp[1] = (adjtime >> 8); 
71     header->th_tstamp[2] = (adjtime >> 0); 
72
73  
74 void update_metainfo(struct flvcombine *combine, FILE *fp, size_t dlen) 
75
76     int i; 
77     size_t len; 
78     char *pmem = NULL; 
79     char buf[256 * 1024]; 
80     double duration = 0.0; 
81     uint8_t duration_bytes[8]; 
82     printf("dlen: %d\n", dlen); 
83     assert (dlen < (256 * 1024)); 
84  
85     len = fread(buf, 1, dlen < sizeof(buf)? dlen: sizeof(buf), fp); 
86     if (len == 0) 
87         return; 
88     pmem = (char *)memmem(buf, len, "duration", 8); 
89     if (pmem == NULL || pmem + 17l - buf > len) 
90         return; 
91     memcpy(&duration_bytes, pmem + 9, 8); 
92     for (i = 0; i < 4; i ++) { 
93         uint8_t tmp = duration_bytes[i]; 
94         duration_bytes[i] = duration_bytes[7 - i]; 
95         duration_bytes[7 - i] = tmp; 
96     } 
97     memcpy(&duration, &duration_bytes, 8); 
98     combine->fc_duration += duration; 
99     if (combine->fc_flags & FLVF_SCRIPT) 
100         return; 
101        combine->fc_duration_offset = 
102         combine->fc_filesize + (pmem + 9l - buf) + sizeof(struct taghdr); 
103     pmem = (char *)memmem(buf, len, "filesize", 8); 
104     if (pmem == NULL || pmem + 17l - buf > len) 
105         return; 
106     combine->fc_filesize_offset = 
107         combine->fc_filesize + (pmem + 9l - buf) + sizeof(struct taghdr); 
108
109  
110 int addflv(struct flvcombine *combine, const char *path) 
111
112     int error = 0; 
113     FILE *fp, *fout; 
114     char magic[4]; 
115     long savepos; 
116     size_t len, dlen, flags; 
117     struct flvhdr header; 
118     struct taghdr *last; 
119     struct taghdr tagvideo; 
120     struct taghdr tagaudio; 
121     struct taghdr tagheader; 
122  
123     fp = fopen(path, "rb"); 
124     fout = combine->fc_file; 
125     if (fp == NULL || fout == NULL) 
126         return 0; 
127  
128     last = NULL; 
129     memset(magic, 0, sizeof(magic)); 
130     memset(&tagvideo, 0, sizeof(tagvideo)); 
131     memset(&tagaudio, 0, sizeof(tagaudio)); 
132  
133     if ( !fread(&header, sizeof(header), 1, fp) ) 
134         goto fail; 
135  
136     memcpy(magic, header.fh_magic, 3); 
137     if ( strcmp("FLV", magic) ) 
138         goto fail; 
139  
140     if ((combine->fc_flags & FLVF_HEADER) == 0) { 
141         fwrite(&header, sizeof(header), 1, fout); 
142          combine->fc_filesize += sizeof(header); 
143         combine->fc_flags |= FLVF_HEADER; 
144     } 
145  
146     printf("magic: %s\n", magic); 
147     printf("flags: 0x%02x\n", header.fh_flags); 
148     printf("version: 0x%02x\n", header.fh_version); 
149     printf("header len: %d\n", buftoint(header.fh_hlen, sizeof(header.fh_hlen))); 
150  
151     while (feof(fp) == 0) { 
152         if ( !fread(&tagheader, sizeof(tagheader), 1, fp) ) 
153             goto fail; 
154  
155         dlen = buftoint(tagheader.th_dlen, sizeof(tagheader.th_dlen)); 
156  
157         switch (tagheader.th_type) 
158         { 
159             case 0x09: 
160                 adjtimestamp(&tagheader, combine->fc_timestamp); 
161                 tagvideo = tagheader; 
162                 last = &tagvideo; 
163                 break; 
164             case 0x08: 
165                 adjtimestamp(&tagheader, combine->fc_timestamp); 
166                 tagaudio = tagheader; 
167                 last = &tagaudio; 
168                 break; 
169             default: 
170                 flags = combine->fc_flags; 
171                 savepos = ftell(fp); 
172                 if (savepos == -1) 
173                     goto fail; 
174                 savepos = (flags & FLVF_SCRIPT)? (savepos + dlen + 4): savepos; 
175                 update_metainfo(combine, fp, dlen); 
176                  combine->fc_flags |= FLVF_SCRIPT; 
177                 if ( fseek(fp, savepos, SEEK_SET) ) 
178                     goto fail; 
179                 if (flags & FLVF_SCRIPT) 
180                     continue; 
181                 break; 
182         } 
183          fwrite(&tagheader, sizeof(tagheader), 1, fout); 
184          combine->fc_filesize += sizeof(tagheader); 
185         combine->fc_filesize += (dlen + 4); 
186          if ( dd_copy(fout, fp, dlen + 4)) { 
187             error = -__LINE__; 
188             break; 
189         } 
190     } 
191  
192 fail: 
193     fclose(fp); 
194     if (last == &tagvideo || last == &tagaudio) { 
195         combine->fc_timestamp = buftoint(last->th_tstamp, sizeof(last->th_tstamp)); 
196         combine->fc_timestamp |= (last->th_xstamp << 24); 
197         printf("time stamp: %d\n", combine->fc_timestamp); 
198     } 
199     return 0; 
200
201  
202 void fixedflv(struct flvcombine *context) 
203
204     int i; 
205     double dblval = 0.0; 
206     uint8_t dblbytes[8]; 
207     FILE *fout = context->fc_file; 
208  
209     if (context->fc_filesize_offset > 0) { 
210         if ( fseek(fout, context->fc_filesize_offset, SEEK_SET) ) 
211             return; 
212         dblval = context->fc_filesize; 
213         memcpy(dblbytes, &dblval, 8); 
214      
215         for (i = 0; i < 4; i ++) { 
216              uint8_t tmp = dblbytes[i]; 
217              dblbytes[i] = dblbytes[7 - i]; 
218              dblbytes[7 - i] = tmp; 
219          } 
220         fwrite(dblbytes, 8, 1, fout); 
221     } 
222  
223     if (context->fc_duration_offset > 0) { 
224         if ( fseek(fout, context->fc_duration_offset, SEEK_SET) ) 
225             return; 
226         dblval = context->fc_duration; 
227         memcpy(dblbytes, &dblval, 8); 
228  
229         for (i = 0; i < 4; i ++) { 
230              uint8_t tmp = dblbytes[i]; 
231              dblbytes[i] = dblbytes[7 - i]; 
232              dblbytes[7 - i] = tmp; 
233          } 
234         fwrite(dblbytes, 8, 1, fout); 
235     } 
236
237  
238 int main(int argc, char *argv[]) 
239
240     int i; 
241     struct flvcombine context; 
242     memset(&context, 0, sizeof(context)); 
243     context.fc_file = fopen("out.flv", "wb"); 
244     if (context.fc_file == NULL) 
245         return -1; 
246     context.fc_duration = 0; 
247     for (i = 1; i < argc; i++) 
248         addflv(&context, argv[i]); 
249     fixedflv(&context); 
250     fclose(context.fc_file); 
251  
252     printf("seconds: %d\n", context.fc_timestamp); 
253     return 0; 
254