diff options
Diffstat (limited to 'plugins/decoder/ffmpeg')
-rw-r--r-- | plugins/decoder/ffmpeg/CMakeLists.txt | 3 | ||||
-rw-r--r-- | plugins/decoder/ffmpeg/Makefile.am | 15 | ||||
-rw-r--r-- | plugins/decoder/ffmpeg/configure.in.bot | 25 | ||||
-rw-r--r-- | plugins/decoder/ffmpeg/configure.in.in | 68 | ||||
-rw-r--r-- | plugins/decoder/ffmpeg/k3bffmpegdecoder.h | 4 | ||||
-rw-r--r-- | plugins/decoder/ffmpeg/k3bffmpegdecoder.plugin | 6 | ||||
-rw-r--r-- | plugins/decoder/ffmpeg/k3bffmpegwrapper.cpp | 581 |
7 files changed, 314 insertions, 388 deletions
diff --git a/plugins/decoder/ffmpeg/CMakeLists.txt b/plugins/decoder/ffmpeg/CMakeLists.txt index 08a977c..7197348 100644 --- a/plugins/decoder/ffmpeg/CMakeLists.txt +++ b/plugins/decoder/ffmpeg/CMakeLists.txt @@ -44,6 +44,7 @@ tde_add_kpart( libk3bffmpegdecoder AUTOMOC ##### other data ################################ -install( FILES k3bffmpegdecoder.plugin +tde_create_translated_desktop( + SOURCE k3bffmpegdecoder.plugin DESTINATION ${DATA_INSTALL_DIR}/k3b/plugins ) diff --git a/plugins/decoder/ffmpeg/Makefile.am b/plugins/decoder/ffmpeg/Makefile.am deleted file mode 100644 index 2e00dc5..0000000 --- a/plugins/decoder/ffmpeg/Makefile.am +++ /dev/null @@ -1,15 +0,0 @@ -AM_CPPFLAGS = -I$(srcdir)/../../../libk3b/core -I$(srcdir)/../../../libk3b/plugin -I$(srcdir)/../../../libk3bdevice $(all_includes) -KDE_CXXFLAGS = -D__STDC_CONSTANT_MACROS - -kde_module_LTLIBRARIES = libk3bffmpegdecoder.la - -libk3bffmpegdecoder_la_SOURCES = k3bffmpegdecoder.cpp k3bffmpegwrapper.cpp - -libk3bffmpegdecoder_la_LIBADD = ../../../libk3b/libk3b.la $(LIB_TDEUI) -lavcodec -lavformat -libk3bffmpegdecoder_la_LDFLAGS = -avoid-version -module -no-undefined $(all_libraries) - -pluginsdir = $(kde_datadir)/k3b/plugins -plugins_DATA = k3bffmpegdecoder.plugin - -METASOURCES = AUTO - diff --git a/plugins/decoder/ffmpeg/configure.in.bot b/plugins/decoder/ffmpeg/configure.in.bot deleted file mode 100644 index 3d24645..0000000 --- a/plugins/decoder/ffmpeg/configure.in.bot +++ /dev/null @@ -1,25 +0,0 @@ -echo "" - -echo "K3b - FFMpeg decoder plugin (decodes wma and others):" -if test x$have_ffmpeg = xyes; then - echo "K3b - yes" - if test x$enable_ffmpeg_all_codecs = xyes; then - echo "K3b - WARNING: You enabled all codecs in the ffmpeg decoder plugin." - echo "K3b - Be aware that most are not tested and track lengths" - echo "K3b - will be wrong in many cases." - fi -else - echo "K3b - no" -if test "$ac_cv_use_ffmpeg" = "yes"; then - if test "$ffmpeg_compiles" = "yes"; then - echo "K3b - You are missing the ffmpeg libraries." - echo "K3b - Make sure ffmpeg has been configured as a" - echo "K3b - shared library (which is not the default)." - else - echo "K3b - You are missing the ffmpeg headers and libraries" - echo "K3b - version 0.4.9 or higher." - fi - echo "K3b - The ffmpeg audio decoding plugin (decodes wma and" - echo "K3b - others) won't be compiled." -fi -fi diff --git a/plugins/decoder/ffmpeg/configure.in.in b/plugins/decoder/ffmpeg/configure.in.in deleted file mode 100644 index 84b345a..0000000 --- a/plugins/decoder/ffmpeg/configure.in.in +++ /dev/null @@ -1,68 +0,0 @@ -dnl --------------- FFMPEG CHECK --------------------------------- - -AC_ARG_WITH( - ffmpeg, - AS_HELP_STRING( - [--without-ffmpeg], - [build K3b without ffmpeg audio decoder support (default=no)]), - [ac_cv_use_ffmpeg=$withval], - [ac_cv_use_ffmpeg=yes] -) - -# -# The ffmpeg decoder plugin needs ffmpeg 0.4.9 or higher -# -have_ffmpeg=no -if test "$ac_cv_use_ffmpeg" = "yes"; then - k3b_cxxflags_save="$CXXFLAGS" - CXXFLAGS="$CXXFLAGS -D__STDC_CONSTANT_MACROS" - AC_MSG_CHECKING(for ffmpeg >= 0.4.9) - AC_LANG_SAVE - AC_LANG_CPLUSPLUS - AC_COMPILE_IFELSE( - extern "C" { - #include <libavformat/avformat.h> - #include <libavcodec/avcodec.h> - } - - int main() { - AVFormatContext* fc = 0; - AVPacket* p = 0; - av_register_all(); - return av_read_frame( fc, p ); - }, - [ffmpeg_compiles=yes], [ffmpeg_compiles=no] ) - OLD_LIBS=$LIBS - LIBS="-lavformat -lavcodec $LIBS" - AC_LINK_IFELSE( - extern "C" { - #include <libavformat/avformat.h> - #include <libavcodec/avcodec.h> - } - - int main() { - AVFormatContext* fc = 0; - AVPacket* p = 0; - av_register_all(); - return av_read_frame( fc, p ); - }, - [ffmpeg_links=yes], [ffmpeg_links=no] ) - AC_LANG_RESTORE - LIBS=$OLD_LIBS - have_ffmpeg=$ffmpeg_links - AC_MSG_RESULT($have_ffmpeg) - CXXFLAGS=$k3b_cxxflags_save -fi -AM_CONDITIONAL(include_FFMPEG, [test x$have_ffmpeg = xyes]) - -dnl --------------- FFMPEG CHECK END ------------------------------ - -AC_ARG_ENABLE( - ffmpeg-all-codecs, - AS_HELP_STRING( - [--enable-ffmpeg-all-codecs], - [Build K3b's ffmeg decoder plugin with all audio codecs enabled (default=disabled)]), - [AC_DEFINE(K3B_FFMPEG_ALL_CODECS, 1, [Defined if all ffmpeg codecs should be allowed]) - enable_ffmpeg_all_codecs=yes], - [enable_ffmpeg_all_codecs=no] -) diff --git a/plugins/decoder/ffmpeg/k3bffmpegdecoder.h b/plugins/decoder/ffmpeg/k3bffmpegdecoder.h index 1b493b7..0afd20a 100644 --- a/plugins/decoder/ffmpeg/k3bffmpegdecoder.h +++ b/plugins/decoder/ffmpeg/k3bffmpegdecoder.h @@ -23,7 +23,7 @@ class K3bFFMpegFile; class K3bFFMpegDecoderFactory : public K3bAudioDecoderFactory { - Q_OBJECT + TQ_OBJECT public: @@ -43,7 +43,7 @@ class K3bFFMpegDecoderFactory : public K3bAudioDecoderFactory class K3bFFMpegDecoder : public K3bAudioDecoder { - Q_OBJECT + TQ_OBJECT public: diff --git a/plugins/decoder/ffmpeg/k3bffmpegdecoder.plugin b/plugins/decoder/ffmpeg/k3bffmpegdecoder.plugin index 3592388..a3e3251 100644 --- a/plugins/decoder/ffmpeg/k3bffmpegdecoder.plugin +++ b/plugins/decoder/ffmpeg/k3bffmpegdecoder.plugin @@ -1,9 +1,9 @@ [K3b Plugin] -Lib=libk3bffmpegdecoder -Group=AudioDecoder Name=K3b FFMpeg Decoder +Comment=Decoding module to decode wma files Author=Sebastian Trueg Email=trueg@k3b.org Version=0.9.1 -Comment=Decoding module to decode wma files License=GPL +Group=AudioDecoder +Lib=libk3bffmpegdecoder diff --git a/plugins/decoder/ffmpeg/k3bffmpegwrapper.cpp b/plugins/decoder/ffmpeg/k3bffmpegwrapper.cpp index 96f8bfe..983c808 100644 --- a/plugins/decoder/ffmpeg/k3bffmpegwrapper.cpp +++ b/plugins/decoder/ffmpeg/k3bffmpegwrapper.cpp @@ -1,10 +1,10 @@ /* * - * $Id: k3bffmpegwrapper.cpp 641819 2007-03-12 17:29:23Z trueg $ - * Copyright (C) 2004-2007 Sebastian Trueg <trueg@k3b.org> + * + * Copyright (C) 2004-2008 Sebastian Trueg <trueg@k3b.org> * * This file is part of the K3b project. - * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * Copyright (C) 1998-2008 Sebastian Trueg <trueg@k3b.org> * * 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 @@ -16,19 +16,48 @@ #include <config.h> #include "k3bffmpegwrapper.h" +#include <tdelocale.h> extern "C" { +/* + Recent versions of FFmpeg uses C99 constant macros which are not present in C++ + standard. The macro __STDC_CONSTANT_MACROS allow C++ to use these macros. + Although it's not defined by C++ standard it's supported by many + implementations. See bug 236036 and discussion: + https://lists.ffmpeg.org/pipermail/ffmpeg-devel/2010-May/095488.html + */ +#define __STDC_CONSTANT_MACROS #include <libavcodec/avcodec.h> #include <libavformat/avformat.h> } +#include <math.h> #include <string.h> -#include <tdelocale.h> - +#if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(52, 101, 0) +#define av_dump_format(c, x, f, y) dump_format(c, x, f, y) +#endif +#if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(53, 2, 0) +// this works because the parameters/options are not used +#define avformat_open_input(c, s, f, o) av_open_input_file(c, s, f, 0, o) +#endif +#if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(53, 6, 0) +#define avformat_find_stream_info(c, o) av_find_stream_info(c) +#endif +#if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(53, 17, 0) +#define avformat_close_input(c) av_close_input_file(*c) +#endif +#if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(57, 41, 100) +#define codecpar codec +#endif -#if LIBAVFORMAT_BUILD < 4629 -#define FFMPEG_BUILD_PRE_4629 +#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(55, 45, 101) +#define av_frame_alloc avcodec_alloc_frame +#endif +#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(54, 28, 0) +#define av_frame_free(f) av_free(*(f)) +#elif LIBAVCODEC_VERSION_INT < AV_VERSION_INT(55, 45, 101) +#define av_frame_free avcodec_free_frame #endif #if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(52, 64, 0) @@ -36,416 +65,420 @@ extern "C" { #define AVMEDIA_TYPE_VIDEO CODEC_TYPE_VIDEO #define AVMEDIA_TYPE_SUBTITLE CODEC_TYPE_SUBTITLE #endif - -// From libavcodec version 54.25, CodecID have been renamed to AVCodecID and all CODEC_ID_* to AV_CODEC_ID_*. -// This code can be simplified once all supported distros have updated to libavcodec version >=54.25 +#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(53, 8, 0) +#define avcodec_open2(a, c, o) avcodec_open(a, c) +#endif #if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(54, 25, 0) -#define K3B_CODEC_ID_WMAV1 CODEC_ID_WMAV1 -#define K3B_CODEC_ID_WMAV2 CODEC_ID_WMAV2 -#define K3B_CODEC_ID_MP3 CODEC_ID_MP3 -#define K3B_CODEC_ID_AAC CODEC_ID_AAC -#else -#define K3B_CODEC_ID_WMAV1 AV_CODEC_ID_WMAV1 -#define K3B_CODEC_ID_WMAV2 AV_CODEC_ID_WMAV2 -#define K3B_CODEC_ID_MP3 AV_CODEC_ID_MP3 -#define K3B_CODEC_ID_AAC AV_CODEC_ID_AAC +// From libavcodec version 54.25, CodecID have been renamed to AVCodecID and all +// CODEC_ID_* to AV_CODEC_ID_*. This code can be simplified once all supported +// distros have updated to libavcodec version >=54.25 +#define AV_CODEC_ID_WMAV1 CODEC_ID_WMAV1 +#define AV_CODEC_ID_WMAV2 CODEC_ID_WMAV2 +#define AV_CODEC_ID_MP3 CODEC_ID_MP3 +#define AV_CODEC_ID_AAC CODEC_ID_AAC +#define AV_CODEC_ID_APE CODEC_ID_APE +#define AV_CODEC_ID_WAVPACK CODEC_ID_WAVPACK +#endif +#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(55,39,101) +#define av_packet_unref av_free_packet #endif +// TODO: most of the used av_functions there are deprecated and there +// are troubles with improper frame/packet processing that +// leads to aborting of decode process +// +// [wmav2 @ 0xxxxx] Multiple frames in a packet. +// [wmav2 @ 0xxxxx] Got unexpected packet size after a partial decode -K3bFFMpegWrapper* K3bFFMpegWrapper::s_instance = 0; - +K3bFFMpegWrapper *K3bFFMpegWrapper::s_instance = NULL; -class K3bFFMpegFile::Private -{ +class K3bFFMpegFile::Private { public: - AVFormatContext* formatContext; - AVCodec* codec; - + TQ_UINT8 *packetData; K3b::Msf length; - // for decoding - char outputBuffer[192000]; - char* outputBufferPos; + ::AVFormatContext *formatContext; + ::AVCodec *codec; + ::AVStream *audio_stream; + ::AVCodecContext *audio_stream_ctx; + ::AVSampleFormat sampleFormat; + ::AVFrame *frame; + ::AVPacket *packet; +#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(57, 12, 100) + ::AVPacket _packet; +#endif + + char *outputBufferPos; int outputBufferSize; - AVPacket packet; - TQ_UINT8* packetData; int packetSize; + bool isSpacious; }; - -K3bFFMpegFile::K3bFFMpegFile( const TQString& filename ) - : m_filename(filename) -{ +K3bFFMpegFile::K3bFFMpegFile(const TQString &filename) : m_filename(filename) { d = new Private; - d->formatContext = 0; - d->codec = 0; + d->formatContext = NULL; + d->codec = NULL; + d->audio_stream = NULL; + d->audio_stream_ctx = NULL; + d->frame = av_frame_alloc(); + d->outputBufferPos = NULL; + d->packet = NULL; } - -K3bFFMpegFile::~K3bFFMpegFile() -{ +K3bFFMpegFile::~K3bFFMpegFile() { close(); + av_frame_free(&d->frame); delete d; } - -bool K3bFFMpegFile::open() -{ +bool K3bFFMpegFile::open() { close(); // open the file -# if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(53, 2, 0) - int err = avformat_open_input( &d->formatContext, m_filename.local8Bit(), 0, 0); -# else - int err = av_open_input_file( &d->formatContext, m_filename.local8Bit(), 0, 0, 0); -# endif - if( err < 0 ) { - kdDebug() << "(K3bFFMpegFile) unable to open " << m_filename << " with error " << err << endl; + int err = ::avformat_open_input(&d->formatContext, m_filename.local8Bit(), + NULL, NULL); + if (err < 0) { + kdDebug() << "(K3bFFMpegFile) unable to open " << m_filename + << " with error " << err; return false; } // analyze the streams -# if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(53, 6, 0) - avformat_find_stream_info( d->formatContext, NULL ); -# else - av_find_stream_info( d->formatContext ); -# endif + ::avformat_find_stream_info(d->formatContext, NULL); // we only handle files containing one audio stream - if( d->formatContext->nb_streams != 1 ) { - kdDebug() << "(K3bFFMpegFile) more than one stream in " << m_filename << endl; - return false; + for (uint i = 0; i < d->formatContext->nb_streams; ++i) { + if (d->formatContext->streams[i]->codecpar->codec_type == + AVMEDIA_TYPE_AUDIO) { + if (!d->audio_stream) { + d->audio_stream = d->formatContext->streams[i]; + } else { + d->audio_stream = NULL; + kdDebug() << "(K3bFFMpegFile) more than one audio stream in " + << m_filename; + return false; + } + } } // urgh... ugly -#ifdef FFMPEG_BUILD_PRE_4629 - AVCodecContext* codecContext = &d->formatContext->streams[0]->codec; +#if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(57, 33, 100) + if (d->audio_stream->codecpar->codec_type != AVMEDIA_TYPE_AUDIO) #else - AVCodecContext* codecContext = d->formatContext->streams[0]->codec; + d->audio_stream_ctx = d->audio_stream->codec; + if (d->audio_stream_ctx->codec_type != AVMEDIA_TYPE_AUDIO) #endif - if( codecContext->codec_type != AVMEDIA_TYPE_AUDIO ) { - kdDebug() << "(K3bFFMpegFile) not a simple audio stream: " << m_filename << endl; + { + kdDebug() << "(K3bFFMpegFile) not a simple audio stream: " << m_filename; return false; } // get the codec - d->codec = avcodec_find_decoder(codecContext->codec_id); - if( !d->codec ) { - kdDebug() << "(K3bFFMpegFile) no codec found for " << m_filename << endl; +#if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(57, 33, 100) + d->codec = (AVCodec *)::avcodec_find_decoder(d->audio_stream->codecpar->codec_id); +#else + d->codec = (AVCodec *)::avcodec_find_decoder(d->audio_stream_ctx->codec_id); +#endif + if (!d->codec) { + kdDebug() << "(K3bFFMpegFile) no codec found for " << m_filename; return false; } +#if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(57, 33, 100) + // allocate a codec context + d->audio_stream_ctx = avcodec_alloc_context3(d->codec); + if (d->audio_stream_ctx) { + avcodec_parameters_to_context(d->audio_stream_ctx, d->audio_stream->codecpar); + } + else { + kdDebug() << "(K3bFFMpegFile) failed to allocate a codec context for " + << m_filename; + } +#endif + // open the codec on our context kdDebug() << "(K3bFFMpegFile) found codec for " << m_filename << endl; - if( -# if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(53, 8, 0) - avcodec_open2( codecContext, d->codec, NULL ) < 0 -# else - avcodec_open( codecContext, d->codec ) < 0 -# endif - ) { - kdDebug() << "(K3bFFMpegDecoderFactory) could not open codec." << endl; + if (::avcodec_open2(d->audio_stream_ctx, d->codec, NULL) < 0) { + kdDebug() << "(K3bFFMpegDecoderFactory) could not open codec."; return false; } // determine the length of the stream - d->length = K3b::Msf::fromSeconds( (double)d->formatContext->duration / (double)AV_TIME_BASE ); + d->length = K3b::Msf::fromSeconds(double(d->formatContext->duration) / + double(AV_TIME_BASE)); - if( d->length == 0 ) { - kdDebug() << "(K3bFFMpegDecoderFactory) invalid length." << endl; + if (d->length == 0) { + kdDebug() << "(K3bFFMpegDecoderFactory) invalid length."; return false; } +#if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(57, 41, 100) + d->sampleFormat = d->audio_stream->codec->sample_fmt; +#else + d->sampleFormat = static_cast<::AVSampleFormat>(d->audio_stream->codecpar->format); +#endif + d->isSpacious = ::av_sample_fmt_is_planar(d->sampleFormat) && + d->audio_stream->codecpar->channels > 1; + // dump some debugging info -# if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(52, 101, 0) - av_dump_format( d->formatContext, 0, m_filename.local8Bit(), 0 ); -# else - dump_format( d->formatContext, 0, m_filename.local8Bit(), 0 ); -# endif + ::av_dump_format(d->formatContext, 0, m_filename.local8Bit(), 0); return true; } - -void K3bFFMpegFile::close() -{ +void K3bFFMpegFile::close() { d->outputBufferSize = 0; d->packetSize = 0; - d->packetData = 0; + d->packetData = NULL; - if( d->codec ) { -#ifdef FFMPEG_BUILD_PRE_4629 - avcodec_close( &d->formatContext->streams[0]->codec ); + if (d->codec) { +#if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(57, 33, 100) + ::avcodec_free_context(&d->audio_stream_ctx); #else - avcodec_close( d->formatContext->streams[0]->codec ); + ::avcodec_close(d->audio_stream_ctx); + d->codec = NULL; #endif - d->codec = 0; } - if( d->formatContext ) { -# if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(53, 17, 0) - avformat_close_input( &d->formatContext ); -# else - av_close_input_file( d->formatContext ); -# endif - d->formatContext = 0; + if (d->formatContext) { + ::avformat_close_input(&d->formatContext); + d->formatContext = NULL; } -} - -K3b::Msf K3bFFMpegFile::length() const -{ - return d->length; + d->audio_stream = NULL; } +K3b::Msf K3bFFMpegFile::length() const { return d->length; } -int K3bFFMpegFile::sampleRate() const -{ -#ifdef FFMPEG_BUILD_PRE_4629 - return d->formatContext->streams[0]->codec.sample_rate; -#else - return d->formatContext->streams[0]->codec->sample_rate; -#endif +int K3bFFMpegFile::sampleRate() const { + return d->audio_stream->codecpar->sample_rate; } - -int K3bFFMpegFile::channels() const -{ -#ifdef FFMPEG_BUILD_PRE_4629 - return d->formatContext->streams[0]->codec.channels; -#else - return d->formatContext->streams[0]->codec->channels; -#endif -} - - -int K3bFFMpegFile::type() const -{ -#ifdef FFMPEG_BUILD_PRE_4629 - return d->formatContext->streams[0]->codec.codec_id; -#else - return d->formatContext->streams[0]->codec->codec_id; -#endif +int K3bFFMpegFile::channels() const { + return d->audio_stream->codecpar->channels; } +int K3bFFMpegFile::type() const { return d->audio_stream->codecpar->codec_id; } -TQString K3bFFMpegFile::typeComment() const -{ - switch( type() ) { - case K3B_CODEC_ID_WMAV1: +TQString K3bFFMpegFile::typeComment() const { + switch (type()) { + case AV_CODEC_ID_WMAV1: return i18n("Windows Media v1"); - case K3B_CODEC_ID_WMAV2: + case AV_CODEC_ID_WMAV2: return i18n("Windows Media v2"); - case K3B_CODEC_ID_MP3: - return i18n("MPEG 1 Layer III"); - case K3B_CODEC_ID_AAC: + case AV_CODEC_ID_WAVPACK: + return i18n("WavPack"); + case AV_CODEC_ID_APE: + return i18n("Monkey's Audio (APE)"); + case AV_CODEC_ID_AAC: return i18n("Advanced Audio Coding (AAC)"); default: - return TQString::fromLocal8Bit( d->codec->name ); + return TQString::fromLocal8Bit(d->codec->name); } } - -TQString K3bFFMpegFile::title() const -{ +TQString K3bFFMpegFile::title() const { // FIXME: is this UTF8 or something?? -#if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(53, 2, 0) - if( d->formatContext->title[0] != '\0' ) - return TQString::fromLocal8Bit( d->formatContext->title ); -#else - AVDictionaryEntry *entry = av_dict_get(d->formatContext->metadata, "title", NULL, 0); - if( entry->value[0] != '\0' ) - return TQString::fromLocal8Bit( entry->value ); -#endif - else - return TQString(); + AVDictionaryEntry *ade = + av_dict_get(d->formatContext->metadata, "TITLE", NULL, 0); + return ade && ade->value && ade->value[0] != '\0' + ? TQString::fromLocal8Bit(ade->value) + : TQString(); } - -TQString K3bFFMpegFile::author() const -{ +TQString K3bFFMpegFile::author() const { // FIXME: is this UTF8 or something?? -#if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(53, 2, 0) - if( d->formatContext->author[0] != '\0' ) - return TQString::fromLocal8Bit( d->formatContext->author ); -#else - AVDictionaryEntry *entry = av_dict_get(d->formatContext->metadata, "author", NULL, 0); - if( entry->value[0] != '\0' ) - return TQString::fromLocal8Bit( entry->value ); -#endif - else - return TQString(); + AVDictionaryEntry *ade = + av_dict_get(d->formatContext->metadata, "ARTIST", NULL, 0); + return ade && ade->value && ade->value[0] != '\0' + ? TQString::fromLocal8Bit(ade->value) + : TQString(); } - -TQString K3bFFMpegFile::comment() const -{ +TQString K3bFFMpegFile::comment() const { // FIXME: is this UTF8 or something?? -#if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(53, 2, 0) - if( d->formatContext->comment[0] != '\0' ) - return TQString::fromLocal8Bit( d->formatContext->comment ); -#else - AVDictionaryEntry *entry = av_dict_get(d->formatContext->metadata, "comment", NULL, 0); - if( entry->value[0] != '\0' ) - return TQString::fromLocal8Bit( entry->value ); -#endif - else - return TQString(); + AVDictionaryEntry *ade = + av_dict_get(d->formatContext->metadata, "COMMENT", NULL, 0); + return ade && ade->value && ade->value[0] != '\0' + ? TQString::fromLocal8Bit(ade->value) + : TQString(); } +int K3bFFMpegFile::read(char *buf, int bufLen) { -int K3bFFMpegFile::read( char* buf, int bufLen ) -{ - if( fillOutputBuffer() > 0 ) { - int len = TQMIN(bufLen, d->outputBufferSize); - ::memcpy( buf, d->outputBufferPos, len ); + int ret = fillOutputBuffer(); + if (ret <= 0) { + return ret; + } - // TODO: only swap if needed - for( int i = 0; i < len-1; i+=2 ) { - char a = buf[i]; - buf[i] = buf[i+1]; - buf[i+1] = a; - } + int len = TQMIN(bufLen, d->outputBufferSize); + ::memcpy(buf, d->outputBufferPos, len); + if (d->isSpacious && bufLen > d->outputBufferSize) + delete[] d->outputBufferPos; // clean up allocated space + + // TODO: only swap if needed + for (int i = 0; i < len - 1; i += 2) + tqSwap(buf[i], buf[i + 1]); // BE -> LE + + d->outputBufferSize -= len; + if (d->outputBufferSize > 0) d->outputBufferPos += len; - d->outputBufferSize -= len; - return len; - } - else - return 0; + return len; } - // fill d->packetData with data to decode -int K3bFFMpegFile::readPacket() -{ - if( d->packetSize <= 0 ) { - av_init_packet( &d->packet ); +int K3bFFMpegFile::readPacket() { + if (d->packetSize <= 0) { +#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 12, 100) + d->packet = ::av_packet_alloc(); +#else + ::av_init_packet(&d->_packet); + d->packet = &d->_packet; +#endif - if( av_read_frame( d->formatContext, &d->packet ) < 0 ) { + if (::av_read_frame(d->formatContext, d->packet) < 0) { return 0; } - - d->packetSize = d->packet.size; - d->packetData = d->packet.data; + d->packetSize = d->packet->size; + d->packetData = d->packet->data; } return d->packetSize; } - // decode data in d->packetData and fill d->outputBuffer -int K3bFFMpegFile::fillOutputBuffer() -{ +int K3bFFMpegFile::fillOutputBuffer() { // decode if the output buffer is empty - if( d->outputBufferSize <= 0 ) { + while (d->outputBufferSize <= 0) { // make sure we have data to decode - if( readPacket() == 0 ) { + if (readPacket() == 0) { return 0; } - d->outputBufferPos = d->outputBuffer; - -#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(52, 64, 0) - AVPacket avp; - av_init_packet( &avp ); - avp.data = d->packetData; - avp.size = d->packetSize; -# if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(53, 25, 0) -int len = avcodec_decode_audio4( d->formatContext->streams[0]->codec, - (AVFrame*)d->outputBuffer, &d->outputBufferSize, - &avp ); -# else -int len = avcodec_decode_audio3( d->formatContext->streams[0]->codec, - (short*)d->outputBuffer, &d->outputBufferSize, - &avp ); -# endif + int gotFrame = 0; +#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 106, 100) + int len = avcodec_receive_frame(d->audio_stream_ctx, d->frame); + if (len == 0) { + gotFrame = 1; + } + else if (len == AVERROR(EAGAIN)) { + len = 0; + } + + if (len == 0) { + len = avcodec_send_packet(d->audio_stream_ctx, d->packet); + if (len == AVERROR(EAGAIN)) { + len = 0; + } + } #else -#ifdef FFMPEG_BUILD_PRE_4629 - int len = avcodec_decode_audio2( &d->formatContext->streams[0]->codec, + int len = ::avcodec_decode_audio4(d->audio_stream_ctx, d->frame, + &gotFrame, d->packet); +#endif + + if (d->packetSize <= 0 || len < 0) { +#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 12, 100) + ::av_packet_free(&d->packet); #else - int len = avcodec_decode_audio2( d->formatContext->streams[0]->codec, + ::av_packet_unref(d->packet); + d->packet = NULL; #endif - (short*)d->outputBuffer, &d->outputBufferSize, - d->packetData, d->packetSize ); + } + if (len < 0) { + kdDebug() << "(K3bFFMpegFile) decoding failed for " << m_filename; + return -1; + } + +#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 12, 100) + len = d->packet->size; #endif + if (gotFrame) { + int nb_s = d->frame->nb_samples; + int nb_ch = 2; // copy only two channels even if there're more + d->outputBufferSize = nb_s * nb_ch * 2; // 2 means 2 bytes (16bit) + d->outputBufferPos = reinterpret_cast<char *>(d->frame->extended_data[0]); + if (d->isSpacious) { + d->outputBufferPos = new char[d->outputBufferSize]; + if (d->sampleFormat == AV_SAMPLE_FMT_FLTP) { + int width = sizeof(float); // sample width of float audio + for (int sample = 0; sample < nb_s; sample++) { + for (int ch = 0; ch < nb_ch; ch++) { + double val = *(reinterpret_cast<float *>( + d->frame->extended_data[ch] + sample * width)); + val = ::abs(val) > 1 ? ::copysign(1.0, val) : val; + int16_t result = + static_cast<int16_t>(val * 32767.0 + 32768.5) - 32768; + ::memcpy(d->outputBufferPos + (sample * nb_ch + ch) * 2, &result, + 2); // 2 is sample width of 16 bit audio + } + } + } else { + for (int sample = 0; sample < nb_s; sample++) { + for (int ch = 0; ch < nb_ch; ch++) { + ::memcpy(d->outputBufferPos + (sample * nb_ch + ch) * 2, + d->frame->extended_data[ch] + sample * 2, + 2); // 16 bit here as well + } + } + } + } + } d->packetSize -= len; d->packetData += len; - - if( d->packetSize <= 0 ) - av_free_packet( &d->packet ); } - // if it is still empty try again - if( d->outputBufferSize <= 0 ) - return fillOutputBuffer(); - else - return d->outputBufferSize; + return d->outputBufferSize; } - -bool K3bFFMpegFile::seek( const K3b::Msf& msf ) -{ +bool K3bFFMpegFile::seek(const K3b::Msf &msf) { d->outputBufferSize = 0; d->packetSize = 0; - double seconds = (double)msf.totalFrames()/75.0; - TQ_UINT64 timestamp = (TQ_UINT64)(seconds * (double)AV_TIME_BASE); + double seconds = double(msf.totalFrames()) / 75.0; + int64_t timestamp = static_cast<int64_t>(seconds * double(AV_TIME_BASE)); // FIXME: do we really need the start_time and why? -#if LIBAVFORMAT_BUILD >= 4619 - return ( av_seek_frame( d->formatContext, -1, timestamp + d->formatContext->start_time, 0 ) >= 0 ); -#else - return ( av_seek_frame( d->formatContext, -1, timestamp + d->formatContext->start_time ) >= 0 ); -#endif + return (::av_seek_frame(d->formatContext, -1, + timestamp + d->formatContext->start_time, 0) >= 0); } - - - - - -K3bFFMpegWrapper::K3bFFMpegWrapper() -{ - av_register_all(); -} - - -K3bFFMpegWrapper::~K3bFFMpegWrapper() -{ - s_instance = 0; +// +// av_register_all is deprecated since ffmpeg 4.0, can be dropped +K3bFFMpegWrapper::K3bFFMpegWrapper() { +#if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(58,9,100) + ::av_register_all(); +#endif } +K3bFFMpegWrapper::~K3bFFMpegWrapper() { s_instance = NULL; } -K3bFFMpegWrapper* K3bFFMpegWrapper::instance() -{ - if( !s_instance ) { +K3bFFMpegWrapper *K3bFFMpegWrapper::instance() { + if (!s_instance) { s_instance = new K3bFFMpegWrapper(); } return s_instance; } - -K3bFFMpegFile* K3bFFMpegWrapper::open( const TQString& filename ) const -{ - K3bFFMpegFile* file = new K3bFFMpegFile( filename ); - if( file->open() ) { +K3bFFMpegFile *K3bFFMpegWrapper::open(const TQString &filename) const { + K3bFFMpegFile *file = new K3bFFMpegFile(filename); + if (file->open()) { #ifndef K3B_FFMPEG_ALL_CODECS // - // only allow tested formats. ffmpeg seems not to be too reliable with every format. - // mp3 being one of them sadly. Most importantly: allow the libsndfile decoder to do - // its thing. + // only allow tested formats. ffmpeg seems not to be too reliable with every + // format. mp3 being one of them sadly. Most importantly: allow the + // libsndfile decoder to do its thing. // - if( file->type() == K3B_CODEC_ID_WMAV1 || - file->type() == K3B_CODEC_ID_WMAV2 || - file->type() == K3B_CODEC_ID_AAC ) + if (file->type() == AV_CODEC_ID_WMAV1 || + file->type() == AV_CODEC_ID_WMAV2 || file->type() == AV_CODEC_ID_AAC || + file->type() == AV_CODEC_ID_APE || file->type() == AV_CODEC_ID_WAVPACK) #endif return file; } delete file; - return 0; + return NULL; } |