blob: 9fbebd57002af7cb90baa396c63f724ab0280c6b [file] [log] [blame]
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001From be6163cfa3a255493f9d75bad9541cbfe1723fee Mon Sep 17 00:00:00 2001
2From: Mingke Wang <mingke.wang@freescale.com>
3Date: Thu, 19 Mar 2015 14:17:10 +0800
4Subject: [PATCH 3/4] ssaparse: enhance SSA text lines parsing.
5
6some parser will pass in the original ssa text line which starts with "Dialog:"
7and there's are maybe multiple Dialog lines in one input buffer.
8
9Upstream-Status: Submitted [https://bugzilla.gnome.org/show_bug.cgi?id=747496]
10
11Signed-off-by: Mingke Wang <mingke.wang@freescale.com>
12
13diff --git a/gst/subparse/gstssaparse.c b/gst/subparse/gstssaparse.c
14old mode 100644
15new mode 100755
16index 06ecef9..0ab5dce
17--- a/gst/subparse/gstssaparse.c
18+++ b/gst/subparse/gstssaparse.c
19@@ -260,6 +260,7 @@ gst_ssa_parse_remove_override_codes (GstSsaParse * parse, gchar * txt)
20 * gst_ssa_parse_push_line:
21 * @parse: caller element
22 * @txt: text to push
23+ * @size: text size need to be parse
24 * @start: timestamp for the buffer
25 * @duration: duration for the buffer
26 *
27@@ -269,27 +270,133 @@ gst_ssa_parse_remove_override_codes (GstSsaParse * parse, gchar * txt)
28 * Returns: result of the push of the created buffer
29 */
30 static GstFlowReturn
31-gst_ssa_parse_push_line (GstSsaParse * parse, gchar * txt,
32+gst_ssa_parse_push_line (GstSsaParse * parse, gchar * txt, gint size,
33 GstClockTime start, GstClockTime duration)
34 {
35 GstFlowReturn ret;
36 GstBuffer *buf;
37- gchar *t, *escaped;
38+ gchar *t, *text, *p, *escaped, *p_start, *p_end;
39 gint num, i, len;
40+ GstClockTime start_time = G_MAXUINT64, end_time = 0;
41
42- num = atoi (txt);
43- GST_LOG_OBJECT (parse, "Parsing line #%d at %" GST_TIME_FORMAT,
44- num, GST_TIME_ARGS (start));
45-
46- /* skip all non-text fields before the actual text */
47+ p = text = g_malloc(size + 1);
48+ *p = '\0';
49 t = txt;
50- for (i = 0; i < 8; ++i) {
51- t = strchr (t, ',');
52+
53+ /* there are may have multiple dialogue lines at a time */
54+ while (*t) {
55+ /* ignore leading white space characters */
56+ while (isspace(*t))
57+ t++;
58+
59+ /* ignore Format: and Style: lines */
60+ if (strncmp(t, "Format:", 7) == 0 || strncmp(t, "Style:", 6) == 0) {
61+ while (*t != '\0' && *t != '\n') {
62+ t++;
63+ }
64+ }
65+
66+ if (*t == '\0')
67+ break;
68+
69+ /* continue with next line */
70+ if (*t == '\n') {
71+ t++;
72+ continue;
73+ }
74+
75+ if(strncmp(t, "Dialogue:", 9) != 0) {
76+ /* not started with "Dialogue:", it must be a line trimmed by demuxer */
77+ num = atoi (t);
78+ GST_LOG_OBJECT (parse, "Parsing line #%d at %" GST_TIME_FORMAT,
79+ num, GST_TIME_ARGS (start));
80+
81+ /* skip all non-text fields before the actual text */
82+ for (i = 0; i < 8; ++i) {
83+ t = strchr (t, ',');
84+ if (t == NULL)
85+ break;
86+ ++t;
87+ }
88+ } else {
89+ /* started with "Dialogue:", update timestamp and duration */
90+ /* time format are like Dialog:Mark,0:00:01.02,0:00:03.04,xx,xxx,... */
91+ guint hour, min, sec, msec, len;
92+ GstClockTime tmp;
93+ gchar t_str[12] = {0};
94+
95+ /* find the first ',' */
96+ p_start = strchr (t, ',');
97+ if (p_start)
98+ p_end = strchr (++p_start, ',');
99+
100+ if (p_start && p_end) {
101+ /* copy text between first ',' and second ',' */
102+ strncpy(t_str, p_start, p_end - p_start);
103+ if (sscanf (t_str, "%u:%u:%u.%u", &hour, &min, &sec, &msec) == 4) {
104+ tmp = ((hour*3600) + (min*60) + sec) * GST_SECOND + msec*GST_MSECOND;
105+ GST_DEBUG_OBJECT (parse, "Get start time:%02d:%02d:%02d:%03d\n",
106+ hour, min, sec, msec);
107+ if (start_time > tmp)
108+ start_time = tmp;
109+ } else {
110+ GST_WARNING_OBJECT (parse,
111+ "failed to parse ssa start timestamp string :%s", t_str);
112+ }
113+
114+ p_start = p_end;
115+ p_end = strchr (++p_start, ',');
116+ if (p_end) {
117+ /* copy text between second ',' and third ',' */
118+ strncpy(t_str, p_start, p_end - p_start);
119+ if (sscanf (t_str, "%u:%u:%u.%u", &hour, &min, &sec, &msec) == 4) {
120+ tmp = ((hour*3600) + (min*60) + sec)*GST_SECOND + msec*GST_MSECOND;
121+ GST_DEBUG_OBJECT(parse, "Get end time:%02d:%02d:%02d:%03d\n",
122+ hour, min, sec, msec);
123+ if (end_time < tmp)
124+ end_time = tmp;
125+ } else {
126+ GST_WARNING_OBJECT (parse,
127+ "failed to parse ssa end timestamp string :%s", t_str);
128+ }
129+ }
130+ }
131+
132+ /* now skip all non-text fields before the actual text */
133+ for (i = 0; i <= 8; ++i) {
134+ t = strchr (t, ',');
135+ if (t == NULL)
136+ break;
137+ ++t;
138+ }
139+ }
140+
141+ /* line end before expected number of ',', not a Dialogue line */
142 if (t == NULL)
143- return GST_FLOW_ERROR;
144- ++t;
145+ break;
146+
147+ /* if not the first line, and the last character of previous line is '\0',
148+ * then replace it with '\N' */
149+ if (p != text && *p == '\0') {
150+ *p++ = '\\';
151+ *p++ = 'N';
152+ }
153+
154+ /* copy all actual text of this line */
155+ while ((*t != '\0') && (*t != '\n'))
156+ *p++ = *t++;
157+
158+ /* add a terminator at the end */
159+ *p = '\0';
160+ }
161+
162+ /* not valid text found in this buffer return OK to let caller unref buffer */
163+ if (strlen(text) <= 0) {
164+ GST_WARNING_OBJECT (parse, "Not valid text found in this buffer\n");
165+ return GST_FLOW_ERROR;
166 }
167
168+ t = text;
169 GST_LOG_OBJECT (parse, "Text : %s", t);
170
171 if (gst_ssa_parse_remove_override_codes (parse, t)) {
172@@ -307,13 +414,22 @@ gst_ssa_parse_push_line (GstSsaParse * parse, gchar * txt,
173 gst_buffer_fill (buf, 0, escaped, len + 1);
174 gst_buffer_set_size (buf, len);
175 g_free (escaped);
176+ g_free(t);
177+
178+ if (start_time != G_MAXUINT64)
179+ GST_BUFFER_TIMESTAMP (buf) = start_time;
180+ else
181+ GST_BUFFER_TIMESTAMP (buf) = start;
182
183- GST_BUFFER_TIMESTAMP (buf) = start;
184- GST_BUFFER_DURATION (buf) = duration;
185+ if (end_time > start_time)
186+ GST_BUFFER_DURATION (buf) = end_time - start_time;
187+ else
188+ GST_BUFFER_DURATION (buf) = duration;
189
190 GST_LOG_OBJECT (parse, "Pushing buffer with timestamp %" GST_TIME_FORMAT
191- " and duration %" GST_TIME_FORMAT, GST_TIME_ARGS (start),
192- GST_TIME_ARGS (duration));
193+ " and duration %" GST_TIME_FORMAT,
194+ GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
195+ GST_TIME_ARGS (GST_BUFFER_DURATION (buf)));
196
197 ret = gst_pad_push (parse->srcpad, buf);
198
199@@ -333,6 +449,7 @@ gst_ssa_parse_chain (GstPad * sinkpad, GstObject * parent, GstBuffer * buf)
200 GstClockTime ts;
201 gchar *txt;
202 GstMapInfo map;
203+ gint size;
204
205 if (G_UNLIKELY (!parse->framed))
206 goto not_framed;
207@@ -350,13 +467,14 @@ gst_ssa_parse_chain (GstPad * sinkpad, GstObject * parent, GstBuffer * buf)
208 /* make double-sure it's 0-terminated and all */
209 gst_buffer_map (buf, &map, GST_MAP_READ);
210 txt = g_strndup ((gchar *) map.data, map.size);
211+ size = map.size;
212 gst_buffer_unmap (buf, &map);
213
214 if (txt == NULL)
215 goto empty_text;
216
217 ts = GST_BUFFER_TIMESTAMP (buf);
218- ret = gst_ssa_parse_push_line (parse, txt, ts, GST_BUFFER_DURATION (buf));
219+ ret = gst_ssa_parse_push_line (parse, txt, size, ts, GST_BUFFER_DURATION (buf));
220
221 if (ret != GST_FLOW_OK && GST_CLOCK_TIME_IS_VALID (ts)) {
222 GstSegment segment;
223--
2241.7.9.5
225