diff --git a/CMakeLists.txt b/CMakeLists.txt index fb73e5cf9d35ad7de7e1a2cbf66826d802c0b749..6640f5d7ee46c3511254604ae0840e49cb9e91d6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -230,6 +230,7 @@ add_subdirectory(applications/calibration) add_subdirectory(applications/groupview) add_subdirectory(applications/player) add_subdirectory(applications/recorder) +add_subdirectory(applications/merger) if (HAVE_AVFORMAT) add_subdirectory(applications/ftl2mkv) diff --git a/applications/merger/CMakeLists.txt b/applications/merger/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..ccc625afb0241966628bf8bffa790cf8a041afa7 --- /dev/null +++ b/applications/merger/CMakeLists.txt @@ -0,0 +1,11 @@ +set(FTLMERGER + src/main.cpp +) + +add_executable(ftl-merge ${FTLMERGER}) + +target_include_directories(ftl-merge PRIVATE src) + +target_link_libraries(ftl-merge ftlcommon ftlcodecs ftlrgbd Threads::Threads ${OpenCV_LIBS}) + + diff --git a/applications/merger/src/main.cpp b/applications/merger/src/main.cpp new file mode 100644 index 0000000000000000000000000000000000000000..06d73202f231eca06902f7eb834e10c6aa28fa9b --- /dev/null +++ b/applications/merger/src/main.cpp @@ -0,0 +1,102 @@ +#include <loguru.hpp> +#include <ftl/configuration.hpp> +#include <ftl/codecs/reader.hpp> +#include <ftl/codecs/writer.hpp> +#include <ftl/codecs/packet.hpp> +#include <ftl/rgbd/camera.hpp> +#include <ftl/codecs/hevc.hpp> + +#include <fstream> + +int main(int argc, char **argv) { + auto root = ftl::configure(argc, argv, "merger_default"); + + std::string outputfile = root->value("out", std::string("output.ftl")); + std::vector<std::string> paths = *root->get<std::vector<std::string>>("paths"); + int timeoff = int(root->value("offset", 0.0f) * 1000.0f); + int stream_mask1 = root->value("mask1",0xFF); + int stream_mask2 = root->value("mask2",0xFF); + + if (paths.size() == 0) { + LOG(ERROR) << "Missing input ftl file(s)."; + return -1; + } + + // Generate the output writer... + std::ofstream of; + of.open(outputfile); + if (!of.is_open()) { + LOG(ERROR) << "Could not open output file: " << outputfile; + return -1; + } + + ftl::codecs::Writer out(of); + out.begin(); + + std::vector<std::ifstream> fs; + std::vector<ftl::codecs::Reader*> rs; + fs.resize(paths.size()); + rs.resize(paths.size()); + + for (size_t i=0; i<paths.size(); ++i) { + fs[i].open(paths[i]); + if (!fs[i].is_open()) { + LOG(ERROR) << "Could not open file: " << paths[i]; + return -1; + } + + rs[i] = new ftl::codecs::Reader(fs[i]); + if (!rs[i]->begin()) { + LOG(ERROR) << "Bad ftl file format"; + return -1; + } + } + + std::map<int,int> idmap; + int lastid = 0; + + bool res = rs[0]->read(90000000000000, [&rs,&out,&idmap,&lastid,stream_mask1,stream_mask2,timeoff](const ftl::codecs::StreamPacket &spkt, const ftl::codecs::Packet &pkt) { + if (((0x1 << spkt.streamID) & stream_mask1) == 0) return; + + ftl::codecs::StreamPacket spkt2 = spkt; + if (idmap.find(spkt.streamID) == idmap.end()) { + idmap[spkt.streamID] = lastid++; + } + spkt2.streamID = idmap[spkt.streamID]; + + // Now read all other sources up to the same packet timestamp. + out.write(spkt2, pkt); + + for (size_t j=1; j<rs.size(); ++j) { + ftl::codecs::Reader *r = rs[j]; + + // FIXME: Need to truncate other stream if the following returns + // no frames, meaning the timeshift causes this stream to run out + // before the main stream. + rs[j]->read(spkt.timestamp+timeoff, [&out,&idmap,&lastid,j,r,stream_mask2,timeoff](const ftl::codecs::StreamPacket &spkt, const ftl::codecs::Packet &pkt) { + if (((0x1 << spkt.streamID) & stream_mask2) == 0) return; + if (int(spkt.channel) < 32 && spkt.timestamp < r->getStartTime()+timeoff) return; + + ftl::codecs::StreamPacket spkt2 = spkt; + if (idmap.find(spkt.streamID + (j << 16)) == idmap.end()) { + idmap[spkt.streamID+(j << 16)] = lastid++; + } + spkt2.streamID = idmap[spkt.streamID + (j << 16)]; + spkt2.timestamp -= timeoff; + + out.write(spkt2, pkt); + }); + } + }); + + out.end(); + of.close(); + + for (size_t i=0; i<rs.size(); ++i) { + rs[i]->end(); + delete rs[i]; + fs[i].close(); + } + + return 0; +} \ No newline at end of file