34 #define CHAR_CARRIAGE_RETURN '\r'
35 #define CHAR_LINE_FEED '\n'
36 #define CHAR_SPACE ' '
38 #define VTT_QUEUE_TIMER_INTERVAL 250 //milliseconds
57 static char * parsePercentageValueSetting(
char *settingValue)
60 char *percentageSym = strchr(settingValue,
'%');
61 if ((std::isdigit(
static_cast<unsigned char>(settingValue[0]) ) != 0) && (percentageSym != NULL))
63 *percentageSym =
'\0';
77 static char * findWebVTTLineBreak(
char *buffer)
80 char *lineBreak = strpbrk(buffer,
"\r\n");
86 if (*lineBreak == CHAR_CARRIAGE_RETURN && *next == CHAR_LINE_FEED)
103 static long long convertHHMMSSToTime(
char *str)
105 long long timeValueMs = 0;
107 char *args[4] = { str, NULL, NULL, NULL };
109 while(*(++str) !=
'\0' && argCount < 4)
111 if(*str ==
':' || *str ==
'.')
113 args[argCount++] = (str + 1);
120 AAMPLOG_ERR(
"Unsupported value received!");
125 timeValueMs = atoll(args[--argCount]);
129 timeValueMs += (atoll(args[--argCount]) * multiplier * 1000);
147 static gboolean SendVttCueToExt(gpointer user_data)
150 parser->sendCueData();
151 return G_SOURCE_CONTINUE;
164 mStartPTS(0), mCurrentPos(0), mStartPos(0), mPtsOffset(0),
165 mReset(true), mVttQueue(), mVttQueueIdleTaskId(0), mVttQueueMutex(), lastCue(),
168 pthread_mutex_init(&mVttQueueMutex, NULL);
179 WebVTTParser::~WebVTTParser()
194 bool WebVTTParser::init(
double startPosSeconds,
unsigned long long basePTS)
204 AAMPLOG_WARN(
"WebVTTParser::startPos:%.3f and mStartPTS:%lld", startPosSeconds,
mStartPTS);
221 bool WebVTTParser::processData(
char* buffer,
size_t bufferLen,
double position,
double duration)
225 AAMPLOG_TRACE(
"WebVTTParser::Enter with position:%.3f and duration:%.3f ", position, duration);
231 AAMPLOG_WARN(
"WebVTTParser::Received first buffer after reset with mStartPos:%.3f",
mStartPos);
237 char *next = findWebVTTLineBreak(buffer);
238 if (next && strlen(buffer) >= 6)
240 char *token = strtok(buffer,
" \t\n\r");
244 if ((
unsigned char) token[0] == 0xEF && (
unsigned char) token[1] == 0xBB && (
unsigned char) token[2] == 0xBF)
249 if (strlen(token) == 6 && strncmp(token,
"WEBVTT", 6) == 0)
257 AAMPLOG_WARN(
"token is null");
266 char *nextLine = findWebVTTLineBreak(buffer);
269 if (strstr(buffer,
"X-TIMESTAMP-MAP") != NULL)
271 unsigned long long mpegTime = 0;
272 unsigned long long localTime = 0;
274 char* token = strtok(buffer,
"=,");
279 localTime = convertHHMMSSToTime(token + 6);
281 else if (token[0] ==
'M')
283 mpegTime = atoll(token + 7);
285 token = strtok(NULL,
"=,");
288 AAMPLOG_INFO(
"Parsed local time:%lld and PTS:%lld and cuePTSOffset:%lld", localTime, mpegTime,
mPtsOffset);
290 else if (strstr(buffer,
" --> ") != NULL)
292 AAMPLOG_INFO(
"Found cue:%s", buffer);
293 long long start = -1;
297 char *cueLine = NULL;
298 char *cueLineAlign = NULL;
299 char *cuePosition = NULL;
300 char *cuePosAlign = NULL;
301 char *cueSize = NULL;
302 char *cueTextAlign = NULL;
304 char *token = strtok(buffer,
" -->\t");
305 while (token != NULL)
308 if (std::isdigit(
static_cast<unsigned char>(token[0]) ) != 0)
312 start = convertHHMMSSToTime(token);
316 end = convertHHMMSSToTime(token);
324 char *value = strchr(token,
':');
329 if (strncmp(key,
"line", 4) == 0)
331 char *lineAlign = strchr(value,
',');
332 if (lineAlign != NULL)
338 cueLineAlign = lineAlign;
341 cueLine = parsePercentageValueSetting(value);
343 else if (strncmp(key,
"position", 8) == 0)
345 char *posAlign = strchr(value,
',');
346 if (posAlign != NULL)
352 cuePosAlign = posAlign;
355 cuePosition = parsePercentageValueSetting(value);
357 else if (strncmp(key,
"size", 4) == 0)
359 cueSize = parsePercentageValueSetting(value);
361 else if (strncmp(key,
"align", 5) == 0)
365 cueTextAlign = value;
370 token = strtok(NULL,
" -->\t");
374 nextLine = findWebVTTLineBreak(nextLine);
375 while(nextLine && (*nextLine != CHAR_LINE_FEED && *nextLine != CHAR_CARRIAGE_RETURN && *nextLine !=
'\0'))
378 if (nextLine[-1] ==
'\0')
382 if (nextLine[-2] ==
'\0')
386 nextLine = findWebVTTLineBreak(nextLine);
388 double cueStartInMpegTime = (start +
mPtsOffset);
389 double duration = (end - start);
390 double mpegTimeOffset = cueStartInMpegTime - (
mStartPTS / 90);
391 double relativeStartPos =
mStartPos + mpegTimeOffset;
392 AAMPLOG_INFO(
"So found cue with startPTS:%.3f and duration:%.3f, and mpegTimeOffset:%.3f and relative time being:%.3f", cueStartInMpegTime/1000.0, duration/1000.0, mpegTimeOffset/1000.0, relativeStartPos/1000.0);
393 addCueData(
new VTTCue(relativeStartPos, duration, std::string(text), std::string()));
411 bool WebVTTParser::close()
447 void WebVTTParser::reset()
451 AAMPLOG_WARN(
"WebVTTParser::Reset subtitle parser at position:%.3f",
mCurrentPos);
471 void WebVTTParser::addCueData(
VTTCue *cue)
473 if (
lastCue.mStart != cue->mStart ||
lastCue.mDuration != cue->mDuration)
480 lastCue.mDuration = cue->mDuration;
490 void WebVTTParser::sendCueData()
505 AAMPLOG_WARN(
"Discarding cue with start:%.3f and text:%s", cue->mStart/1000.0, cue->mText.c_str());