Mercurial > mplayer.hg
comparison subreader.c @ 8207:467ffae428b0
I recently sent a patch for a new subtitles format, JACOsub. Since then I
found a better definition of jacosub standard, and this patch is the
result. It supports timeresolutions changes and shifts.
Salvatore Falco <sfalco@studenti.ing.uniroma1.it>
author | arpi |
---|---|
date | Sat, 16 Nov 2002 03:25:37 +0000 |
parents | 72647ce8471f |
children | ad75993b8deb |
comparison
equal
deleted
inserted
replaced
8206:72647ce8471f | 8207:467ffae428b0 |
---|---|
603 return current; | 603 return current; |
604 } | 604 } |
605 | 605 |
606 subtitle *sub_read_line_jacosub(FILE * fd, subtitle * current) | 606 subtitle *sub_read_line_jacosub(FILE * fd, subtitle * current) |
607 { | 607 { |
608 char commands[LINE_LEN], line1[LINE_LEN], line2[LINE_LEN], | 608 char line1[LINE_LEN], line2[LINE_LEN], directive[LINE_LEN], *p, *q; |
609 text[LINE_LEN], *p, *q; | 609 unsigned a1, a2, a3, a4, b1, b2, b3, b4, comment = 0; |
610 int a1, a2, a3, a4, b1, b2, b3, b4, comment = 0; | 610 static unsigned jacoTimeres = 30; |
611 unsigned short directive = 0; | 611 static int jacoShift = 0; |
612 | 612 |
613 bzero(current, sizeof(subtitle)); | 613 bzero(current, sizeof(subtitle)); |
614 bzero(commands, sizeof(char) * LINE_LEN); | 614 bzero(line1, LINE_LEN); |
615 bzero(line1, sizeof(char) * LINE_LEN); | 615 bzero(line2, LINE_LEN); |
616 bzero(line2, sizeof(char) * LINE_LEN); | 616 bzero(directive, LINE_LEN); |
617 while (!current->text[0]) { | 617 while (!current->text[0]) { |
618 if (!fgets(line1, LINE_LEN, fd)) | 618 if (!fgets(line1, LINE_LEN, fd)) { |
619 return NULL; | 619 return NULL; |
620 } | |
620 if (sscanf | 621 if (sscanf |
621 (line1, "%d:%d:%d.%d %d:%d:%d.%d %[^\n\r]", &a1, &a2, &a3, &a4, | 622 (line1, "%u:%u:%u.%u %u:%u:%u.%u %[^\n\r]", &a1, &a2, &a3, &a4, |
622 &b1, &b2, &b3, &b4, line2) < 9) | 623 &b1, &b2, &b3, &b4, line2) < 9) { |
623 continue; | 624 if (sscanf(line1, "@%u @%u %[^\n\r]", &a4, &b4, line2) < 3) { |
624 //a Jacosub script *may* have some commands before the text, so let's recognize them | 625 if (line1[0] == '#') { |
625 switch (toupper(line2[0])) { | 626 int hours = 0, minutes = 0, seconds, delta, inverter = |
626 case 'C': | 627 1; |
627 switch (toupper(line2[1])) { | 628 unsigned units = jacoShift; |
628 case 'F': | 629 switch (toupper(line1[1])) { |
629 case 'P': | 630 case 'S': |
630 case 'S': | 631 if (isalpha(line1[2])) { |
631 case 'B': | 632 delta = 6; |
632 if (isdigit(line2[2])) | 633 } else { |
633 directive = 1; | 634 delta = 2; |
635 } | |
636 if (sscanf(&line1[delta], "%d", &hours)) { | |
637 if (hours < 0) { | |
638 hours *= -1; | |
639 inverter = -1; | |
640 } | |
641 if (sscanf(&line1[delta], "%*d:%d", &minutes)) { | |
642 if (sscanf | |
643 (&line1[delta], "%*d:%*d:%d", | |
644 &seconds)) { | |
645 sscanf(&line1[delta], "%*d:%*d:%*d.%d", | |
646 &units); | |
647 } else { | |
648 hours = 0; | |
649 sscanf(&line1[delta], "%d:%d.%d", | |
650 &minutes, &seconds, &units); | |
651 minutes *= inverter; | |
652 } | |
653 } else { | |
654 hours = minutes = 0; | |
655 sscanf(&line1[delta], "%d.%d", &seconds, | |
656 &units); | |
657 seconds *= inverter; | |
658 } | |
659 jacoShift = | |
660 ((hours * 3600 + minutes * 60 + | |
661 seconds) * jacoTimeres + | |
662 units) * inverter; | |
663 } | |
664 break; | |
665 case 'T': | |
666 if (isalpha(line1[2])) { | |
667 delta = 8; | |
668 } else { | |
669 delta = 2; | |
670 } | |
671 sscanf(&line1[delta], "%u", &jacoTimeres); | |
672 break; | |
673 } | |
674 } | |
675 continue; | |
676 } else { | |
677 current->start = | |
678 (unsigned long) ((a4 + jacoShift) * 100.0 / | |
679 jacoTimeres); | |
680 current->end = | |
681 (unsigned long) ((b4 + jacoShift) * 100.0 / | |
682 jacoTimeres); | |
634 } | 683 } |
635 break; | 684 } else { |
636 case 'D': | 685 current->start = |
637 if ((line2[1] == ' ') || isdigit(line2[1])) | 686 (unsigned |
638 directive = 1; | 687 long) (((a1 * 3600 + a2 * 60 + a3) * jacoTimeres + a4 + |
639 // special case | 688 jacoShift) * 100.0 / jacoTimeres); |
640 if (toupper(line2[1]) == 'C') | 689 current->end = |
641 directive = 1; | 690 (unsigned |
642 break; | 691 long) (((b1 * 3600 + b2 * 60 + b3) * jacoTimeres + b4 + |
643 case 'E': | 692 jacoShift) * 100.0 / jacoTimeres); |
644 switch (toupper(line2[1])) { | 693 } |
645 case 'D': | 694 current->lines = 0; |
646 case 'P': | 695 p = line2; |
647 if (isdigit(line2[2])) | 696 while ((*p == ' ') || (*p == '\t')) { |
648 directive = 1; | 697 ++p; |
649 break; | 698 } |
650 case 'I': | 699 if (isalpha(*p)||*p == '[') { |
651 if ((toupper(line2[2]) == 'O') && (isdigit(line2[3]))) | 700 int cont, jLength; |
652 directive = 1; | 701 |
653 break; | 702 if (sscanf(p, "%s %[^\n\r]", directive, line1) < 2) |
654 case 'R': | 703 return (subtitle *) ERR; |
655 if ((toupper(line2[2]) == 'D') && (isdigit(line2[3]))) | 704 jLength = strlen(directive); |
656 directive = 1; | 705 for (cont = 0; cont < jLength; ++cont) { |
657 break; | 706 if (isalpha(*(directive + cont))) |
658 case 'W': | 707 *(directive + cont) = toupper(*(directive + cont)); |
659 if ((toupper(line2[2]) == 'L') | |
660 || (toupper(line2[2]) == 'R')) | |
661 directive = 1; | |
662 break; | |
663 } | 708 } |
664 break; | 709 if ((strstr(directive, "RDB") != NULL) |
665 case 'F': | 710 || (strstr(directive, "RDC") != NULL) |
666 if (isdigit(line2[1])) | 711 || (strstr(directive, "RLB") != NULL) |
667 directive = 1; | 712 || (strstr(directive, "RLG") != NULL)) { |
668 else | 713 continue; |
669 switch (toupper(line2[1])) { | |
670 case 'O': | |
671 if (isdigit(line2[2])) | |
672 directive = 1; | |
673 break; | |
674 case 'S': | |
675 directive = 1; | |
676 } | |
677 break; | |
678 case 'G': | |
679 if ((line2[1] == 'G') && (isdigit(line2[2]))) | |
680 directive = 2; | |
681 break; | |
682 case 'H': | |
683 switch (toupper(line2[1])) { | |
684 case 'L': | |
685 case 'R': | |
686 if (isdigit(line2[2])) | |
687 directive = 1; | |
688 } | 714 } |
689 break; | 715 strcpy(line2, line1); |
690 case 'J': | 716 p = line2; |
691 switch (toupper(line2[1])) { | 717 } |
692 case 'B': | 718 for (q = line1; (!eol(*p)) && (current->lines < SUB_MAX_TEXT); |
693 if (toupper(line2[2]) == 'C') | 719 ++p) { |
694 directive = 1; | |
695 break; | |
696 case 'C': | |
697 case 'L': | |
698 case 'R': | |
699 directive = 1; | |
700 break; | |
701 case 'F': | |
702 if ((line2[2] == ':') && (toupper(line2[3]) == 'L')) | |
703 directive = 1; | |
704 } | |
705 break; | |
706 case 'R': | |
707 if (((toupper(line2[1]) == 'D') && (toupper(line2[2]) == 'B')) | |
708 || ((toupper(line2[1]) == 'D') | |
709 && (toupper(line2[2]) == 'C')) | |
710 || ((toupper(line2[1]) == 'L') | |
711 && (toupper(line2[2]) == 'B'))) | |
712 directive = 2; | |
713 break; | |
714 case 'V': | |
715 switch (toupper(line2[1])) { | |
716 case 'A': | |
717 case 'B': | |
718 case 'M': | |
719 case 'T': | |
720 case 'U': | |
721 directive = 1; | |
722 break; | |
723 case 'L': | |
724 case 'P': | |
725 if (isdigit(line2[2])) | |
726 directive = 1; | |
727 } | |
728 break; | |
729 case '[': | |
730 directive = 1; | |
731 break; | |
732 case '~': | |
733 directive = 2; | |
734 } | |
735 if (directive == 1) { | |
736 strcpy(line1, line2); | |
737 sscanf(line1, "%s %[^\n\r]", commands, line2); | |
738 } else if (directive == 2) { | |
739 continue; | |
740 } | |
741 current->start = a1 * 360000 + a2 * 6000 + a3 * 100 + a4; | |
742 current->end = b1 * 360000 + b2 * 6000 + b3 * 100 + b4; | |
743 current->lines = 0; | |
744 | |
745 q = text; | |
746 p = line2; | |
747 while ((*p) == ' ') | |
748 p++; | |
749 | |
750 for (; (!eol(*p)) && (current->lines < SUB_MAX_TEXT); p++) { | |
751 switch (*p) { | 720 switch (*p) { |
752 case '{': | 721 case '{': |
753 comment++; | 722 comment++; |
754 break; | 723 break; |
755 case '}': | 724 case '}': |
756 comment--; | 725 if (comment) { |
757 //the next to get rid of a blank after the comment | 726 --comment; |
758 if ((*(p + 1)) == ' ') | 727 //the next line to get rid of a blank after the comment |
759 p++; | 728 if ((*(p + 1)) == ' ') |
729 p++; | |
730 } | |
731 break; | |
732 case '~': | |
733 if (!comment) { | |
734 *q = ' '; | |
735 ++q; | |
736 } | |
737 break; | |
738 case ' ': | |
739 case '\t': | |
740 if ((*(p + 1) == ' ') || (*(p + 1) == '\t')) | |
741 break; | |
742 if (!comment) { | |
743 *q = ' '; | |
744 ++q; | |
745 } | |
760 break; | 746 break; |
761 case '\\': | 747 case '\\': |
762 if (*(p + 1) == 'n') { | 748 if (*(p + 1) == 'n') { |
763 *q = '\0'; | 749 *q = '\0'; |
764 q = text; | 750 q = line1; |
765 current->text[current->lines++] = strdup(text); | 751 current->text[current->lines++] = strdup(line1); |
766 p++; | 752 ++p; |
767 break; | 753 break; |
768 } else if (toupper(*(p + 1)) == 'C') { | 754 } |
769 p++; | 755 if ((toupper(*(p + 1)) == 'C') |
770 p++; | 756 || (toupper(*(p + 1)) == 'F')) { |
757 ++p,++p; | |
771 break; | 758 break; |
772 } else if ((toupper(*(p + 1)) == 'I') | 759 } |
773 || (toupper(*(p + 1)) == 'B') | 760 if ((*(p + 1) == 'B') || (*(p + 1) == 'b') || (*(p + 1) == 'D') || //actually this means "insert current date here" |
774 || (toupper(*(p + 1)) == 'N')) { | 761 (*(p + 1) == 'I') || (*(p + 1) == 'i') || (*(p + 1) == 'N') || (*(p + 1) == 'T') || //actually this means "insert current time here" |
775 p++; | 762 (*(p + 1) == 'U') || (*(p + 1) == 'u')) { |
763 ++p; | |
776 break; | 764 break; |
765 } | |
766 if ((*(p + 1) == '\\') || | |
767 (*(p + 1) == '~') || (*(p + 1) == '{')) { | |
768 ++p; | |
777 } else if (eol(*(p + 1))) { | 769 } else if (eol(*(p + 1))) { |
778 if (!fgets(line1, LINE_LEN, fd)) | 770 if (!fgets(directive, LINE_LEN, fd)) |
779 return NULL; | 771 return NULL; |
780 trail_space(line1); | 772 trail_space(directive); |
781 p = line1; | 773 strncat(line2, directive, |
774 (LINE_LEN > 511) ? LINE_LEN : 511); | |
775 break; | |
782 } | 776 } |
783 default: | 777 default: |
784 if (!comment) { | 778 if (!comment) { |
785 *q = *p; | 779 *q = *p; |
786 q++; | 780 ++q; |
787 } | 781 } |
788 } | 782 } //-- switch |
789 } | 783 } //-- for |
790 *q = '\0'; | 784 *q = '\0'; |
791 current->text[current->lines] = strdup(text); | 785 current->text[current->lines] = strdup(line1); |
792 } | 786 } //-- while |
793 current->lines++; | 787 current->lines++; |
794 return current; | 788 return current; |
795 } | 789 } |
796 | 790 |
797 int sub_autodetect (FILE *fd) { | 791 int sub_autodetect (FILE *fd) { |
815 if (sscanf (line, "{T %d:%d:%d:%d",&i, &i, &i, &i)) | 809 if (sscanf (line, "{T %d:%d:%d:%d",&i, &i, &i, &i)) |
816 {sub_uses_time=1;return SUB_SUBVIEWER2;} | 810 {sub_uses_time=1;return SUB_SUBVIEWER2;} |
817 if (strstr (line, "<SAMI>")) | 811 if (strstr (line, "<SAMI>")) |
818 {sub_uses_time=1; return SUB_SAMI;} | 812 {sub_uses_time=1; return SUB_SAMI;} |
819 if (sscanf(line, "%d:%d:%d.%d %d:%d:%d.%d", &i, &i, &i, &i, &i, &i, &i, &i) == 8) | 813 if (sscanf(line, "%d:%d:%d.%d %d:%d:%d.%d", &i, &i, &i, &i, &i, &i, &i, &i) == 8) |
814 {sub_uses_time = 1; return SUB_JACOSUB;} | |
815 if (sscanf(line, "@%d @%d", &i, &i) == 2) | |
820 {sub_uses_time = 1; return SUB_JACOSUB;} | 816 {sub_uses_time = 1; return SUB_JACOSUB;} |
821 if (sscanf (line, "%d:%d:%d:", &i, &i, &i )==3) | 817 if (sscanf (line, "%d:%d:%d:", &i, &i, &i )==3) |
822 {sub_uses_time=1;return SUB_VPLAYER;} | 818 {sub_uses_time=1;return SUB_VPLAYER;} |
823 if (sscanf (line, "%d:%d:%d ", &i, &i, &i )==3) | 819 if (sscanf (line, "%d:%d:%d ", &i, &i, &i )==3) |
824 {sub_uses_time=1;return SUB_VPLAYER;} | 820 {sub_uses_time=1;return SUB_VPLAYER;} |