[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