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
This commit is contained in:
Joerg Mueller 2011-04-18 14:24:36 +00:00
parent 54f3167270
commit 5f08bfd46c
3 changed files with 59 additions and 8 deletions

@ -172,7 +172,8 @@ static const char* fileopen_error = "AUD_FFMPEGReader: File couldn't be "
AUD_FFMPEGReader::AUD_FFMPEGReader(std::string filename) : AUD_FFMPEGReader::AUD_FFMPEGReader(std::string filename) :
m_pkgbuf(AVCODEC_MAX_AUDIO_FRAME_SIZE<<1), m_pkgbuf(AVCODEC_MAX_AUDIO_FRAME_SIZE<<1),
m_byteiocontext(NULL) m_byteiocontext(NULL),
m_membuf(NULL)
{ {
// open file // open file
if(av_open_input_file(&m_formatCtx, filename.c_str(), NULL, 0, NULL)!=0) 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<AUD_Buffer> buffer) : AUD_FFMPEGReader::AUD_FFMPEGReader(AUD_Reference<AUD_Buffer> buffer) :
m_pkgbuf(AVCODEC_MAX_AUDIO_FRAME_SIZE<<1), 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<data_t*>(av_malloc(FF_MIN_BUFFER_SIZE + FF_INPUT_BUFFER_PADDING_SIZE));
if(init_put_byte(m_byteiocontext, (data_t*)buffer.get()->getBuffer(), m_byteiocontext = av_alloc_put_byte(m_membuf, FF_MIN_BUFFER_SIZE, 0, this,
buffer.get()->getSize(), 0, NULL, NULL, NULL, NULL) != 0) read_packet, NULL, seek_packet);
if(!m_byteiocontext)
{ {
av_free(m_byteiocontext); av_free(m_byteiocontext);
AUD_THROW(AUD_ERROR_FILE, fileopen_error); AUD_THROW(AUD_ERROR_FILE, fileopen_error);
@ -207,7 +211,7 @@ AUD_FFMPEGReader::AUD_FFMPEGReader(AUD_Reference<AUD_Buffer> buffer) :
AVProbeData probe_data; AVProbeData probe_data;
probe_data.filename = ""; probe_data.filename = "";
probe_data.buf = (data_t*)buffer.get()->getBuffer(); probe_data.buf = reinterpret_cast<data_t*>(buffer.get()->getBuffer());
probe_data.buf_size = buffer.get()->getSize(); probe_data.buf_size = buffer.get()->getSize();
AVInputFormat* fmt = av_probe_input_format(&probe_data, 1); AVInputFormat* fmt = av_probe_input_format(&probe_data, 1);
@ -243,6 +247,40 @@ AUD_FFMPEGReader::~AUD_FFMPEGReader()
av_close_input_file(m_formatCtx); av_close_input_file(m_formatCtx);
} }
int AUD_FFMPEGReader::read_packet(void* opaque, uint8_t* buf, int buf_size)
{
AUD_FFMPEGReader* reader = reinterpret_cast<AUD_FFMPEGReader*>(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<AUD_FFMPEGReader*>(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 bool AUD_FFMPEGReader::isSeekable() const
{ {
return true; return true;

@ -106,10 +106,20 @@ private:
AUD_convert_f m_convert; 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<AUD_Buffer> m_membuffer; AUD_Reference<AUD_Buffer> 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. * Decodes a packet into the given buffer.
* \param packet The AVPacket to decode. * \param packet The AVPacket to decode.
@ -149,6 +159,9 @@ public:
*/ */
virtual ~AUD_FFMPEGReader(); 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 bool isSeekable() const;
virtual void seek(int position); virtual void seek(int position);
virtual int getLength() const; virtual int getLength() const;

@ -254,7 +254,7 @@ static int sound_unpack_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(even
if(G.fileflags & G_AUTOPACK) if(G.fileflags & G_AUTOPACK)
BKE_report(op->reports, RPT_WARNING, "AutoPack is enabled, so image will be packed again on file save."); BKE_report(op->reports, RPT_WARNING, "AutoPack is enabled, so image will be packed again on file save.");
unpack_menu(C, "SOUND_OT_unpack", sound->id.name+2, sound->name, "audio", sound->packedfile); unpack_menu(C, "SOUND_OT_unpack", sound->id.name+2, sound->name, "sounds", sound->packedfile);
return OPERATOR_FINISHED; return OPERATOR_FINISHED;
} }