-
Notifications
You must be signed in to change notification settings - Fork 43
/
Copy pathCompositeSource.cpp
89 lines (84 loc) · 2.91 KB
/
CompositeSource.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
#include "CompositeSource.h"
#include "strutil.h"
size_t CompositeSource::readSamples(void *buffer, size_t nsamples)
{
if (m_cur_file == m_sources.size())
return 0;
size_t rc = m_sources[m_cur_file]->readSamples(buffer, nsamples);
if (rc > 0) {
m_position += rc;
return rc;
} else {
++m_cur_file;
if (m_cur_file < m_sources.size())
m_sources[m_cur_file]->seekTo(0);
return readSamples(buffer, nsamples);
}
}
void CompositeSource::seekTo(int64_t pos)
{
uint64_t acc = 0;
for (m_cur_file = 0; m_cur_file < m_sources.size(); ++m_cur_file) {
uint64_t len = m_sources[m_cur_file]->length();
if (acc <= pos && pos < acc + len)
break;
acc += len;
}
if (m_cur_file == m_sources.size())
throw std::runtime_error("Invalid seek offset");
m_sources[m_cur_file]->seekTo(pos - acc);
m_position = pos;
}
void CompositeSource::addSource(const std::shared_ptr<ISeekableSource> &src)
{
if (!count())
m_asbd = src->getSampleFormat();
else if (std::memcmp(&m_asbd, &src->getSampleFormat(), sizeof m_asbd))
throw std::runtime_error("Concatenation of multiple inputs with "
"different sample format is not supported");
m_sources.push_back(src);
uint64_t len = src->length();
m_length = (len > ~0ULL - m_length) ? ~0ULL : m_length + len;
/*
* Want to discard tags that take different values on each track.
* This way, only (per-album) common tags should finally remain.
*/
auto parser = dynamic_cast<ITagParser*>(src.get());
if (!parser)
return;
auto tags = parser->getTags();
bool is_empty = m_tags.empty();
std::for_each(tags.begin(), tags.end(),
[&](decltype(*tags.begin()) &kv) {
if (is_empty)
m_tags[kv.first] = kv.second;
else {
auto it = m_tags.find(kv.first);
if (it != m_tags.end() && it->second != kv.second)
m_tags.erase(it);
}
});
}
void CompositeSource::addSourceWithChapter(
const std::shared_ptr<ISeekableSource> &src,
const std::wstring &title)
{
addSource(src);
std::wstring name(title);
auto parser = dynamic_cast<ITagParser*>(src.get());
auto cp = dynamic_cast<IChapterParser*>(src.get());
if (cp) {
auto &chaps = cp->getChapters();
if (chaps.size()) {
std::copy(chaps.begin(), chaps.end(),
std::back_inserter(m_chapters));
return;
}
}
if (parser) {
auto tags = parser->getTags();
if (tags.find("title") != tags.end())
name = strutil::us2w(tags["title"]);
}
addChapter(name, src->length() / m_asbd.mSampleRate);
}