Skip to content

Commit 91bd440

Browse files
jordicenzanometa-codesync[bot]
authored andcommitted
Move MOQMI to FLV translation to its own class / dir to make the code more scalable
Summary: Move MOQMI to FLV translation to its own class / dir to make the code more scalable. Functionality should remain the same Reviewed By: sharmafb Differential Revision: D92020167 fbshipit-source-id: bd4ce9784c3c8d522f9cdf10307fb8ea9758e508
1 parent 7e6a187 commit 91bd440

6 files changed

Lines changed: 185 additions & 91 deletions

File tree

moxygen/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,7 @@ add_subdirectory(samples/date)
160160
add_subdirectory(samples/flv_streamer_client)
161161
add_subdirectory(samples/flv_receiver_client)
162162
add_subdirectory(moq_mi)
163+
add_subdirectory(moq_mi_to_flv)
163164
add_subdirectory(moqtest)
164165
add_subdirectory(flv_parser)
165166
add_subdirectory(test)
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# Copyright (c) Meta Platforms, Inc. and affiliates.
2+
# All rights reserved.
3+
#
4+
# This source code is licensed under the BSD-style license found in the
5+
# LICENSE file in the root directory of this source tree.
6+
7+
# MoQMiToFlv
8+
add_library(moqmitoflv
9+
MoQMiToFlv.cpp
10+
)
11+
12+
target_include_directories(
13+
moqmitoflv PUBLIC
14+
$<BUILD_INTERFACE:${MOXYGEN_FBCODE_ROOT}>
15+
)
16+
target_compile_options(
17+
moqmitoflv PRIVATE
18+
${_MOXYGEN_COMMON_COMPILE_OPTIONS}
19+
)
20+
target_link_libraries(
21+
moqmitoflv PUBLIC
22+
Folly::folly
23+
mvfst::mvfst_codec_types
24+
mvfst::mvfst_folly_utils
25+
flvparser
26+
)
27+
28+
install(
29+
TARGETS moqmitoflv
30+
EXPORT moxygen-exports
31+
ARCHIVE DESTINATION ${LIB_INSTALL_DIR}
32+
LIBRARY DESTINATION ${LIB_INSTALL_DIR}
33+
)
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
/*
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
* This source code is licensed under the MIT license found in the
4+
* LICENSE file in the root directory of this source tree.
5+
*/
6+
7+
#include "moxygen/moq_mi_to_flv/MoQMiToFlv.h"
8+
#include <folly/logging/xlog.h>
9+
10+
namespace moxygen {
11+
12+
std::list<flv::FlvTag> MoQMiToFlv::MoQMiToFlvPayload(
13+
MoQMi::MoqMiItem moqMiItem) {
14+
std::list<flv::FlvTag> ret;
15+
if (moqMiItem.index() ==
16+
MoQMi::MoqMIItemTypeIndex::MOQMI_ITEM_INDEX_READCMD) {
17+
return ret;
18+
}
19+
20+
if (moqMiItem.index() ==
21+
MoQMi::MoqMIItemTypeIndex::MOQMI_ITEM_INDEX_VIDEO_H264_AVC) {
22+
auto moqv = std::move(
23+
std::get<MoQMi::MoqMIItemTypeIndex::MOQMI_ITEM_INDEX_VIDEO_H264_AVC>(
24+
moqMiItem));
25+
26+
// Since PTS >= DTS lets check 1st PTS for rollover
27+
uint32_t pts =
28+
static_cast<int32_t>(moqv->pts & 0x7FFFFFFF); // 31 lower bits
29+
uint32_t dts =
30+
static_cast<int32_t>(moqv->dts & 0x7FFFFFFF); // 31 lower bits
31+
// This already handles the case where PTS rolled over and DTS NOT yet
32+
int32_t compositionTime = pts - dts;
33+
if (moqv->pts > std::numeric_limits<int32_t>::max()) {
34+
XLOG_EVERY_N(WARNING, 1000)
35+
<< "PTS video truncated! Rolling over. From " << moqv->pts
36+
<< ", to: " << pts << ", compositionTime: " << compositionTime;
37+
}
38+
CHECK_GE(compositionTime, 0);
39+
40+
if (moqv->metadata != nullptr && !videoHeaderSeen_) {
41+
XLOG(INFO) << "Writing video header";
42+
auto vhtag = flv::createVideoTag(
43+
pts, 1, 7, 0, compositionTime, std::move(moqv->metadata));
44+
if (vhtag) {
45+
ret.emplace_back(std::move(vhtag));
46+
}
47+
videoHeaderSeen_ = true;
48+
}
49+
bool isIdr = moqv->isIdr();
50+
if (videoHeaderSeen_ && moqv->data != nullptr &&
51+
moqv->data->computeChainDataLength() > 0) {
52+
if ((!firstIDRSeen_ && isIdr) || firstIDRSeen_) {
53+
// Write frame
54+
uint8_t frameType = isIdr ? 1 : 0;
55+
XLOG(DBG1) << "Writing video frame, type: " << frameType;
56+
auto vtag = flv::createVideoTag(
57+
static_cast<uint32_t>(moqv->pts),
58+
frameType,
59+
7,
60+
1,
61+
compositionTime,
62+
std::move(moqv->data));
63+
if (vtag) {
64+
ret.emplace_back(std::move(vtag));
65+
66+
if (isIdr && !firstIDRSeen_) {
67+
firstIDRSeen_ = true;
68+
XLOG(INFO) << "Wrote first IDR frame";
69+
}
70+
}
71+
}
72+
}
73+
} else if (
74+
moqMiItem.index() ==
75+
MoQMi::MoqMIItemTypeIndex::MOQMI_ITEM_INDEX_AUDIO_AAC_LC) {
76+
auto moqa = std::move(
77+
std::get<MoQMi::MoqMIItemTypeIndex::MOQMI_ITEM_INDEX_AUDIO_AAC_LC>(
78+
moqMiItem));
79+
if (!audioHeaderSeen_) {
80+
XLOG(INFO) << "Writing audio header";
81+
auto ascHeader = moqa->getAscHeader();
82+
uint32_t pts =
83+
static_cast<int32_t>(moqa->pts & 0x7FFFFFFF); // 31 lower bits
84+
if (moqa->pts > std::numeric_limits<int32_t>::max()) {
85+
XLOG_EVERY_N(WARNING, 1000)
86+
<< "PTS audio truncated! Rolling over. From " << moqa->pts
87+
<< ", to: " << pts;
88+
}
89+
auto ahtag =
90+
flv::createAudioTag(pts, 10, 3, 1, 1, 0, std::move(ascHeader));
91+
if (ahtag) {
92+
ret.emplace_back(std::move(ahtag));
93+
}
94+
audioHeaderSeen_ = true;
95+
}
96+
if (audioHeaderSeen_) {
97+
XLOG(DBG1) << "Writing audio frame";
98+
auto atag = flv::createAudioTag(
99+
static_cast<uint32_t>(moqa->pts),
100+
10,
101+
3,
102+
1,
103+
1,
104+
1,
105+
std::move(moqa->data));
106+
if (atag) {
107+
ret.emplace_back(std::move(atag));
108+
}
109+
}
110+
}
111+
return ret;
112+
};
113+
114+
} // namespace moxygen

moxygen/moq_mi_to_flv/MoQMiToFlv.h

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/*
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
* This source code is licensed under the MIT license found in the
4+
* LICENSE file in the root directory of this source tree.
5+
*/
6+
7+
#pragma once
8+
9+
#include "moxygen/flv_parser/FlvCommon.h"
10+
#include "moxygen/moq_mi/MoQMi.h"
11+
12+
namespace moxygen {
13+
14+
class MoQMiToFlv {
15+
public:
16+
MoQMiToFlv() = default;
17+
~MoQMiToFlv() = default;
18+
19+
std::list<flv::FlvTag> MoQMiToFlvPayload(MoQMi::MoqMiItem moqMiItem);
20+
21+
private:
22+
bool videoHeaderSeen_{false};
23+
bool audioHeaderSeen_{false};
24+
bool firstIDRSeen_{false};
25+
};
26+
27+
} // namespace moxygen

moxygen/samples/flv_receiver_client/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ target_link_libraries(
2727
flvparser
2828
moqmi
2929
moxygenwtclient
30+
moqmitoflv
3031
)
3132

3233
install(

moxygen/samples/flv_receiver_client/MoQFlvReceiverClient.cpp

Lines changed: 9 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include "moxygen/dejitter/DeJitter.h"
1717
#include "moxygen/flv_parser/FlvWriter.h"
1818
#include "moxygen/moq_mi/MoQMi.h"
19+
#include "moxygen/moq_mi_to_flv/MoQMiToFlv.h"
1920

2021
DEFINE_string(
2122
connect_url,
@@ -73,101 +74,21 @@ class TrackType {
7374
TrackType::MediaType mediaType_;
7475
};
7576

76-
class FlvWriterShared : flv::FlvWriter {
77+
class FlvWriterShared : public flv::FlvWriter, public MoQMiToFlv {
7778
public:
7879
explicit FlvWriterShared(const std::string& flvOutPath)
7980
: flv::FlvWriter(flvOutPath) {}
8081

8182
bool writeMoqMiPayload(MoQMi::MoqMiItem moqMiItem) {
82-
bool ret = false;
83-
if (moqMiItem.index() ==
84-
MoQMi::MoqMIItemTypeIndex::MOQMI_ITEM_INDEX_READCMD) {
85-
return ret;
86-
}
87-
88-
if (moqMiItem.index() ==
89-
MoQMi::MoqMIItemTypeIndex::MOQMI_ITEM_INDEX_VIDEO_H264_AVC) {
90-
auto moqv = std::move(
91-
std::get<MoQMi::MoqMIItemTypeIndex::MOQMI_ITEM_INDEX_VIDEO_H264_AVC>(
92-
moqMiItem));
93-
94-
// Since PTS >= DTS lets check 1st PTS for rollover
95-
uint32_t pts =
96-
static_cast<int32_t>(moqv->pts & 0x7FFFFFFF); // 31 lower bits
97-
uint32_t dts =
98-
static_cast<int32_t>(moqv->dts & 0x7FFFFFFF); // 31 lower bits
99-
// This already handles the case where PTS rolled over and DTS NOT yet
100-
int32_t compositionTime = pts - dts;
101-
if (moqv->pts > std::numeric_limits<int32_t>::max()) {
102-
XLOG_EVERY_N(WARNING, 1000)
103-
<< "PTS video truncated! Rolling over. From " << moqv->pts
104-
<< ", to: " << pts << ", compositionTime: " << compositionTime;
105-
}
106-
CHECK_GE(compositionTime, 0);
107-
108-
if (moqv->metadata != nullptr && !videoHeaderWritten_) {
109-
XLOG(INFO) << "Writing video header";
110-
auto vhtag = flv::createVideoTag(
111-
pts, 1, 7, 0, compositionTime, std::move(moqv->metadata));
112-
ret = writeTag(std::move(vhtag));
113-
if (!ret) {
114-
return ret;
115-
}
116-
videoHeaderWritten_ = true;
117-
}
118-
bool isIdr = moqv->isIdr();
119-
if (videoHeaderWritten_ && moqv->data != nullptr &&
120-
moqv->data->computeChainDataLength() > 0) {
121-
if ((!firstIDRWritten_ && isIdr) || firstIDRWritten_) {
122-
// Write frame
123-
uint8_t frameType = isIdr ? 1 : 0;
124-
XLOG(DBG1) << "Writing video frame, type: " << frameType;
125-
auto vtag = flv::createVideoTag(
126-
moqv->pts,
127-
frameType,
128-
7,
129-
1,
130-
compositionTime,
131-
std::move(moqv->data));
132-
ret = writeTag(std::move(vtag));
133-
if (isIdr && !firstIDRWritten_) {
134-
firstIDRWritten_ = true;
135-
XLOG(INFO) << "Wrote first IDR frame";
136-
}
137-
}
138-
}
139-
} else if (
140-
moqMiItem.index() ==
141-
MoQMi::MoqMIItemTypeIndex::MOQMI_ITEM_INDEX_AUDIO_AAC_LC) {
142-
auto moqa = std::move(
143-
std::get<MoQMi::MoqMIItemTypeIndex::MOQMI_ITEM_INDEX_AUDIO_AAC_LC>(
144-
moqMiItem));
145-
if (!audioHeaderWritten_) {
146-
XLOG(INFO) << "Writing audio header";
147-
auto ascHeader = moqa->getAscHeader();
148-
uint32_t pts =
149-
static_cast<int32_t>(moqa->pts & 0x7FFFFFFF); // 31 lower bits
150-
if (moqa->pts > std::numeric_limits<int32_t>::max()) {
151-
XLOG_EVERY_N(WARNING, 1000)
152-
<< "PTS audio truncated! Rolling over. From " << moqa->pts
153-
<< ", to: " << pts;
154-
}
155-
auto ahtag =
156-
flv::createAudioTag(pts, 10, 3, 1, 1, 0, std::move(ascHeader));
157-
ret = writeTag(std::move(ahtag));
158-
if (!ret) {
159-
return ret;
160-
}
161-
audioHeaderWritten_ = true;
162-
}
163-
if (audioHeaderWritten_) {
164-
XLOG(DBG1) << "Writing audio frame";
165-
auto atag = flv::createAudioTag(
166-
moqa->pts, 10, 3, 1, 1, 1, std::move(moqa->data));
167-
ret = writeTag(std::move(atag));
83+
auto tags = MoQMiToFlv::MoQMiToFlvPayload(std::move(moqMiItem));
84+
while (!tags.empty()) {
85+
flv::FlvTag tag = std::move(tags.front());
86+
tags.pop_front(); // Remove the now-empty unique_ptr from the list
87+
if (!writeTag(std::move(tag))) {
88+
return false;
16889
}
16990
}
170-
return ret;
91+
return true;
17192
}
17293

17394
private:
@@ -177,9 +98,6 @@ class FlvWriterShared : flv::FlvWriter {
17798
}
17899

179100
std::mutex mutex_;
180-
bool videoHeaderWritten_{false};
181-
bool audioHeaderWritten_{false};
182-
bool firstIDRWritten_{false};
183101
};
184102

185103
class TrackReceiverHandler : public ObjectReceiverCallback {

0 commit comments

Comments
 (0)