mirror of
https://github.com/clangen/musikcube.git
synced 2025-01-30 15:32:37 +00:00
- Added IDecoder::Exhausted() method that returns true if the input
source has been completely depleted, false otherwise - Fixed a memory leak in LogWindow - Fixed CddaDataStream to only allow reading one track at a time. This is a safety mechanism so clients can't thrash the read head. This also means remote clients can stream real-time transcoded CD audio. - Fixed some bugs in TranscodingDataStream where temp files weren't always getting cleaned up properly until a restart
This commit is contained in:
parent
791f923892
commit
78a146aa07
@ -46,6 +46,7 @@ namespace musik { namespace core { namespace sdk {
|
||||
virtual bool GetBuffer(IBuffer *buffer) = 0;
|
||||
virtual double GetDuration() = 0;
|
||||
virtual bool Open(IDataStream *stream) = 0;
|
||||
virtual bool Exhausted() = 0;
|
||||
};
|
||||
|
||||
} } }
|
||||
|
@ -59,6 +59,7 @@ LogWindow::LogWindow(IWindow *parent)
|
||||
}
|
||||
|
||||
LogWindow::~LogWindow() {
|
||||
delete this->adapter;
|
||||
}
|
||||
|
||||
IScrollAdapter& LogWindow::GetScrollAdapter() {
|
||||
|
@ -39,18 +39,8 @@
|
||||
#include <set>
|
||||
#include <mutex>
|
||||
|
||||
#if ENABLE_LOOKAHEAD_BUFFER
|
||||
/* as it turns out having a small lookahead buffer is better than a
|
||||
large one. if the buffer is too large, the device seems to start to
|
||||
power down, then takes a while to power back up. we just want a little
|
||||
but of wiggle room, but to generally keep the device reading small
|
||||
chunks of data constantly. */
|
||||
#define MAX_SECTORS_IN_LOOKAHEAD 20
|
||||
#define MAX_SECTORS_PER_READ 10
|
||||
#define BUFFER_SIZE_BYTES (MAX_SECTORS_IN_LOOKAHEAD * BYTES_PER_SECTOR)
|
||||
#endif
|
||||
|
||||
static std::mutex driveAccessMutex; /* one track can read at a time */
|
||||
static CddaDataStream* activeRead = nullptr;
|
||||
|
||||
CddaDataStream::CddaDataStream() {
|
||||
this->closed = false;
|
||||
@ -58,11 +48,6 @@ CddaDataStream::CddaDataStream() {
|
||||
this->position = this->length = 0;
|
||||
memset(&this->toc, 0, sizeof(this->toc));
|
||||
this->startSector = this->stopSector = 0;
|
||||
|
||||
#if ENABLE_LOOKAHEAD_BUFFER
|
||||
this->lookahead = new char[BUFFER_SIZE_BYTES];
|
||||
this->lookaheadOffset = this->lookaheadTotal = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
CddaDataStream::~CddaDataStream() {
|
||||
@ -154,8 +139,14 @@ bool CddaDataStream::Close() {
|
||||
this->drive = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
this->closed = true;
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(driveAccessMutex);
|
||||
if (activeRead == this) {
|
||||
activeRead = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
this->closed = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -168,6 +159,17 @@ void CddaDataStream::Destroy() {
|
||||
}
|
||||
|
||||
PositionType CddaDataStream::Read(void* buffer, PositionType readBytes) {
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(driveAccessMutex);
|
||||
if (activeRead == nullptr) {
|
||||
activeRead = this;
|
||||
}
|
||||
}
|
||||
|
||||
if (activeRead != this) {
|
||||
return (PositionType) ReadError::DeviceBusy;
|
||||
}
|
||||
|
||||
if (this->position >= this->length) {
|
||||
return 0;
|
||||
}
|
||||
@ -187,12 +189,6 @@ bool CddaDataStream::SetPosition(PositionType position) {
|
||||
this->position++;
|
||||
}
|
||||
|
||||
#if ENABLE_LOOKAHEAD_BUFFER
|
||||
this->RefillInternalBuffer();
|
||||
this->lookaheadOffset = 0;
|
||||
Sleep(250);
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -220,70 +216,12 @@ const char* CddaDataStream::Uri() {
|
||||
return uri.c_str();
|
||||
}
|
||||
|
||||
#if ENABLE_LOOKAHEAD_BUFFER
|
||||
void CddaDataStream::RefillInternalBuffer() {
|
||||
std::unique_lock<std::mutex> lock(driveAccessMutex);
|
||||
|
||||
LONGLONG pos = this->position;
|
||||
int iterations = MAX_SECTORS_IN_LOOKAHEAD / MAX_SECTORS_PER_READ;
|
||||
DWORD totalBytesRead = 0;
|
||||
|
||||
RAW_READ_INFO rawReadInfo = { 0 };
|
||||
rawReadInfo.SectorCount = MAX_SECTORS_PER_READ;
|
||||
rawReadInfo.TrackMode = CDDA;
|
||||
|
||||
DWORD bytesActuallyRead = 0;
|
||||
|
||||
while (iterations > 0) {
|
||||
UINT sectorOffset = this->startSector + (int)(pos / BYTES_PER_SECTOR);
|
||||
rawReadInfo.DiskOffset.QuadPart = sectorOffset * 2048;
|
||||
|
||||
DeviceIoControl(
|
||||
this->drive,
|
||||
IOCTL_CDROM_RAW_READ,
|
||||
&rawReadInfo,
|
||||
sizeof(rawReadInfo),
|
||||
&this->lookahead[totalBytesRead],
|
||||
BYTES_PER_SECTOR * MAX_SECTORS_PER_READ,
|
||||
&bytesActuallyRead,
|
||||
0);
|
||||
|
||||
totalBytesRead += bytesActuallyRead;
|
||||
pos += bytesActuallyRead;
|
||||
|
||||
if (totalBytesRead == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
--iterations;
|
||||
}
|
||||
|
||||
this->lookaheadOffset = 0;
|
||||
this->lookaheadTotal = totalBytesRead;
|
||||
}
|
||||
#endif
|
||||
|
||||
HRESULT CddaDataStream::Read(PBYTE pbBuffer, DWORD dwBytesToRead, BOOL bAlign, LPDWORD pdwBytesRead) {
|
||||
if (this->closed) {
|
||||
pdwBytesRead = 0;
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
#if ENABLE_LOOKAHEAD_BUFFER
|
||||
size_t avail = this->lookaheadTotal - this->lookaheadOffset;
|
||||
|
||||
if (avail == 0) {
|
||||
this->RefillInternalBuffer();
|
||||
avail = this->lookaheadTotal;
|
||||
}
|
||||
|
||||
DWORD readSize = min(avail, (size_t) dwBytesToRead);
|
||||
if (readSize >= 0) {
|
||||
memcpy(pbBuffer, &this->lookahead[this->lookaheadOffset], readSize);
|
||||
this->position += readSize;
|
||||
this->lookaheadOffset += readSize;
|
||||
}
|
||||
#else
|
||||
DWORD readSize = 0;
|
||||
LONGLONG pos = this->position;
|
||||
UINT sectorOffset = this->startSector + (int)(pos / BYTES_PER_SECTOR);
|
||||
@ -304,7 +242,6 @@ HRESULT CddaDataStream::Read(PBYTE pbBuffer, DWORD dwBytesToRead, BOOL bAlign, L
|
||||
0);
|
||||
|
||||
this->position += readSize;
|
||||
#endif
|
||||
|
||||
if (pdwBytesRead) {
|
||||
*pdwBytesRead = readSize;
|
||||
|
@ -37,13 +37,16 @@
|
||||
#include "ntddcdrm.h"
|
||||
#include "devioctl.h"
|
||||
#include <string>
|
||||
|
||||
#define ENABLE_LOOKAHEAD_BUFFER 0
|
||||
#include <mutex>
|
||||
|
||||
using namespace musik::core::sdk;
|
||||
|
||||
class CddaDataStream : public IDataStream {
|
||||
public:
|
||||
enum class ReadError : int {
|
||||
DeviceBusy = -128
|
||||
};
|
||||
|
||||
CddaDataStream();
|
||||
~CddaDataStream();
|
||||
|
||||
@ -73,11 +76,4 @@ class CddaDataStream : public IDataStream {
|
||||
UINT firstSector, startSector, stopSector;
|
||||
unsigned long channels;
|
||||
volatile bool closed;
|
||||
|
||||
#if ENABLE_LOOKAHEAD_BUFFER
|
||||
char* lookahead;
|
||||
DWORD lookaheadOffset;
|
||||
DWORD lookaheadTotal;
|
||||
void RefillInternalBuffer();
|
||||
#endif
|
||||
};
|
@ -43,6 +43,7 @@ CddaDecoder::CddaDecoder() {
|
||||
this->duration = -1.0f;
|
||||
this->data = nullptr;
|
||||
this->buffer = new BYTE[CDDA_BUFFER_SIZE];
|
||||
this->exhausted = false;
|
||||
}
|
||||
|
||||
CddaDecoder::~CddaDecoder() {
|
||||
@ -87,6 +88,11 @@ bool CddaDecoder::GetBuffer(IBuffer *buffer) {
|
||||
PositionType count = this->data->Read(
|
||||
(void *) this->buffer, CDDA_BUFFER_SIZE);
|
||||
|
||||
if (count == (PositionType) CddaDataStream::ReadError::DeviceBusy) {
|
||||
this->exhausted = false; /* stream not exhausted, waiting for data */
|
||||
return false;
|
||||
}
|
||||
|
||||
if (count > 0) {
|
||||
short* t = (short*) this->buffer;
|
||||
|
||||
@ -99,5 +105,6 @@ bool CddaDecoder::GetBuffer(IBuffer *buffer) {
|
||||
return true;
|
||||
}
|
||||
|
||||
this->exhausted = true;
|
||||
return false;
|
||||
}
|
||||
|
@ -47,14 +47,16 @@ class CddaDecoder : public IDecoder {
|
||||
CddaDecoder();
|
||||
~CddaDecoder();
|
||||
|
||||
virtual bool Open(IDataStream* data);
|
||||
virtual void Destroy();
|
||||
virtual double SetPosition(double seconds);
|
||||
virtual double GetDuration();
|
||||
virtual bool GetBuffer(IBuffer *buffer);
|
||||
virtual bool Open(IDataStream* data) override;
|
||||
virtual void Destroy() override;
|
||||
virtual double SetPosition(double seconds) override;
|
||||
virtual double GetDuration() override;
|
||||
virtual bool GetBuffer(IBuffer *buffer) override;
|
||||
virtual bool Exhausted() override { return this->exhausted; }
|
||||
|
||||
private:
|
||||
CddaDataStream* data;
|
||||
double duration;
|
||||
BYTE* buffer;
|
||||
bool exhausted;
|
||||
};
|
||||
|
@ -47,7 +47,8 @@ FlacDecoder::FlacDecoder()
|
||||
, sampleRate(0)
|
||||
, bitsPerSample(0)
|
||||
, totalSamples(0)
|
||||
, duration(-1.0f) {
|
||||
, duration(-1.0f)
|
||||
, exhausted(false) {
|
||||
this->decoder = FLAC__stream_decoder_new();
|
||||
}
|
||||
|
||||
@ -62,18 +63,21 @@ FlacDecoder::~FlacDecoder() {
|
||||
}
|
||||
|
||||
FLAC__StreamDecoderReadStatus FlacDecoder::FlacRead(
|
||||
const FLAC__StreamDecoder *decoder,
|
||||
const FLAC__StreamDecoder *dec,
|
||||
FLAC__byte buffer[],
|
||||
size_t *bytes,
|
||||
void *clientData)
|
||||
{
|
||||
size_t readBytes = (size_t)((FlacDecoder*) clientData)->stream->Read(buffer,(long)(*bytes));
|
||||
auto decoder = (FlacDecoder*) clientData;
|
||||
size_t readBytes = (size_t) decoder->stream->Read(buffer,(long)(*bytes));
|
||||
*bytes = readBytes;
|
||||
|
||||
if (readBytes == 0) {
|
||||
decoder->exhausted = true;
|
||||
return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
|
||||
}
|
||||
else if(readBytes == (size_t) -1) {
|
||||
else if (readBytes == (size_t) -1) {
|
||||
decoder->exhausted = true;
|
||||
return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
|
||||
}
|
||||
|
||||
|
@ -47,11 +47,12 @@ class FlacDecoder : public musik::core::sdk::IDecoder {
|
||||
FlacDecoder();
|
||||
~FlacDecoder();
|
||||
|
||||
virtual void Destroy();
|
||||
virtual double SetPosition(double seconds);
|
||||
virtual bool GetBuffer(IBuffer *buffer);
|
||||
virtual double GetDuration();
|
||||
virtual bool Open(musik::core::sdk::IDataStream *stream);
|
||||
virtual void Destroy() override;
|
||||
virtual double SetPosition(double seconds) override;
|
||||
virtual bool GetBuffer(IBuffer *buffer) override;
|
||||
virtual double GetDuration() override;
|
||||
virtual bool Open(musik::core::sdk::IDataStream *stream) override;
|
||||
virtual bool Exhausted() override { return this->exhausted; }
|
||||
|
||||
private:
|
||||
static FLAC__StreamDecoderReadStatus FlacRead(
|
||||
@ -104,6 +105,7 @@ class FlacDecoder : public musik::core::sdk::IDecoder {
|
||||
uint64_t totalSamples;
|
||||
int bitsPerSample;
|
||||
double duration;
|
||||
bool exhausted;
|
||||
|
||||
float *outputBuffer;
|
||||
unsigned long outputBufferSize;
|
||||
|
@ -83,6 +83,7 @@ M4aDecoder::M4aDecoder() {
|
||||
this->decoderFile = nullptr;
|
||||
memset(&decoderCallbacks, 0, sizeof(this->decoderCallbacks));
|
||||
this->duration = -1.0f;
|
||||
this->exhausted = false;
|
||||
}
|
||||
|
||||
M4aDecoder::~M4aDecoder() {
|
||||
@ -90,7 +91,9 @@ M4aDecoder::~M4aDecoder() {
|
||||
|
||||
bool M4aDecoder::Open(musik::core::sdk::IDataStream *stream) {
|
||||
decoder = NeAACDecOpen();
|
||||
|
||||
if (!decoder) {
|
||||
this->exhausted = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -177,63 +180,57 @@ double M4aDecoder::GetDuration() {
|
||||
}
|
||||
|
||||
bool M4aDecoder::GetBuffer(IBuffer* target) {
|
||||
if (this->decoderSampleId < 0) {
|
||||
return false;
|
||||
if (this->decoderSampleId >= 0) {
|
||||
void* sampleBuffer = NULL;
|
||||
unsigned char* encodedData = NULL;
|
||||
unsigned int encodedDataLength = 0;
|
||||
NeAACDecFrameInfo frameInfo;
|
||||
|
||||
long duration = mp4ff_get_sample_duration(
|
||||
decoderFile, audioTrackId, decoderSampleId);
|
||||
|
||||
if (duration > 0) {
|
||||
/* read the raw data required */
|
||||
|
||||
int rc =
|
||||
mp4ff_read_sample(
|
||||
decoderFile,
|
||||
audioTrackId,
|
||||
decoderSampleId,
|
||||
&encodedData,
|
||||
&encodedDataLength);
|
||||
|
||||
decoderSampleId++;
|
||||
|
||||
if (rc == 0 || encodedData == NULL) {
|
||||
this->exhausted = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
sampleBuffer =
|
||||
NeAACDecDecode(
|
||||
decoder,
|
||||
&frameInfo,
|
||||
encodedData,
|
||||
encodedDataLength);
|
||||
|
||||
free(encodedData);
|
||||
|
||||
if (frameInfo.error <= 0 && decoderSampleId <= this->totalSamples) {
|
||||
target->SetSampleRate(frameInfo.samplerate);
|
||||
target->SetChannels(frameInfo.channels);
|
||||
target->SetSamples(frameInfo.samples);
|
||||
|
||||
memcpy(
|
||||
static_cast<void*>(target->BufferPointer()),
|
||||
static_cast<void*>(sampleBuffer),
|
||||
sizeof(float) * frameInfo.samples);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void* sampleBuffer = NULL;
|
||||
unsigned char* encodedData = NULL;
|
||||
unsigned int encodedDataLength = 0;
|
||||
NeAACDecFrameInfo frameInfo;
|
||||
|
||||
long duration = mp4ff_get_sample_duration(
|
||||
decoderFile, audioTrackId, decoderSampleId);
|
||||
|
||||
if (duration <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* read the raw data required */
|
||||
|
||||
int rc =
|
||||
mp4ff_read_sample(
|
||||
decoderFile,
|
||||
audioTrackId,
|
||||
decoderSampleId,
|
||||
&encodedData,
|
||||
&encodedDataLength);
|
||||
|
||||
decoderSampleId++;
|
||||
|
||||
if (rc == 0 || encodedData == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
sampleBuffer =
|
||||
NeAACDecDecode(
|
||||
decoder,
|
||||
&frameInfo,
|
||||
encodedData,
|
||||
encodedDataLength);
|
||||
|
||||
free(encodedData);
|
||||
|
||||
if (frameInfo.error > 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (decoderSampleId > this->totalSamples) {
|
||||
return false;
|
||||
}
|
||||
|
||||
target->SetSampleRate(frameInfo.samplerate);
|
||||
target->SetChannels(frameInfo.channels);
|
||||
target->SetSamples(frameInfo.samples);
|
||||
|
||||
memcpy(
|
||||
static_cast<void*>(target->BufferPointer()),
|
||||
static_cast<void*>(sampleBuffer),
|
||||
sizeof(float) * frameInfo.samples);
|
||||
|
||||
return true;
|
||||
this->exhausted = true;
|
||||
return false;
|
||||
}
|
||||
|
@ -43,11 +43,12 @@ class M4aDecoder : public musik::core::sdk::IDecoder {
|
||||
M4aDecoder();
|
||||
~M4aDecoder();
|
||||
|
||||
virtual void Destroy();
|
||||
virtual double SetPosition(double seconds);
|
||||
virtual bool GetBuffer(musik::core::sdk::IBuffer *buffer);
|
||||
virtual double GetDuration();
|
||||
virtual bool Open(musik::core::sdk::IDataStream *stream);
|
||||
virtual void Destroy() override;
|
||||
virtual double SetPosition(double seconds) override;
|
||||
virtual bool GetBuffer(musik::core::sdk::IBuffer *buffer) override;
|
||||
virtual double GetDuration() override;
|
||||
virtual bool Open(musik::core::sdk::IDataStream *stream) override;
|
||||
virtual bool Exhausted() override { return this->exhausted; }
|
||||
|
||||
private:
|
||||
NeAACDecHandle decoder;
|
||||
@ -59,4 +60,5 @@ class M4aDecoder : public musik::core::sdk::IDecoder {
|
||||
unsigned char channelCount;
|
||||
long decoderSampleId;
|
||||
double duration;
|
||||
bool exhausted;
|
||||
};
|
||||
|
@ -77,6 +77,7 @@ static int nomadClose(void *datasource) {
|
||||
}
|
||||
|
||||
NomadDecoder::NomadDecoder() {
|
||||
this->exhausted = false;
|
||||
this->duration = -1.0f;
|
||||
this->nomadContext = nullptr;
|
||||
this->callbacks.read = &nomadRead;
|
||||
@ -118,7 +119,12 @@ bool NomadDecoder::GetBuffer(IBuffer *buffer) {
|
||||
buffer->SetSamples(read > 0 ? read : 0);
|
||||
buffer->SetSampleRate(info->sample_rate);
|
||||
|
||||
return (read > 0) ? true : false;
|
||||
if (read > 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
this->exhausted = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool NomadDecoder::Open(IDataStream *stream) {
|
||||
@ -148,7 +154,12 @@ bool NomadDecoder::Open(IDataStream *stream) {
|
||||
this->nomadContext = nullptr;
|
||||
}
|
||||
|
||||
return result ? false : true;
|
||||
if (!result) {
|
||||
return true;
|
||||
}
|
||||
|
||||
this->exhausted = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
/* adapted from http://stackoverflow.com/a/3520427 */
|
||||
|
@ -46,15 +46,16 @@ class NomadDecoder : public musik::core::sdk::IDecoder {
|
||||
NomadDecoder();
|
||||
~NomadDecoder();
|
||||
|
||||
virtual bool Open(musik::core::sdk::IDataStream *dataStream);
|
||||
virtual double SetPosition(double seconds);
|
||||
virtual bool GetBuffer(musik::core::sdk::IBuffer *buffer);
|
||||
virtual double GetDuration();
|
||||
virtual void Destroy();
|
||||
virtual bool Open(musik::core::sdk::IDataStream *dataStream) override;
|
||||
virtual double SetPosition(double seconds) override;
|
||||
virtual bool GetBuffer(musik::core::sdk::IBuffer *buffer) override;
|
||||
virtual double GetDuration() override;
|
||||
virtual void Destroy() override;
|
||||
virtual bool Exhausted() override { return this->exhausted; }
|
||||
|
||||
private:
|
||||
size_t GetId3v2HeaderLength(musik::core::sdk::IDataStream *stream);
|
||||
|
||||
bool exhausted;
|
||||
double duration;
|
||||
nomad_callbacks callbacks;
|
||||
nomad *nomadContext;
|
||||
|
@ -39,6 +39,7 @@
|
||||
|
||||
OggDecoder::OggDecoder() {
|
||||
this->duration = -1.0f;
|
||||
this->exhausted = false;
|
||||
this->oggCallbacks.read_func = &OggRead;
|
||||
this->oggCallbacks.seek_func = &OggSeek;
|
||||
this->oggCallbacks.tell_func = &OggTell;
|
||||
@ -99,6 +100,7 @@ bool OggDecoder::Open(musik::core::sdk::IDataStream *fileStream) {
|
||||
this->fileStream = fileStream;
|
||||
|
||||
if (ov_open_callbacks(this, &this->oggFile, NULL, 0, this->oggCallbacks) != 0) {
|
||||
this->exhausted = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -137,6 +139,7 @@ bool OggDecoder::GetBuffer(IBuffer *buffer) {
|
||||
&bitstream);
|
||||
|
||||
if (samplesRead == 0) {
|
||||
this->exhausted = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -45,11 +45,12 @@ class OggDecoder : public IDecoder {
|
||||
OggDecoder();
|
||||
~OggDecoder();
|
||||
|
||||
virtual void Destroy();
|
||||
virtual double SetPosition(double second);
|
||||
virtual bool GetBuffer(IBuffer *buffer);
|
||||
virtual double GetDuration();
|
||||
virtual bool Open(musik::core::sdk::IDataStream *fileStream);
|
||||
virtual void Destroy() override;
|
||||
virtual double SetPosition(double second) override;
|
||||
virtual bool GetBuffer(IBuffer *buffer) override;
|
||||
virtual double GetDuration() override;
|
||||
virtual bool Open(musik::core::sdk::IDataStream *fileStream) override;
|
||||
virtual bool Exhausted() { return this->exhausted; }
|
||||
|
||||
/* libvorbis callbacks */
|
||||
static size_t OggRead(void *buffer, size_t nofParts, size_t partSize, void *datasource);
|
||||
@ -59,6 +60,7 @@ class OggDecoder : public IDecoder {
|
||||
|
||||
private:
|
||||
musik::core::sdk::IDataStream *fileStream;
|
||||
bool exhausted;
|
||||
OggVorbis_File oggFile;
|
||||
ov_callbacks oggCallbacks;
|
||||
double duration;
|
||||
|
@ -215,6 +215,10 @@ PositionType TranscodingDataStream::Read(void *buffer, PositionType bytesToRead)
|
||||
hasBuffer = this->decoder->GetBuffer(this->pcmBuffer);
|
||||
}
|
||||
|
||||
if (!hasBuffer && !decoder->Exhausted()) {
|
||||
goto internal_error;
|
||||
}
|
||||
|
||||
/* done with spillover. read new data... */
|
||||
while (hasBuffer && bytesWritten < (size_t) bytesToRead) {
|
||||
/* calculated according to lame.h */
|
||||
@ -314,26 +318,36 @@ PositionType TranscodingDataStream::Read(void *buffer, PositionType bytesToRead)
|
||||
if (bytesWritten == 0) {
|
||||
encodedBytes.reset();
|
||||
|
||||
size_t count = lame_encode_flush(
|
||||
/* 7200 bytes minimum is required for the flush op; see lame.h */
|
||||
if (encodedBytes.length < 7200) {
|
||||
encodedBytes.realloc(7200);
|
||||
}
|
||||
|
||||
int count = lame_encode_flush(
|
||||
lame,
|
||||
encodedBytes.data,
|
||||
encodedBytes.length);
|
||||
|
||||
memcpy(dst + bytesWritten, encodedBytes.data, count);
|
||||
this->eof = true;
|
||||
|
||||
if (this->outFile) {
|
||||
fwrite(encodedBytes.data, 1, count, this->outFile);
|
||||
fclose(this->outFile);
|
||||
this->outFile = nullptr;
|
||||
if (count >= 0) {
|
||||
memcpy(dst + bytesWritten, encodedBytes.data, count);
|
||||
|
||||
boost::system::error_code ec;
|
||||
boost::filesystem::rename(this->tempFilename, this->finalFilename, ec);
|
||||
if (ec) {
|
||||
boost::filesystem::remove(this->tempFilename, ec);
|
||||
if (this->outFile) {
|
||||
fwrite(encodedBytes.data, 1, count, this->outFile);
|
||||
fclose(this->outFile);
|
||||
this->outFile = nullptr;
|
||||
|
||||
boost::system::error_code ec;
|
||||
boost::filesystem::rename(this->tempFilename, this->finalFilename, ec);
|
||||
if (ec) {
|
||||
boost::filesystem::remove(this->tempFilename, ec);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this->eof = true;
|
||||
else {
|
||||
goto internal_error;
|
||||
}
|
||||
}
|
||||
|
||||
this->position += bytesWritten;
|
||||
@ -343,6 +357,8 @@ internal_error:
|
||||
this->eof = true;
|
||||
fclose(this->outFile);
|
||||
this->outFile = nullptr;
|
||||
boost::system::error_code ec;
|
||||
boost::filesystem::remove(this->tempFilename, ec);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user