8585
|
1
|
|
2 #include <stdio.h>
|
|
3 #include <stdlib.h>
|
|
4 #include <string.h>
|
|
5 #include <sys/types.h>
|
|
6
|
|
7 #include "config.h"
|
|
8 #include "../version.h"
|
|
9
|
|
10 #include "wine/mmreg.h"
|
|
11 #include "wine/avifmt.h"
|
|
12 #include "wine/vfw.h"
|
|
13 #include "bswap.h"
|
|
14
|
|
15 #include "muxer.h"
|
|
16
|
|
17 // 18 bytes reserved for block headers and STD
|
|
18 #define MUXER_MPEG_DATASIZE (MUXER_MPEG_BLOCKSIZE-18)
|
|
19
|
|
20 // ISO-11172 requirements
|
|
21 #define MPEG_MAX_PTS_DELAY 90000 /* 1s */
|
|
22 #define MPEG_MAX_SCR_INTERVAL 63000 /* 0.7s */
|
|
23
|
|
24 // suggestions
|
|
25 #define MPEG_STARTPTS 45000 /* 0.5s */
|
|
26 #define MPEG_MIN_PTS_DELAY 9000 /* 0.1s */
|
|
27 #define MPEG_STARTSCR 9 /* 0.1ms */
|
|
28
|
|
29 //static unsigned int mpeg_min_delay;
|
|
30 //static unsigned int mpeg_max_delay;
|
|
31
|
|
32 static muxer_stream_t* mpegfile_new_stream(muxer_t *muxer,int type){
|
|
33 muxer_stream_t *s;
|
|
34
|
|
35 if(muxer->avih.dwStreams>=MUXER_MAX_STREAMS){
|
|
36 printf("Too many streams! increase MUXER_MAX_STREAMS !\n");
|
|
37 return NULL;
|
|
38 }
|
|
39 switch (type) {
|
|
40 case MUXER_TYPE_VIDEO:
|
|
41 if (muxer->num_videos >= 15) {
|
|
42 printf ("MPEG stream can't contain above of 15 video streams!\n");
|
|
43 return NULL;
|
|
44 }
|
|
45 break;
|
|
46 case MUXER_TYPE_AUDIO:
|
|
47 if (muxer->avih.dwStreams - muxer->num_videos >= 31) {
|
|
48 printf ("MPEG stream can't contain above of 31 audio streams!\n");
|
|
49 return NULL;
|
|
50 }
|
|
51 break;
|
|
52 default:
|
|
53 printf ("Unknown stream type!\n");
|
|
54 return NULL;
|
|
55 }
|
|
56 s=malloc(sizeof(muxer_stream_t));
|
|
57 memset(s,0,sizeof(muxer_stream_t));
|
|
58 if(!s) return NULL; // no mem!?
|
|
59 if (!(s->b_buffer = malloc (MUXER_MPEG_BLOCKSIZE))) {
|
|
60 free (s);
|
|
61 return NULL; // no mem?!
|
|
62 } else if (type == MUXER_TYPE_VIDEO) {
|
|
63 s->ckid = be2me_32 (0x1e0 + muxer->num_videos);
|
|
64 muxer->num_videos++;
|
|
65 s->h.fccType=streamtypeVIDEO;
|
|
66 if(!muxer->def_v) muxer->def_v=s;
|
|
67 // printf ("Added video stream %d\n", muxer->num_videos);
|
|
68 } else { // MUXER_TYPE_AUDIO
|
|
69 s->ckid = be2me_32 (0x1c0 + s->id - muxer->num_videos);
|
|
70 s->h.fccType=streamtypeAUDIO;
|
|
71 // printf ("Added audio stream %d\n", s->id - muxer->num_videos + 1);
|
|
72 }
|
|
73 muxer->streams[muxer->avih.dwStreams]=s;
|
|
74 s->type=type;
|
|
75 s->id=muxer->avih.dwStreams;
|
|
76 s->timer=0.0;
|
|
77 s->size=0;
|
|
78 muxer->avih.dwStreams++;
|
|
79 return s;
|
|
80 }
|
|
81
|
|
82 static void write_mpeg_ts(unsigned char *b, unsigned int ts, char mod) {
|
|
83 b[0] = ((ts >> 29) & 0xf) | 1 | mod;
|
|
84 b[1] = (ts >> 22) & 0xff;
|
|
85 b[2] = ((ts >> 14) & 0xff) | 1;
|
|
86 b[3] = (ts >> 7) & 0xff;
|
|
87 b[4] = ((ts << 1) & 0xff) | 1;
|
|
88 }
|
|
89
|
|
90 static void write_mpeg_rate(unsigned char *b, unsigned int rate) {
|
|
91 if (rate)
|
|
92 rate--; // for round upward
|
|
93 rate /= 50;
|
|
94 rate++; // round upward
|
|
95 b[0] = ((rate >> 15) & 0x7f) | 0x80;
|
|
96 b[1] = (rate >> 7) & 0xff;
|
|
97 b[2] = ((rate << 1) & 0xff) | 1;
|
|
98 }
|
|
99
|
|
100 static void write_mpeg_std(unsigned char *b, unsigned int size, char mod) {
|
|
101 if (size)
|
|
102 size--; // for round upward
|
|
103 if (size < (128 << 8))
|
|
104 size >>= 7; // by 128 bytes
|
|
105 else {
|
|
106 size >>= 10;
|
|
107 size |= 0x2000; // by 1kbyte
|
|
108 }
|
|
109 size++; // round upward
|
|
110 b[0] = ((size >> 8) & 0x3f) | 0x40 | mod;
|
|
111 b[1] = size & 0xff;
|
|
112 }
|
|
113
|
|
114 static int write_mpeg_block(muxer_t *muxer, muxer_stream_t *s, FILE *f, char *bl, size_t len, int isoend){
|
|
115 size_t sz; // rest in block buffer
|
|
116 unsigned char buff[12]; // 0x1ba header
|
|
117 unsigned int mints=0;
|
|
118 uint16_t l1;
|
|
119
|
|
120 if (s->b_buffer_ptr == 0) { // 00001111 if no PTS
|
|
121 s->b_buffer[0] = 0xf;
|
|
122 s->b_buffer_ptr = 1;
|
|
123 sz = MUXER_MPEG_DATASIZE-1;
|
|
124 } else if (s->b_buffer_ptr > MUXER_MPEG_DATASIZE) {
|
|
125 printf ("Unknown error in write_mpeg_block()!\n");
|
|
126 return 0;
|
|
127 } else {
|
|
128 sz = MUXER_MPEG_DATASIZE - s->b_buffer_ptr;
|
|
129 if (s->b_buffer[7] == 0xff) // PTS not set yet
|
|
130 s->b_buffer[11] = 0xf; // terminate stuFFing bytes
|
|
131 }
|
|
132 if (len > sz)
|
|
133 len = sz;
|
|
134 *(uint32_t *)buff = be2me_32 (0x1ba);
|
|
135 write_mpeg_ts (buff+4, muxer->file_end, 0x20); // 0010 and SCR
|
|
136 write_mpeg_rate (buff+9, muxer->sysrate);
|
|
137 fwrite (buff, 12, 1, f);
|
|
138 fwrite (&s->ckid, 4, 1, f); // stream_id
|
|
139 memset (buff, 0xff, 12); // stuFFing bytes
|
|
140 sz -= len;
|
|
141 // calculate padding bytes in buffer
|
|
142 while (mints < s->b_buffer_ptr && s->b_buffer[mints] == 0xff) mints++;
|
|
143 if (mints+sz < 12) { // cannot write padding block so write up to 12 stuFFing bytes
|
|
144 l1 = be2me_16 (MUXER_MPEG_DATASIZE);
|
|
145 fwrite (&l1, 2, 1, f);
|
|
146 mints = 0; // so stuFFed bytes will be written all
|
|
147 if (sz)
|
|
148 fwrite (buff, sz, 1, f);
|
|
149 sz = 0; // no padding block anyway
|
|
150 } else { // use padding block
|
|
151 if (sz > 6) // sufficient for PAD header so don't shorter data
|
|
152 mints = 0;
|
|
153 else
|
|
154 sz += mints; // skip stuFFing bytes (sz>8 here)
|
|
155 l1 = be2me_16 (s->b_buffer_ptr+len-mints);
|
|
156 fwrite (&l1, 2, 1, f);
|
|
157 }
|
|
158 if (s->b_buffer_ptr)
|
|
159 fwrite (s->b_buffer+mints, s->b_buffer_ptr-mints, 1, f);
|
|
160 if (len)
|
|
161 fwrite (bl, len, 1, f);
|
|
162 if (sz > 6) { // padding block (0x1be)
|
|
163 uint32_t l0;
|
|
164
|
|
165 if (isoend)
|
|
166 l0 = be2me_32 (0x1b9);
|
|
167 else
|
|
168 l0 = be2me_32 (0x1be);
|
|
169 sz -= 6;
|
|
170 l1 = be2me_16 (sz);
|
|
171 fwrite (&l0, 4, 1, f);
|
|
172 fwrite (&l1, 2, 1, f);
|
|
173 memset (s->b_buffer, 0xff, sz); // stuFFing bytes
|
|
174 fwrite (s->b_buffer, sz, 1, f);
|
|
175 }
|
|
176 s->b_buffer_ptr = 0;
|
|
177 muxer->movi_end += MUXER_MPEG_BLOCKSIZE;
|
|
178 // prepare timestamps for next pack
|
|
179 mints = (MUXER_MPEG_BLOCKSIZE*90000/muxer->sysrate)+1; // min ts delta
|
|
180 sz = (int)(s->timer*90000) + MPEG_STARTPTS; // new PTS
|
|
181 if (sz > muxer->file_end)
|
|
182 sz -= muxer->file_end; // suggested ts delta
|
|
183 else
|
|
184 {
|
|
185 sz = 0;
|
|
186 printf ("Error in stream: PTS earlier than SCR!\n");
|
|
187 }
|
|
188 if (sz > MPEG_MAX_PTS_DELAY) {
|
|
189 // printf ("Warning: attempt to set PTS to SCR delay to %u \n", sz);
|
|
190 mints = sz-MPEG_MAX_PTS_DELAY; // try to compensate
|
|
191 if (mints > MPEG_MAX_SCR_INTERVAL) {
|
|
192 printf ("Error in stream: SCR interval %u is too big!\n", mints);
|
|
193 }
|
|
194 } else if (sz > 54000) // assume 0.3...0.7s is optimal
|
|
195 mints += (sz-45000)>>2; // reach 0.5s in 4 blocks ?
|
|
196 else if (sz < 27000) {
|
|
197 unsigned int newsysrate = 0;
|
|
198
|
|
199 if (s->timer > 0.5) // too early to calculate???
|
|
200 newsysrate = muxer->movi_end/(s->timer*0.4); // pike-factor 2.5 (8dB)
|
|
201 if (sz < MPEG_MIN_PTS_DELAY)
|
|
202 printf ("Error in stream: PTS to SCR delay %u is too little!\n", sz);
|
|
203 if (muxer->sysrate < newsysrate)
|
|
204 muxer->sysrate = newsysrate; // increase next rate to current rate
|
|
205 else if (!newsysrate)
|
|
206 muxer->sysrate += muxer->sysrate>>3; // increase next rate by 25%
|
|
207 }
|
|
208 muxer->file_end += mints; // update the system timestamp
|
|
209 return len;
|
|
210 }
|
|
211
|
|
212 static void set_mpeg_pts(muxer_t *muxer, muxer_stream_t *s, unsigned int pts) {
|
|
213 unsigned int dts, nts;
|
|
214
|
|
215 if (s->b_buffer_ptr != 0 && s->b_buffer[7] != 0xff)
|
|
216 return; // already set
|
|
217 if (s->b_buffer_ptr == 0) {
|
|
218 memset (s->b_buffer, 0xff, 7); // reserved for PTS or STD, stuFFing for now
|
|
219 s->b_buffer_ptr = 12;
|
|
220 }
|
|
221 dts = (int)(s->timer*90000) + MPEG_STARTPTS; // PTS
|
|
222 if (pts) {
|
|
223 write_mpeg_ts (s->b_buffer+2, pts, 0x30); // 0011 and both PTS/DTS
|
|
224 } else {
|
|
225 write_mpeg_ts (s->b_buffer+7, dts, 0x20); // 0010 and PTS only
|
|
226 return;
|
|
227 }
|
|
228 nts = dts - muxer->file_end;
|
|
229 // if (nts < mpeg_min_delay) mpeg_min_delay = nts;
|
|
230 // if (nts > mpeg_max_delay) mpeg_max_delay = nts;
|
|
231 nts = 180000*s->h.dwScale/s->h.dwRate; // two frames
|
|
232 if (dts-nts < muxer->file_end) {
|
|
233 dts += muxer->file_end;
|
|
234 dts /= 2; // calculate average time
|
|
235 printf ("Warning: DTS to SCR delay is too small\n");
|
|
236 }
|
|
237 else
|
|
238 dts -= nts/2; // one frame :)
|
|
239 write_mpeg_ts (s->b_buffer+7, dts, 0x10);
|
|
240 }
|
|
241
|
|
242 static void mpegfile_write_chunk(muxer_t *muxer,muxer_stream_t *s,FILE *f,size_t len,unsigned int flags){
|
|
243 size_t ptr=0, sz;
|
|
244 unsigned int pts=0;
|
|
245
|
|
246 if (s->type == MUXER_TYPE_VIDEO) { // try to recognize frame type...
|
|
247 if (s->buffer[0] != 0 || s->buffer[1] != 0 || s->buffer[2] != 1 || len<6) {
|
|
248 printf ("Unknown block type, possibly non-MPEG stream!\n");
|
|
249 sz = len;
|
|
250 // return;
|
|
251 } else if (s->buffer[3] == 0 || s->buffer[3] == 0xb3 ||
|
|
252 s->buffer[3] == 0xb8) { // Picture or GOP
|
|
253 int temp_ref;
|
|
254 int pt;
|
|
255
|
|
256 if (s->buffer[3]) { // GOP -- scan for Picture
|
|
257 s->gop_start = s->h.dwLength;
|
|
258 while (ptr < len-5 && (s->buffer[ptr] != 0 || s->buffer[ptr+1] != 0 ||
|
|
259 s->buffer[ptr+2] != 1 || s->buffer[ptr+3] != 0)) ptr++;
|
|
260 if (s->b_buffer_ptr > MUXER_MPEG_DATASIZE-39-12) { // 39 bytes for Gop+Pic+Slice headers
|
|
261 write_mpeg_block (muxer, s, f, NULL, 0, 0);
|
|
262 }
|
|
263 }
|
|
264 if (ptr >= len-5) {
|
|
265 pt = 0; // Picture not found?!
|
|
266 temp_ref = 0;
|
|
267 printf ("Warning: picture not found in GOP!\n");
|
|
268 } else {
|
|
269 pt = (s->buffer[ptr+5]>>3) & 7;
|
|
270 temp_ref = (s->buffer[ptr+4]<<2)+(s->buffer[ptr+5]>>6);
|
|
271 }
|
|
272 ptr = 0;
|
|
273 temp_ref += s->gop_start;
|
|
274 switch (pt) {
|
|
275 case 2: // predictive
|
|
276 if (s->ipb[0]) {
|
|
277 sz = len + s->ipb[0];
|
|
278 if (s->ipb[0] < s->ipb[2])
|
|
279 s->ipb[0] = s->ipb[2];
|
|
280 s->ipb[2] = 0;
|
|
281 } else if (s->ipb[2]) {
|
|
282 sz = len + s->ipb[2];
|
|
283 s->ipb[0] = s->ipb[2];
|
|
284 s->ipb[2] = 0;
|
|
285 } else
|
|
286 sz = 4 * len; // no bidirectional frames yet?
|
|
287 s->ipb[1] = len;
|
|
288 // pictires may be not in frame sequence so recalculate timer
|
|
289 pts = (int)(90000*((double)temp_ref*s->h.dwScale/s->h.dwRate)) + MPEG_STARTPTS;
|
|
290 break;
|
|
291 case 3: // bidirectional
|
|
292 s->ipb[2] += len;
|
|
293 sz = s->ipb[1] + s->ipb[2];
|
|
294 // pictires may be not in frame sequence so recalculate timer
|
|
295 s->timer = (double)temp_ref*s->h.dwScale/s->h.dwRate;
|
|
296 break;
|
|
297 default: // intra-coded
|
|
298 // pictires may be not in frame sequence so recalculate timer
|
|
299 pts = (int)(90000*((double)temp_ref*s->h.dwScale/s->h.dwRate)) + MPEG_STARTPTS;
|
|
300 sz = len; // no extra buffer for it...
|
|
301 }
|
|
302 } else {
|
|
303 printf ("Unknown block type, possibly non-MPEG stream!\n");
|
|
304 sz = len;
|
|
305 // return;
|
|
306 }
|
|
307 sz <<= 1;
|
|
308 } else { // MUXER_TYPE_AUDIO
|
|
309 if (len < 2*MUXER_MPEG_DATASIZE)
|
|
310 sz = 2*MUXER_MPEG_DATASIZE; // min requirement
|
|
311 else
|
|
312 sz = len;
|
|
313 }
|
|
314 set_mpeg_pts (muxer, s, pts);
|
|
315 // alter counters:
|
|
316 if (s->h.dwSampleSize) {
|
|
317 // CBR
|
|
318 s->h.dwLength += len/s->h.dwSampleSize;
|
|
319 if (len%s->h.dwSampleSize) printf("Warning! len isn't divisable by samplesize!\n");
|
|
320 } else {
|
|
321 // VBR
|
|
322 s->h.dwLength++;
|
|
323 }
|
|
324 if (!muxer->sysrate) {
|
|
325 muxer->sysrate = 2108000/8; // constrained stream parameter
|
|
326 muxer->file_end = MUXER_MPEG_BLOCKSIZE*90000/muxer->sysrate + MPEG_STARTSCR+1;
|
|
327 }
|
|
328 if (sz > s->h.dwSuggestedBufferSize) { // increase and set STD
|
|
329 s->h.dwSuggestedBufferSize = sz;
|
|
330 if (s->b_buffer[2] != 0xff) // has both PTS and DTS
|
|
331 write_mpeg_std (s->b_buffer, s->h.dwSuggestedBufferSize, 0x40); // 01
|
|
332 else // has only PTS
|
|
333 write_mpeg_std (s->b_buffer+5, s->h.dwSuggestedBufferSize, 0x40); // 01
|
|
334 }
|
|
335 s->size += len;
|
|
336 // write out block(s) if it's ready
|
|
337 while (s->b_buffer_ptr+len >= MUXER_MPEG_DATASIZE-12) { // reserved for std and pts
|
|
338 // write out the block
|
|
339 sz = write_mpeg_block (muxer, s, f, &s->buffer[ptr], len, 0);
|
|
340 // recalculate the rest of chunk
|
|
341 ptr += sz;
|
|
342 len -= sz;
|
|
343 }
|
|
344 s->timer = (double)s->h.dwLength*s->h.dwScale/s->h.dwRate;
|
|
345 if (len) { // save rest in buffer
|
|
346 if (s->b_buffer_ptr == 0) {
|
|
347 memset (s->b_buffer, 0xff, 12); // stuFFing bytes for now
|
|
348 if (s->type == MUXER_TYPE_AUDIO && s->h.dwSampleSize) { // CBR audio
|
|
349 sz = s->h.dwLength - len/s->h.dwSampleSize; // first sample number
|
|
350 write_mpeg_ts (s->b_buffer+7,
|
|
351 (int)(90000*((double)sz*s->h.dwScale/s->h.dwRate)) + MPEG_STARTPTS,
|
|
352 0x20); // 0010 and PTS only
|
|
353 }
|
|
354 s->b_buffer_ptr = 12;
|
|
355 }
|
|
356 memcpy (s->b_buffer+s->b_buffer_ptr, s->buffer+ptr, len);
|
|
357 s->b_buffer_ptr += len;
|
|
358 }
|
|
359 }
|
|
360
|
|
361 static void mpegfile_write_header(muxer_t *muxer,FILE *f){
|
|
362 unsigned int i;
|
|
363 size_t sz = MUXER_MPEG_BLOCKSIZE-24;
|
|
364 unsigned char buff[12];
|
|
365 muxer_stream_t *s = muxer->streams[0];
|
|
366 uint32_t l1;
|
|
367 uint16_t l2;
|
|
368
|
|
369 if (s == NULL)
|
|
370 return; // no streams!?
|
|
371 // packet header (0x1ba) -- rewrite first stream buffer
|
|
372 *(uint32_t *)buff = be2me_32 (0x1ba);
|
|
373 write_mpeg_ts (buff+4, MPEG_STARTSCR, 0x20); // 0010 -- pack
|
|
374 write_mpeg_rate (buff+9, muxer->sysrate);
|
|
375 fwrite (buff, 12, 1, f);
|
|
376 // start system stream (in own block): Sys (0x1bb)
|
|
377 l1 = be2me_32 (0x1bb);
|
|
378 l2 = be2me_16 (6 + 3*muxer->avih.dwStreams); // header_length
|
|
379 fwrite (&l1, 4, 1, f);
|
|
380 fwrite (&l2, 2, 1, f);
|
|
381 write_mpeg_rate (buff, muxer->sysrate); // rate_bound
|
|
382 // set number of audio/video, fixed_flag=CSPS_flag=system_*_lock_flag=0
|
|
383 buff[3] = (muxer->avih.dwStreams - muxer->num_videos) << 2; // audio_bound
|
|
384 buff[4] = muxer->num_videos | 0x20;
|
|
385 buff[5] = 0xff; // reserved_byte
|
|
386 fwrite (buff, 6, 1, f);
|
|
387 for (i = 0; i < muxer->avih.dwStreams; i++) {
|
|
388 buff[0] = ((char *)&muxer->streams[i]->ckid)[3]; // last char in big endian
|
|
389 //fprintf (stderr, "... stream 0x1%02x; bufsize %u", (int)buff[0], muxer->streams[i]->h.dwSuggestedBufferSize);
|
|
390 write_mpeg_std (buff+1, muxer->streams[i]->h.dwSuggestedBufferSize, 0xc0); // 11
|
|
391 fwrite (buff, 3, 1, f);
|
|
392 sz -= 3;
|
|
393 }
|
|
394 if (sz >= 6) { // padding block
|
|
395 l1 = be2me_32 (0x1be);
|
|
396 sz -= 6;
|
|
397 l2 = be2me_16 (sz);
|
|
398 fwrite (&l1, 4, 1, f);
|
|
399 fwrite (&l2, 2, 1, f);
|
|
400 }
|
|
401 s->b_buffer[0] = 0x0f; // end of list - next bit has to be 0
|
|
402 // stuFFing bytes -- rewrite first stream buffer
|
|
403 if (sz > 1)
|
|
404 memset (s->b_buffer+1, 0xff, sz-1);
|
|
405 fwrite (s->b_buffer, sz, 1, f);
|
|
406 muxer->movi_start = 0;
|
|
407 muxer->movi_end = MUXER_MPEG_BLOCKSIZE;
|
|
408 }
|
|
409
|
|
410 static void mpegfile_write_index(muxer_t *muxer,FILE *f){
|
|
411 unsigned int i;
|
|
412 unsigned int rsr;
|
|
413
|
|
414 if (!muxer->avih.dwStreams) return; // no streams?!
|
|
415 // finish all but one video and audio streams
|
|
416 rsr = muxer->sysrate; // reserve it since it's silly change it at that point
|
|
417 for (i = 0; i < muxer->avih.dwStreams-1; i++)
|
|
418 write_mpeg_block (muxer, muxer->streams[i], f, NULL, 0, 0);
|
|
419 // end sequence: ISO-11172-End (0x1b9) and finish very last block
|
|
420 write_mpeg_block (muxer, muxer->streams[i], f, NULL, 0, 1);
|
|
421 //fprintf (stderr, "PTS to SCR delay: min %u.%03u, max %u.%03u\n",
|
|
422 // mpeg_min_delay/90000, (mpeg_min_delay/90)%1000,
|
|
423 // mpeg_max_delay/90000, (mpeg_max_delay/90)%1000);
|
|
424 muxer->sysrate = rsr;
|
|
425 }
|
|
426
|
|
427 void muxer_init_muxer_mpeg(muxer_t *muxer){
|
|
428 muxer->cont_new_stream = &mpegfile_new_stream;
|
|
429 muxer->cont_write_chunk = &mpegfile_write_chunk;
|
|
430 muxer->cont_write_header = &mpegfile_write_header;
|
|
431 muxer->cont_write_index = &mpegfile_write_index;
|
|
432 // mpeg_min_delay = mpeg_max_delay = MPEG_STARTPTS-MPEG_STARTSCR;
|
|
433 }
|
|
434
|