History

sd_ass: allow get_text to return more than 500 bytes

rcombs committed 2 years ago

Commit aa0a9ce1 parent e3fd2444 files · +56 −58Browse files

Unified · Split

4 files
  1. sub/filter_jsre.c +1 −1
  2. sub/filter_regex.c +1 −1
  3. sub/sd.h +5 −3
  4. sub/sd_ass.c +49 −53
sub/filter_jsre.c+1−1
@@ -115,7 +115,7 @@ static struct demux_packet *jsre_filter(struct sd_filter *ft, · 114 unmodified lines
115 bool drop = false;115 bool drop = false;
116 116
117 if (ft->opts->rf_plain)117 if (ft->opts->rf_plain)
118 sd_ass_to_plaintext(text, strlen(text), text);118 sd_ass_to_plaintext(&text, text);
119 119
120 for (int n = 0; n < p->num_regexes; n++) {120 for (int n = 0; n < p->num_regexes; n++) {
121 int found, err = p_regexec(p->J, n, text, &found);121 int found, err = p_regexec(p->J, n, text, &found);
sub/filter_regex.c+1−1
@@ -64,7 +64,7 @@ static struct demux_packet *rf_filter(struct sd_filter *ft, · 63 unmodified lines
64 bool drop = false;64 bool drop = false;
65 65
66 if (ft->opts->rf_plain)66 if (ft->opts->rf_plain)
67 sd_ass_to_plaintext(text, strlen(text), text);67 sd_ass_to_plaintext(&text, text);
68 68
69 for (int n = 0; n < p->num_regexes; n++) {69 for (int n = 0; n < p->num_regexes; n++) {
70 int err = regexec(&p->regexes[n], text, 0, NULL, 0);70 int err = regexec(&p->regexes[n], text, 0, NULL, 0);
sub/sd.h+5−3
@@ -107,8 +107,10 @@ int sd_ass_fmt_offset(const char *event_format); · 106 unmodified lines
107bstr sd_ass_pkt_text(struct sd_filter *ft, struct demux_packet *pkt, int offset);107bstr sd_ass_pkt_text(struct sd_filter *ft, struct demux_packet *pkt, int offset);
108 108
109// convert \0-terminated "Text" (ass) content to plaintext, possibly in-place.109// convert \0-terminated "Text" (ass) content to plaintext, possibly in-place.
110// result.start is out, result.len is MIN(out_siz, strlen(in)) or smaller.110// result.start is *out, result.len is strlen(in) or smaller.
111// if there's room: out[result.len] is set to \0. out == in is allowed.111// (*out)[result.len] is always set to \0. *out == in is allowed.
112bstr sd_ass_to_plaintext(char *out, size_t out_siz, const char *in);112// *out must be a talloc-allocated buffer or NULL, and will be reallocated if needed.
113// *out will not be reallocated if *out == in.
114bstr sd_ass_to_plaintext(char **out, const char *in);
113 115
114#endif116#endif
sub/sd_ass.c+49−53
@@ -51,7 +51,7 @@ struct sd_ass_priv { · 50 unmodified lines
51 bool clear_once;51 bool clear_once;
52 struct mp_ass_packer *packer;52 struct mp_ass_packer *packer;
53 struct sub_bitmap_copy_cache *copy_cache;53 struct sub_bitmap_copy_cache *copy_cache;
54 char last_text[500];54 bstr last_text;
55 struct mp_image_params video_params;55 struct mp_image_params video_params;
56 struct mp_image_params last_params;56 struct mp_image_params last_params;
57 struct mp_osd_res osd;57 struct mp_osd_res osd;
@@ -709,30 +709,23 @@ done: · 651 unmodified lines
709 return res;709 return res;
710}710}
711 711
712struct buf {712#define MAX_BUF_SIZE 1024 * 1024
713 char *start;713#define MIN_EXPAND_SIZE 4096
714 int size;
715 int len;
716};
717 714
718static void append(struct buf *b, char c)715static void append(bstr *b, char c)
719{716{
720 if (b->len < b->size) {717 bstr_xappend(NULL, b, (bstr){&c, 1});
721 b->start[b->len] = c;
722 b->len++;
723 }
724}718}
725 719
726static void ass_to_plaintext(struct buf *b, const char *in)720static void ass_to_plaintext(bstr *b, const char *in)
727{721{
728 bool in_tag = false;
729 const char *open_tag_pos = NULL;722 const char *open_tag_pos = NULL;
730 bool in_drawing = false;723 bool in_drawing = false;
731 while (*in) {724 while (*in) {
732 if (in_tag) {725 if (open_tag_pos) {
733 if (in[0] == '}') {726 if (in[0] == '}') {
734 in += 1;727 in += 1;
735 in_tag = false;728 open_tag_pos = NULL;
736 } else if (in[0] == '\\' && in[1] == 'p' && in[2] != 'o') {729 } else if (in[0] == '\\' && in[1] == 'p' && in[2] != 'o') {
737 in += 2;730 in += 2;
738 // Skip text between \pN and \p0 tags. A \p without a number731 // Skip text between \pN and \p0 tags. A \p without a number
@@ -756,7 +749,6 @@ static void ass_to_plaintext(struct buf *b, const char *in) · 17 unmodified lines
756 } else if (in[0] == '{') {749 } else if (in[0] == '{') {
757 open_tag_pos = in;750 open_tag_pos = in;
758 in += 1;751 in += 1;
759 in_tag = true;
760 } else {752 } else {
761 if (!in_drawing)753 if (!in_drawing)
762 append(b, in[0]);754 append(b, in[0]);
@@ -765,65 +757,64 @@ static void ass_to_plaintext(struct buf *b, const char *in) · 2 unmodified lines
765 }757 }
766 }758 }
767 // A '{' without a closing '}' is always visible.759 // A '{' without a closing '}' is always visible.
768 if (in_tag) {760 if (open_tag_pos) {
769 while (*open_tag_pos)761 bstr_xappend(NULL, b, bstr0(open_tag_pos));
770 append(b, *open_tag_pos++);
771 }762 }
772}763}
773 764
774// Empty string counts as whitespace. Reads s[len-1] even if there are \0s.765// Empty string counts as whitespace.
775static bool is_whitespace_only(char *s, int len)766static bool is_whitespace_only(bstr b)
776{767{
777 for (int n = 0; n < len; n++) {768 for (int n = 0; n < b.len; n++) {
778 if (s[n] != ' ' && s[n] != '\t')769 if (b.start[n] != ' ' && b.start[n] != '\t')
779 return false;770 return false;
780 }771 }
781 return true;772 return true;
782}773}
783 774
784static char *get_text_buf(struct sd *sd, double pts, enum sd_text_type type)775static bstr get_text_buf(struct sd *sd, double pts, enum sd_text_type type)
785{776{
786 struct sd_ass_priv *ctx = sd->priv;777 struct sd_ass_priv *ctx = sd->priv;
787 ASS_Track *track = ctx->ass_track;778 ASS_Track *track = ctx->ass_track;
788 779
789 if (pts == MP_NOPTS_VALUE)780 if (pts == MP_NOPTS_VALUE)
790 return NULL;781 return (bstr){0};
791 long long ipts = find_timestamp(sd, pts);782 long long ipts = find_timestamp(sd, pts);
792 783
793 struct buf b = {ctx->last_text, sizeof(ctx->last_text) - 1};784 bstr *b = &ctx->last_text;
785
786 if (!b->start)
787 b->start = talloc_size(ctx, 4096);
788
789 b->len = 0;
794 790
795 for (int i = 0; i < track->n_events; ++i) {791 for (int i = 0; i < track->n_events; ++i) {
796 ASS_Event *event = track->events + i;792 ASS_Event *event = track->events + i;
797 if (ipts >= event->Start && ipts < event->Start + event->Duration) {793 if (ipts >= event->Start && ipts < event->Start + event->Duration) {
798 if (event->Text) {794 if (event->Text) {
799 int start = b.len;795 int start = b->len;
800 if (type == SD_TEXT_TYPE_PLAIN) {796 if (type == SD_TEXT_TYPE_PLAIN) {
801 ass_to_plaintext(&b, event->Text);797 ass_to_plaintext(b, event->Text);
802 } else {798 } else {
803 char *t = event->Text;799 bstr_xappend(NULL, b, bstr0(event->Text));
804 while (*t)
805 append(&b, *t++);
806 }800 }
807 if (is_whitespace_only(&b.start[start], b.len - start)) {801 if (is_whitespace_only(bstr_cut(*b, start))) {
808 b.len = start;802 b->len = start;
809 } else {803 } else {
810 append(&b, '\n');804 append(b, '\n');
811 }805 }
812 }806 }
813 }807 }
814 }808 }
815 809
816 b.start[b.len] = '\0';810 bstr_eatend(b, (bstr)bstr0_lit("\n"));
817
818 if (b.len > 0 && b.start[b.len - 1] == '\n')
819 b.start[b.len - 1] = '\0';
820 811
821 return ctx->last_text;812 return *b;
822}813}
823 814
824static char *get_text(struct sd *sd, double pts, enum sd_text_type type)815static char *get_text(struct sd *sd, double pts, enum sd_text_type type)
825{816{
826 return talloc_strdup(NULL, get_text_buf(sd, pts, type));817 return bstrto0(NULL, get_text_buf(sd, pts, type));
827}818}
828 819
829static struct sd_times get_times(struct sd *sd, double pts)820static struct sd_times get_times(struct sd *sd, double pts)
@@ -862,20 +853,26 @@ static void fill_plaintext(struct sd *sd, double pts) · 32 unmodified lines
862 853
863 ass_flush_events(track);854 ass_flush_events(track);
864 855
865 char *text = get_text_buf(sd, pts, SD_TEXT_TYPE_PLAIN);856 bstr text = get_text_buf(sd, pts, SD_TEXT_TYPE_PLAIN);
866 if (!text)857 if (!text.len)
867 return;858 return;
868 859
869 bstr dst = {0};860 bstr dst = {0};
870 861
871 while (*text) {862 while (text.len) {
872 if (*text == '{')863 if (*text.start == '{') {
864 bstr_xappend(NULL, &dst, bstr0("\\{"));
865 text = bstr_cut(text, 1);
866 } else if (*text.start == '\\') {
873 bstr_xappend(NULL, &dst, bstr0("\\"));867 bstr_xappend(NULL, &dst, bstr0("\\"));
874 bstr_xappend(NULL, &dst, (bstr){text, 1});868 // Break ASS escapes with U+2060 WORD JOINER
875 // Break ASS escapes with U+2060 WORD JOINER
876 if (*text == '\\')
877 mp_append_utf8_bstr(NULL, &dst, 0x2060);869 mp_append_utf8_bstr(NULL, &dst, 0x2060);
878 text++;870 text = bstr_cut(text, 1);
871 }
872
873 int i = bstrcspn(text, "{\\");
874 bstr_xappend(NULL, &dst, (bstr){text.start, i});
875 text = bstr_cut(text, i);
879 }876 }
880 877
881 if (!dst.start)878 if (!dst.start)
@@ -1103,11 +1100,10 @@ bstr sd_ass_pkt_text(struct sd_filter *ft, struct demux_packet *pkt, int offset) · 221 unmodified lines
1103 return txt;1100 return txt;
1104}1101}
1105 1102
1106bstr sd_ass_to_plaintext(char *out, size_t out_siz, const char *in)1103bstr sd_ass_to_plaintext(char **out, const char *in)
1107{1104{
1108 struct buf b = {out, out_siz, 0};1105 bstr b = {*out};
1109 ass_to_plaintext(&b, in);1106 ass_to_plaintext(&b, in);
1110 if (b.len < out_siz)1107 *out = b.start;
1111 out[b.len] = 0;1108 return b;
1112 return (bstr){out, b.len};
1113}1109}

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t