Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Move the following classes out of transcode.cpp to make things a little cleaner and allow later reuse of the audio and video classes in a HTTP Live Streaming encoder which will not be contained within transcode.cpp. AudioBuffer AudioReencodeBuffer Cutter TranscodeFrameQueue (renamed to VideoDecodeBuffer) There is no new functionality in this patch, only a code re-org.
- Loading branch information
Showing
8 changed files
with
711 additions
and
684 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,228 @@ | ||
|
||
#include "audioreencodebuffer.h" | ||
|
||
extern "C" { | ||
#include "libavutil/mem.h" | ||
} | ||
|
||
|
||
AudioBuffer::AudioBuffer() | ||
: m_frames(0), m_time(-1) | ||
{ | ||
m_size = 0; | ||
m_buffer = (uint8_t *)av_malloc(ABLOCK_SIZE); | ||
if (m_buffer == NULL) | ||
{ | ||
throw std::bad_alloc(); | ||
} | ||
m_realsize = ABLOCK_SIZE; | ||
} | ||
|
||
AudioBuffer::AudioBuffer(const AudioBuffer &old) | ||
: m_size(old.m_size), m_realsize(old.m_realsize), | ||
m_frames(old.m_frames), m_time(old.m_time) | ||
{ | ||
m_buffer = (uint8_t *)av_malloc(m_realsize); | ||
if (m_buffer == NULL) | ||
{ | ||
throw std::bad_alloc(); | ||
} | ||
memcpy(m_buffer, old.m_buffer, m_size); | ||
} | ||
|
||
AudioBuffer::~AudioBuffer() | ||
{ | ||
av_free(m_buffer); | ||
} | ||
|
||
void AudioBuffer::appendData(unsigned char *buffer, int len, int frames, | ||
long long time) | ||
{ | ||
if ((m_size + len) > m_realsize) | ||
{ | ||
// buffer is too small to fit all | ||
// can't use av_realloc as it doesn't guarantee reallocated memory | ||
// to be 16 bytes aligned | ||
m_realsize = ((m_size + len) / ABLOCK_SIZE + 1 ) * ABLOCK_SIZE; | ||
uint8_t *tmp = (uint8_t *)av_malloc(m_realsize); | ||
if (tmp == NULL) | ||
{ | ||
throw std::bad_alloc(); | ||
} | ||
memcpy(tmp, m_buffer, m_size); | ||
av_free(m_buffer); | ||
m_buffer = tmp; | ||
} | ||
|
||
memcpy(m_buffer + m_size, buffer, len); | ||
m_size += len; | ||
m_frames += frames; | ||
m_time = time; | ||
} | ||
|
||
////////////////////////////////////////////////////////////////////////////// | ||
|
||
AudioReencodeBuffer::AudioReencodeBuffer(AudioFormat audio_format, | ||
int audio_channels, bool passthru) | ||
: m_saveBuffer(NULL) | ||
{ | ||
Reset(); | ||
const AudioSettings settings(audio_format, audio_channels, 0, 0, false); | ||
Reconfigure(settings); | ||
m_initpassthru = passthru; | ||
m_audioFrameSize = 0; | ||
} | ||
|
||
AudioReencodeBuffer::~AudioReencodeBuffer() | ||
{ | ||
Reset(); | ||
if (m_saveBuffer) | ||
delete m_saveBuffer; | ||
} | ||
|
||
// reconfigure sound out for new params | ||
void AudioReencodeBuffer::Reconfigure(const AudioSettings &settings) | ||
{ | ||
ClearError(); | ||
|
||
m_passthru = settings.use_passthru; | ||
m_channels = settings.channels; | ||
m_bytes_per_frame = m_channels * | ||
AudioOutputSettings::SampleSize(settings.format); | ||
m_eff_audiorate = settings.samplerate; | ||
} | ||
|
||
// dsprate is in 100 * frames/second | ||
void AudioReencodeBuffer::SetEffDsp(int dsprate) | ||
{ | ||
m_eff_audiorate = (dsprate / 100); | ||
} | ||
|
||
void AudioReencodeBuffer::Reset(void) | ||
{ | ||
QMutexLocker locker(&m_bufferMutex); | ||
foreach (AudioBuffer *ab, m_bufferList) | ||
{ | ||
delete ab; | ||
} | ||
m_bufferList.clear(); | ||
} | ||
|
||
// timecode is in milliseconds. | ||
bool AudioReencodeBuffer::AddFrames(void *buffer, int frames, int64_t timecode) | ||
{ | ||
return AddData(buffer, frames * m_bytes_per_frame, timecode, frames); | ||
} | ||
|
||
// timecode is in milliseconds. | ||
bool AudioReencodeBuffer::AddData(void *buffer, int len, int64_t timecode, | ||
int frames) | ||
{ | ||
unsigned char *buf = (unsigned char *)buffer; | ||
|
||
// Test if target is using a fixed buffer size. | ||
if (m_audioFrameSize) | ||
{ | ||
int index = 0; | ||
|
||
// Target has a fixed buffer size, which may not match len. | ||
// Redistribute the bytes into appropriately sized buffers. | ||
while (index < len) | ||
{ | ||
// See if we have some saved from last iteration in | ||
// m_saveBuffer. If not create a new empty buffer. | ||
if (!m_saveBuffer) | ||
m_saveBuffer = new AudioBuffer(); | ||
|
||
// Use as many of the remaining frames as will fit in the space | ||
// left in the buffer. | ||
int bufsize = m_saveBuffer->size(); | ||
int part = min(len - index, m_audioFrameSize - bufsize); | ||
int out_frames = part / m_bytes_per_frame; | ||
timecode += out_frames * 1000 / m_eff_audiorate; | ||
|
||
// Store frames in buffer, basing frame count on number of | ||
// bytes, which works only for uncompressed data. | ||
m_saveBuffer->appendData(&buf[index], part, | ||
out_frames, timecode); | ||
|
||
// If we have filled the buffer... | ||
if (m_saveBuffer->size() == m_audioFrameSize) | ||
{ | ||
QMutexLocker locker(&m_bufferMutex); | ||
|
||
// store the buffer | ||
m_bufferList.append(m_saveBuffer); | ||
// mark m_saveBuffer as emtpy. | ||
m_saveBuffer = NULL; | ||
// m_last_audiotime is updated iff we store a buffer. | ||
m_last_audiotime = timecode; | ||
} | ||
|
||
index += part; | ||
} | ||
} | ||
else | ||
{ | ||
// Target has no fixed buffer size. We can use a simpler algorithm | ||
// and use 'frames' directly rather than 'len / m_bytes_per_frame', | ||
// thus also covering the passthrough case. | ||
m_saveBuffer = new AudioBuffer(); | ||
timecode += frames * 1000 / m_eff_audiorate; | ||
m_saveBuffer->appendData(buf, len, frames, timecode); | ||
|
||
QMutexLocker locker(&m_bufferMutex); | ||
m_bufferList.append(m_saveBuffer); | ||
m_saveBuffer = NULL; | ||
m_last_audiotime = timecode; | ||
} | ||
|
||
return true; | ||
} | ||
|
||
AudioBuffer *AudioReencodeBuffer::GetData(long long time) | ||
{ | ||
QMutexLocker locker(&m_bufferMutex); | ||
|
||
if (m_bufferList.isEmpty()) | ||
return NULL; | ||
|
||
AudioBuffer *ab = m_bufferList.front(); | ||
|
||
if (ab->m_time <= time) | ||
{ | ||
m_bufferList.pop_front(); | ||
return ab; | ||
} | ||
|
||
return NULL; | ||
} | ||
|
||
long long AudioReencodeBuffer::GetSamples(long long time) | ||
{ | ||
QMutexLocker locker(&m_bufferMutex); | ||
|
||
if (m_bufferList.isEmpty()) | ||
return 0; | ||
|
||
long long samples = 0; | ||
for (QList<AudioBuffer *>::iterator it = m_bufferList.begin(); | ||
it != m_bufferList.end(); ++it) | ||
{ | ||
AudioBuffer *ab = *it; | ||
|
||
if (ab->m_time <= time) | ||
samples += ab->m_frames; | ||
else | ||
break; | ||
} | ||
return samples; | ||
} | ||
|
||
void AudioReencodeBuffer::SetTimecode(int64_t timecode) | ||
{ | ||
m_last_audiotime = timecode; | ||
} | ||
|
||
/* vim: set expandtab tabstop=4 shiftwidth=4: */ | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
#ifndef AUDIOREENCODEBUFFER_H | ||
#define AUDIOREENCODEBUFFER_H | ||
|
||
#include "mythconfig.h" | ||
#include "audiooutput.h" | ||
|
||
#define ABLOCK_SIZE 8192 | ||
|
||
class AudioBuffer | ||
{ | ||
public: | ||
AudioBuffer(); | ||
AudioBuffer(const AudioBuffer &old); | ||
~AudioBuffer(); | ||
|
||
void appendData(unsigned char *buffer, int len, int frames, long long time); | ||
char *data(void) { return (char *)m_buffer; } | ||
int size(void) { return m_size; } | ||
|
||
uint8_t *m_buffer; | ||
int m_size; | ||
int m_realsize; | ||
int m_frames; | ||
long long m_time; | ||
}; | ||
|
||
// This class is to act as a fake audio output device to store the data | ||
// for reencoding. | ||
class AudioReencodeBuffer : public AudioOutput | ||
{ | ||
public: | ||
AudioReencodeBuffer(AudioFormat audio_format, int audio_channels, | ||
bool passthru); | ||
~AudioReencodeBuffer(); | ||
|
||
virtual void Reconfigure(const AudioSettings &settings); | ||
virtual void SetEffDsp(int dsprate); | ||
virtual void Reset(void); | ||
virtual bool AddFrames(void *buffer, int frames, int64_t timecode); | ||
virtual bool AddData(void *buffer, int len, int64_t timecode, | ||
int frames); | ||
AudioBuffer *GetData(long long time); | ||
long long GetSamples(long long time); | ||
virtual void SetTimecode(int64_t timecode); | ||
virtual bool IsPaused(void) const { return false; } | ||
virtual void Pause(bool paused) { (void)paused; } | ||
virtual void PauseUntilBuffered(void) { } | ||
virtual void Drain(void) { } | ||
virtual int64_t GetAudiotime(void) { return m_last_audiotime; } | ||
virtual int GetVolumeChannel(int) const { return 100; } | ||
virtual void SetVolumeChannel(int, int) { } | ||
virtual void SetVolumeAll(int) { } | ||
virtual uint GetCurrentVolume(void) const { return 100; } | ||
virtual void SetCurrentVolume(int) { } | ||
virtual void AdjustCurrentVolume(int) { } | ||
virtual void SetMute(bool) { } | ||
virtual void ToggleMute(void) { } | ||
virtual MuteState GetMuteState(void) const { return kMuteOff; } | ||
virtual MuteState IterateMutedChannels(void) { return kMuteOff; } | ||
virtual bool IsUpmixing(void) { return false; } | ||
virtual bool ToggleUpmix(void) { return false; } | ||
virtual bool CanUpmix(void) { return false; } | ||
virtual void SetSWVolume(int new_volume, bool save) { return; } | ||
virtual int GetSWVolume(void) { return 100; } | ||
virtual bool CanPassthrough(int, int, int, int) const | ||
{ return m_initpassthru; } | ||
|
||
// These are pure virtual in AudioOutput, but we don't need them here | ||
virtual void bufferOutputData(bool) { return; } | ||
virtual int readOutputData(unsigned char*, int ) { return 0; } | ||
|
||
int m_channels; | ||
int m_bits; | ||
int m_bytes_per_frame; | ||
int m_eff_audiorate; | ||
long long m_last_audiotime; | ||
bool m_passthru; | ||
int m_audioFrameSize; | ||
|
||
private: | ||
bool m_initpassthru; | ||
QMutex m_bufferMutex; | ||
QList<AudioBuffer *> m_bufferList; | ||
AudioBuffer *m_saveBuffer; | ||
}; | ||
|
||
#endif | ||
/* vim: set expandtab tabstop=4 shiftwidth=4: */ | ||
|
Oops, something went wrong.