Refactor calculating duration of OGG streams

This commit is contained in:
Martchus 2017-09-03 18:54:46 +02:00
parent 9448c3bc92
commit 15af444e5a
2 changed files with 36 additions and 40 deletions

View File

@ -58,9 +58,6 @@ void OggStream::internalParseHeader()
iterator.setFilter(firstPage.streamSerialNumber());
iterator.setPageIndex(m_startPage);
// predicate for finding pages of this stream by its stream serial number
const auto pred = bind(&OggPage::matchesStreamSerialNumber, _1, firstPage.streamSerialNumber());
// iterate through segments using OggIterator
for(bool hasIdentificationHeader = false, hasCommentHeader = false; iterator && (!hasIdentificationHeader || !hasCommentHeader); ++iterator) {
const uint32 currentSize = iterator.currentSegmentSize();
@ -98,19 +95,10 @@ void OggStream::internalParseHeader()
} else if(ind.maxBitrate() == ind.minBitrate()) {
m_bitrate = ind.maxBitrate();
}
if(m_bitrate) {
m_bitrate = static_cast<double>(m_bitrate) / 1000.0;
}
// determine sample count and duration if all pages have been fetched
if(iterator.areAllPagesFetched()) {
const auto &pages = iterator.pages();
const auto firstPage = find_if(pages.cbegin(), pages.cend(), pred);
const auto lastPage = find_if(pages.crbegin(), pages.crend(), pred);
if(firstPage != pages.cend() && lastPage != pages.crend()) {
m_sampleCount = lastPage->absoluteGranulePosition() - firstPage->absoluteGranulePosition();
m_duration = TimeSpan::fromSeconds(static_cast<double>(m_sampleCount) / m_samplingFrequency);
}
if(m_bitrate != 0.0) {
m_bitrate /= 1000.0;
}
calculateDurationViaSampleCount();
hasIdentificationHeader = true;
} else {
addNotification(NotificationType::Critical, "Vorbis identification header appears more than once. Oversupplied occurrence will be ignored.", context);
@ -151,22 +139,7 @@ void OggStream::internalParseHeader()
m_version = ind.version();
m_channelCount = ind.channels();
m_samplingFrequency = ind.sampleRate();
// determine sample count and duration if all pages have been fetched
if(iterator.areAllPagesFetched()) {
const auto &pages = iterator.pages();
const auto firstPage = find_if(pages.cbegin(), pages.cend(), pred);
const auto lastPage = find_if(pages.crbegin(), pages.crend(), pred);
if(firstPage != pages.cend() && lastPage != pages.crend()) {
m_sampleCount = lastPage->absoluteGranulePosition() - firstPage->absoluteGranulePosition();
// must apply "pre-skip" here do calculate effective sample count and duration?
if(m_sampleCount > ind.preSkip()) {
m_sampleCount -= ind.preSkip();
} else {
m_sampleCount = 0;
}
m_duration = TimeSpan::fromSeconds(static_cast<double>(m_sampleCount) / m_samplingFrequency);
}
}
calculateDurationViaSampleCount(ind.preSkip());
hasIdentificationHeader = true;
} else {
addNotification(NotificationType::Critical, "Opus identification header appears more than once. Oversupplied occurrence will be ignored.", context);
@ -217,15 +190,7 @@ void OggStream::internalParseHeader()
m_channelCount = streamInfo.channelCount();
m_samplingFrequency = streamInfo.samplingFrequency();
m_sampleCount = streamInfo.totalSampleCount();
if(!m_sampleCount && iterator.areAllPagesFetched()) {
const auto &pages = iterator.pages();
const auto firstPage = find_if(pages.cbegin(), pages.cend(), pred);
const auto lastPage = find_if(pages.crbegin(), pages.crend(), pred);
if(firstPage != pages.cend() && lastPage != pages.crend()) {
m_sampleCount = lastPage->absoluteGranulePosition() - firstPage->absoluteGranulePosition();
}
}
m_duration = TimeSpan::fromSeconds(static_cast<double>(m_sampleCount) / m_samplingFrequency);
calculateDurationViaSampleCount();
hasIdentificationHeader = true;
} else {
addNotification(NotificationType::Critical, "FLAC-to-Ogg mapping header appears more than once. Oversupplied occurrence will be ignored.", context);
@ -304,6 +269,7 @@ void OggStream::internalParseHeader()
// TODO: reduce code duplication
}
// estimate duration from size and bitrate if sample count and sample rate could not be determined
if(m_duration.isNull() && m_size && m_bitrate != 0.0) {
// calculate duration from stream size and bitrate, assuming 1 % overhead
m_duration = TimeSpan::fromSeconds(static_cast<double>(m_size) / (m_bitrate * 125.0) * 1.1);
@ -311,4 +277,32 @@ void OggStream::internalParseHeader()
m_headerValid = true;
}
void OggStream::calculateDurationViaSampleCount(uint16 preSkip)
{
// define predicate for finding pages of this stream by its stream serial number
const auto pred = bind(&OggPage::matchesStreamSerialNumber, _1, m_id);
// determine sample count
const auto &iterator = m_container.m_iterator;
if(!m_sampleCount && iterator.areAllPagesFetched()) {
const auto &pages = iterator.pages();
const auto firstPage = find_if(pages.cbegin(), pages.cend(), pred);
const auto lastPage = find_if(pages.crbegin(), pages.crend(), pred);
if(firstPage != pages.cend() && lastPage != pages.crend()) {
m_sampleCount = lastPage->absoluteGranulePosition() - firstPage->absoluteGranulePosition();
// must apply "pre-skip" here to calculate effective sample count and duration?
if(m_sampleCount > preSkip) {
m_sampleCount -= preSkip;
} else {
m_sampleCount = 0;
}
}
}
// actually calculate the duration
if(m_sampleCount && m_samplingFrequency != 0.0) {
m_duration = TimeSpan::fromSeconds(static_cast<double>(m_sampleCount) / m_samplingFrequency);
}
}
}

View File

@ -25,6 +25,8 @@ protected:
void internalParseHeader();
private:
void calculateDurationViaSampleCount(uint16 preSkip = 0);
std::size_t m_startPage;
OggContainer &m_container;
uint32 m_currentSequenceNumber;