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