Skip to content

Commit 5297953

Browse files
committed
cras_bag_tools: bag_filter: Added AddSubtitles generator.
1 parent 5694566 commit 5297953

File tree

2 files changed

+111
-2
lines changed

2 files changed

+111
-2
lines changed
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# SPDX-License-Identifier: BSD-3-Clause
2+
# SPDX-FileCopyrightText: Czech Technical University in Prague
3+
4+
out_format: '{name}.subs{ext}'
5+
compression: lz4
6+
filters:
7+
- AddSubtitles:
8+
subtitles_file: '/media/data/bags/outdoor-dataset/marv_2024-10-05-12-34-53.small.bag.srt'
9+
topic: /events

cras_bag_tools/src/cras_bag_tools/message_filters.py

Lines changed: 102 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,13 +37,14 @@
3737
from kdl_parser_py.urdf import treeFromUrdfModel
3838
from ros_numpy import msgify, numpify
3939
from sensor_msgs.msg import CameraInfo, CompressedImage, Image, JointState
40-
from std_msgs.msg import Header
40+
from std_msgs.msg import Header, String
4141
from tf2_msgs.msg import TFMessage
4242
from tf2_py import BufferCore
4343
from urdf_parser_py import urdf, xml_reflection
4444
from vision_msgs.msg import Detection2DArray, Detection2D, ObjectHypothesisWithPose
4545

46-
from .message_filter import DeserializedMessageFilter, DeserializedMessageFilterWithTF, RawMessageFilter, TopicSet
46+
from .message_filter import DeserializedMessageFilter, DeserializedMessageFilterWithTF, Passthrough, RawMessageFilter, \
47+
TopicSet
4748

4849

4950
def urdf_error(message):
@@ -1247,6 +1248,105 @@ def _str_params(self):
12471248
return ", ".join(parts)
12481249

12491250

1251+
class AddSubtitles(Passthrough):
1252+
"""Read subtitles from a text file and add them to the output as std_msgs/String messages."""
1253+
1254+
def __init__(self, subtitles_file, topic, latch=False, time_offset=0.0):
1255+
"""
1256+
:param subtitles_file: The file to read subtitles from.
1257+
:param topic: The topic to put the subtitles on.
1258+
:param latch: Whether the topic should be latched.
1259+
:param time_offset: Relative time offset to add to the absolute subtitle time.
1260+
"""
1261+
super(AddSubtitles, self).__init__()
1262+
self._subtitles_file = subtitles_file
1263+
self._topic = topic
1264+
self._start_time = None
1265+
self._latch = latch
1266+
self._time_offset = rospy.Duration(time_offset)
1267+
1268+
self._subtitles = self._parse_subtitles(subtitles_file)
1269+
1270+
def _parse_subtitles(self, subtitles_file):
1271+
if subtitles_file.endswith(".srt"):
1272+
return self._parse_srt(subtitles_file)
1273+
raise RuntimeError("Unsupported subtitles type. Only SRT is supported so far.")
1274+
1275+
def _parse_srt(self, subtitles_file):
1276+
class State(Enum):
1277+
INIT = 0
1278+
COUNTER_READ = 1
1279+
TIME_READ = 2
1280+
1281+
state = State.INIT
1282+
start_time = None
1283+
end_time = None
1284+
lines = list()
1285+
1286+
subtitles = list()
1287+
1288+
def parse_time_str(time_str):
1289+
h, m, s = time_str.split(':')
1290+
s, ss = s.split(',')
1291+
return rospy.Duration(
1292+
int(h, base=10) * 3600 + int(m, base=10) * 60 + int(s, base=10),
1293+
int(float('0.' + ss) * 1e9))
1294+
1295+
with open(subtitles_file, 'r') as f:
1296+
for line in f:
1297+
line = line.strip()
1298+
if state == State.INIT:
1299+
_ = int(line)
1300+
state = State.COUNTER_READ
1301+
elif state == State.COUNTER_READ:
1302+
start_time_str, end_time_str = line.split(" --> ")
1303+
start_time = parse_time_str(start_time_str)
1304+
end_time = parse_time_str(end_time_str)
1305+
state = State.TIME_READ
1306+
elif state == State.TIME_READ:
1307+
if len(line) == 0:
1308+
subtitles.append((start_time, end_time, "\n".join(lines)))
1309+
lines = list()
1310+
state = State.INIT
1311+
else:
1312+
lines.append(line)
1313+
1314+
# in case the last empty line is missing
1315+
if len(lines) > 0:
1316+
subtitles.append((start_time, end_time, "\n".join(lines)))
1317+
1318+
return subtitles
1319+
1320+
def set_bag(self, bag):
1321+
super(AddSubtitles, self).set_bag(bag)
1322+
self._start_time = rospy.Time(bag.get_start_time()) + self._time_offset
1323+
1324+
def extra_initial_messages(self):
1325+
connection_header = {
1326+
"callerid": "/bag_filter",
1327+
"topic": self._topic,
1328+
"message_definition": String._full_text,
1329+
"type": String._type,
1330+
"md5sum": String._md5sum,
1331+
}
1332+
if self._latch:
1333+
connection_header["latching"] = "1"
1334+
1335+
for start_time, end_time, subtitle in self._subtitles:
1336+
msg = String(data=subtitle)
1337+
abs_time = self._start_time + start_time
1338+
yield self._topic, msg, abs_time, connection_header
1339+
1340+
def _str_params(self):
1341+
params = ["topic=" + self._topic, "subtitles_file=" + self._subtitles_file]
1342+
if self._time_offset != rospy.Duration(0, 0):
1343+
params.append("time_offset=%f" % (self._time_offset.to_sec(),))
1344+
parent_params = super(AddSubtitles, self)._str_params()
1345+
if len(parent_params) > 0:
1346+
params.append(parent_params)
1347+
return ",".join(params)
1348+
1349+
12501350
class FixSpotCams(RawMessageFilter):
12511351
"""Fix a problem with Spot robot cameras that publish a bit weird message header."""
12521352

0 commit comments

Comments
 (0)