123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375 |
- #include <array>
- #include <regex>
- #include <string.h>
- #include "utils.hh"
- #include "mpegts.hh"
- using std::string;
- using std::vector;
- using std::map;
- using std::regex;
- class TSPacket
- {
- public:
- enum class ID { awmk_file, awmk_data, unknown };
- private:
- std::array<unsigned char, 188> m_data;
- std::array<unsigned char, 12>
- get_id_bytes (ID type)
- {
- if (type == ID::awmk_file)
- return { 'G', 0x1F, 0xFF, 0x10, 'A', 'W', 'M', 'K', 'f', 'i', 'l', 'e' };
- if (type == ID::awmk_data)
- return { 'G', 0x1F, 0xFF, 0x10, 'A', 'W', 'M', 'K', 'd', 'a', 't', 'a' };
- return {0,};
- }
- public:
- bool
- read (FILE *file, Error& err)
- {
- size_t bytes_read = fread (m_data.data(), 1, m_data.size(), file);
- if (bytes_read == 0)
- return false;
- if (bytes_read == m_data.size())
- {
- if (m_data[0] == 'G')
- return true;
- err = Error ("bad packet sync while reading transport (.ts) packet");
- return false;
- }
- err = Error ("short read while reading transport stream (.ts) packet");
- return false;
- }
- Error
- write (FILE *file)
- {
- size_t bytes_written = fwrite (m_data.data(), 1, m_data.size(), file);
- if (bytes_written != m_data.size())
- return Error ("short write while writing transport stream (.ts) packet");
- return Error::Code::NONE;
- }
- void
- clear (ID type)
- {
- std::fill (m_data.begin(), m_data.end(), 0);
- auto id = get_id_bytes (type);
- std::copy (id.begin(), id.end(), m_data.begin());
- }
- unsigned char&
- operator[] (size_t n)
- {
- return m_data[n];
- }
- bool
- id_eq (size_t offset, unsigned char a, unsigned char b, unsigned char c, unsigned char d)
- {
- return m_data[offset] == a && m_data[offset + 1] == b && m_data[offset + 2] == c && m_data[offset + 3] == d;
- }
- ID
- get_id()
- {
- if (id_eq (0, 'G', 0x1F, 0xFF, 0x10) && id_eq (4, 'A', 'W', 'M', 'K'))
- {
- if (id_eq (8, 'f', 'i', 'l', 'e'))
- return ID::awmk_file;
- if (id_eq (8, 'd', 'a', 't', 'a'))
- return ID::awmk_data;
- }
- return ID::unknown;
- }
- constexpr size_t
- size()
- {
- return m_data.size();
- }
- const std::array<unsigned char, 188>&
- data()
- {
- return m_data;
- }
- };
- Error
- TSWriter::append_file (const string& name, const string& filename)
- {
- vector<unsigned char> data;
- FILE *datafile = fopen (filename.c_str(), "r");
- ScopedFile datafile_s (datafile);
- if (!datafile)
- return Error ("unable to open data file");
- int c;
- while ((c = fgetc (datafile)) >= 0)
- data.push_back (c);
- entries.push_back ({name, data});
- return Error::Code::NONE;
- }
- void
- TSWriter::append_vars (const string& name, const map<string, string>& vars)
- {
- vector<unsigned char> data;
- for (auto kv : vars)
- {
- for (auto k : kv.first)
- data.push_back (k);
- data.push_back ('=');
- for (auto v : kv.second)
- data.push_back (v);
- data.push_back (0);
- }
- entries.push_back ({name, data});
- }
- void
- TSWriter::append_data (const string& name, const vector<unsigned char>& data)
- {
- entries.push_back ({name, data});
- }
- Error
- TSWriter::process (const string& inname, const string& outname)
- {
- FILE *infile = fopen (inname.c_str(), "r");
- FILE *outfile = fopen (outname.c_str(), "w");
- ScopedFile infile_s (infile);
- ScopedFile outfile_s (outfile);
- if (!infile)
- {
- error ("audiowmark: unable to open %s for reading\n", inname.c_str());
- return Error (strerror (errno));
- }
- if (!outfile)
- {
- error ("audiowmark: unable to open %s for writing\n", outname.c_str());
- return Error (strerror (errno));
- }
- while (!feof (infile))
- {
- TSPacket p;
- Error err;
- bool read_ok = p.read (infile, err);
- if (!read_ok)
- {
- if (err)
- return err;
- }
- else
- {
- err = p.write (outfile);
- if (err)
- return err;
- }
- }
- for (auto entry : entries)
- {
- string header = string_printf ("%zd:%s", entry.data.size(), entry.name.c_str()) + '\0';
- vector<unsigned char> data = entry.data;
- for (size_t i = 0; i < header.size(); i++)
- data.insert (data.begin() + i, header[i]);
- TSPacket p_file;
- p_file.clear (TSPacket::ID::awmk_file);
- size_t data_pos = 0;
- int pos = 12;
- while (data_pos < data.size())
- {
- p_file[pos++] = data[data_pos];
- if (pos == 188)
- {
- Error err = p_file.write (outfile);
- if (err)
- return err;
- p_file.clear (TSPacket::ID::awmk_data);
- pos = 12;
- }
- data_pos++;
- }
- if (pos != 12)
- {
- Error err = p_file.write (outfile);
- if (err)
- return err;
- }
- }
- return Error::Code::NONE;
- }
- bool
- TSReader::parse_header (Header& header, vector<unsigned char>& data)
- {
- for (size_t i = 0; i < data.size(); i++)
- {
- if (data[i] == 0)
- {
- string s = (const char *) (&data[0]);
- static const regex header_re ("([0-9]*):(.*)");
- std::smatch sm;
- if (regex_match (s, sm, header_re))
- {
- header.data_size = atoi (sm[1].str().c_str());
- header.filename = sm[2];
-
- data.erase (data.begin(), data.begin() + i + 1);
- return true;
- }
- }
- }
- return false;
- }
- Error
- TSReader::load (const string& inname)
- {
- if (inname == "-")
- {
- return load (stdin);
- }
- else
- {
- FILE *infile = fopen (inname.c_str(), "r");
- ScopedFile infile_s (infile);
- if (!infile)
- return Error (string_printf ("error opening input .ts '%s'", inname.c_str()));
- return load (infile);
- }
- }
- Error
- TSReader::load (FILE *infile)
- {
- vector<unsigned char> awmk_stream;
- Header header;
- bool header_valid = false;
- Error err;
- while (!feof (infile))
- {
- TSPacket p;
- bool read_ok = p.read (infile, err);
- if (!read_ok)
- {
- if (err)
- return err;
- }
- else
- {
- TSPacket::ID id = p.get_id();
- if (id == TSPacket::ID::awmk_file)
- {
-
- header_valid = false;
- awmk_stream.clear();
- }
- if (id == TSPacket::ID::awmk_file || id == TSPacket::ID::awmk_data)
- {
- awmk_stream.insert (awmk_stream.end(), p.data().begin() + 12, p.data().end());
- if (!header_valid)
- {
- if (parse_header (header, awmk_stream))
- {
- awmk_stream.reserve (header.data_size + p.size());
- header_valid = true;
- }
- }
-
- if (header_valid && awmk_stream.size() >= header.data_size)
- {
- awmk_stream.resize (header.data_size);
- m_entries.push_back ({ header.filename, std::move (awmk_stream)});
- header_valid = false;
- awmk_stream.clear();
- }
- }
- }
- }
- return Error::Code::NONE;
- }
- const vector<TSReader::Entry>&
- TSReader::entries()
- {
- return m_entries;
- }
- const TSReader::Entry *
- TSReader::find (const string& name) const
- {
- for (const auto& entry : m_entries)
- if (entry.filename == name)
- return &entry;
- return nullptr;
- }
- map<string, string>
- TSReader::parse_vars (const string& name)
- {
- map<string, string> vars;
- auto entry = find (name);
- if (!entry)
- return vars;
- enum { KEY, VALUE } mode = KEY;
- string s;
- string key;
- for (auto c : entry->data)
- {
- if (c == '=' && mode == KEY)
- {
- key = s;
- s.clear();
- mode = VALUE;
- }
- else if (c == '\0' && mode == VALUE)
- {
- vars[key] = s;
- s.clear();
- mode = KEY;
- }
- else
- {
- s += c;
- }
- }
- return vars;
- }
|