/* Copyright (C) 2014 CSP Innovazione nelle ICT s.c.a r.l. (http://rd.csp.it/) Copyright (C) 2014, 2015 Matthias P. Braendli (http://opendigitalradio.org) Copyright (C) 2015, 2016, 2017, 2018 Stefan Pöschel (http://opendigitalradio.org) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ /*! \file sls.h \brief Slideshow related code \author Sergio Sagliocco \author Matthias P. Braendli \author Stefan Pöschel */ #ifndef SLS_H_ #define SLS_H_ #include "common.h" #include "pad_common.h" #if HAVE_MAGICKWAND # if HAVE_MAGICKWAND_LEGACY # include # else # include # endif #endif #include #include #include #include #include #include #include // --- MSCDG ----------------------------------------------------------------- struct MSCDG { // MSC Data Group Header (extension field not supported) unsigned char extflag; // 1 bit unsigned char crcflag; // 1 bit unsigned char segflag; // 1 bit unsigned char accflag; // 1 bit unsigned char dgtype; // 4 bits unsigned char cindex; // 4 bits unsigned char rindex; // 4 bits /// Session header - Segment field unsigned char last; // 1 bit unsigned short int segnum; // 16 bits // Session header - User access field unsigned char rfa; // 3 bits unsigned char tidflag; // 1 bit unsigned char lenid; // 4 bits - Fixed to value 2 in this implemntation unsigned short int tid; // 16 bits // MSC data group data field // Mot Segmentation header unsigned char rcount; // 3 bits unsigned short int seglen; // 13 bits // Mot segment const uint8_t* segdata; // MSC data group CRC unsigned short int crc; // 16 bits }; // --- slide_metadata_t ----------------------------------------------------------------- /*! Between collection of slides and transmission, the slide data is saved * in this structure. */ struct slide_metadata_t { // complete path to slide std::string filepath; // index, values from 0 to MAXSLIDEID, rolls over int fidx; // This is used to define the order in which several discovered // slides are transmitted bool operator<(const slide_metadata_t& other) const { return this->fidx < other.fidx; } }; // --- fingerprint_t ----------------------------------------------------------------- /*! A simple fingerprint for each slide transmitted. * Allows us to reuse the same fidx if the same slide * is transmitted more than once. */ struct fingerprint_t { // file name std::string s_name; // file size, in bytes off_t s_size; // time of last modification unsigned long s_mtime; // assigned fidx, -1 means invalid int fidx; /*! The comparison is not done on fidx, only * on the file-specific data */ bool operator==(const fingerprint_t& other) const { return (((s_name == other.s_name && s_size == other.s_size) && s_mtime == other.s_mtime)); } void disp(void) { printf("%s_%ld_%lu:%d\n", s_name.c_str(), s_size, s_mtime, fidx); } void load_from_file(const char* filepath) { struct stat file_attribue; const char * final_slash; stat(filepath, &file_attribue); final_slash = strrchr(filepath, '/'); // load filename, size and mtime // Save only the basename of the filepath this->s_name.assign((final_slash == NULL) ? filepath : final_slash + 1); this->s_size = file_attribue.st_size; this->s_mtime = file_attribue.st_mtime; this->fidx = -1; } }; // --- History ----------------------------------------------------------------- /*! We keep track of transmitted files so that we can retransmit * identical slides with the same index, in case the receivers cache * them. * * \c MAXHISTORYLEN defines for how how many slides we want to keep this * history. */ class History { public: History() : History(MAXHISTORYLEN) {} History(size_t hist_size) : m_hist_size(hist_size), m_last_given_fidx(0) {} void disp_database(); // controller of id base on database int get_fidx(const char* filepath); private: static const size_t MAXHISTORYLEN; static const int MAXSLIDEID; std::deque m_database; size_t m_hist_size; int m_last_given_fidx; // find the fingerprint fp in database. // returns the fidx when found, // or -1 if not found int find(const fingerprint_t& fp) const; // add a new fingerprint into database // returns its fidx void add(fingerprint_t& fp); }; // --- SlideStore ----------------------------------------------------------------- class SlideStore { private: std::list slides; History history; static int FilterSlides(const struct dirent* file); public: bool InitFromDir(const std::string& dir); bool Empty() {return slides.empty();} void Clear() {slides.clear();} slide_metadata_t GetSlide(); }; // --- MOTHeader ----------------------------------------------------------------- class MOTHeader { private: size_t header_size; uint8_vector_t data; void IncrementHeaderSize(size_t size); void AddParamHeader(int pli, int param_id) {data.push_back((pli << 6) | (param_id & 0x3F));} void AddExtensionFixedSize(int pli, int param_id, const uint8_t* data_field, size_t data_field_len); void AddExtensionVarSize(int param_id, const uint8_t* data_field, size_t data_field_len); public: MOTHeader(size_t body_size, int content_type, int content_subtype); void AddExtension(int param_id, const uint8_t* data_field, size_t data_field_len); const uint8_vector_t GetData() {return data;} }; // --- SLSEncoder ----------------------------------------------------------------- class SLSEncoder { private: static const size_t MAXSEGLEN; static const int MINQUALITY; static const std::string SLS_PARAMS_SUFFIX; void warnOnSmallerImage(size_t height, size_t width, const std::string& fname); #if HAVE_MAGICKWAND size_t resizeImage(MagickWand* m_wand, unsigned char** blob, const std::string& fname, bool* jfif_not_png, size_t max_slide_size); #endif bool parse_sls_param_id(const std::string &key, const std::string &value, uint8_t &target); bool check_sls_param_len(const std::string &key, size_t len, size_t len_max); void process_mot_params_file(MOTHeader& header, const std::string ¶ms_fname); uint8_vector_t createMotHeader(size_t blobsize, int fidx, bool jfif_not_png, const std::string ¶ms_fname); void createMscDG(MSCDG* msc, unsigned short int dgtype, int *cindex, unsigned short int segnum, unsigned short int lastseg, unsigned short int tid, const uint8_t* data, unsigned short int datalen); DATA_GROUP* packMscDG(MSCDG* msc); PADPacketizer* pad_packetizer; int cindex_header; int cindex_body; public: static const size_t MAXSLIDESIZE_SIMPLE; static const int APPTYPE_MOT_START; static const int APPTYPE_MOT_CONT; static const std::string REQUEST_REREAD_FILENAME; SLSEncoder(PADPacketizer* pad_packetizer) : pad_packetizer(pad_packetizer), cindex_header(0), cindex_body(0) {} bool encodeSlide(const std::string& fname, int fidx, bool raw_slides, size_t max_slide_size, const std::string& dump_name); static bool isSlideParamFileFilename(const std::string& filename); }; #endif /* SLS_H_ */