RDK Documentation (Open Sourced RDK Components)
TtmlSubtecParser.cpp
1 /*
2  * If not stated otherwise in this file or this component's license file the
3  * following copyright and licenses apply:
4  *
5  * Copyright 2020 RDK Management
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18 */
19 
20 #include "TtmlSubtecParser.hpp"
21 #include <regex>
22 
23 
24 TtmlSubtecParser::TtmlSubtecParser(AampLogManager *logObj, PrivateInstanceAAMP *aamp, SubtitleMimeType type) : SubtitleParser(logObj, aamp, type), m_channel(nullptr)
25 {
26  m_channel = SubtecChannel::SubtecChannelFactory(SubtecChannel::ChannelType::TTML);
27  if (!m_channel->InitComms())
28  {
29  AAMPLOG_INFO("Init failed - subtitle parsing disabled");
30  throw std::runtime_error("PacketSender init failed");
31  }
32  m_channel->SendResetAllPacket();
33 
34  int width = 1920, height = 1080;
35  mAamp->GetPlayerVideoSize(width, height);
36  m_channel->SendSelectionPacket(width, height);
37  m_channel->SendMutePacket();
38  mAamp->ResumeTrackDownloads(eMEDIATYPE_SUBTITLE);
39 }
40 
41 bool TtmlSubtecParser::init(double startPosSeconds, unsigned long long basePTS)
42 {
43  AAMPLOG_INFO("startPos %.3fs", startPosSeconds);
44  m_channel->SendTimestampPacket(static_cast<uint64_t>(startPosSeconds * 1000.0));
45  mAamp->ResumeTrackDownloads(eMEDIATYPE_SUBTITLE);
46 
47  m_parsedFirstPacket = false;
48  m_sentOffset = false;
49  m_firstBeginOffset = 0.0;
50 
51  return true;
52 }
53 
54 void TtmlSubtecParser::updateTimestamp(unsigned long long positionMs)
55 {
56  m_channel->SendTimestampPacket(positionMs);
57 }
58 
59 void TtmlSubtecParser::reset()
60 {
61  m_channel->SendResetChannelPacket();
62 }
63 
64 static std::int64_t parseFirstBegin(std::stringstream &ss)
65 {
66  std::int64_t firstBegin = std::numeric_limits<std::int64_t>::max();
67  std::string line;
68  static const std::regex beginRegex(R"(begin="([0-9]+):([0-9][0-9]?):([0-9][0-9]?)\.?([0-9]+)?")");
69 
70  while(std::getline(ss, line))
71  {
72  try {
73  bool matched = false;
74  //Regex still works with no hours and/or no ms. Mins and secs are required
75  std::smatch match;
76  matched = std::regex_search(line, match, beginRegex);
77 
78  if (matched) {
79  std::int64_t hours = 0, minutes = 0, seconds = 0, milliseconds = 0;
80 
81  if (!match.str(1).empty()) AAMPLOG_WARN("h:%s", match.str(1).c_str()); hours = std::stol(match.str(1));
82  if (!match.str(2).empty()) AAMPLOG_WARN("m:%s", match.str(2).c_str()); minutes = std::stol(match.str(2));
83  if (!match.str(3).empty()) AAMPLOG_WARN("s:%s", match.str(3).c_str()); seconds = std::stol(match.str(3));
84  if (!match.str(4).empty()) AAMPLOG_WARN("ms:%s", match.str(4).c_str()); milliseconds = std::stol(match.str(4));
85 
86  firstBegin = milliseconds + (1000 * (seconds + (60 * (minutes + (60 * hours)))));
87  break;
88  }
89  }
90  catch (const std::regex_error& e) {
91  AAMPLOG_WARN("Regex error %s from line %s", std::to_string(e.code()).c_str(), line.c_str());
92  }
93  }
94 
95  return firstBegin;
96 }
97 
98 bool TtmlSubtecParser::processData(char* buffer, size_t bufferLen, double position, double duration)
99 {
100  IsoBmffBuffer isobuf(mLogObj);
101 
102  isobuf.setBuffer(reinterpret_cast<uint8_t *>(buffer), bufferLen);
103  isobuf.parseBuffer();
104 
105  if (!isobuf.isInitSegment())
106  {
107  uint8_t *mdat;
108  size_t mdatLen;
109 
110  //isobuf.printBoxes();
111  isobuf.getMdatBoxSize(mdatLen);
112 
113  mdat = (uint8_t *)malloc(mdatLen);
114  isobuf.parseMdatBox(mdat, mdatLen);
115 
116  std::vector<uint8_t> data(mdatLen);
117  data.assign(mdat, mdat+mdatLen);
118 
119  //LLAMA-3328 - this hack is necessary because the offset into the TTML
120  //is not available in the linear manifest
121  //Take the first instance of the "begin" tag as the time offset for subtec
122  if (!m_parsedFirstPacket && m_isLinear)
123  {
124  m_firstBeginOffset = position;
125  m_parsedFirstPacket = true;
126  }
127 
128  if (!m_sentOffset && m_parsedFirstPacket && m_isLinear)
129  {
130  AAMPLOG_TRACE("Linear content - parsing first begin as offset - pos %.3f dur %.3f m_firstBeginOffset %.3f",
131  position, duration, m_firstBeginOffset);
132  std::stringstream ss(std::string(data.begin(), data.end()));
133  std::int64_t offset = parseFirstBegin(ss);
134 
135  if (offset != std::numeric_limits<std::int64_t>::max())
136  {
137  auto positionDeltaSecs = (position - m_firstBeginOffset);
138  auto timeFromStartMs = mAamp->GetPositionMs() - (mAamp->seek_pos_seconds * 1000.0);
139  std::int64_t totalOffset = offset - (positionDeltaSecs * 1000.0) + timeFromStartMs;
140 
141  std::stringstream output;
142  output << "setting totalOffset " << totalOffset << " positionDeltaSecs " << positionDeltaSecs <<
143  " timeFromStartMs " << timeFromStartMs;
144  AAMPLOG_TRACE("%s", output.str().c_str());
145  m_sentOffset = true;
146  m_channel->SendTimestampPacket(totalOffset);
147  }
148  }
149 
150  m_channel->SendDataPacket(std::move(data), 0);
151 
152  free(mdat);
153  AAMPLOG_TRACE("Sent buffer with size %zu position %.3f", bufferLen, position);
154  }
155  else
156  {
157  AAMPLOG_INFO("Init Segment");
158  }
159  return true;
160 }
161 
162 void TtmlSubtecParser::mute(bool mute)
163 {
164  if (mute)
165  m_channel->SendMutePacket();
166  else
167  m_channel->SendUnmutePacket();
168 }
169 
170 void TtmlSubtecParser::pause(bool pause)
171 {
172  if (pause)
173  m_channel->SendPausePacket();
174  else
175  m_channel->SendResumePacket();
176 }
AampLogManager
AampLogManager Class.
Definition: AampLogManager.h:150
IsoBmffBuffer
Class for ISO BMFF Buffer.
Definition: isobmffbuffer.h:39
SubtitleMimeType
SubtitleMimeType
Subtitle data types.
Definition: subtitleParser.h:37
AAMPLOG_TRACE
#define AAMPLOG_TRACE(FORMAT,...)
AAMP logging defines, this can be enabled through setLogLevel() as per the need.
Definition: AampLogManager.h:83
PrivateInstanceAAMP
Class representing the AAMP player's private instance, which is not exposed to outside world.
Definition: priv_aamp.h:640
eMEDIATYPE_SUBTITLE
@ eMEDIATYPE_SUBTITLE
Definition: AampMediaType.h:41
SubtitleParser
Subtitle parser class.
Definition: subtitleParser.h:52