Skip to content

Commit

Permalink
Merge pull request #1339 from CastagnaIT/webvtt_segments
Browse files Browse the repository at this point in the history
[DashTree] Cleanup subtitles stream/container detection
  • Loading branch information
glennguy authored Jul 29, 2023
2 parents b3bfc65 + 66e75e7 commit 37705b2
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 20 deletions.
47 changes: 27 additions & 20 deletions src/parser/DASHTree.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -67,16 +67,18 @@ PLAYLIST::ContainerType DetectContainerType(std::string_view mimeType)
return ContainerType::WEBM;
if (STRING::Contains(mimeType, "/x-matroska"))
return ContainerType::MATROSKA;
if (STRING::Contains(mimeType, "/ttml+xml") || STRING::Contains(mimeType, "vtt"))
return ContainerType::TEXT;

return ContainerType::MP4;
}

std::string DetectCodecFromMimeType(std::string_view mimeType)
{
if (mimeType == "text/vtt")
return "wvtt";
return CODEC::FOURCC_WVTT;
if (mimeType == "application/ttml+xml")
return "ttml";
return CODEC::FOURCC_TTML;

return "";
}
Expand Down Expand Up @@ -683,28 +685,24 @@ void adaptive::CDashTree::ParseTagRepresentation(pugi::xml_node nodeRepr,
{
StreamType streamType = DetectStreamType("", repr->GetMimeType());
const auto& codecs = repr->GetCodecs();
if (streamType == StreamType::NOTYPE && (CODEC::Contains(codecs, CODEC::FOURCC_WVTT) ||
CODEC::Contains(codecs, CODEC::FOURCC_TTML) ||
CODEC::Contains(codecs, CODEC::FOURCC_STPP)))
if (streamType == StreamType::NOTYPE)
{
streamType = StreamType::SUBTITLE;
// Try find stream type by checking the codec string
for (const std::string& codec : codecs)
{
if (CODEC::IsSubtitleFourCC(codec))
{
streamType = StreamType::SUBTITLE;
break;
}
}
}

adpSet->SetStreamType(streamType);
}

// Set properties for subtitles types
if (repr->GetMimeType() != "application/mp4") // Handle text type only, not ISOBMFF format
{
const auto& codecs = repr->GetCodecs();
if (repr->GetMimeType() == "application/ttml+xml" || repr->GetMimeType() == "text/vtt" ||
CODEC::Contains(codecs, CODEC::FOURCC_WVTT) ||
CODEC::Contains(codecs, CODEC::FOURCC_TTML) || CODEC::Contains(codecs, CODEC::FOURCC_STPP))
{
if (adpSet->SegmentTimelineDuration().IsEmpty())
repr->SetIsSubtitleFileStream(true); // Treat as single subtitle file
else
repr->SetContainerType(ContainerType::TEXT); // Segmented subtitles
}
if (streamType == StreamType::SUBTITLE &&
repr->GetMimeType() != "application/mp4") // Text format type only, not ISOBMFF
repr->SetContainerType(ContainerType::TEXT);
}

// ISA custom attribute
Expand Down Expand Up @@ -972,6 +970,15 @@ void adaptive::CDashTree::ParseTagRepresentation(pugi::xml_node nodeRepr,
else if (adpSet->GetStreamType() == StreamType::AUDIO && repr->GetAudioChannels() == 0)
repr->SetAudioChannels(2); // Fallback to 2 channels when no value is set

// For subtitles that are not as ISOBMFF format and where there is no timeline for segments
// we should treat them as a single subtitle file
if (repr->GetContainerType() == ContainerType::TEXT && repr->GetMimeType() != "application/mp4" &&
!adpSet->HasSegmentTimelineDuration() && !repr->HasSegmentTimeline())
{

repr->SetIsSubtitleFileStream(true);
}

// Generate timeline segments
if (!repr->HasSegmentTimeline() && repr->HasSegmentTemplate())
{
Expand Down
12 changes: 12 additions & 0 deletions src/test/TestDASHTree.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -409,46 +409,57 @@ TEST_F(DASHTreeAdaptiveStreamTest, subtitles)
EXPECT_EQ(adpSets[1]->GetStreamType(), PLAYLIST::StreamType::SUBTITLE);
EXPECT_EQ(adpSets[1]->GetRepresentations()[0]->IsSubtitleFileStream(), true);
EXPECT_EQ(CODEC::Contains(adpSets[1]->GetRepresentations()[0]->GetCodecs(), CODEC::FOURCC_TTML), true);
EXPECT_EQ(adpSets[1]->GetRepresentations()[0]->GetContainerType(), PLAYLIST::ContainerType::TEXT);

EXPECT_EQ(adpSets[2]->GetStreamType(), PLAYLIST::StreamType::SUBTITLE);
EXPECT_EQ(adpSets[2]->GetRepresentations()[0]->IsSubtitleFileStream(), true);
EXPECT_EQ(CODEC::Contains(adpSets[2]->GetRepresentations()[0]->GetCodecs(), CODEC::FOURCC_TTML), true);
EXPECT_EQ(adpSets[2]->GetRepresentations()[0]->GetContainerType(), PLAYLIST::ContainerType::TEXT);

EXPECT_EQ(adpSets[3]->GetStreamType(), PLAYLIST::StreamType::SUBTITLE);
EXPECT_EQ(adpSets[3]->GetRepresentations()[0]->IsSubtitleFileStream(), true);
EXPECT_EQ(CODEC::Contains(adpSets[3]->GetRepresentations()[0]->GetCodecs(), CODEC::FOURCC_TTML), true);
EXPECT_EQ(adpSets[3]->GetRepresentations()[0]->GetContainerType(), PLAYLIST::ContainerType::TEXT);

EXPECT_EQ(adpSets[4]->GetStreamType(), PLAYLIST::StreamType::SUBTITLE);
EXPECT_EQ(adpSets[4]->GetRepresentations()[0]->IsSubtitleFileStream(), true);
EXPECT_EQ(CODEC::Contains(adpSets[4]->GetRepresentations()[0]->GetCodecs(), CODEC::FOURCC_TTML), true);
EXPECT_EQ(adpSets[4]->GetRepresentations()[0]->GetContainerType(), PLAYLIST::ContainerType::TEXT);

EXPECT_EQ(adpSets[5]->GetStreamType(), PLAYLIST::StreamType::SUBTITLE);
EXPECT_EQ(adpSets[5]->GetRepresentations()[0]->IsSubtitleFileStream(), true);
EXPECT_EQ(CODEC::Contains(adpSets[5]->GetRepresentations()[0]->GetCodecs(), CODEC::FOURCC_WVTT), true);
EXPECT_EQ(adpSets[5]->GetRepresentations()[0]->GetContainerType(), PLAYLIST::ContainerType::TEXT);

EXPECT_EQ(adpSets[6]->GetStreamType(), PLAYLIST::StreamType::SUBTITLE);
EXPECT_EQ(adpSets[6]->GetRepresentations()[0]->IsSubtitleFileStream(), true);
EXPECT_EQ(CODEC::Contains(adpSets[6]->GetRepresentations()[0]->GetCodecs(), CODEC::FOURCC_WVTT), true);
EXPECT_EQ(adpSets[6]->GetRepresentations()[0]->GetContainerType(), PLAYLIST::ContainerType::TEXT);

EXPECT_EQ(adpSets[7]->GetStreamType(), PLAYLIST::StreamType::SUBTITLE);
EXPECT_EQ(adpSets[7]->GetRepresentations()[0]->IsSubtitleFileStream(), true);
EXPECT_EQ(CODEC::Contains(adpSets[7]->GetRepresentations()[0]->GetCodecs(), CODEC::FOURCC_WVTT), true);
EXPECT_EQ(adpSets[7]->GetRepresentations()[0]->GetContainerType(), PLAYLIST::ContainerType::TEXT);

EXPECT_EQ(adpSets[8]->GetStreamType(), PLAYLIST::StreamType::SUBTITLE);
EXPECT_EQ(adpSets[8]->GetRepresentations()[0]->IsSubtitleFileStream(), true);
EXPECT_EQ(CODEC::Contains(adpSets[8]->GetRepresentations()[0]->GetCodecs(), CODEC::FOURCC_WVTT), true);
EXPECT_EQ(adpSets[8]->GetRepresentations()[0]->GetContainerType(), PLAYLIST::ContainerType::TEXT);

EXPECT_EQ(adpSets[9]->GetStreamType(), PLAYLIST::StreamType::SUBTITLE);
EXPECT_EQ(adpSets[9]->GetRepresentations()[0]->IsSubtitleFileStream(), true);
EXPECT_EQ(CODEC::Contains(adpSets[9]->GetRepresentations()[0]->GetCodecs(), "my_codec"), true);
EXPECT_EQ(adpSets[9]->GetRepresentations()[0]->GetContainerType(), PLAYLIST::ContainerType::TEXT);

EXPECT_EQ(adpSets[10]->GetStreamType(), PLAYLIST::StreamType::SUBTITLE);
EXPECT_EQ(adpSets[10]->GetRepresentations()[0]->IsSubtitleFileStream(), true);
EXPECT_EQ(CODEC::Contains(adpSets[10]->GetRepresentations()[0]->GetCodecs(), CODEC::FOURCC_TTML), true);
EXPECT_EQ(adpSets[10]->GetRepresentations()[0]->GetContainerType(), PLAYLIST::ContainerType::TEXT);

EXPECT_EQ(adpSets[11]->GetStreamType(), PLAYLIST::StreamType::SUBTITLE);
EXPECT_EQ(STR(adpSets[11]->GetRepresentations()[0]->GetMimeType()), "application/mp4");
EXPECT_EQ(CODEC::Contains(adpSets[11]->GetRepresentations()[0]->GetCodecs(), CODEC::FOURCC_STPP), true);
EXPECT_EQ(adpSets[11]->GetRepresentations()[0]->GetContainerType(), PLAYLIST::ContainerType::MP4);

SetTestStream(NewStream(adpSets[11].get()));
testStream->start_stream();
Expand All @@ -459,6 +470,7 @@ TEST_F(DASHTreeAdaptiveStreamTest, subtitles)
EXPECT_EQ(adpSets[12]->GetStreamType(), PLAYLIST::StreamType::SUBTITLE);
EXPECT_EQ(STR(adpSets[12]->GetMimeType()), "application/mp4");
EXPECT_EQ(CODEC::Contains(adpSets[12]->GetRepresentations()[0]->GetCodecs(), "stpp.ttml.im1t"), true);
EXPECT_EQ(adpSets[12]->GetRepresentations()[0]->GetContainerType(), PLAYLIST::ContainerType::MP4);

SetTestStream(NewStream(adpSets[12].get()));
testStream->start_stream();
Expand Down
10 changes: 10 additions & 0 deletions src/utils/Utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -400,3 +400,13 @@ bool UTILS::CODEC::IsAudio(std::string_view codec)
}
return false;
}

bool UTILS::CODEC::IsSubtitleFourCC(std::string_view codec)
{
for (const auto fourcc : CODEC::SUBTITLES_FOURCC_LIST)
{
if (STRING::Contains(codec, fourcc))
return true;
}
return false;
}
9 changes: 9 additions & 0 deletions src/utils/Utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,8 @@ constexpr char* FOURCC_TTML = "ttml";
// for example "stpp.ttml.im1t", or only "stpp"
constexpr char* FOURCC_STPP = "stpp";

constexpr std::array SUBTITLES_FOURCC_LIST = {FOURCC_WVTT, FOURCC_TTML, FOURCC_STPP};

/*!
* \brief Make a FourCC code as unsigned integer value
* \param fourcc The FourCC code (4 chars)
Expand Down Expand Up @@ -166,6 +168,13 @@ std::string GetVideoDesc(const std::set<std::string>& list);
*/
bool IsAudio(std::string_view codec);

/*!
* \brief Determines if the codec string contains a fourcc of type subtitles.
* \param codec The codec string
* \return True if contains a fourcc of type subtitles, otherwise false
*/
bool IsSubtitleFourCC(std::string_view codec);

}

} // namespace UTILS

0 comments on commit 37705b2

Please sign in to comment.