diff --git a/CMakeLists.txt b/CMakeLists.txt index 6fe1ca7..e9b9969 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,6 +10,7 @@ function(em_file name) -o ${CMAKE_BINARY_DIR}/${name}.js -s WASM=0 -g4 + -s TOTAL_MEMORY=64MB ) endfunction(em_file) diff --git a/decoder.cpp b/decoder.cpp index 8ea3656..0a3bf58 100644 --- a/decoder.cpp +++ b/decoder.cpp @@ -2,30 +2,27 @@ #include Decoder::Decoder(): -state(empty), sampleRate(0), channels(0), cachedLength(0), samplesPerFrame(0), -glue(new uint8_t[GLUE_LENGTH]), -cachedNext(NULL), -cachedThis(NULL), -cachedError(MAD_ERROR_NONE), +buffer(new uint8_t[BUFFER_LENGTH]), cached(false), synth(new mad_synth()), stream(new mad_stream()), frame(new mad_frame()), -context(0), -pending() +context(0) { - for (int i = 0; i < GLUE_LENGTH; ++i) { - glue[i] = 0; + for (int i = 0; i < BUFFER_LENGTH; ++i) { + buffer[i] = 0; } mad_frame_init(frame); mad_stream_init(stream); mad_synth_init(synth); + mad_stream_buffer(stream, buffer, 0); + emscripten::val AudioContext = emscripten::val::global("AudioContext"); if (!AudioContext.as()) { AudioContext = emscripten::val::global("webkitAudioContext"); @@ -46,52 +43,23 @@ Decoder::~Decoder() delete stream; delete frame; - delete[] glue; + delete[] buffer; } void Decoder::addFragment(intptr_t bufferPtr, uint32_t length) { - if (length < GLUE_LENGTH / 2) { - std::cout << "An attempt to add fragment smaller then half of the glue buffer, ignoring"; - return; - } std::cout << "Adding new fragment " << length << " bytes long" << std::endl; - uint8_t* buffer = (uint8_t(*))bufferPtr; - RawBuffer rb = {buffer, length, 0, 0}; - pending.push_back(rb); + uint8_t* bf = (uint8_t(*))bufferPtr; + uint64_t ol = stream->bufend - stream->buffer; - switch (state) { - case empty: - mad_stream_buffer(stream, buffer, length); - - for (int i = 0; i < GLUE_LENGTH/2; ++i) { - glue[i] = buffer[length - GLUE_LENGTH/2 + i]; - } - - state = onBufferHalf; - prepareNextBuffer(); - break; - case onBufferHalf: - for (int i = 0; i < GLUE_LENGTH/2; ++i) { - glue[GLUE_LENGTH/2 + i] = buffer[i]; - } - - state = onBufferFull; - break; - case onBufferFull: - break; - case onGlueHalf: - for (int i = 0; i < GLUE_LENGTH/2; ++i) { - glue[GLUE_LENGTH/2 + i] = buffer[i]; - } - - state = onGlueFull; - cached = false; - prepareNextBuffer(); - break; - case onGlueFull: - break; + for (int i = 0; i < length; ++i) { + buffer[ol + i] = bf[i]; } + //free(bf); + + stream->bufend = stream->bufend + length; + cached = false; + framesLeft(); } emscripten::val Decoder::decode(uint32_t count) @@ -108,7 +76,7 @@ emscripten::val Decoder::decode(uint32_t count) chans[i] = ret.call("getChannelData", i); } - for (int i = 0; success < available; ++i) { + for (int i = 0; i < available; ++i) { int res = mad_frame_decode(frame, stream); if (res == 0) { @@ -137,8 +105,7 @@ emscripten::val Decoder::decode(uint32_t count) std::cout << "Processed " << available << " frames, " << success << " successfully, last error " << mad_stream_errorstr(stream) << std::endl; if (cachedLength == 0) { - cached = false; - prepareNextBuffer(); + framesLeft(); } } @@ -147,20 +114,17 @@ emscripten::val Decoder::decode(uint32_t count) bool Decoder::hasMore() const { - if (pending.size() == 1) { - return stream->error != MAD_ERROR_BUFLEN; - } else { - return true; - } + return stream->bufend != stream->buffer && stream->error != MAD_ERROR_BUFLEN; } uint32_t Decoder::framesLeft(uint32_t max) { - if (state == empty || state == onGlueHalf) { + if (!hasMore()) { return 0; } if (cached == false) { + bool found = false; mad_stream probe; mad_header ph; initializeProbe(probe); @@ -168,6 +132,7 @@ uint32_t Decoder::framesLeft(uint32_t max) while (cachedLength < max) { if (mad_header_decode(&ph, &probe) == 0) { + found = true; if (sampleRate == 0) { sampleRate = ph.samplerate; channels = MAD_NCHANNELS(&ph); @@ -181,6 +146,9 @@ uint32_t Decoder::framesLeft(uint32_t max) ++cachedLength; } } else { + if (!found) { + stream->next_frame = probe.next_frame; + } std::cout << "framesLeft error: " << mad_stream_errorstr(&probe) << std::endl; if (!MAD_RECOVERABLE(probe.error)) { break; @@ -188,9 +156,6 @@ uint32_t Decoder::framesLeft(uint32_t max) } } - cachedNext = probe.next_frame; - cachedThis = probe.this_frame; - cachedError = probe.error; mad_header_finish(&ph); mad_stream_finish(&probe); std::cout << cachedLength << " frames are available for decoding" << std::endl; @@ -200,69 +165,6 @@ uint32_t Decoder::framesLeft(uint32_t max) return std::min(cachedLength, max); } -void Decoder::pullBuffer() -{ - if (cached == false) { - std::cout << "Error in pullBuffer method!" << std::endl; - } - stream->this_frame = cachedThis; - stream->next_frame = cachedNext; - stream->error = cachedError; -} - -void Decoder::changeBuffer() -{ - switch (state) { - case empty: - std::cout << "Wrong state on switchBuffer method - empty, aborting" << std::endl; - case onBufferHalf: - switchToGlue(); - state = onGlueHalf; - break; - case onBufferFull: - switchToGlue(); - state = onGlueFull; - break; - case onGlueHalf: - std::cout << "Wrong state on switchBuffer method - onGlueHalf, aborting" << std::endl; - break; - case onGlueFull: - std::cout << "Having another fragment " << pending[0].length << " bytes long" << std::endl; - - switchBuffer(pending[0].ptr, pending[0].length); - - for (int i = 0; i < GLUE_LENGTH/2; ++i) { - glue[i] = pending[0].ptr[pending[0].length - GLUE_LENGTH/2 + i]; - } - - state = onBufferHalf; - - if (pending.size() > 1) { - for (int i = 0; i < GLUE_LENGTH/2; ++i) { - glue[GLUE_LENGTH/2 + i] = pending[1].ptr[i]; - } - - state = onBufferFull; - } - } - - cached = false; -} - -void Decoder::prepareNextBuffer() -{ - bool shift; - do { - shift = false; - framesLeft(); - if (cachedLength == 0 && state != empty && state != onGlueHalf) { - pullBuffer(); - changeBuffer(); - shift = true; - } - } while (shift); -} - void Decoder::initializeProbe(mad_stream& probe) { mad_stream_init(&probe); @@ -286,37 +188,3 @@ void Decoder::initializeProbe(mad_stream& probe) //probe.options = stream->options; //probe.error = stream->error; } - -void Decoder::switchToGlue() -{ - std::cout << "Switching to glue" << std::endl; - switchBuffer(glue, GLUE_LENGTH); - - std::cout << "Freeing the drained fragment" << std::endl; - free(pending[0].ptr); - pending.pop_front(); -} - -void Decoder::switchBuffer(uint8_t* bufferPtr, uint32_t length) -{ - uint32_t left; - - if (stream->error != MAD_ERROR_BUFLEN) { - std::cout << "WARNING: Switching buffers while the previous one is not drained, error: " << mad_stream_errorstr(stream) << std::endl; - } - if (stream->next_frame != NULL) { - left = stream->bufend - stream->next_frame; - } else { - std::cout << "WARNING: not supposed to happen" << std::endl; - } - - if (left > GLUE_LENGTH / 2) { - std::cout << "Error: bytes to read in the buffer are more then glue buffer can fit (" << left << ")" << std::endl; - throw 1; - } - - mad_stream_buffer(stream, bufferPtr + GLUE_LENGTH / 2 - left, length - (GLUE_LENGTH / 2 - left)); - stream->error = MAD_ERROR_NONE; - - while (mad_header_decode(&frame->header, stream) != 0 && stream->error != MAD_ERROR_BUFLEN) {} -} diff --git a/decoder.h b/decoder.h index 5a8bc9b..7745403 100644 --- a/decoder.h +++ b/decoder.h @@ -9,7 +9,7 @@ #include #include "mad.h" -#define GLUE_LENGTH 6000 +#define BUFFER_LENGTH 30000000 class Decoder { public: @@ -22,32 +22,11 @@ public: uint32_t framesLeft(uint32_t max = UINT32_MAX); private: - - enum State { - empty, - onBufferHalf, - onBufferFull, - onGlueHalf, - onGlueFull - }; - - struct RawBuffer { - uint8_t* ptr; - uint32_t length; - uint32_t offset; - uint32_t gueard; - }; - - State state; - uint32_t sampleRate; uint8_t channels; uint32_t cachedLength; uint16_t samplesPerFrame; - uint8_t* glue; - uint8_t const* cachedNext; - uint8_t const* cachedThis; - mad_error cachedError; + uint8_t* buffer; bool cached; mad_synth* synth; @@ -55,15 +34,9 @@ private: mad_frame* frame; emscripten::val context; - std::deque pending; - private: - void pullBuffer(); - void changeBuffer(); - void prepareNextBuffer(); void initializeProbe(mad_stream& probe); - void switchToGlue(); - void switchBuffer(uint8_t* bufferPtr, uint32_t length); + }; #endif // DECODER_H diff --git a/index.html b/index.html index ca3eaba..1db3e3b 100644 --- a/index.html +++ b/index.html @@ -12,8 +12,8 @@