diff --git a/configure.ac b/configure.ac index 33a136c..358cf63 100644 --- a/configure.ac +++ b/configure.ac @@ -3571,6 +3571,21 @@ if test x"${build_media_ffmpeg}" = x"yes"; then DEB_INSTALL([libswscale-dev]) PKG_ALTERNATIVE(or reconfigure with --enable-media=gst) fi + + if test x"${have_ffmpeg_libavutil}" = "xno"; then + PKG_ERR([No libavutil development package installed!]) + PKG_SUGGEST([You can install libavutil from http://ffmpeg.org]) + DEB_INSTALL([libavutil-dev]) + PKG_ALTERNATIVE(or reconfigure with --enable-media=gst) + fi + + if test x"${have_ffmpeg_swresample}" = "xno" -a \ + x"${have_libav_avresample}" = "xno"; then + PKG_REC([Please install libswresample/libavresample development package. If you don't, Gnash will be unable to resample some formats (e.g. AAC on youtube]) + PKG_SUGGEST([You can install libswresample from http://ffmpeg.org]) + DEB_INSTALL([libavresample-dev]) + PKG_ALTERNATIVE(or reconfigure with --enable-media=gst) + fi fi if test x$build_cairo = xyes; then diff --git a/libmedia/ffmpeg/AudioDecoderFfmpeg.cpp b/libmedia/ffmpeg/AudioDecoderFfmpeg.cpp index f45a42d..6526aed 100644 --- a/libmedia/ffmpeg/AudioDecoderFfmpeg.cpp +++ b/libmedia/ffmpeg/AudioDecoderFfmpeg.cpp @@ -30,14 +30,6 @@ //#define GNASH_DEBUG_AUDIO_DECODING -#if LIBAVCODEC_VERSION_MAJOR >= 53 -#define AVCODEC_DECODE_AUDIO avcodec_decode_audio3 -#else -#define AVCODEC_DECODE_AUDIO avcodec_decode_audio2 -#endif - -#define MAX_AUDIO_FRAME_SIZE 192000 - namespace gnash { namespace media { namespace ffmpeg { @@ -523,45 +515,70 @@ AudioDecoderFfmpeg::decodeFrame(const boost::uint8_t* input, #ifdef GNASH_DEBUG_AUDIO_DECODING log_debug("AudioDecoderFfmpeg: about to decode %d bytes; " - "ctx->channels:%d, avctx->frame_size:%d", + "ctx->channels:%d, ctx->frame_size:%d", inputSize, _audioCodecCtx->channels, _audioCodecCtx->frame_size); #endif // older ffmpeg versions didn't accept a const input.. -#if LIBAVCODEC_VERSION_MAJOR >= 53 AVPacket pkt; + int got_frm = 0; av_init_packet(&pkt); - pkt.data = (uint8_t*) input; + pkt.data = const_cast(input); pkt.size = inputSize; -#endif - int tmp = AVCODEC_DECODE_AUDIO(_audioCodecCtx, outPtr, &outSize, -#if LIBAVCODEC_VERSION_MAJOR >= 53 - &pkt); -#else - input, inputSize); -#endif + AVFrame *frm = avcodec_alloc_frame(); + if (!frm) { + log_error(_("failed to allocate frame.")); + return NULL; + } + int tmp = avcodec_decode_audio4(_audioCodecCtx, frm, &got_frm, &pkt); #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); + const char* fmtname = av_get_sample_fmt_name(_audioCodecCtx->sample_fmt); + log_debug(" decodeFrame | frm->nb_samples: %d | &got_frm: %d | " + "returned %d | inputSize: %d", + frm->nb_samples, got_frm, tmp, inputSize); #endif - if (tmp < 0) { - log_error(_("avcodec_decode_audio returned %d. Upgrading " - "ffmpeg/libavcodec might fix this issue."), tmp); - outputSize = 0; + int plane_size; + if (tmp >= 0 && got_frm) { + int planar = av_sample_fmt_is_planar(_audioCodecCtx->sample_fmt); + int data_size = av_samples_get_buffer_size( &plane_size, + _audioCodecCtx->channels, frm->nb_samples, + _audioCodecCtx->sample_fmt, 1); + if (outSize < data_size) { + log_error(_("output buffer size is too small for the current frame " + "(%d < %d)"), outSize, data_size); + return NULL; + } - av_free(output); - return NULL; - } + memcpy(outPtr, frm->extended_data[0], plane_size); - 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; +#if !(defined(HAVE_SWRESAMPLE_H) || defined(HAVE_AVRESAMPLE_H)) + int ch; + if (planar && _audioCodecCtx->channels > 1) { + uint8_t *out = ((uint8_t *)outPtr) + plane_size; + for (ch = 1; ch < _audioCodecCtx->channels; ch++) { + memcpy(out, frm->extended_data[ch], plane_size); + out += plane_size; + } + } +#endif + outSize = data_size; +#ifdef GNASH_DEBUG_AUDIO_DECODING + log_debug(" decodeFrame | fmt: %d | fmt_name: %s | planar: %d | " + "plane_size: %d | outSize: %d", + _audioCodecCtx->sample_fmt, fmtname, planar, plane_size, outSize); +#endif + } else { + if (tmp < 0) + log_error(_("avcodec_decode_audio returned %d."), tmp); + if (outSize < 2) + log_error(_("outputSize:%d after decoding %d bytes of input audio " + "data."), outputSize, inputSize); + log_error(_("Upgrading ffmpeg/libavcodec might fix this issue.")); + outputSize = 0; + av_freep(&frm); av_free(output); return NULL; } @@ -585,25 +602,27 @@ AudioDecoderFfmpeg::decodeFrame(const boost::uint8_t* input, boost::uint8_t* resampledOutput = new boost::uint8_t[resampledFrameSize]; #ifdef GNASH_DEBUG_AUDIO_DECODING - log_debug("Calling the resampler; resampleFactor:%d; " - "ouput to 44100hz, 2channels, %dbytes; " - "input is %dhz, %dchannels, %dbytes, %dsamples", - resampleFactor, - resampledFrameSize, _audioCodecCtx->sample_rate, - _audioCodecCtx->channels, outSize, inSamples); + log_debug(" decodeFrame | Calling the resampler, resampleFactor: %d | " + "in %d hz %d ch %d bytes %d samples, %s fmt", resampleFactor, + _audioCodecCtx->sample_rate, _audioCodecCtx->channels, outSize, + inSamples, fmtname); + log_debug(" decodeFrame | out 44100 hz 2 ch %d bytes", + resampledFrameSize); #endif - int outSamples = _resampler.resample(outPtr, // input - reinterpret_cast(resampledOutput), // output - inSamples); // input.. + int outSamples = _resampler.resample(frm->extended_data, // input + plane_size, // input + frm->nb_samples, // input + &resampledOutput); // output + + // make sure to set outPtr *after* we use it as input to the resampler + outPtr = reinterpret_cast(resampledOutput); #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(resampledOutput); - + av_freep(&frm); av_free(output); if (expectedMaxOutSamples < outSamples) { @@ -633,6 +652,7 @@ AudioDecoderFfmpeg::decodeFrame(const boost::uint8_t* input, boost::uint8_t* newOutput = new boost::uint8_t[outSize]; std::memcpy(newOutput, output, outSize); outPtr = reinterpret_cast(newOutput); + av_freep(&frm); av_free(output); } diff --git a/libmedia/ffmpeg/AudioResamplerFfmpeg.cpp b/libmedia/ffmpeg/AudioResamplerFfmpeg.cpp index 98ac8b5..71a852f 100644 --- a/libmedia/ffmpeg/AudioResamplerFfmpeg.cpp +++ b/libmedia/ffmpeg/AudioResamplerFfmpeg.cpp @@ -33,48 +33,70 @@ AudioResamplerFfmpeg::AudioResamplerFfmpeg() :_context(NULL) { } - -AudioResamplerFfmpeg::~AudioResamplerFfmpeg() -{ - if ( _context ) { - audio_resample_close( _context ); - } +AudioResamplerFfmpeg::~AudioResamplerFfmpeg() { + if (_context) { +#ifdef HAVE_SWRESAMPLE_H + swr_free(&_context); +#elif HAVE_AVRESAMPLE_H + avresample_close(_context); + avresample_free(&_context); +#else + audio_resample_close(_context); +#endif + } } bool -AudioResamplerFfmpeg::init( AVCodecContext* ctx ) -{ - if ( (ctx->sample_rate != 44100) || (ctx->channels != 2) ) { - if ( ! _context ) { -#if LIBAVCODEC_VERSION_MAJOR >= 53 - _context = av_audio_resample_init( - 2, ctx->channels, 44100, ctx->sample_rate, - AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_S16, - 16, 10, 0, 0.8 +AudioResamplerFfmpeg::init(AVCodecContext* ctx) { + if ((ctx->sample_rate != 44100) || (ctx->channels != 2) || + (ctx->sample_fmt != AV_SAMPLE_FMT_S16)) { + if (! _context) { +#ifdef HAVE_SWRESAMPLE_H + _context = swr_alloc(); +#elif HAVE_AVRESAMPLE_H + _context = avresample_alloc_context(); #else - _context = audio_resample_init( - 2, ctx->channels, 44100, ctx->sample_rate + _context = av_audio_resample_init(2, ctx->channels, + 44100, ctx->sample_rate, + AV_SAMPLE_FMT_S16, ctx->sample_fmt, + 16, 10, 0, 0.8); +#endif +#if defined(HAVE_SWRESAMPLE_H) || defined(HAVE_AVRESAMPLE_H) + av_opt_set_int(_context, "in_channel_layout", ctx->channel_layout, 0); + av_opt_set_int(_context, "out_channel_layout", AV_CH_LAYOUT_STEREO, 0); + av_opt_set_int(_context, "in_sample_rate", ctx->sample_rate, 0); + av_opt_set_int(_context, "out_sample_rate", 44100, 0); + av_opt_set_int(_context, "in_sample_fmt", ctx->sample_fmt, 0); + av_opt_set_int(_context, "out_sample_fmt", AV_SAMPLE_FMT_S16, 0); #endif - ); +#ifdef HAVE_SWRESAMPLE_H + swr_init(_context); +#elif HAVE_AVRESAMPLE_H + avresample_open(_context); +#endif + } + return true; } - - return true; - } - - return false; + return false; } int -AudioResamplerFfmpeg::resample( - boost::int16_t* input, - boost::int16_t* output, - int samples - ) -{ - return audio_resample( _context, output, input, samples ); +AudioResamplerFfmpeg::resample(boost::uint8_t** input, int plane_size, + int samples, boost::uint8_t** output) { +#ifdef HAVE_SWRESAMPLE_H + return swr_convert(_context, + output, MAX_AUDIO_FRAME_SIZE, + const_cast(input), samples); +#elif HAVE_AVRESAMPLE_H + return avresample_convert(_context, + output, 0, MAX_AUDIO_FRAME_SIZE, + input, plane_size, samples); +#else + return audio_resample(_context, reinterpret_cast(output), + reinterpret_cast(input), samples); +#endif } - } // gnash.media.ffmpeg namespace } // gnash.media namespace } // namespace gnash diff --git a/libmedia/ffmpeg/AudioResamplerFfmpeg.h b/libmedia/ffmpeg/AudioResamplerFfmpeg.h index e77aec4..3dc2748 100644 --- a/libmedia/ffmpeg/AudioResamplerFfmpeg.h +++ b/libmedia/ffmpeg/AudioResamplerFfmpeg.h @@ -56,21 +56,29 @@ public: /// @param input /// A pointer to the audio data that needs resampling /// - /// @param output - /// A pointer to where the resampled output should be placed + /// @param plane_size + /// Input plane/line size /// /// @param samples /// Number of samples in the audio /// + /// @param output + /// A pointer to where the resampled output should be placed + /// /// @return the number of samples in the output data. /// - DSOEXPORT int resample( - boost::int16_t* input, boost::int16_t* output, int samples - ); + DSOEXPORT int resample(boost::uint8_t** input, int plane_size, + int samples, boost::uint8_t** output); private: - // The container of the resample format information. - ReSampleContext* _context; + // The container of the resample format information. +#ifdef HAVE_SWRESAMPLE_H + SwrContext* _context; +#elif HAVE_AVRESAMPLE_H + AVAudioResampleContext* _context; +#else + ReSampleContext* _context; +#endif }; } // gnash.media.ffmpeg namespace diff --git a/libmedia/ffmpeg/ffmpegHeaders.h b/libmedia/ffmpeg/ffmpegHeaders.h index a05cee7..5cd3785 100644 --- a/libmedia/ffmpeg/ffmpegHeaders.h +++ b/libmedia/ffmpeg/ffmpegHeaders.h @@ -38,6 +38,8 @@ #endif #endif +#define MAX_AUDIO_FRAME_SIZE 192000 + #ifdef HAVE_FFMPEG_AVCODEC_H extern "C" { # include @@ -100,4 +102,50 @@ extern "C" { #define CODECID CodecID #endif +#ifdef HAVE_SWRESAMPLE_H +extern "C" { +#include +} +#endif + +#ifdef HAVE_FFMPEG_SWRESAMPLE_H +extern "C" { +#include +} +#define HAVE_SWRESAMPLE_H 1 +#endif + +#ifdef HAVE_LIBSWRESAMPLE_SWRESAMPLE_H +extern "C" { +#include +} +#define HAVE_SWRESAMPLE_H 1 +#endif + +#ifdef HAVE_AVRESAMPLE_H +extern "C" { +#include +} +#endif + +#ifdef HAVE_LIBAV_AVRESAMPLE_H +extern "C" { +#include +} +#define HAVE_AVRESAMPLE_H 1 +#endif + +#ifdef HAVE_LIBAVRESAMPLE_AVRESAMPLE_H +extern "C" { +#include +} +#define HAVE_AVRESAMPLE_H 1 +#endif + +#ifdef HAVE_LIBAVUTIL_OPT_H +extern "C" { +#include +} +#endif + #endif // GNASH_MEDIA_FFMPEG_HEADERS_H diff --git a/macros/ffmpeg.m4 b/macros/ffmpeg.m4 index 7e042d9..7f8cb45 100644 --- a/macros/ffmpeg.m4 +++ b/macros/ffmpeg.m4 @@ -255,27 +255,14 @@ AC_DEFUN([GNASH_PATH_FFMPEG], AC_MSG_RESULT($ffmpeg_version ($ffmpeg_num_version)) -dnl AC_EGREP_HEADER(avcodec_decode_audio2, ${avcodec_h}, [avfound=yes], [avfound=no]) - - if test -z "$ffmpeg_num_version" -o "$ffmpeg_num_version" -lt 512800; then - AC_MSG_WARN([Wrong ffmpeg/libavcodec version! 51.28.0 or greater required, $ffmpeg_version detected.]) - else - ffmpeg_version_check=ok - fi +dnl minimum supported libavcodec version = Debian stable one = currently Wheezy 7.0 53.35.00 - if test -z "$ffmpeg_num_version" -o "$ffmpeg_num_version" -lt 514900; then - dnl 51.49.0 or higher required - AC_MSG_WARN([This version of ffmpeg/libavcodec ($ffmpeg_version) is not able to play VP6A encoded video: 51.49.0 or higher required!]) + if test -z "$ffmpeg_num_version" -o "$ffmpeg_num_version" -lt 533500; then + AC_MSG_WARN([Wrong ffmpeg/libavcodec version! 53.35.0 or greater required, $ffmpeg_version detected.]) else - AC_DEFINE(FFMPEG_VP6A, 1, [Define if ffmpeg can play VP6A.]) + ffmpeg_version_check=ok fi - if test -z "$ffmpeg_num_version" -o "$ffmpeg_num_version" -lt 514600; then - dnl 51.46.0 (r10741) or higher required for CODEC_ID_NELLYMOSER - AC_MSG_WARN([This version of ffmpeg/libavcodec ($ffmpeg_version) is not able to decode NELLYMOSER encoded audio: 51.46.0 (r10741) or higher required!]) - else - AC_DEFINE(FFMPEG_NELLYMOSER, 1, [Define if ffmpeg can decode NELLYMOSER audio]) - fi else AC_MSG_WARN([Could not check ffmpeg version (can't find avcodec.h file)]) # ffmpeg_version_check=ok # this is NOT ok, why would it be ?! @@ -319,6 +306,46 @@ dnl AC_EGREP_HEADER(avcodec_decode_audio2, ${avcodec_h}, [avfound=yes], [avfou ffmpeg_version_check= fi + AC_MSG_CHECKING([for libavutil/opt.h]) + have_ffmpeg_libavutil=no + if test -f "${ffmpeg_top_incl}/libavutil/opt.h"; then + have_ffmpeg_libavutil=yes + AC_DEFINE(HAVE_LIBAVUTIL_OPT_H, 1, [Define if libavutil/opt.h is found]) + fi + AC_MSG_RESULT($have_ffmpeg_libavutil) + + AC_MSG_CHECKING([for swresample.h]) + have_ffmpeg_swresample=no + if test -f "${ffmpeg_top_incl}/ffmpeg/swresample.h"; then + have_ffmpeg_swresample=yes + AC_DEFINE(HAVE_FFMPEG_SWRESAMPLE_H, 1, [Define if swresample.h is found]) + fi + if test -f "${ffmpeg_top_incl}/libswresample/swresample.h"; then + have_ffmpeg_swresample=yes + AC_DEFINE(HAVE_LIBSWRESAMPLE_SWRESAMPLE_H, 1, [Define if swresample.h is found]) + fi + if test -f "${ffmpeg_top_incl}/swresample.h"; then + have_ffmpeg_swresample=yes + AC_DEFINE(HAVE_SWRESAMPLE_H, 1, [Define if swresample.h is found]) + fi + AC_MSG_RESULT($have_ffmpeg_swresample) + + AC_MSG_CHECKING([for avresample.h]) + have_libav_avresample=no + if test -f "${ffmpeg_top_incl}/libav/avresample.h"; then + have_libav_avresample=yes + AC_DEFINE(HAVE_LIBAV_AVRESAMPLE_H, 1, [Define if avresample.h is found]) + fi + if test -f "${ffmpeg_top_incl}/libavresample/avresample.h"; then + have_libav_avresample=yes + AC_DEFINE(HAVE_LIBAVRESAMPLE_AVRESAMPLE_H, 1, [Define if avresample.h is found]) + fi + if test -f "${ffmpeg_top_incl}/avresample.h"; then + have_libav_avresample=yes + AC_DEFINE(HAVE_AVRESAMPLE_H, 1, [Define if avresample.h is found]) + fi + AC_MSG_RESULT($have_libav_avresample) + AC_MSG_CHECKING([for libavcodec/vaapi.h]) have_ffmpeg_vaapi="no" if test -f "${ffmpeg_top_incl}/ffmpeg/vaapi.h"; then @@ -625,6 +652,51 @@ dnl AC_EGREP_HEADER(avcodec_decode_audio2, ${avcodec_h}, [avfound=yes], [avfou fi dnl End of SWSCALE library looking } + dnl Look for the {SW,AV}RESAMPLE libraries { + dnl + AC_MSG_CHECKING([for libswresample library]) + if test x"$PKG_CONFIG" != x -a x${cross_compiling} = xno; then + $PKG_CONFIG --exists libswresample && libswresample=`$PKG_CONFIG --libs-only-l libswresample` + else + libswresample="" + fi + if test x"${libswresample}" = x; then + if test -f ${top_lib_dir}/libswresample.a -o -f ${top_lib_dir}/libswresample.${shlibext}; then + ac_cv_path_ffmpeg_lib="${ac_cv_path_ffmpeg_lib} -lswresample" + AC_MSG_RESULT(yes) + else + AC_MSG_RESULT(no) + if test x${cross_compiling} = xno; then + AC_CHECK_LIB(swresample, swresample, [ac_cv_path_ffmpeg_lib="${ac_cv_path_ffmpeg_lib} -lswresample"]) + fi + fi + else + AC_MSG_RESULT(${libswresample}) + ac_cv_path_ffmpeg_lib="${ac_cv_path_ffmpeg_lib} ${libswresample}" + fi + + AC_MSG_CHECKING([for libavresample library]) + if test x"$PKG_CONFIG" != x -a x${cross_compiling} = xno; then + $PKG_CONFIG --exists libavresample && libavresample=`$PKG_CONFIG --libs-only-l libavresample` + else + libavresample="" + fi + if test x"${libavresample}" = x; then + if test -f ${top_lib_dir}/libavresample.a -o -f ${top_lib_dir}/libavresample.${shlibext}; then + ac_cv_path_ffmpeg_lib="${ac_cv_path_ffmpeg_lib} -lavresample" + AC_MSG_RESULT(yes) + else + AC_MSG_RESULT(no) + if test x${cross_compiling} = xno; then + AC_CHECK_LIB(avresample, avresample, [ac_cv_path_ffmpeg_lib="${ac_cv_path_ffmpeg_lib} -lavresample"]) + fi + fi + else + AC_MSG_RESULT(${libavresample}) + ac_cv_path_ffmpeg_lib="${ac_cv_path_ffmpeg_lib} ${libavresample}" + fi + dnl End of {SW,AV}RESAMPLE libraries looking } + fi dnl End of all optional library tests }