[prev in list] [next in list] [prev in thread] [next in thread] 

List:       gnash-commit
Subject:    [Gnash-commit] buildbot failure in Gnash on sid-linux-i386
From:       buildbot () gnashdev ! org
Date:       2011-08-20 22:04:31
Message-ID: 201108202204.p7KM4Vks031378 () mx1 ! gnashdev ! org
[Download RAW message or body]

[Attachment #2 (text/plain)]

The Buildbot has detected a new failure on builder sid-linux-i386 while building Gnash.
Full details are available at:
 http://gnashdev.org:8010/builders/sid-linux-i386/builds/153

Buildbot URL: http://gnashdev.org:8010/

Buildslave for this Build: sid-linux-i386

Build Reason: 'try' job
Build Source Stamp: [branch master] HEAD (plus patch)
Blamelist: 

BUILD FAILED: failed git

sincerely,
 -The Buildbot




["source patch 0" (text/plain)]

diff --git a/configure.ac b/configure.ac
index 0f00b6c..aae1563 100644
--- a/configure.ac
+++ b/configure.ac
@@ -784,6 +784,15 @@ if test x"$build_media_ffmpeg" != x"no"; then # yes or auto
   fi
 fi
 
+dnl This method of checking is most likely not good enough.
+OLDLIBS="$LIBS"
+LIBS="$FFMPEG_LIBS"
+AC_CHECK_FUNCS(avcodec_decode_audio2)
+AC_CHECK_FUNCS(avcodec_decode_audio3)
+AC_CHECK_FUNCS(av_parser_parse)
+AC_CHECK_FUNCS(av_parser_parse2)
+LIBS="$OLDLIBS"
+
 MEDIA_CONFIG="${media_list}"
 AC_SUBST(MEDIA_CONFIG)
 
@@ -1117,6 +1126,12 @@ AM_CONDITIONAL(HAVE_PERL, test x"$PERL" != x)
 AC_PATH_PROG(CSOUND, csound)
 AM_CONDITIONAL(HAVE_CSOUND, test x"$CSOUND" != x)
 
+AC_PATH_PROG(FFMPEG, ffmpeg)
+AM_CONDITIONAL(HAVE_FFMPEG, test x"$FFMPEG" != x)
+
+AC_PATH_PROG(LAME, lame)
+AM_CONDITIONAL(HAVE_LAME, test x"$LAME" != x)
+
 AC_PATH_PROG(GIT, git)
 AC_SUBST(GIT)
 
@@ -3567,7 +3582,7 @@ fi
   if test x"$PERL" != x; then
     echo "        PERL is $PERL"
   else
-    PKG_WAR([You need to have perl installed to run some of the tests in Gnash \
testsuite.]) +    PKG_WAR([You need to have perl installed to run some of the tests \
in the Gnash testsuite.])  PKG_SUGGEST([Install it from http://perl.org])
     DEB_INSTALL([perl])
     RPM_INSTALL([perl])
@@ -3576,6 +3591,29 @@ fi
 if test x"$testsuite" = x"yes"; then
   if test x"$CSOUND" != x; then
     echo "        CSOUND is $CSOUND"
+  else
+    PKG_WAR([You need to have csound installed to run some of the tests in the Gnash \
testsuite.]) +    PKG_SUGGEST([Install it from http://csounds.com])
+    DEB_INSTALL([csound])
+    RPM_INSTALL([csound])
+  fi
+
+  if test x"$FFMPEG" != x; then
+    echo "        FFMPEG is $FFMPEG"
+  else
+    PKG_WAR([You need to have ffmpeg installed to run some of the tests in the Gnash \
testsuite.]) +    PKG_SUGGEST([Install it from http://ffmpeg.org])
+    DEB_INSTALL([ffmpeg])
+    RPM_INSTALL([ffmpeg])
+  fi
+
+  if test x"$LAME" != x; then
+    echo "        LAME is $LAME"
+  else
+    PKG_WAR([You need to have lame installed to run some of the tests in Gnash the \
testsuite.]) +    PKG_SUGGEST([Install it from http://lame.sourceforge.net/])
+    DEB_INSTALL([lame])
+    RPM_INSTALL([lame])
   fi
 fi
 
diff --git a/libcore/asobj/NetStream_as.cpp b/libcore/asobj/NetStream_as.cpp
index 3c453b5..8eb5244 100644
--- a/libcore/asobj/NetStream_as.cpp
+++ b/libcore/asobj/NetStream_as.cpp
@@ -662,10 +662,18 @@ NetStream_as::decodeNextAudioFrame()
         return 0;
     }
 
+#ifdef GNASH_DEBUG_DECODING
+    int framesize = frame->dataSize;
+#endif
+    boost::uint32_t datasize;
+    boost::uint8_t* data = _audioDecoder->decode(frame, datasize);
+    if ( data == 0 ) { return 0; }
+
     // TODO: make the buffer cursored later ?
     BufferedAudioStreamer::CursoredBuffer* raw =
         new BufferedAudioStreamer::CursoredBuffer();
-    raw->m_data = _audioDecoder->decode(*frame, raw->m_size);
+    raw->m_data = data;
+    raw->m_size = datasize;
 
     // TODO: let the sound_handler do this .. sounds cleaner
     if (_audioController) {
@@ -687,7 +695,7 @@ NetStream_as::decodeNextAudioFrame()
     log_debug("NetStream_as::decodeNextAudioFrame: "
         "%d bytes of encoded audio "
         "decoded to %d bytes",
-        frame->dataSize,
+        framesize,
         raw->m_size);
 #endif 
 
diff --git a/libcore/asobj/Sound_as.cpp b/libcore/asobj/Sound_as.cpp
index 5ec4559..c3e150e 100644
--- a/libcore/asobj/Sound_as.cpp
+++ b/libcore/asobj/Sound_as.cpp
@@ -849,10 +849,11 @@ Sound_as::getAudio(boost::int16_t* samples, unsigned int \
nSamples, bool& atEOF)  continue;
             }
 
-            _leftOverData.reset( _audioDecoder->decode(*frame, _leftOverSize) );
+            _leftOverData.reset( _audioDecoder->decode(frame, _leftOverSize) );
             _leftOverPtr = _leftOverData.get();
             if ( ! _leftOverData ) {
-                log_error("No samples decoded from input of %d bytes", \
frame->dataSize); +                log_error("Error during audio decoding");
+                atEOF=true;
                 continue;
             }
 
diff --git a/libmedia/AudioDecoder.h b/libmedia/AudioDecoder.h
index 8c34ff8..a90bc76 100644
--- a/libmedia/AudioDecoder.h
+++ b/libmedia/AudioDecoder.h
@@ -19,6 +19,7 @@
 #ifndef GNASH_AUDIODECODER_H
 #define GNASH_AUDIODECODER_H
 
+#include <memory>
 #include <boost/cstdint.hpp> // for C99 int types
 
 // Forward declarations
@@ -75,10 +76,12 @@ public:
 	///
 	/// @return a pointer to the decoded data, or NULL if decoding fails.
 	///     The caller owns the decoded data, which was allocated with new [].
+	///     If no data is available yet, the function returns a buffer of size
+	///     of size 0 allocated with new [].
 	///
 	/// @todo return a SimpleBuffer by auto_ptr
 	///
-	virtual boost::uint8_t* decode(const EncodedAudioFrame& input,
+	virtual boost::uint8_t* decode(std::auto_ptr<EncodedAudioFrame> input,
 	                               boost::uint32_t& outputSize);
 
 };
@@ -91,7 +94,7 @@ AudioDecoder::decode(const boost::uint8_t*, boost::uint32_t, \
boost::uint32_t&,  }
 
 inline boost::uint8_t*
-AudioDecoder::decode(const EncodedAudioFrame&, boost::uint32_t&)
+AudioDecoder::decode(std::auto_ptr<EncodedAudioFrame>, boost::uint32_t&)
 {
     return 0;
 }
diff --git a/libmedia/MediaParser.h b/libmedia/MediaParser.h
index 5a32431..69a7adb 100644
--- a/libmedia/MediaParser.h
+++ b/libmedia/MediaParser.h
@@ -419,9 +419,12 @@ public:
 	boost::uint32_t dataSize;
 	boost::scoped_array<boost::uint8_t> data;
 	boost::uint64_t timestamp;
+    int dataAlreadyUsed;
 
 	// FIXME: should have better encapsulation for this sort of stuff.
 	std::auto_ptr<EncodedExtraData> extradata;
+
+    EncodedAudioFrame() : dataAlreadyUsed(0) { }
 };
 
 /// The MediaParser class provides cursor-based access to encoded %media frames 
diff --git a/libmedia/ffmpeg/AudioDecoderFfmpeg.cpp \
b/libmedia/ffmpeg/AudioDecoderFfmpeg.cpp index 2b1ce0e..1dc8dce 100644
--- a/libmedia/ffmpeg/AudioDecoderFfmpeg.cpp
+++ b/libmedia/ffmpeg/AudioDecoderFfmpeg.cpp
@@ -19,6 +19,7 @@
 
 #include "AudioDecoderFfmpeg.h"
 
+#include <cstring> // for memcpy and memset
 #include <cmath> // for std::ceil
 #include <algorithm> // for std::copy, std::max
 
@@ -29,14 +30,13 @@
 
 //#define GNASH_DEBUG_AUDIO_DECODING
 
-#define AVCODEC_DECODE_AUDIO avcodec_decode_audio2
-
 namespace gnash {
 namespace media {
 namespace ffmpeg {
     
 AudioDecoderFfmpeg::AudioDecoderFfmpeg(const AudioInfo& info)
     :
+    _output8cached(NULL),
     _audioCodec(NULL),
     _audioCodecCtx(NULL),
     _parser(NULL),
@@ -57,6 +57,7 @@ AudioDecoderFfmpeg::AudioDecoderFfmpeg(const AudioInfo& info)
 
 AudioDecoderFfmpeg::AudioDecoderFfmpeg(SoundInfo& info)
     :
+    _output8cached(NULL),
     _audioCodec(NULL),
     _audioCodecCtx(NULL),
     _parser(NULL)
@@ -75,6 +76,7 @@ AudioDecoderFfmpeg::~AudioDecoderFfmpeg()
         av_free(_audioCodecCtx);
     }
     if (_parser) av_parser_close(_parser);
+    if (_output8cached) delete[] _output8cached;
 }
 
 void AudioDecoderFfmpeg::setup(SoundInfo& info)
@@ -402,19 +404,31 @@ AudioDecoderFfmpeg::decode(const boost::uint8_t* input,
             continue;
         }
 
+        // Here's a bit of a problem. The FFmpeg parser function garbage
+        // collects anything it gives us upon the next call, and the real decoding
+        // may not succceed right-away. While inefficient, we *need* to make a
+        // copy of the data.
+        boost::uint8_t* framecopy = new boost::uint8_t[framesize +
+                                        FF_INPUT_BUFFER_PADDING_SIZE];
+        memcpy(framecopy, frame, framesize);
+        memset(framecopy + framesize, 0, FF_INPUT_BUFFER_PADDING_SIZE);
 
         // Now, decode the frame. We use the ::decodeFrame specialized function
         // here so resampling is done appropriately
+        std::auto_ptr<EncodedAudioFrame> frameptr(new EncodedAudioFrame);
+        frameptr->data.reset(framecopy);
+        frameptr->dataSize = framesize;
+
         boost::uint32_t outSize = 0;
-        boost::scoped_array<boost::uint8_t> outBuf(
-                decodeFrame(frame, framesize, outSize));
+        boost::scoped_array<boost::uint8_t> outBuf(decode(frameptr, outSize));
 
         if (!outBuf)
         {
             // Setting data position to data size will get the sound removed
             // from the active sound list later on.
             decodedBytes = inputSize;
-            break;
+            delete[] retBuf;
+            return NULL;
         }
 
 #ifdef GNASH_DEBUG_AUDIO_DECODING
@@ -461,145 +475,164 @@ AudioDecoderFfmpeg::decode(const boost::uint8_t* input,
 }
 
 boost::uint8_t*
-AudioDecoderFfmpeg::decode(const EncodedAudioFrame& ef,
-        boost::uint32_t& outputSize)
-{
-    return decodeFrame(ef.data.get(), ef.dataSize, outputSize);
-}
-
-boost::uint8_t*
-AudioDecoderFfmpeg::decodeFrame(const boost::uint8_t* input,
-        boost::uint32_t inputSize, boost::uint32_t& outputSize)
+AudioDecoderFfmpeg::decode(std::auto_ptr<EncodedAudioFrame> af,
+         boost::uint32_t& outputSize)
 {
-    //GNASH_REPORT_FUNCTION;
-
-    assert(inputSize);
-
-    const size_t bufsize = AVCODEC_MAX_AUDIO_FRAME_SIZE;
+    boost::shared_ptr<EncodedAudioFrame> packet(af.release());
 
-    // TODO: make this a private member, to reuse (see NetStreamFfmpeg in 0.8.3)
-    boost::uint8_t* output;
-
-    output = reinterpret_cast<boost::uint8_t*>(av_malloc(bufsize));
-    if (!output) {
-        log_error(_("failed to allocate audio buffer."));
-        outputSize = 0;
-        return NULL;
+    // We may have older, unhandled packets we need to decode first.
+    if ( packet.get() != NULL && !_pendingPackets.empty() )
+    {
+        assert(packet.get()->data.get() != NULL);
+        _pendingPackets.push_back(packet);
+        packet.reset();
+    }
+    if ( packet.get() == NULL )
+    {
+        assert(!_pendingPackets.empty());
+        packet = _pendingPackets.front();
+        _pendingPackets.pop_front();
     }
 
-    boost::int16_t* outPtr = reinterpret_cast<boost::int16_t*>(output);
-
-    // We initialize output size to the full size
-    // then decoding will eventually reduce it
-    int outSize = bufsize; 
+    const size_t bufsize = AVCODEC_MAX_AUDIO_FRAME_SIZE;
 
-#ifdef GNASH_DEBUG_AUDIO_DECODING
-    log_debug("AudioDecoderFfmpeg: about to decode %d bytes; "
-        "ctx->channels:%d, avctx->frame_size:%d",
-        inputSize, _audioCodecCtx->channels, _audioCodecCtx->frame_size);
+    union
+    {
+        boost::uint8_t* output8;
+        boost::int16_t* output16;
+    };
+
+    // Create an output buffer or recycle an old one.
+    output8 = (_output8cached) ? _output8cached : new boost::uint8_t[bufsize];
+    _output8cached = NULL;
+
+    // Ignore data we have already decoded.
+    boost::uint8_t* data = packet->data.get() + packet->dataAlreadyUsed;
+    int dataSize = packet->dataSize - packet->dataAlreadyUsed;
+    assert(0 < dataSize);
+
+    int outSize = bufsize;
+#ifdef HAVE_AVCODEC_DECODE_AUDIO3
+    AVPacket avpacket;
+    av_init_packet(&avpacket);
+    avpacket.data = data;
+    avpacket.size = (int) dataSize;
+    int bytesdecoded = avcodec_decode_audio3(_audioCodecCtx, output16,
+                                             &outSize, &avpacket);
+#elif defined(HAVE_AVCODEC_DECODE_AUDIO2)
+    int bytesdecoded = avcodec_decode_audio2(_audioCodecCtx, output16,
+                                             &outSize, data, dataSize);
+#else
+    // In case of avcodec_decode_audio4.
+    #error "too old or new libavcodec"
 #endif
 
-    // older ffmpeg versions didn't accept a const input..
-    int tmp = AVCODEC_DECODE_AUDIO(_audioCodecCtx, outPtr, &outSize,
-                                   input, inputSize);
-
 #ifdef GNASH_DEBUG_AUDIO_DECODING
-    log_debug(" avcodec_decode_audio[2](ctx, bufptr, %d, input, %d) "
-            "returned %d; set frame_size=%d",
-            bufsize, inputSize, tmp, outSize);
+    log_debug("gave %d bytes to avcodec_decode_audio, it accepted %d of them, "
+              "and gave us %d bytes in return", dataSize, bytesdecoded,
+              outSize);
 #endif
 
-    if (tmp < 0) {
+    if ( bytesdecoded < 0 )
+    {
         log_error(_("avcodec_decode_audio returned %d. Upgrading "
-                    "ffmpeg/libavcodec might fix this issue."), tmp);
-        outputSize = 0;
+                    "ffmpeg/libavcodec might fix this issue."), bytesdecoded);
+        delete[] output8;
+        return NULL;
+    }
 
-        av_free(output);
+    // If no data was used, save it for later.
+    if ( bytesdecoded == 0 )
+    {
+        // TODO: FIXME: Does this really mean that libavcodec wants us to
+        // discard the data or provide it as a prefix to the next packet?
+        log_error(_("avcodec_decode_audio used no input data - this situation "
+                    "is not supported just yet!"));
+        assert(false);
+        delete[] output8;
         return NULL;
     }
 
-    if (outSize < 2) {
-        log_error(_("outputSize:%d after decoding %d bytes of input audio "
-                    "data. Upgrading ffmpeg/libavcodec might fix this issue."),
-                    outputSize, inputSize);
-        outputSize = 0;
+    outputSize = outSize;
 
-        av_free(output);
-        return NULL;
+    // If the whole packet was not used (e.g. multiple frames), save some data
+    // for later by putting it in our packet queue. Then return we we got.
+    assert(bytesdecoded <= dataSize);
+    if ( bytesdecoded < dataSize )
+    {
+        packet->dataAlreadyUsed += bytesdecoded;
+        assert((unsigned) packet->dataAlreadyUsed < packet->dataSize);
+        _pendingPackets.push_back(packet);
     }
 
-    // Resampling is needed.
-    if (_resampler.init(_audioCodecCtx)) {
-        // Resampling is needed.
+    // If no data is ready, just return a buffer of containing nothing.
+    if ( outputSize == 0 )
+    {
+        _output8cached = output8;
+        
+        // Check if we have any pending packets that we might as well decode.
+        if ( !_pendingPackets.empty() )
+        {
+            std::auto_ptr<EncodedAudioFrame> autonull(NULL);
+            return decode(autonull, outputSize);
+        }
 
-        // Compute new size based on frame_size and
-        // resampling configuration
-        double resampleFactor = (44100.0/_audioCodecCtx->sample_rate) * \
(2.0/_audioCodecCtx->channels); +        output8 = new boost::uint8_t[0];
+        outputSize = 0;
+        return output8;
+    }
+
+    if (_resampler.init(_audioCodecCtx))
+    {
+        // Resampling is needed.
+        // Compute new size based on frame_size and resampling configuration
+        double resampleFactor = (44100.0/_audioCodecCtx->sample_rate) *
+                                (2.0/_audioCodecCtx->channels);
         bool stereo = _audioCodecCtx->channels > 1 ? true : false;
-        int inSamples = stereo ? outSize >> 2 : outSize >> 1;
+        int inSamples = stereo ? outputSize >> 2 : outputSize >> 1;
 
         int expectedMaxOutSamples = std::ceil(inSamples*resampleFactor);
 
         // *channels *sampleSize 
-        int resampledFrameSize = expectedMaxOutSamples*2*2;
+        int resampledFrameSize = expectedMaxOutSamples*2*sizeof(boost::int16_t);
 
         // Allocate just the required amount of bytes
-        boost::uint8_t* resampledOutput = new boost::uint8_t[resampledFrameSize]; 
+        union
+        {
+            boost::uint8_t* resampled8;
+            boost::int16_t* resampled16;
+        };
+
+        resampled8 = new boost::uint8_t[resampledFrameSize];
 
 #ifdef GNASH_DEBUG_AUDIO_DECODING
         log_debug("Calling the resampler; resampleFactor:%d; "
-            "ouput to 44100hz, 2channels, %dbytes; "
+            "output to 44100hz, 2channels, %dbytes; "
             "input is %dhz, %dchannels, %dbytes, %dsamples",
             resampleFactor,
             resampledFrameSize, _audioCodecCtx->sample_rate,
-            _audioCodecCtx->channels, outSize, inSamples);
+            _audioCodecCtx->channels, outputSize, inSamples);
 #endif
 
-        int outSamples = _resampler.resample(outPtr, // input
-            reinterpret_cast<boost::int16_t*>(resampledOutput), // output
-            inSamples); // input..
+        int outSamples = _resampler.resample(output16, resampled16, inSamples);
 
 #ifdef GNASH_DEBUG_AUDIO_DECODING
         log_debug("resampler returned %d samples ", outSamples);
 #endif
 
-        // make sure to set outPtr *after* we use it as input to the resampler
-        outPtr = reinterpret_cast<boost::int16_t*>(resampledOutput);
+        // make sure to set output8 *after* we use it as input to the resampler
+        _output8cached = output8; // Recycle this memory buffer.
+        output8 = resampled8;
 
-        av_free(output);
-
-        if (expectedMaxOutSamples < outSamples) {
-            log_error(" --- Computation of resampled samples (%d) < then the actual \
                returned samples (%d)",
-                expectedMaxOutSamples, outSamples);
-
-            log_debug(" input frame size: %d", outSize);
-            log_debug(" input sample rate: %d", _audioCodecCtx->sample_rate);
-            log_debug(" input channels: %d", _audioCodecCtx->channels);
-            log_debug(" input samples: %d", inSamples);
-
-            log_debug(" output sample rate (assuming): %d", 44100);
-            log_debug(" output channels (assuming): %d", 2);
-            log_debug(" output samples: %d", outSamples);
-
-            /// Memory errors...
-            abort();
-        }
+        assert(outSamples <= expectedMaxOutSamples);
 
         // Use the actual number of samples returned, multiplied
         // to get size in bytes (not two-byte samples) and for 
         // stereo?
-        outSize = outSamples * 2 * 2;
-
-    }
-    else {
-        boost::uint8_t* newOutput = new boost::uint8_t[outSize];
-        std::memcpy(newOutput, output, outSize);
-        outPtr = reinterpret_cast<boost::int16_t*>(newOutput);
-        av_free(output);
+        outputSize = outSamples * 2 * sizeof(boost::int16_t);
     }
 
-    outputSize = outSize;
-    return reinterpret_cast<uint8_t*>(outPtr);
+    return output8;
 }
 
 int
@@ -609,6 +642,14 @@ AudioDecoderFfmpeg::parseInput(const boost::uint8_t* input,
 {
     if ( _needsParsing )
     {
+
+#ifdef HAVE_AV_PARSER_PARSE2
+        return av_parser_parse2(_parser, _audioCodecCtx,
+                    const_cast<boost::uint8_t**>(outFrame),
+                    outFrameSize,
+                    input, inputSize,
+                    0, 0, AV_NOPTS_VALUE); // pts & dts
+#elif defined(HAVE_AV_PARSER_PARSE)
         return av_parser_parse(_parser, _audioCodecCtx,
                     // as of 2008-10-28 SVN, ffmpeg doesn't
                     // accept a pointer to pointer to const..
@@ -616,6 +657,10 @@ AudioDecoderFfmpeg::parseInput(const boost::uint8_t* input,
                     outFrameSize,
                     input, inputSize,
                     0, 0); // pts & dts
+#else
+// In case of av_parser_parse3.
+#error "Your libavcodec version is too new"
+#endif
     }
     else
     {
diff --git a/libmedia/ffmpeg/AudioDecoderFfmpeg.h \
b/libmedia/ffmpeg/AudioDecoderFfmpeg.h index e28b745..8c68ab7 100644
--- a/libmedia/ffmpeg/AudioDecoderFfmpeg.h
+++ b/libmedia/ffmpeg/AudioDecoderFfmpeg.h
@@ -19,6 +19,8 @@
 #ifndef GNASH_AUDIODECODERFFMPEG_H
 #define GNASH_AUDIODECODERFFMPEG_H
 
+#include <list>
+
 #include "ffmpegHeaders.h"
 
 #include "log.h"
@@ -59,7 +61,7 @@ public:
             boost::uint32_t inputSize, boost::uint32_t& outputSize,
             boost::uint32_t& decodedBytes);
 
-	boost::uint8_t* decode(const EncodedAudioFrame& af,
+	boost::uint8_t* decode(std::auto_ptr<EncodedAudioFrame> af,
             boost::uint32_t& outputSize);
 
 private:
@@ -67,8 +69,9 @@ private:
 	void setup(const AudioInfo& info);
 	void setup(SoundInfo& info);
 
-	boost::uint8_t* decodeFrame(const boost::uint8_t* input,
-            boost::uint32_t inputSize, boost::uint32_t& outputSize);
+	std::list< boost::shared_ptr<EncodedAudioFrame> > _pendingPackets;
+
+    boost::uint8_t* _output8cached;
 
 	AVCodec* _audioCodec;
 	AVCodecContext* _audioCodecCtx;
diff --git a/libmedia/ffmpeg/MediaParserFfmpeg.cpp \
b/libmedia/ffmpeg/MediaParserFfmpeg.cpp index 492d26d..3c82070 100644
--- a/libmedia/ffmpeg/MediaParserFfmpeg.cpp
+++ b/libmedia/ffmpeg/MediaParserFfmpeg.cpp
@@ -17,6 +17,7 @@
 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 //
 
+#include <cstring> // for memset
 #include "ffmpegHeaders.h"
 #include "MediaParserFfmpeg.h"
 #include "GnashException.h"
@@ -216,12 +217,10 @@ MediaParserFfmpeg::parseAudioFrame(AVPacket& packet)
 
 	std::auto_ptr<EncodedAudioFrame> frame ( new EncodedAudioFrame );
 
-	// TODO: FIXME: *2 is an hack to avoid libavcodec reading past end of allocated \
                space
-	//       we might do proper padding or (better) avoid the copy as a whole by making
-	//       EncodedVideoFrame virtual.
-	size_t allocSize = packet.size*2;
+	size_t allocSize = packet.size + FF_INPUT_BUFFER_PADDING_SIZE;
 	boost::uint8_t* data = new boost::uint8_t[allocSize];
 	std::copy(packet.data, packet.data+packet.size, data);
+	memset(data + packet.size, 0, FF_INPUT_BUFFER_PADDING_SIZE);
 
 	frame->data.reset(data); 
 	frame->dataSize = packet.size;
diff --git a/libmedia/gst/AudioDecoderGst.cpp b/libmedia/gst/AudioDecoderGst.cpp
index 8932e7b..e67acc5 100644
--- a/libmedia/gst/AudioDecoderGst.cpp
+++ b/libmedia/gst/AudioDecoderGst.cpp
@@ -225,7 +225,8 @@ AudioDecoderGst::pullBuffers(boost::uint32_t&  outputSize)
   
     if (!outputSize) {
         log_debug(_("Pushed data, but there's nothing to pull (yet)"));
-        return 0;   
+        outputSize = 0;
+        return new boost::uint8_t[0];
     }
     
     boost::uint8_t* rbuf = new boost::uint8_t[outputSize];
@@ -270,20 +271,20 @@ AudioDecoderGst::decode(const boost::uint8_t* input, \
boost::uint32_t inputSize,  }
 
 boost::uint8_t*
-AudioDecoderGst::decode(const EncodedAudioFrame& ef, boost::uint32_t& outputSize)
+AudioDecoderGst::decode(std::auto_ptr<EncodedAudioFrame> ef, boost::uint32_t& \
outputSize)  {
     outputSize = 0;
     
     GstBuffer* gstbuf;
     
-    EncodedExtraGstData* extradata = \
dynamic_cast<EncodedExtraGstData*>(ef.extradata.get()); +    EncodedExtraGstData* \
extradata = dynamic_cast<EncodedExtraGstData*>(ef->extradata.get());  
     if (extradata) {
         gstbuf = extradata->buffer;
     } else {
 
-        gstbuf = gst_buffer_new_and_alloc(ef.dataSize);
-        memcpy (GST_BUFFER_DATA (gstbuf), ef.data.get(), ef.dataSize);
+        gstbuf = gst_buffer_new_and_alloc(ef->dataSize);
+        memcpy (GST_BUFFER_DATA (gstbuf), ef->data.get(), ef->dataSize);
     }
 
     bool success = swfdec_gst_decoder_push(&_decoder, gstbuf);
diff --git a/libmedia/gst/AudioDecoderGst.h b/libmedia/gst/AudioDecoderGst.h
index c25ffa7..cc6eda8 100644
--- a/libmedia/gst/AudioDecoderGst.h
+++ b/libmedia/gst/AudioDecoderGst.h
@@ -50,7 +50,7 @@ public:
 
     boost::uint8_t* decode(const boost::uint8_t* input, boost::uint32_t inputSize,
                            boost::uint32_t& outputSize, boost::uint32_t& \
                decodedData);
-    boost::uint8_t* decode(const EncodedAudioFrame& ef, boost::uint32_t& \
outputSize); +    boost::uint8_t* decode(std::auto_ptr<EncodedAudioFrame> ef, \
boost::uint32_t& outputSize);  
 private:
 
diff --git a/testsuite/libmedia.all/.gitignore b/testsuite/libmedia.all/.gitignore
new file mode 100644
index 0000000..81154dd
--- /dev/null
+++ b/testsuite/libmedia.all/.gitignore
@@ -0,0 +1 @@
+samples
diff --git a/testsuite/libmedia.all/Makefile.am b/testsuite/libmedia.all/Makefile.am
index b1e1e2c..6a98aa4 100644
--- a/testsuite/libmedia.all/Makefile.am
+++ b/testsuite/libmedia.all/Makefile.am
@@ -49,7 +49,11 @@ INCLUDES = \
 	$(GSTAPP_CFLAGS) \
 	$(GSTINTERFACES_CFLAGS) 
 
-check_PROGRAMS = 
+check_PROGRAMS = test_decoding
+
+test_decoding_SOURCES = test_decoding.cpp
+test_decoding_LDADD = $(AM_LDFLAGS)
+test_decoding_DEPENDENCIES = site-update
 
 if USE_GST_ENGINE
 
@@ -73,7 +77,8 @@ CLEANFILES =  \
 	site.exp.bak \
 	testrun.* \
 	fooBar* \
-	*.bin
+	*.bin \
+	samples/*
 
 check-DEJAGNU: site-update
 	@runtest=$(RUNTEST); \
@@ -92,3 +97,11 @@ site-update: site.exp
 	@sed -e '/testcases/d' site.exp.bak > site.exp
 	@echo "# This is a list of the pre-compiled testcases" >> site.exp
 	@echo "set testcases \"$(check_PROGRAMS)\"" >> site.exp
+
+test_decoding.cpp: $(builddir)/samples
+
+.PHONY: $(builddir)/samples
+$(builddir)/samples:
+	$(SHELL) $(srcdir)/mksamples.sh "$(srcdir)" "$(builddir)" "$(CSOUND)" "$(FFMPEG)" \
"$(LAME)" +
+
diff --git a/testsuite/libmedia.all/mksamples.sh \
b/testsuite/libmedia.all/mksamples.sh new file mode 100755
index 0000000..d62520b
--- /dev/null
+++ b/testsuite/libmedia.all/mksamples.sh
@@ -0,0 +1,47 @@
+#!/bin/sh
+
+SRCDIR="$1"
+BUILDDIR="$2"
+if [ "$SRCDIR" == "" -o "$BUILDDIR" == "" ]; then
+  echo "usage: $0 <srcdir> <builddir> [csound-program-path] [ffmpeg-program-path] \
[lame-program-path]" +  exit
+fi
+
+CSOUND="$3"
+FFMPEG="$4"
+LAME="$5"
+
+SMPDIR="$BUILDDIR/samples"
+rm -rf "$SMPDIR"
+mkdir -p "$SMPDIR"
+
+# TODO: Add a lot of different codecs in various containers below. The more
+# diverse formats are generated, the better Gnash's media playback abillity
+# is tested.
+
+# TODO: Generate files with video as well as audio, such that video playback is
+# tested thoroughly too.
+
+if [ "$CSOUND" != "" ]; then
+
+  "$CSOUND" --nodisplays --wave "$SRCDIR/sample.orc" "$SRCDIR/sample.sco" -o \
"$SMPDIR/sample-pcm.wav"  +
+  if [ "$FFMPEG" != "" ]; then
+    "$FFMPEG" -i "$SMPDIR/sample-pcm.wav" -y -acodec flac "$SMPDIR/sample-flac.flac"
+    "$FFMPEG" -i "$SMPDIR/sample-pcm.wav" -y -acodec libvorbis \
"$SMPDIR/sample-vorbis.ogg" +    "$FFMPEG" -i "$SMPDIR/sample-pcm.wav" -y -acodec \
libmp3lame "$SMPDIR/sample-mp3.mp4" +    "$FFMPEG" -i "$SMPDIR/sample-pcm.wav" -y \
"$SMPDIR/sample-pcm.flv" +    "$FFMPEG" -i "$SMPDIR/sample-pcm.wav" -y -acodec \
libvorbis "$SMPDIR/sample-vorbis.webm" +    "$FFMPEG" -i "$SMPDIR/sample-pcm.wav" -y \
-acodec libmp3lame "$SMPDIR/sample-mp3.mkv" +    "$FFMPEG" -i \
"$SMPDIR/sample-pcm.wav" -y -acodec libvorbis "$SMPDIR/sample-vorbis.mkv" +  fi
+
+  if [ "$LAME" != "" ]; then
+    "$LAME" "$SMPDIR/sample-pcm.wav" "$SMPDIR/sample-mp3.mp3"
+    if [ "$FFMPEG" != "" ]; then
+      # "$FFMPEG" -i "$SMPDIR/sample-mp3.mp3" -y "$SMPDIR/sample-mp3.mkv" # crashes \
the testcase on some systems +      "$FFMPEG" -i "$SMPDIR/sample-mp3.mp3" -y \
"$SMPDIR/sample-mp3.flv" +    fi
+  fi
+
+fi
diff --git a/testsuite/libmedia.all/sample.orc b/testsuite/libmedia.all/sample.orc
new file mode 100644
index 0000000..8b35f99
--- /dev/null
+++ b/testsuite/libmedia.all/sample.orc
@@ -0,0 +1,9 @@
+sr = 44100 	; audio sampling rate is 44.1 kHz
+kr = 4410 	; control rate is 4410 Hz
+ksmps = 10 	; number of samples in a control period (sr/kr)
+nchnls = 1 	; number of channels of audio output
+		
+instr 1				
+	asig 	oscil 	10000, p5, 1 	; audio oscillator
+	out 	asig 		; send signal to channel 1
+endin
diff --git a/testsuite/libmedia.all/sample.sco b/testsuite/libmedia.all/sample.sco
new file mode 100644
index 0000000..5f8fa19
--- /dev/null
+++ b/testsuite/libmedia.all/sample.sco
@@ -0,0 +1,7 @@
+f1 	0 	256 	10 	1 	;  a sine wave function table
+
+
+;  a pentatonic scale
+i1 	0 	5   	0 	1200
+e
+
diff --git a/testsuite/libmedia.all/test_decoding.cpp \
b/testsuite/libmedia.all/test_decoding.cpp new file mode 100644
index 0000000..841ee6f
--- /dev/null
+++ b/testsuite/libmedia.all/test_decoding.cpp
@@ -0,0 +1,317 @@
+// test_decoding.cpp: Tests installed media handlers,
+// 
+//   Copyright (C) 2011 Free Software Foundation, Inc.
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+
+#ifdef HAVE_CONFIG_H
+#include "gnashconfig.h"
+#endif
+
+#include "check.h"
+#include "log.h"
+#include <iostream>
+#include <sstream>
+#include <cassert>
+#include <vector>
+
+#include "GnashSleep.h"
+#include "MediaHandler.h"
+#include "MediaParser.h"
+#include "AudioDecoder.h"
+#include "tu_file.h"
+
+using namespace std;
+using namespace gnash;
+using namespace gnash::media;
+
+/// Scans the given dir and returns every element in it.
+#include <dirent.h>
+vector<string>*
+lsdir(string path)
+{
+	DIR* dir = opendir(path.c_str());
+	if ( dir == NULL ) { return NULL; }
+
+	vector<string>* result = new vector<string>();
+
+	dirent* entry;
+	while ( (entry = readdir(dir)) != NULL )
+	{
+		if ( entry->d_name[0] == '.' ) { continue; }
+		result->push_back(string(entry->d_name));
+	}
+
+	return result;
+}
+
+/// A simple hack to shorten the description of various mediahandlers.
+string
+getprefix(string desc)
+{
+	if ( desc.compare(0, 3, "FFm") == 0 ) { return "ffmpeg"; }
+	if ( desc.compare(0, 3, "Gst") == 0 ) { return "gst"; }
+	if ( desc.compare(0, 3, "Hai") == 0 ) { return "haiku"; }
+	return desc;
+}
+
+/// Returns whether a file is expected to fail the dest for a given decoder.
+bool
+isFailureExpected(string prefix, string file)
+{
+	// TODO: Produce even more files that can be tested!
+
+	if ( prefix.compare("ffmpeg: ") == 0 )
+	{
+		if ( file.compare("samples/sample-vorbis.ogg") == 0 ) { return false; }
+		if ( file.compare("samples/sample-mp3.flv") == 0 ) { return false; }
+		if ( file.compare("samples/sample-pcm.flv") == 0 ) { return false; }
+		if ( file.compare("samples/sample-mp3.mkv") == 0 ) { return false; }
+		if ( file.compare("samples/sample-vorbis.webm") == 0 ) { return false; }
+		if ( file.compare("samples/sample-vorbis.mkv") == 0 ) { return false; }
+		if ( file.compare("samples/sample-mp3.mp3") == 0 ) { return false; }
+		if ( file.compare("samples/sample-pcm.wav") == 0 ) { return false; }
+		if ( file.compare("samples/sample-flac.flac") == 0 ) { return false; }
+	}
+	else if ( prefix.compare("gst: ") == 0 )
+	{
+		if ( file.compare("samples/sample-vorbis.ogg") == 0 ) { return false; }
+		if ( file.compare("samples/sample-mp3.flv") == 0 ) { return false; }
+		if ( file.compare("samples/sample-pcm.flv") == 0 ) { return false; }
+		if ( file.compare("samples/sample-mp3.mkv") == 0 ) { return false; }
+		if ( file.compare("samples/sample-vorbis.webm") == 0 ) { return false; }
+		if ( file.compare("samples/sample-vorbis.mkv") == 0 ) { return false; }
+		if ( file.compare("samples/sample-mp3.mp3") == 0 ) { return false; }
+		if ( file.compare("samples/sample-pcm.wav") == 0 ) { return true; }
+		if ( file.compare("samples/sample-flac.flac") == 0 ) { return false; }
+	}
+
+	return false;
+}
+
+/// Outputs the correct result to stdout depending on the expected result.
+void
+printresult(bool expectedfail, bool result, string msg)
+{
+	if ( expectedfail && result )
+	{
+		_runtest.xpass(msg);
+	}
+	else if ( expectedfail && !result )
+	{
+		_runtest.xfail(msg);
+	}
+	else if ( !expectedfail && result )
+	{
+		_runtest.pass(msg);
+	}
+	else // if ( !expectedfail && !result )
+	{
+		_runtest.fail(msg);
+	}
+}
+
+/// Attempts to decode 'filepath' using 'handler' and prints information to
+/// stdout depending on whether a failure is expected and what happened.
+void
+testFile(const string& filepath, MediaHandler* handler, bool expectedfail,
+		string prefix)
+{
+	// Open the file for reading.
+	auto_ptr<IOChannel> channel = makeFileChannel(filepath.c_str(), "rb");
+
+	if ( channel.get() == 0 )
+	{
+		printresult(false, false, prefix + filepath + ": could not open for "
+					"reading");
+		return;
+	}
+
+	// Create a media parser to parse the file.
+	std::auto_ptr<MediaParser> parser = handler->createMediaParser(channel);
+
+	if ( parser.get() == 0 )
+	{
+		printresult(expectedfail, false, prefix + filepath + ": could not "
+					"create parser");
+		return;
+	}
+
+	// Wait for the media parser to parse the file's headers and break if it
+	// takes too long. (I don't see any way to detect whether parsing failed).
+	// TODO: This is a very hacky method to detect when the parser->getFooInfo()
+	// is available.
+	boost::uint64_t unused;
+	unsigned waited = 0;
+	while ( !parser->nextFrameTimestamp(unused) )
+	{
+		if ( 2000 < waited )
+		{
+			// NOTE: This could also be because no the headers could not be
+			// parsed or that no sound or video is available.
+			printresult(expectedfail, false, prefix + filepath + ": used more "
+						"than 2 seconds to parse headers");
+			return;
+		}
+
+		gnashSleep(10*1000); waited += 10;
+	}
+
+	VideoInfo* videoInfo = parser->getVideoInfo();
+	AudioInfo* audioInfo = parser->getAudioInfo();
+
+	std::auto_ptr<AudioDecoder> audioDecoder;
+	std::auto_ptr<VideoDecoder> videoDecoder;
+
+	// Create a decoder for any sound found in the file.
+	if ( audioInfo )
+	{
+		try
+		{
+			audioDecoder = handler->createAudioDecoder(*audioInfo);
+		}
+		catch ( gnash::MediaException& e )
+		{
+			printresult(expectedfail, false, prefix + filepath + ": " +
+						e.what());
+			return;
+		}
+	}
+
+	// Create a decoder for any video found in the file.
+	if ( videoInfo )
+	{
+		try
+		{
+			videoDecoder = handler->createVideoDecoder(*videoInfo);
+		}
+		catch ( gnash::MediaException& e )
+		{
+			printresult(expectedfail, false, prefix + filepath + ": " +
+						e.what());
+			return;
+		}
+	}
+
+	size_t read = 0; // Number of bytes decoded.
+
+	// TODO: Attempt to decode video as well as audio.
+
+	// Attempt to decode the entire file to see if bad things happen.
+	while ( audioInfo )
+	{
+		std::auto_ptr<EncodedAudioFrame> audioEncodedFrame;
+
+		unsigned milisecondssincelastframe = 0;
+		const unsigned maxmiliseconds = 2000;
+
+		// Wait for the next frame, and break if we have possibly entered
+		// a deadlock or an infinite loop.
+		while ( audioEncodedFrame.get() == 0 )
+		{
+			if ( maxmiliseconds < milisecondssincelastframe )
+			{
+				printresult(expectedfail, false, prefix + filepath + ": used "
+							"more than 2000 ms to decode a frame");
+				return;
+			}
+
+			audioEncodedFrame = parser->nextAudioFrame();
+			if ( audioEncodedFrame.get() == 0 )
+			{
+				if ( parser->parsingCompleted() ) { break; }
+				gnashSleep(10*1000); milisecondssincelastframe += 10;
+			}
+		}
+
+		// Check for end-of-file conditions and terminate.
+		if ( parser->parsingCompleted() ) { break; }
+
+		// Attempt to decode the packet received.
+		boost::uint32_t soundSize = 0;
+		boost::uint8_t* sound = audioDecoder->decode(audioEncodedFrame,
+													soundSize);
+
+		// Check if the decoding went well (return non-null).
+		if ( sound == NULL )
+		{
+			// NOTE: there is currently no way to tell whether a decoding error
+			// happened or if the decoder has encountered a frame split over
+			// multiple packages. Gstreamer spuriously generates a lot of this.
+			printresult(expectedfail, false, prefix + filepath + ": no frame "
+						"was available after decoding a packet");
+			return;
+		}
+
+		// For debugging reasons, record how much data was decoded.
+		read += soundSize;
+
+		delete[] sound;
+	}
+
+	// Declare the file successfully decoded.
+	printresult(expectedfail, true, prefix + filepath);
+}
+
+/// Tests this media handler on every sample file in the samples/ directory.
+void
+testHandler(MediaHandler* handler)
+{
+	string sampledir = "samples";
+
+	// Get a list of test files.
+	vector<string>* filelist = lsdir(sampledir);
+	if ( filelist == NULL )
+	{
+		cerr << "couldn't list elements in dir '" << sampledir << "'" << endl;
+		return;
+	}
+
+	// Reduce the mediahandler's description in a short string.
+	string prefix = getprefix(handler->description()) + ": ";
+
+	// Test every file in the samples directory with this handler.
+	vector<string>::iterator it;
+	for ( it = filelist->begin(); it != filelist->end(); it++ )
+	{
+		string file = sampledir + "/" + *it;
+		bool expectedFailure = isFailureExpected(prefix, file);
+		testFile(file, handler, expectedFailure, prefix);
+	}
+
+	delete filelist;
+}
+
+/// Tests every install mediahandler on all sample files.
+int
+main(int /*argc*/, char* /*argv*/[])
+{
+	// Useful when determining exactly what is going on.
+	//LogFile::getDefaultInstance().setVerbosity(3);
+
+	// Get a list of each installed mediahandler.
+	vector<string> mediaHandlers;
+	MediaFactory::instance().listKeys(back_inserter(mediaHandlers));
+
+	// Run our test on each of the mediahandlers.
+	vector<string>::iterator it;
+	for ( it = mediaHandlers.begin(); it != mediaHandlers.end(); it++ )
+	{
+		MediaHandler* handler = MediaFactory::instance().get(*it);
+		testHandler(handler);
+	}
+
+	return 0;
+}



_______________________________________________
Gnash-commit mailing list
Gnash-commit@gnu.org
https://lists.gnu.org/mailman/listinfo/gnash-commit


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic