Fix for [#26990] Loading file w packed audio crashes
authorJoerg Mueller <nexyon@gmail.com>
Mon, 18 Apr 2011 14:24:36 +0000 (14:24 +0000)
committerJoerg Mueller <nexyon@gmail.com>
Mon, 18 Apr 2011 14:24:36 +0000 (14:24 +0000)
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
intern/audaspace/ffmpeg/AUD_FFMPEGReader.h
source/blender/editors/sound/sound_ops.c

index 0dc525b0e5a1268fb58256ab0687231d49d77b23..ea6e0c549fa871f606b55aeccd2c80bd378bf1de 100644 (file)
@@ -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<AUD_Buffer> 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<data_t*>(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<AUD_Buffer> buffer) :
 
        AVProbeData probe_data;
        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();
        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<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
 {
        return true;
index 4d8c5e4c46231e4c10ce90795f34cc6805ab4b4f..26e66859451c92ba550bc283d890ac3116bf2d4d 100644 (file)
@@ -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<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.
         * \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;
index a07f4ff0f5f3ac8c31d91ce3ae5d50fe1a0df326..74dbb8f6d12a0f2c19533995595d5c1ce7ef4a11 100644 (file)
@@ -254,7 +254,7 @@ static int sound_unpack_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(even
        if(G.fileflags & G_AUTOPACK)
                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;
 }