From 5f08bfd46c31bb67780ee4081428be0d22f703ae Mon Sep 17 00:00:00 2001 From: Joerg Mueller Date: Mon, 18 Apr 2011 14:24:36 +0000 Subject: Fix for [#26990] Loading file w packed audio crashes FFMPEG was reallocating buffers it didn't own and wasn't allowed to. This workaround should work now flawlessly. Also fixing a bug regarding unpacking sounds, the UI stated unpacking to //audio/filename while it was unpacking to //sounds/filename --- intern/audaspace/ffmpeg/AUD_FFMPEGReader.cpp | 50 ++++++++++++++++++++++++---- intern/audaspace/ffmpeg/AUD_FFMPEGReader.h | 15 ++++++++- 2 files changed, 58 insertions(+), 7 deletions(-) (limited to 'intern/audaspace/ffmpeg') diff --git a/intern/audaspace/ffmpeg/AUD_FFMPEGReader.cpp b/intern/audaspace/ffmpeg/AUD_FFMPEGReader.cpp index 0dc525b0e5a..ea6e0c549fa 100644 --- a/intern/audaspace/ffmpeg/AUD_FFMPEGReader.cpp +++ b/intern/audaspace/ffmpeg/AUD_FFMPEGReader.cpp @@ -172,7 +172,8 @@ static const char* fileopen_error = "AUD_FFMPEGReader: File couldn't be " AUD_FFMPEGReader::AUD_FFMPEGReader(std::string filename) : m_pkgbuf(AVCODEC_MAX_AUDIO_FRAME_SIZE<<1), - m_byteiocontext(NULL) + m_byteiocontext(NULL), + m_membuf(NULL) { // open file if(av_open_input_file(&m_formatCtx, filename.c_str(), NULL, 0, NULL)!=0) @@ -194,12 +195,15 @@ static const char* streamopen_error = "AUD_FFMPEGReader: Stream couldn't be " AUD_FFMPEGReader::AUD_FFMPEGReader(AUD_Reference buffer) : m_pkgbuf(AVCODEC_MAX_AUDIO_FRAME_SIZE<<1), - m_membuffer(buffer) + m_membuffer(buffer), + m_membufferpos(0) { - m_byteiocontext = (ByteIOContext*)av_mallocz(sizeof(ByteIOContext)); + m_membuf = reinterpret_cast(av_malloc(FF_MIN_BUFFER_SIZE + FF_INPUT_BUFFER_PADDING_SIZE)); - if(init_put_byte(m_byteiocontext, (data_t*)buffer.get()->getBuffer(), - buffer.get()->getSize(), 0, NULL, NULL, NULL, NULL) != 0) + m_byteiocontext = av_alloc_put_byte(m_membuf, FF_MIN_BUFFER_SIZE, 0, this, + read_packet, NULL, seek_packet); + + if(!m_byteiocontext) { av_free(m_byteiocontext); AUD_THROW(AUD_ERROR_FILE, fileopen_error); @@ -207,7 +211,7 @@ AUD_FFMPEGReader::AUD_FFMPEGReader(AUD_Reference buffer) : AVProbeData probe_data; probe_data.filename = ""; - probe_data.buf = (data_t*)buffer.get()->getBuffer(); + probe_data.buf = reinterpret_cast(buffer.get()->getBuffer()); probe_data.buf_size = buffer.get()->getSize(); AVInputFormat* fmt = av_probe_input_format(&probe_data, 1); @@ -243,6 +247,40 @@ AUD_FFMPEGReader::~AUD_FFMPEGReader() av_close_input_file(m_formatCtx); } +int AUD_FFMPEGReader::read_packet(void* opaque, uint8_t* buf, int buf_size) +{ + AUD_FFMPEGReader* reader = reinterpret_cast(opaque); + + int size = AUD_MIN(buf_size, reader->m_membuffer.get()->getSize() - reader->m_membufferpos); + + if(size < 0) + return -1; + + memcpy(buf, ((data_t*)reader->m_membuffer.get()->getBuffer()) + reader->m_membufferpos, size); + reader->m_membufferpos += size; + + return size; +} + +int64_t AUD_FFMPEGReader::seek_packet(void* opaque, int64_t offset, int whence) +{ + AUD_FFMPEGReader* reader = reinterpret_cast(opaque); + + switch(whence) + { + case SEEK_SET: + reader->m_membufferpos = 0; + break; + case SEEK_END: + reader->m_membufferpos = reader->m_membuffer.get()->getSize(); + break; + case AVSEEK_SIZE: + return reader->m_membuffer.get()->getSize(); + } + + return (reader->m_membufferpos += offset); +} + bool AUD_FFMPEGReader::isSeekable() const { return true; diff --git a/intern/audaspace/ffmpeg/AUD_FFMPEGReader.h b/intern/audaspace/ffmpeg/AUD_FFMPEGReader.h index 4d8c5e4c462..26e66859451 100644 --- a/intern/audaspace/ffmpeg/AUD_FFMPEGReader.h +++ b/intern/audaspace/ffmpeg/AUD_FFMPEGReader.h @@ -106,10 +106,20 @@ private: AUD_convert_f m_convert; /** - * The memory file to read from, only saved to keep the buffer alive. + * The memory file to read from. */ AUD_Reference m_membuffer; + /** + * The buffer to read with. + */ + data_t* m_membuf; + + /** + * Reading position of the buffer. + */ + int64_t m_membufferpos; + /** * Decodes a packet into the given buffer. * \param packet The AVPacket to decode. @@ -149,6 +159,9 @@ public: */ virtual ~AUD_FFMPEGReader(); + static int read_packet(void* opaque, uint8_t* buf, int buf_size); + static int64_t seek_packet(void* opaque, int64_t offset, int whence); + virtual bool isSeekable() const; virtual void seek(int position); virtual int getLength() const; -- cgit v1.2.3