Skip to content

Commit 7e6a187

Browse files
jordicenzanometa-codesync[bot]
authored andcommitted
Separate FLV writer from coder
Summary: - Separate FLV codec from FLVWriter - Now writes Tags (audio or video frames) instead of inpendent bytes: (relatively) bad for latency, good for CPU usage, especially if we write remote Now is much easier to wrtite FLV to other places than local files (ex: OIL) Reviewed By: sharmafb Differential Revision: D92018700 fbshipit-source-id: 24a065c67072b351da7718ec48e2d080137a50e8
1 parent 926e0ec commit 7e6a187

5 files changed

Lines changed: 183 additions & 118 deletions

File tree

moxygen/flv_parser/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
add_library(flvparser
99
FlvCommon.cpp
1010
FlvReader.cpp
11+
FlvCoder.cpp
1112
FlvWriter.cpp
1213
FlvStreamParser.cpp
1314
)

moxygen/flv_parser/FlvCoder.cpp

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
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/flv_parser/FlvCoder.h"
8+
#include <netinet/in.h>
9+
10+
namespace moxygen::flv {
11+
12+
std::unique_ptr<folly::IOBuf> FlvCoder::writeTag(FlvTag tag) {
13+
folly::IOBufQueue queue =
14+
folly::IOBufQueue(folly::IOBufQueue::cacheChainLength());
15+
if (tag.index() == FlvTagTypeIndex::FLV_TAG_INDEX_READCMD) {
16+
auto readsCmd = std::get<flv::FlvReadCmd>(tag);
17+
if (readsCmd == flv::FlvReadCmd::FLV_EOF) {
18+
return nullptr;
19+
}
20+
return queue.move(); // Empty
21+
}
22+
23+
if (!headerWrote_) {
24+
auto buf = folly::IOBuf::copyBuffer(&flvHeader_, sizeof(flvHeader_));
25+
queue.append(std::move(buf));
26+
uint32_t tagSize = 0x00;
27+
queue.append(write4Bytes(tagSize));
28+
headerWrote_ = true;
29+
}
30+
31+
size_t tagSize = 0;
32+
if (tag.index() == FlvTagTypeIndex::FLV_TAG_INDEX_SCRIPT) {
33+
// Script
34+
auto dataTag =
35+
std::move(std::get<FlvTagTypeIndex::FLV_TAG_INDEX_SCRIPT>(tag));
36+
auto tagHeader = writeTagHeader(*dataTag);
37+
tagSize += TAG_HEADER_SIZE;
38+
queue.append(std::move(tagHeader));
39+
40+
tagSize += dataTag->data->computeChainDataLength();
41+
queue.append(std::move(dataTag->data));
42+
} else if (tag.index() == FlvTagTypeIndex::FLV_TAG_INDEX_VIDEO) {
43+
// Video
44+
auto videoTag =
45+
std::move(std::get<FlvTagTypeIndex::FLV_TAG_INDEX_VIDEO>(tag));
46+
auto tagHeader = writeTagHeader(*videoTag);
47+
tagSize += TAG_HEADER_SIZE;
48+
queue.append(std::move(tagHeader));
49+
50+
auto videoTagHeader = writeVideoTagHeader(*videoTag);
51+
tagSize += VIDEO_TAG_HEADER_SIZE;
52+
queue.append(std::move(videoTagHeader));
53+
54+
tagSize += videoTag->data->computeChainDataLength();
55+
queue.append(std::move(videoTag->data));
56+
} else if (tag.index() == FlvTagTypeIndex::FLV_TAG_INDEX_AUDIO) {
57+
// Audio
58+
auto audioTag =
59+
std::move(std::get<FlvTagTypeIndex::FLV_TAG_INDEX_AUDIO>(tag));
60+
auto tagHeader = writeTagHeader(*audioTag);
61+
tagSize += TAG_HEADER_SIZE;
62+
queue.append(std::move(tagHeader));
63+
64+
auto audioTagHeader = writeAudioTagHeader(*audioTag);
65+
tagSize += AUDIO_TAG_HEADER_SIZE;
66+
queue.append(std::move(audioTagHeader));
67+
68+
tagSize += audioTag->data->computeChainDataLength();
69+
queue.append(std::move(audioTag->data));
70+
}
71+
CHECK_GT(tagSize, 0);
72+
queue.append(write4Bytes(static_cast<uint32_t>(tagSize)));
73+
return queue.move();
74+
}
75+
76+
std::unique_ptr<folly::IOBuf> FlvCoder::writeTagHeader(
77+
const FlvTagBase& tagBase) {
78+
folly::IOBufQueue queue =
79+
folly::IOBufQueue(folly::IOBufQueue::cacheChainLength());
80+
queue.append(writeByte(std::byte(tagBase.type)));
81+
queue.append(write3Bytes(tagBase.size));
82+
queue.append(write3Bytes(tagBase.timestamp & 0xFFFFFF));
83+
queue.append(writeByte(std::byte((tagBase.timestamp >> 24) & 0xFF)));
84+
queue.append(write3Bytes(tagBase.streamId));
85+
86+
return queue.move();
87+
}
88+
89+
std::unique_ptr<folly::IOBuf> FlvCoder::writeVideoTagHeader(
90+
const FlvVideoTag& tagVideo) {
91+
folly::IOBufQueue queue =
92+
folly::IOBufQueue(folly::IOBufQueue::cacheChainLength());
93+
CHECK_EQ(tagVideo.codecId, 7);
94+
std::byte tmp = std::byte(tagVideo.frameType << 4 | (tagVideo.codecId & 0xF));
95+
queue.append(writeByte(tmp));
96+
queue.append(writeByte(std::byte(tagVideo.avcPacketType)));
97+
queue.append(write3Bytes(tagVideo.compositionTime));
98+
99+
return queue.move();
100+
}
101+
102+
std::unique_ptr<folly::IOBuf> FlvCoder::writeAudioTagHeader(
103+
const FlvAudioTag& tagAudio) {
104+
CHECK_EQ(tagAudio.soundFormat, 10);
105+
folly::IOBufQueue queue =
106+
folly::IOBufQueue(folly::IOBufQueue::cacheChainLength());
107+
108+
std::byte tmp = std::byte(
109+
(tagAudio.soundFormat & 0b1111) << 4 | (tagAudio.soundRate & 0b11) << 2 |
110+
(tagAudio.soundSize & 0b1) << 1 | (tagAudio.soundType & 0b1));
111+
queue.append(writeByte(tmp));
112+
queue.append(writeByte(std::byte(tagAudio.aacPacketType)));
113+
114+
return queue.move();
115+
}
116+
117+
std::unique_ptr<folly::IOBuf> FlvCoder::write4Bytes(uint32_t v) {
118+
auto nv = htonl(v);
119+
return folly::IOBuf::copyBuffer(&nv, 4);
120+
}
121+
122+
std::unique_ptr<folly::IOBuf> FlvCoder::write3Bytes(uint32_t v) {
123+
auto nv = htonl(v & 0x00FFFFFF) >> 8;
124+
return folly::IOBuf::copyBuffer(&nv, 3);
125+
}
126+
127+
std::unique_ptr<folly::IOBuf> FlvCoder::writeByte(std::byte b) {
128+
return folly::IOBuf::copyBuffer(&b, 1);
129+
}
130+
131+
} // namespace moxygen::flv

moxygen/flv_parser/FlvCoder.h

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
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 <folly/io/IOBuf.h>
10+
#include "moxygen/flv_parser/FlvCommon.h"
11+
12+
namespace moxygen::flv {
13+
14+
class FlvCoder {
15+
public:
16+
explicit FlvCoder() = default;
17+
~FlvCoder() = default;
18+
19+
std::unique_ptr<folly::IOBuf> writeTag(FlvTag tag);
20+
21+
private:
22+
static constexpr size_t TAG_HEADER_SIZE = 11;
23+
static constexpr size_t VIDEO_TAG_HEADER_SIZE = 5;
24+
// Writes 2 but we need to return 1
25+
static constexpr size_t AUDIO_TAG_HEADER_SIZE = 1;
26+
27+
std::unique_ptr<folly::IOBuf> writeTagHeader(const FlvTagBase& tagBase);
28+
std::unique_ptr<folly::IOBuf> writeVideoTagHeader(
29+
const FlvVideoTag& tagVideo);
30+
std::unique_ptr<folly::IOBuf> writeAudioTagHeader(
31+
const FlvAudioTag& tagAudio);
32+
std::unique_ptr<folly::IOBuf> writeIoBuf(std::unique_ptr<folly::IOBuf> buf);
33+
34+
std::unique_ptr<folly::IOBuf> write3Bytes(uint32_t v);
35+
std::unique_ptr<folly::IOBuf> write4Bytes(uint32_t v);
36+
std::unique_ptr<folly::IOBuf> writeByte(std::byte b);
37+
38+
const char flvHeader_[9] =
39+
{'F', 'L', 'V', 0x1, 0b00000101, 0x00, 0x00, 0x00, 0x09};
40+
41+
bool headerWrote_{false};
42+
};
43+
44+
} // namespace moxygen::flv

moxygen/flv_parser/FlvWriter.cpp

Lines changed: 5 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -10,115 +10,16 @@
1010
namespace moxygen::flv {
1111

1212
bool FlvWriter::writeTag(FlvTag tag) {
13-
if (tag.index() == FlvTagTypeIndex::FLV_TAG_INDEX_READCMD) {
14-
auto readsCmd = std::get<flv::FlvReadCmd>(tag);
15-
if (readsCmd == flv::FlvReadCmd::FLV_EOF) {
16-
return false;
17-
}
18-
return true;
13+
auto buf = FlvCoder::writeTag(std::move(tag));
14+
if (!buf) {
15+
return false;
1916
}
2017

21-
if (!headerWrote_) {
22-
f_.write(flvHeader_, sizeof(flvHeader_));
23-
uint32_t tagSize = 0x00;
24-
write4Bytes(tagSize);
25-
headerWrote_ = true;
26-
}
27-
28-
size_t tagSize = 0;
29-
if (tag.index() == FlvTagTypeIndex::FLV_TAG_INDEX_SCRIPT) {
30-
// Script
31-
auto dataTag =
32-
std::move(std::get<FlvTagTypeIndex::FLV_TAG_INDEX_SCRIPT>(tag));
33-
tagSize = tagSize + writeTagHeader(*dataTag);
34-
tagSize = tagSize + writeIoBuf(std::move(dataTag->data));
35-
} else if (tag.index() == FlvTagTypeIndex::FLV_TAG_INDEX_VIDEO) {
36-
// Video
37-
auto videoTag =
38-
std::move(std::get<FlvTagTypeIndex::FLV_TAG_INDEX_VIDEO>(tag));
39-
tagSize = tagSize + writeTagHeader(*videoTag);
40-
tagSize = tagSize + writeVideoTagHeader(*videoTag);
41-
tagSize = tagSize + writeIoBuf(std::move(videoTag->data));
42-
} else if (tag.index() == FlvTagTypeIndex::FLV_TAG_INDEX_AUDIO) {
43-
// Audio
44-
auto audioTag =
45-
std::move(std::get<FlvTagTypeIndex::FLV_TAG_INDEX_AUDIO>(tag));
46-
tagSize = tagSize + writeTagHeader(*audioTag);
47-
tagSize = tagSize + writeAudioTagHeader(*audioTag);
48-
tagSize = tagSize + writeIoBuf(std::move(audioTag->data));
49-
}
50-
CHECK(tagSize > 0);
51-
write4Bytes(tagSize);
18+
buf->coalesce();
19+
f_.write(reinterpret_cast<const char*>(buf->data()), buf->length());
5220
f_.flush();
5321

5422
return true;
5523
}
5624

57-
size_t FlvWriter::writeTagHeader(const FlvTagBase& tagBase) {
58-
size_t ret = 11;
59-
writeByte(std::byte(tagBase.type));
60-
write3Bytes(tagBase.size);
61-
write3Bytes(tagBase.timestamp & 0xFFFFFF);
62-
writeByte(std::byte((tagBase.timestamp >> 24) & 0xFF));
63-
write3Bytes(tagBase.streamId);
64-
65-
return ret;
66-
}
67-
68-
size_t FlvWriter::writeVideoTagHeader(const FlvVideoTag& tagVideo) {
69-
CHECK(tagVideo.codecId == 7);
70-
size_t ret = 5;
71-
std::byte tmp = std::byte(tagVideo.frameType << 4 | (tagVideo.codecId & 0xF));
72-
writeByte(tmp);
73-
writeByte(std::byte(tagVideo.avcPacketType));
74-
write3Bytes(tagVideo.compositionTime);
75-
76-
return ret;
77-
}
78-
79-
size_t FlvWriter::writeAudioTagHeader(const FlvAudioTag& tagAudio) {
80-
CHECK(tagAudio.soundFormat == 10);
81-
size_t ret = 1;
82-
std::byte tmp = std::byte(
83-
(tagAudio.soundFormat & 0b1111) << 4 | (tagAudio.soundRate & 0b11) << 2 |
84-
(tagAudio.soundSize & 0b1) << 1 | (tagAudio.soundType & 0b1));
85-
writeByte(tmp);
86-
writeByte(std::byte(tagAudio.aacPacketType));
87-
88-
return ret;
89-
}
90-
91-
void FlvWriter::write4Bytes(uint32_t v) {
92-
auto nv = htonl(v);
93-
f_.write(reinterpret_cast<char*>(&nv), 4);
94-
}
95-
96-
void FlvWriter::write3Bytes(uint32_t v) {
97-
auto nv = htonl(v & 0x00FFFFFF) >> 8;
98-
f_.write(reinterpret_cast<char*>(&nv), 3);
99-
}
100-
101-
void FlvWriter::writeByte(std::byte b) {
102-
f_.write(reinterpret_cast<const char*>(&b), 1);
103-
}
104-
105-
size_t FlvWriter::writeIoBuf(std::unique_ptr<folly::IOBuf> buf) {
106-
size_t ret = 0;
107-
CHECK(buf != nullptr);
108-
109-
// Write all the chain if IOBuf without coalesing
110-
const folly::IOBuf* current = buf.get();
111-
do {
112-
if (current->length() > 0) {
113-
f_.write(
114-
reinterpret_cast<const char*>(current->data()), current->length());
115-
ret += current->length();
116-
}
117-
current = current->next();
118-
119-
} while (current != buf.get());
120-
121-
return ret;
122-
}
123-
12425
} // namespace moxygen::flv

moxygen/flv_parser/FlvWriter.h

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,12 @@
88

99
#include <folly/io/IOBuf.h>
1010
#include <fstream> // std::ofstream
11+
#include "moxygen/flv_parser/FlvCoder.h"
1112
#include "moxygen/flv_parser/FlvCommon.h"
1213

1314
namespace moxygen::flv {
1415

15-
class FlvWriter {
16+
class FlvWriter : public FlvCoder {
1617
public:
1718
explicit FlvWriter(const std::string& filename)
1819
: f_(filename, std::ofstream::binary) {}
@@ -24,20 +25,7 @@ class FlvWriter {
2425
bool writeTag(FlvTag tag);
2526

2627
private:
27-
size_t writeTagHeader(const FlvTagBase& tagBase);
28-
size_t writeVideoTagHeader(const FlvVideoTag& tagVideo);
29-
size_t writeAudioTagHeader(const FlvAudioTag& tagAudio);
30-
size_t writeIoBuf(std::unique_ptr<folly::IOBuf> buf);
31-
32-
void write3Bytes(uint32_t v);
33-
void write4Bytes(uint32_t v);
34-
void writeByte(std::byte b);
35-
36-
const char flvHeader_[9] =
37-
{'F', 'L', 'V', 0x1, 0b00000101, 0x00, 0x00, 0x00, 0x09};
38-
3928
std::ofstream f_;
40-
bool headerWrote_{false};
4129
};
4230

4331
} // namespace moxygen::flv

0 commit comments

Comments
 (0)