You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

266 lines
7.0 KiB

/*****************************************************************************
* AES3Buffer.cpp: AES3 audio buffer
*****************************************************************************
* Copyright © 2018 VideoLabs, VideoLAN and VideoLAN Authors
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "AES3Audio.hpp"
#include <algorithm>
#include <cassert>
using namespace sdi_sout;
AES3AudioBuffer::AES3AudioBuffer(unsigned count)
{
setSubFramesCount(count);
block_BytestreamInit(&bytestream);
toconsume = 0;
}
AES3AudioBuffer::~AES3AudioBuffer()
{
block_BytestreamRelease(&bytestream);
}
void AES3AudioBuffer::setSubFramesCount(uint8_t c)
{
buffersubframes = c;
}
void AES3AudioBuffer::push(block_t *p_block)
{
bytestream_mutex.lock();
block_BytestreamPush(&bytestream, p_block);
bytestream_mutex.unlock();
}
void AES3AudioBuffer::read(void *dstbuf, unsigned count,
const AES3AudioSubFrameIndex &dstbufsubframeidx,
const AES3AudioSubFrameIndex &srcchannelidx,
unsigned dstbufframeswidth)
{
if(!srcchannelidx.isValid() || srcchannelidx.index() >= buffersubframes)
return;
if(dstbuf == NULL)
return;
bytestream_mutex.lock();
uint8_t *dst = reinterpret_cast<uint8_t *>(dstbuf);
for(unsigned i=0; i<count; i++)
{
size_t srcoffset = sizeof(uint16_t) * (i * buffersubframes + srcchannelidx.index());
size_t dstoffset = sizeof(uint16_t) * (i * 2 * dstbufframeswidth + dstbufsubframeidx.index());
block_PeekOffsetBytes(&bytestream, srcoffset, &dst[dstoffset], sizeof(uint16_t));
}
bytestream_mutex.unlock();
}
size_t AES3AudioBuffer::FramesToBytes(unsigned f) const
{
return (size_t) f * sizeof(uint16_t) * buffersubframes;
}
vlc_tick_t AES3AudioBuffer::FramesToDuration(unsigned f) const
{
return CLOCK_FREQ * f / 48000;
}
unsigned AES3AudioBuffer::BytesToFrames(size_t s) const
{
return s / (sizeof(uint16_t) * buffersubframes);
}
unsigned AES3AudioBuffer::TicksDurationToFrames(vlc_tick_t t) const
{
return samples_from_vlc_tick(t, 48000);
}
void AES3AudioBuffer::flushConsumed()
{
if(toconsume)
{
size_t bytes = FramesToBytes(toconsume);
bytestream_mutex.lock();
block_SkipBytes(&bytestream, bytes);
block_BytestreamFlush(&bytestream);
bytestream_mutex.unlock();
toconsume = 0;
}
}
void AES3AudioBuffer::tagConsumed(unsigned f)
{
assert(toconsume == 0 || toconsume == f);
toconsume = f;
}
void AES3AudioBuffer::forwardTo(vlc_tick_t t)
{
if(bufferStart() == VLC_TICK_INVALID)
return;
tagConsumed(TicksDurationToFrames(t - bytestream.p_block->i_pts));
}
vlc_tick_t AES3AudioBuffer::bufferStart() const
{
vlc_tick_t start = VLC_TICK_INVALID;
bytestream_mutex.lock();
if(bytestream.p_block)
start = bytestream.p_block->i_pts +
FramesToDuration(BytesToFrames(bytestream.i_block_offset));
bytestream_mutex.unlock();
return start;
}
vlc_tick_t AES3AudioBuffer::bufferEnd() const
{
vlc_tick_t start = bufferStart();
if(start != VLC_TICK_INVALID)
start += CLOCK_FREQ * FramesToDuration(BytesToFrames(block_BytestreamRemaining(&bytestream)));
return start;
}
unsigned AES3AudioBuffer::availableSamples() const
{
bytestream_mutex.lock();
unsigned samples = BytesToFrames(block_BytestreamRemaining(&bytestream));
bytestream_mutex.unlock();
return samples;
}
AES3AudioSubFrameSource::AES3AudioSubFrameSource()
{
aes3AudioBuffer = NULL;
}
AES3AudioSubFrameSource::AES3AudioSubFrameSource(AES3AudioBuffer *buf, AES3AudioSubFrameIndex idx)
{
aes3AudioBuffer = buf;
bufferSubFrameIdx = idx;
}
vlc_tick_t AES3AudioSubFrameSource::bufferStartTime() const
{
if(available())
return VLC_TICK_INVALID;
else return aes3AudioBuffer->bufferStart();
}
void AES3AudioSubFrameSource::copy(void *buf,
unsigned count,
const AES3AudioSubFrameIndex &srcsubframeidx,
unsigned widthinframes)
{
if(aes3AudioBuffer == NULL)
return;
aes3AudioBuffer->read(buf, count, srcsubframeidx, bufferSubFrameIdx, widthinframes);
}
void AES3AudioSubFrameSource::flushConsumed()
{
if(aes3AudioBuffer)
aes3AudioBuffer->flushConsumed();
}
void AES3AudioSubFrameSource::tagConsumed(unsigned count)
{
if(aes3AudioBuffer)
aes3AudioBuffer->tagConsumed(count);
}
const AES3AudioSubFrameIndex & AES3AudioSubFrameSource::index() const
{
return bufferSubFrameIdx;
}
bool AES3AudioSubFrameSource::available() const
{
return aes3AudioBuffer == NULL;
}
unsigned AES3AudioSubFrameSource::availableSamples() const
{
if(aes3AudioBuffer == NULL)
return 0;
return aes3AudioBuffer->availableSamples();
}
AES3AudioFrameSource::AES3AudioFrameSource()
{
}
vlc_tick_t AES3AudioFrameSource::bufferStartTime() const
{
vlc_tick_t ret0 = subframe0.bufferStartTime();
vlc_tick_t ret1 = subframe1.bufferStartTime();
if(ret0 == VLC_TICK_INVALID)
return ret1;
else if(ret1 == VLC_TICK_INVALID || ret1 > ret0)
return ret0;
else
return ret1;
}
unsigned AES3AudioFrameSource::samplesUpToTime(vlc_tick_t t) const
{
int64_t diff = t - bufferStartTime();
if(diff <= 0)
return 0;
return diff / (48000 * 2 * 2);
}
unsigned AES3AudioFrameSource::availableSamples() const
{
if(!subframe0.available() && !subframe1.available())
return std::min(subframe0.availableSamples(), subframe1.availableSamples());
else if(subframe1.available())
return subframe0.availableSamples();
else
return subframe1.availableSamples();
}
void AES3AudioFrameSource::flushConsumed()
{
subframe0.flushConsumed();
subframe1.flushConsumed();
}
void AES3AudioFrameSource::tagConsumed(unsigned samples)
{
subframe0.tagConsumed(samples);
subframe1.tagConsumed(samples);
}
AES3AudioSubFrameIndex::AES3AudioSubFrameIndex(uint8_t v)
{
subframeindex = v;
}
uint8_t AES3AudioSubFrameIndex::index() const
{
return subframeindex;
}
bool AES3AudioSubFrameIndex::isValid() const
{
return subframeindex < MAX_AES3_AUDIO_SUBFRAMES;
}