ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/freemol/trunk/src/mpeg_encode/src/specifics.c
Revision: 22
Committed: Mon Jul 7 22:16:37 2008 UTC (11 years ago) by wdelano
File size: 17213 byte(s)
Log Message:
initial checkin of mpeg_encode source
Line File contents
1 /*===========================================================================*
2 * specifics.c *
3 * *
4 * basic procedures to deal with the specifics file *
5 * *
6 * EXPORTED PROCEDURES: *
7 * Specifics_Init *
8 * Spec_Lookup *
9 * SpecTypeLookup *
10 * *
11 *===========================================================================*/
12
13 /*
14 * Copyright (c) 1995 The Regents of the University of California.
15 * All rights reserved.
16 *
17 * Permission to use, copy, modify, and distribute this software and its
18 * documentation for any purpose, without fee, and without written agreement is
19 * hereby granted, provided that the above copyright notice and the following
20 * two paragraphs appear in all copies of this software.
21 *
22 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
23 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
24 * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
25 * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 *
27 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
28 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
29 * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
30 * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
31 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
32 */
33
34
35 /*==============*
36 * HEADER FILES *
37 *==============*/
38
39 #include "all.h"
40 #include "mtypes.h"
41 #include "frames.h"
42 #include "frame.h"
43 #include "fsize.h"
44 #include "dct.h"
45 #include "specifics.h"
46 #include <stdio.h>
47 #include <string.h>
48 #include "prototypes.h"
49
50 /*====================*
51 * System Information *
52 *====================*/
53
54 #define CPP_LOC "/lib/cpp"
55
56 /*==================*
57 * GLOBAL VARIABLES *
58 *==================*/
59
60 extern boolean specificsOn;
61 extern char specificsFile[];
62 extern char specificsDefines[];
63 FrameSpecList *fsl;
64
65 /*=====================*
66 * Internal procedures *
67 *=====================*/
68
69 void Parse_Specifics_File _ANSI_ARGS_((FILE *fp));
70 void Parse_Specifics_File_v1 _ANSI_ARGS_((FILE *fp));
71 void Parse_Specifics_File_v2 _ANSI_ARGS_((FILE *fp));
72 FrameSpecList *MakeFslEntry _ANSI_ARGS_((void));
73 void AddSlc _ANSI_ARGS_((FrameSpecList *c,int snum, int qs));
74 Block_Specifics *AddBs _ANSI_ARGS_((FrameSpecList *c,int bnum,
75 boolean rel, int qs));
76 FrameSpecList *MakeFslEntry _ANSI_ARGS_((void));
77 #define my_upper(c) (((c>='a') && (c<='z')) ? (c-'a'+'A') : c)
78 #define CvtType(x) ReallyCvt(my_upper(x))
79 #define ReallyCvt(x) (x=='I' ? 1 : (x=='P')?2: ((x=='B')?3:-1))
80 #define SkipToSpace(lp) while ((*lp != ' ') && (*lp != '\n') && (*lp != '\0')) lp++
81 #define EndString(lp) ((*lp == '\n') || (*lp == '\0'))
82
83 /*=============================================================
84 * SPEC FILE FORMAT (version 1):
85
86 Specs files are processed with the c preprecoessor, so use C style comments
87 and #defines if you wish.
88
89 frames, blocks, and slices are numbered from 0.
90 (sorry)
91
92 In order by frame number, slice number, block number
93 (if you skip slices it's fine).
94 Can have specifics for any frame, block, or slice.
95 Format:
96 version N
97 Specify the version of the specifics file format (this is 1)
98 frame N T M
99 Sets frame number N to type T and Qscale M
100 (type T is I,B,P,other, other means unspec. I recomend - )
101 slice M Q
102 Sets slice M (in frame N as defined by a previous frame command)
103 to qscale Q
104 block M Q
105 Sets block M to qscale Q, in frame N previously specified.
106
107 Unspecified frame types are set via the last I frame set, which is forced
108 to act as the first I of the GOP.
109 FORCE_ENCODE_LAST_FRAME overrides specifics on the final frame type.
110 Note that Qscale changes in skipped blocks will be lost!
111
112 Version 2:
113 frames and slices are the same as above, but Q in blocks can be relative, i.e.
114 +N or -N. Clipping to 1..31 is done but sequences like
115 block 1 2
116 block 2 -3
117 block 3 +3
118
119 has undefined results (as present block 3 would be Qscale 2).
120
121 In addition motion vectors can be specified:
122 block M Q skip
123 Says to skip the block (not really an MV, but....)
124 block M Q bi fx fy bx by
125 Sets block M to quality Q. It will be a bidirectional block.
126 fx/fy is the forward (like a P frame) vector, bx/y is the back
127 block M Q forw fx fy
128 block M Q back bx by
129 Single directional.
130
131 All vectors are specified in HALF PIXEL fixed point units, i.e.
132 3.5 pixels is 7
133 To specify a vector but not touch the q factor, set Q to 0
134
135 *=============================================================*/
136
137
138 /*=============*
139 * Local State *
140 *=============*/
141
142 static char version = -1;
143
144 /*================================================================
145 *
146 * Specifics_Init
147 *
148 * Cpp's and reads in the specifics file. Creates fsl data structure.
149 *
150 * Returns: nothing
151 *
152 * Modifies: fsl, file specificsFile".cpp"
153 *
154 *================================================================
155 */
156 void Specifics_Init()
157 {
158 char command[1100];
159 FILE *specificsFP;
160
161 sprintf(command, "/bin/rm -f %s.cpp", specificsFile);
162 system(command);
163 sprintf(command, "%s -P %s %s %s.cpp",
164 CPP_LOC, specificsDefines, specificsFile, specificsFile);
165 system(command);
166 strcat(specificsFile, ".cpp");
167 if ((specificsFP = fopen(specificsFile, "r")) == NULL) {
168 fprintf(stderr, "Error with specifics file, cannot open %s\n", specificsFile);
169 exit(1);
170 }
171 printf("Specifics file: %s\n", specificsFile);
172 Parse_Specifics_File(specificsFP);
173 sprintf(command, "/bin/rm -f %s.cpp", specificsFile);
174 system(command);
175
176 }
177
178
179
180
181 /*================================================================
182 *
183 * Parse_Specifics_File
184 *
185 * Read through the file passed in creating the fsl data structure
186 * There is a primary routine, and helpers for the specific versions.
187 *
188 * Returns: Nothing
189 *
190 * Modifies: fsl
191 *
192 *================================================================
193 */
194 void Parse_Specifics_File(fp)
195 FILE *fp;
196 {
197 char line[1024], *lp;
198 int vers;
199
200 while ((fgets(line, 1023, fp)) != NULL) {
201 lp = &line[0];
202 while ((*lp == ' ') || (*lp == '\t')) lp++;
203 if (( *lp == '#' ) || (*lp=='\n')) {
204 continue;
205 }
206
207 switch (my_upper(*lp)) {
208 case 'F': case 'S': case 'B':
209 fprintf(stderr, "Must specify version at beginning of specifics file\n");
210 exit(0);
211 break;
212 case 'V':
213 lp += 7;
214 if (1 != sscanf(lp, "%d", &vers)) {
215 fprintf(stderr," Improper version line in specs file: %s\n", line);
216 } else {
217 switch (vers) {
218 case 1:
219 version = vers;
220 Parse_Specifics_File_v1(fp);
221 break;
222 case 2:
223 version = vers;
224 Parse_Specifics_File_v2(fp);
225 break;
226 default:
227 fprintf(stderr, "Improper version line in specs file: %s\n", line);
228 fprintf(stderr, "\tSpecifics file will be IGNORED.\n");
229 specificsOn = FALSE;
230 return;
231 break;
232 }}
233 break;
234 default:
235 fprintf(stderr, "Specifics file: What? *%s*\n", line);
236 break;
237 }}
238
239 }
240
241 /* Version 1 */
242 void Parse_Specifics_File_v1(fp)
243 FILE *fp;
244 {
245 char line[1024],*lp;
246 FrameSpecList *current, *new;
247 char typ;
248 int fnum,snum, bnum, qs, newqs;
249 int num_scanned;
250
251 fsl = MakeFslEntry();
252 current = fsl;
253
254 while ((fgets(line,1023, fp)) != NULL) {
255 lp = &line[0];
256 while ((*lp == ' ') || (*lp == '\t')) lp++;
257 if (( *lp == '#' ) || (*lp=='\n')) {
258 continue;
259 }
260
261 switch (my_upper(*lp)) {
262 case 'F':
263 lp += 6;
264 sscanf(lp, "%d %c %d", &fnum, &typ, &qs);
265 if (current->framenum != -1) {
266 new=MakeFslEntry();
267 current->next = new;
268 current = new;
269 }
270 current->framenum = fnum;
271 current->frametype = CvtType(typ);
272 if (qs <= 0) qs = -1;
273 current->qscale = qs;
274 break;
275 case 'S':
276 lp += 6;
277 sscanf(lp, "%d %d", &snum, &newqs);
278 if (qs == newqs) break;
279 qs = newqs;
280 AddSlc(current, snum, qs);
281 break;
282 case 'B':
283 lp += 6;
284 num_scanned = sscanf(lp, "%d %d", &bnum, &newqs);
285 if (qs == newqs) break;
286 qs = newqs;
287 AddBs(current, bnum, FALSE, qs);
288 break;
289 case 'V':
290 fprintf(stderr, "Cannot specify version twice! Taking first (%d)\n", version);
291 break;
292 default:
293 fprintf(stderr," What? *%s*\n", line);
294 break;
295 }}
296
297 }
298
299 /* Version 2 */
300 void Parse_Specifics_File_v2(fp)
301 FILE *fp;
302 {
303 char line[1024], *lp;
304 FrameSpecList *current, *new;
305 char typ;
306 int fnum, snum, bnum, qs, newqs;
307 int num_scanned, fx=0, fy=0, sx=0, sy=0;
308 char kind[100];
309 Block_Specifics *new_blk;
310 boolean relative;
311
312 fsl = MakeFslEntry();
313 current = fsl;
314
315 while ((fgets(line,1023,fp))!=NULL) {
316 lp = &line[0];
317 while ((*lp == ' ') || (*lp == '\t')) lp++;
318 if (( *lp == '#' ) || (*lp=='\n')) {
319 continue;
320 }
321
322 switch (my_upper(*lp)) {
323 case 'F':
324 lp += 6;
325 sscanf(lp,"%d %c %d", &fnum, &typ, &qs);
326 new = MakeFslEntry();
327 if (current->framenum != -1) {
328 current->next = new;
329 current = new;
330 }
331 current->framenum = fnum;
332 current->frametype = CvtType(typ);
333 if (qs <= 0) qs = -1;
334 current->qscale = qs;
335 break;
336 case 'S':
337 lp += 6;
338 sscanf(lp,"%d %d", &snum, &newqs);
339 if (qs == newqs) break;
340 qs = newqs;
341 AddSlc(current, snum, qs);
342 break;
343 case 'B':
344 lp += 6;
345 num_scanned = 0;
346 bnum = atoi(lp);
347 SkipToSpace(lp);
348 while ((*lp != '-') && (*lp != '+') &&
349 ((*lp < '0') || (*lp > '9'))) lp++;
350 relative = ((*lp == '-') || (*lp == '+'));
351 newqs = atoi(lp);
352 SkipToSpace(lp);
353 if (EndString(lp)) {
354 num_scanned = 2;
355 } else {
356 num_scanned = 2+sscanf(lp, "%s %d %d %d %d", kind, &fx, &fy, &sx, &sy);
357 }
358
359 qs = newqs;
360 new_blk = AddBs(current, bnum, relative, qs);
361 if (num_scanned > 2) {
362 BlockMV *tmp;
363 tmp = (BlockMV *) malloc(sizeof(BlockMV));
364 switch (num_scanned) {
365 case 7:
366 tmp->typ = TYP_BOTH;
367 tmp->fx = fx;
368 tmp->fy = fy;
369 tmp->bx = sx;
370 tmp->by = sy;
371 new_blk->mv = tmp;
372 break;
373 case 3:
374 tmp->typ = TYP_SKIP;
375 new_blk->mv = tmp;
376 break;
377 case 5:
378 if (my_upper(kind[0]) == 'B') {
379 tmp->typ = TYP_BACK;
380 tmp->bx = fx;
381 tmp->by = fy;
382 } else {
383 tmp->typ = TYP_FORW;
384 tmp->fx = fx;
385 tmp->fy = fy;
386 }
387 new_blk->mv = tmp;
388 break;
389 default:
390 fprintf(stderr,
391 "Bug in specifics file! Skipping short/long entry: %s\n",line);
392 break;
393 }
394 } else {
395 new_blk->mv = (BlockMV *) NULL;
396 }
397
398 break;
399 case 'V':
400 fprintf(stderr,
401 "Cannot specify version twice! Taking first (%d).\n",
402 version);
403 break;
404 default:
405 printf("What? *%s*\n",line);
406 break;
407 }}
408
409 }
410
411
412
413
414 /*=================================================================
415 *
416 * MakeFslEntry
417 *
418 * Makes a single entry in for the fsl linked list (makes a frame)
419 *
420 * Returns: the new entry
421 *
422 * Modifies: nothing
423 *
424 *=================================================================
425 */
426 FrameSpecList *MakeFslEntry()
427 {
428 FrameSpecList *fslp;
429 fslp = (FrameSpecList *) malloc(sizeof(FrameSpecList));
430 fslp->framenum = -1;
431 fslp->slc = (Slice_Specifics *) NULL;
432 fslp->bs = (Block_Specifics *) NULL;
433 return fslp;
434 }
435
436
437
438
439
440 /*================================================================
441 *
442 * AddSlc
443 *
444 * Adds a slice to framespeclist c with values snum and qs
445 *
446 * Returns: nothing
447 *
448 * Modifies: fsl's structure
449 *
450 *================================================================
451 */
452 void AddSlc(c, snum, qs)
453 FrameSpecList *c;
454 int snum,qs;
455 {
456 Slice_Specifics *new;
457 static Slice_Specifics *last;
458
459 new = (Slice_Specifics *) malloc(sizeof(Slice_Specifics));
460 new->num = snum;
461 new->qscale = qs;
462 new->next = (Slice_Specifics *)NULL;
463 if (c->slc == (Slice_Specifics *)NULL) {
464 last = new;
465 c->slc = new;
466 } else {
467 last->next = new;
468 last = new;
469 }
470 }
471
472
473
474
475
476 /*================================================================
477 *
478 * AddBs
479 *
480 * Adds a sliceblock to framespeclist c with values bnum and qs
481 *
482 * Returns: pointer to the new block spec
483 *
484 * Modifies: fsl's structure
485 *
486 *================================================================
487 */
488 Block_Specifics *AddBs(c,bnum,rel,qs)
489 FrameSpecList *c;
490 boolean rel;
491 int bnum,qs;
492 {
493 Block_Specifics *new;
494 static Block_Specifics *last;
495
496 new = (Block_Specifics *) malloc(sizeof(Block_Specifics));
497 new->num = bnum;
498 if (qs == 0) rel = TRUE;
499 new->relative = rel;
500 new->qscale = qs;
501 new->next = (Block_Specifics *)NULL;
502 new->mv = (BlockMV *) NULL;
503 if (c->bs == (Block_Specifics *)NULL) {
504 last = new;
505 c->bs = new;
506 } else {
507 last->next = new;
508 last = new;
509 }
510 return new;
511 }
512
513
514
515
516
517
518 /*================================================================
519 *
520 * SpecLookup
521 *
522 * Find out if there is any changes to be made for the qscale
523 * at entry fn.num (which is of type typ). Sets info to point to
524 * motion vector info (if any), else NULL.
525 *
526 * Returns: new qscale or -1
527 *
528 * Modifies: *info (well, internal cache can change)
529 *
530 *================================================================
531 */
532
533 int SpecLookup(fn,typ,num,info,start_qs)
534 int fn,typ,num;
535 BlockMV **info;
536 int start_qs;
537 {
538 static FrameSpecList *last = (FrameSpecList *) NULL;
539 Slice_Specifics *sptr=(Slice_Specifics *) NULL;
540 Block_Specifics *bptr=(Block_Specifics *) NULL;
541 FrameSpecList *tmp;
542 boolean found_it;
543 static int leftovers = 0; /* Used in case of forced movement into 1..31 range */
544
545 *info = (BlockMV * )NULL;
546 if (last == (FrameSpecList *) NULL){
547 /* No cache, try to find number fn */
548 tmp = fsl;
549 found_it = FALSE;
550 while (tmp != (FrameSpecList *) NULL) {
551 if (tmp->framenum == fn) {
552 found_it = TRUE;
553 break;
554 } else tmp = tmp->next;
555 }
556 if (!found_it) return -1;
557 last=tmp;
558 } else {
559 if (last->framenum != fn) { /* cache miss! */
560 /* first check if it is next */
561 if ((last->next != (FrameSpecList *) NULL) &&
562 (last->next->framenum == fn)) {
563 last = last->next;
564 } else {
565 /* if not next, check from the start.
566 (this allows people to put frames out of order,even
567 though the spec doesnt allow it.) */
568 tmp = fsl;
569 found_it = FALSE;
570 while (tmp != (FrameSpecList *) NULL) {
571 if (tmp->framenum==fn) {found_it = TRUE; break;}
572 tmp = tmp->next;
573 }
574 if (!found_it) return -1;
575 last = tmp;
576 }
577 }
578 }
579 /* neither of these should ever be true, unless there is a bug above */
580 if (last == (FrameSpecList *) NULL) {
581 fprintf(stderr, "PROGRAMMER ERROR: last is null!\n");
582 return -1;
583 }
584 if (last->framenum!=fn) {
585 fprintf(stderr, "PROGRAMMER ERROR: last has wrong number!\n");
586 return -1; /* no data on it */
587 }
588
589 switch(typ) {
590 case 0: /* Frame: num is ignored */
591 leftovers = 0;
592 #ifdef BLEAH
593 printf("QSchange frame %d to %d\n", fn, last->qscale);
594 #endif
595 return last->qscale;
596 break;
597
598 case 1: /* Slice */
599 leftovers = 0;
600 /* So, any data on slices? */
601 if (last->slc == (Slice_Specifics *) NULL) return -1;
602 for (sptr = last->slc; sptr != (Slice_Specifics *) NULL; sptr = sptr->next) {
603 if (sptr->num == num) {
604 #ifdef BLEAH
605 printf("QSchange Slice %d.%d to %d\n", fn, num, sptr->qscale);
606 #endif
607 if (sptr->qscale == 0) return -1;
608 return sptr->qscale;
609 }
610 }
611 break;
612
613 case 2: /* block */
614 /* So, any data on blocks? */
615 if (last->bs == (Block_Specifics *) NULL) {
616 return -1;
617 }
618 for (bptr=last->bs; bptr != (Block_Specifics *) NULL; bptr=bptr->next) {
619 if (bptr->num == num) {
620 int new_one;
621 #ifdef BLEAH
622 printf("QSchange Block %d.%d to %d\n", fn, num, bptr->qscale);
623 #endif
624 *info = bptr->mv;
625 if (bptr->relative) {
626 if (bptr->qscale == 0) {
627 /* Do nothing! */
628 new_one = start_qs;
629 } else {
630 new_one = start_qs + bptr->qscale + leftovers;
631 if (new_one < 1) {
632 leftovers = new_one - 1;
633 new_one = 1;
634 } else if (new_one > 31) {
635 leftovers = new_one - 31;
636 new_one = 31;
637 } else leftovers = 0;
638 }}
639 else {
640 new_one = bptr->qscale;
641 leftovers = 0;
642 }
643 return new_one;
644 }
645 }
646 break;
647 default:
648 fprintf(stderr, "PROGRAMMER ERROR: reached unreachable code in SpecLookup\n");
649 break;
650 }
651 /* no luck */
652 return -1;
653 }
654
655
656 /*================================================================
657 *
658 * SpecTypeLookup
659 *
660 * Find out if there is any changes to be made for the type of frame
661 * at frame fn.
662 *
663 * Returns: new type or -1 (unspecified)
664 *
665 *================================================================
666 */
667 int SpecTypeLookup(fn)
668 int fn;
669 {
670 FrameSpecList *tmp;
671
672 /* try to find number fn */
673 tmp = fsl;
674 do {
675 if (tmp->framenum == fn) break;
676 else tmp = tmp->next;
677 } while (tmp != (FrameSpecList *) NULL);
678 if (tmp == (FrameSpecList *) NULL) {
679 #ifdef BLEAH
680 printf("Frame %d type not specified\n", fn);
681 #endif
682 return -1;
683 }
684 #ifdef BLEAH
685 printf("Frame %d type set to %d\n", fn, tmp->frametype);
686 #endif
687 return tmp->frametype;
688 }