Implement support to use libmp3lame via dlopen
==========================================================================
--- a/configure
+++ b/configure
@@ -141,6 +141,7 @@
                            Supported bindings: perl, python
                            comma-separated list
   --python=PATH            Force a specific python executable to use [$python_default]
+  --enable-dlopen-libmp3lame enable libmp3lame use via dlopen [autodetect]
 EOF
 
 #following is ffmpeg's configure help text
@@ -1338,6 +1339,7 @@
     dvdv
     opengl
     vdpau
+    dlopen_libmp3lame
 '
 
 CMDLINE_SELECT="
@@ -2020,6 +2022,12 @@
             fi
         done
     ;;
+    --enable-dlopen-libmp3lame)
+      dlopen_libmp3lame="yes"
+    ;;
+    --disable-dlopen-libmp3lame)
+      dlopen_libmp3lame="no"
+    ;;
     --disable-devices) disable $INDEV_LIST $OUTDEV_LIST
     ;;
     --enable-debug=*) debuglevel="$optval"
@@ -3770,8 +3778,19 @@
 enabled freetype2 ||
     die "ERROR! You must have FreeType installed to compile MythTV."
 
-enabled lamemp3 && check_lib2 lame/lame.h lame_init -lmp3lame -lm ||
-    die "ERROR! You must have the Lame MP3 encoding library installed to compile MythTV."
+# libmp3lame probe
+if test -z "$dlopen_libmp3lame" || test x"$dlopen_libmp3lame" = x"yes"; then
+  { check_header lame/lame.h &&
+    enable dlopen_libmp3lame
+  } || disable dlopen_libmp3lame
+else
+  disable dlopen_libmp3lame
+fi
+
+if disabled dlopen_libmp3lame; then
+  enabled lamemp3 && check_lib2 lame/lame.h lame_init -lmp3lame -lm ||
+    die "ERROR! You must have the Lame MP3 encoding library or header installed to compile MythTV."
+fi
 
 if $(pkg-config --atleast-version 4.4.0 QtWebKit) ; then
     enable qtwebkit
@@ -4251,6 +4270,7 @@
 echo "# Bindings"
 echo "bindings_perl             ${bindings_perl-no}"
 echo "bindings_python           ${bindings_python-no}"
+echo "dlopen libmp3lame         ${dlopen_libmp3lame-no}"
 echo ""
 
 MYTH_CONFIG_H=libs/libmythdb/mythconfig.h
@@ -4564,6 +4584,10 @@
   echo "CONFIG_OPENGL_LIBS=-lGL -lGLU" >> $MYTH_CONFIG_MAK
 fi
 
+if enabled dlopen_libmp3lame; then
+  echo "#define CONFIG_DLOPEN_LIBMP3LAME 1" >>$TMPH
+fi
+
 if test x"$CCONFIG" != x"" ; then
   echo "CCONFIG=$CCONFIG" >> $MYTH_CONFIG_MAK
   echo "#define MYTH_BUILD_CONFIG \"$CCONFIG\"" >>$TMPH
--- /dev/null
+++ b/libs/libmythtv/myth_mp3.h
@@ -0,0 +1,69 @@
+#ifndef MYTH_MP3_H
+#define MYTH_MP3_H
+
+#ifdef MMX
+#undef MMX
+#define MMXBLAH
+#endif
+#include <lame/lame.h>
+#ifdef MMXBLAH
+#define MMX
+#undef MMXBLAH
+#endif
+
+typedef struct {
+    void *handle;
+    int CDECL (*lame_close)(lame_global_flags *);
+    lame_global_flags * CDECL (*lame_init)(void);
+    int CDECL (*lame_set_bWriteVbrTag)(lame_global_flags *, int);
+    int CDECL (*lame_set_quality)(lame_global_flags *, int);
+    int CDECL (*lame_set_compression_ratio)(lame_global_flags *, float);
+    int CDECL (*lame_set_mode)(lame_global_flags *, MPEG_mode);
+    int CDECL (*lame_set_num_channels)(lame_global_flags *, int);
+    int CDECL (*lame_set_in_samplerate)(lame_global_flags *, int);
+    int CDECL (*lame_init_params)(lame_global_flags *);
+    int CDECL (*lame_encode_buffer_interleaved)(lame_global_flags*,short int*,int,
+                                                unsigned char*,int);
+    int CDECL (*lame_encode_buffer)(lame_global_flags*,const short int*,
+                                    const short int*,const int,unsigned char*,
+                                    const int);
+    int CDECL (*lame_encode_flush_nogap)(lame_global_flags*,unsigned char*,int);
+} MythMP3Context;
+
+class MythMP3
+{
+  public:
+    MythMP3();
+    ~MythMP3();
+    bool IsInitilized();
+    int CDECL lame_close(lame_global_flags *);
+    lame_global_flags * CDECL lame_init(void);
+    int CDECL lame_set_bWriteVbrTag(lame_global_flags *, int);
+    int CDECL lame_set_quality(lame_global_flags *, int);
+    int CDECL lame_set_compression_ratio(lame_global_flags *, float);
+    int CDECL lame_set_mode(lame_global_flags *, MPEG_mode);
+    int CDECL lame_set_num_channels(lame_global_flags *, int);
+    int CDECL lame_set_in_samplerate(lame_global_flags *, int);
+    int CDECL lame_init_params(lame_global_flags *);
+    int CDECL lame_encode_buffer_interleaved(
+            lame_global_flags*  gfp,
+            short int           pcm[],
+            int                 num_samples,
+            unsigned char*      mp3buf,
+            int                 mp3buf_size);
+    int CDECL lame_encode_buffer(
+            lame_global_flags*  gfp,
+            const short int     buffer_l [],
+            const short int     buffer_r [],
+            const int           nsamples,
+            unsigned char*      mp3buf,
+            const int           mp3buf_size);
+    int CDECL lame_encode_flush_nogap(
+            lame_global_flags *  gfp,
+            unsigned char*       mp3buf,
+            int                  size);
+  private:
+    MythMP3Context *s;
+};
+
+#endif
--- a/libs/libmythtv/libmythtv.pro
+++ b/libs/libmythtv/libmythtv.pro
@@ -52,7 +52,7 @@
 using_mheg: LIBS += -L../libmythfreemheg -lmythfreemheg-$$LIBVERSION
 using_live: LIBS += -L../libmythlivemedia -lmythlivemedia-$$LIBVERSION
 using_hdhomerun: LIBS += -L../libmythhdhomerun -lmythhdhomerun-$$LIBVERSION
-using_backend: LIBS += -lmp3lame
+using_backend:!using_dlopen_libmp3lame LIBS += -lmp3lame
 LIBS += -lz $$EXTRA_LIBS $$QMAKE_LIBS_DYNLOAD
 
 TARGETDEPS += ../libmyth/libmyth-$${MYTH_SHLIB_EXT}
@@ -432,6 +432,9 @@
     using_ffmpeg_threads:DEFINES += USING_FFMPEG_THREADS
     HEADERS += NuppelVideoRecorder.h       fifowriter.h        audioinput.h
     SOURCES += NuppelVideoRecorder.cpp     fifowriter.cpp      audioinput.cpp
+    HEADERS += myth_mp3.h
+    SOURCES += myth_mp3.cpp
+    LIBS += -ldl
     using_alsa {
         HEADERS += audioinputalsa.h
         SOURCES += audioinputalsa.cpp
--- a/libs/libmythtv/NuppelVideoRecorder.cpp
+++ b/libs/libmythtv/NuppelVideoRecorder.cpp
@@ -190,7 +190,7 @@
     if (mp3buf)
         delete [] mp3buf;
     if (gf)
-        lame_close(gf);
+        myth_mp3.lame_close(gf);
     if (strm)
         delete [] strm;
     if (audio_device)
@@ -717,17 +717,17 @@
 
     if (compressaudio)
     {
-        gf = lame_init();
-        lame_set_bWriteVbrTag(gf, 0);
-        lame_set_quality(gf, mp3quality);
-        lame_set_compression_ratio(gf, 11);
-        lame_set_mode(gf, audio_channels == 2 ? STEREO : MONO);
-        lame_set_num_channels(gf, audio_channels);
-        lame_set_in_samplerate(gf, audio_samplerate);
-        if ((tmp = lame_init_params(gf)) != 0)
+        gf = myth_mp3.lame_init();
+        myth_mp3.lame_set_bWriteVbrTag(gf, 0);
+        myth_mp3.lame_set_quality(gf, mp3quality);
+        myth_mp3.lame_set_compression_ratio(gf, 11);
+        myth_mp3.lame_set_mode(gf, audio_channels == 2 ? STEREO : MONO);
+        myth_mp3.lame_set_num_channels(gf, audio_channels);
+        myth_mp3.lame_set_in_samplerate(gf, audio_samplerate);
+        if ((tmp = myth_mp3.lame_init_params(gf)) != 0)
         {
             VERBOSE(VB_IMPORTANT, LOC_ERR +
-                    QString("AudioInit(): lame_init_params error %1").arg(tmp));
+                    QString("AudioInit(): myth_mp3.lame_init_params error %1").arg(tmp));
             compressaudio = false;
         }
 
@@ -3194,13 +3194,13 @@
 
         if (audio_channels == 2)
         {
-            lameret = lame_encode_buffer_interleaved(
+            lameret = myth_mp3.lame_encode_buffer_interleaved(
                 gf, (short int*) buf, sample_cnt,
                 (unsigned char*) mp3buf, mp3buf_size);
         }
         else
         {
-            lameret = lame_encode_buffer(
+            lameret = myth_mp3.lame_encode_buffer(
                 gf, (short int*) buf, (short int*) buf, sample_cnt,
                 (unsigned char*) mp3buf, mp3buf_size);
         }
@@ -3213,7 +3213,7 @@
         }
         compressedsize = lameret;
 
-        lameret = lame_encode_flush_nogap(gf, (unsigned char *)mp3gapless,
+        lameret = myth_mp3.lame_encode_flush_nogap(gf, (unsigned char *)mp3gapless,
                                           7200);
         if (lameret < 0)
         {
--- /dev/null
+++ b/libs/libmythtv/myth_mp3.cpp
@@ -0,0 +1,199 @@
+extern "C" {
+#include <dlfcn.h>
+}
+#include "mythconfig.h"
+#include "myth_mp3.h"
+
+#if (defined __APPLE__)
+#define LIBMP3LAME "libmp3lame.dylib"
+#else
+#define LIBMP3LAME "libmp3lame.so.0"
+#endif
+
+MythMP3::MythMP3()
+{
+#ifndef CONFIG_DLOPEN_LIBMP3LAME
+    s = NULL;
+#else
+    /* use the initializer function to initilize the libmp3lame library */
+    const char* const libmp3lame = LIBMP3LAME;
+    s->handle = dlopen(libmp3lame, RTLD_LOCAL | RTLD_LAZY);
+    if (!s->handle)
+        return;
+    const char* err = 0;
+#define TOSTRING(s) #s
+#define init_sym(a, b) do {                                      \
+        const char* n = TOSTRING(lame_##b);                      \
+        if (!err && !(s->lame_##b = (a)dlsym(s->handle, n))) {   \
+            err = n;                                             \
+        }                                                        \
+    } while(0)
+    /* resolve function calls */
+    init_sym(int CDECL (*)(lame_global_flags*), close);
+    init_sym(lame_global_flags * CDECL (*)(void), init);
+    init_sym(int CDECL (*)(lame_global_flags*, int), set_bWriteVbrTag);
+    init_sym(int CDECL (*)(lame_global_flags*, int), set_quality);
+    init_sym(int CDECL (*)(lame_global_flags*, float), set_compression_ratio);
+    init_sym(int CDECL (*)(lame_global_flags*, MPEG_mode), set_mode);
+    init_sym(int CDECL (*)(lame_global_flags*, int), set_num_channels);
+    init_sym(int CDECL (*)(lame_global_flags*, int), set_in_samplerate);
+    init_sym(int CDECL (*)(lame_global_flags*), init_params);
+    init_sym(int CDECL (*)(lame_global_flags*,short int*,int,unsigned char*,
+                           int),
+             encode_buffer_interleaved);
+    init_sym(int CDECL (*)(lame_global_flags*,const short int*,const short int*,
+                           const int,unsigned char*,const int),
+             encode_buffer);
+    init_sym(int CDECL (*)(lame_global_flags*,unsigned char*,int),
+             encode_flush_nogap);
+    if (err)
+    {
+        dlclose(s->handle);
+        s->handle = NULL;
+        return;
+    }
+#endif /* CONFIG_DLOPEN_LIBMP3LAME */
+}
+
+MythMP3::~MythMP3()
+{
+#ifdef CONFIG_DLOPEN_LIBMP3LAME
+    dlclose(s->handle);
+#endif
+}
+
+bool MythMP3::IsInitilized()
+{
+#ifndef CONFIG_DLOPEN_LIBMP3LAME
+    return true;
+#else
+    return (s->handle != NULL);
+#endif
+}
+
+/* libmp3lame calls */
+lame_global_flags * CDECL MythMP3::lame_init(void)
+{
+#ifndef CONFIG_DLOPEN_LIBMP3LAME
+    return ::lame_init();
+#else
+    return (*s->lame_init)();
+#endif
+}
+
+int CDECL MythMP3::lame_close(lame_global_flags *a)
+{
+#ifndef CONFIG_DLOPEN_LIBMP3LAME
+    return ::lame_close(a);
+#else
+    return (*s->lame_close)(a);
+#endif
+}
+
+int CDECL MythMP3::lame_set_bWriteVbrTag(lame_global_flags *a, int b)
+{
+#ifndef CONFIG_DLOPEN_LIBMP3LAME
+    return ::lame_set_bWriteVbrTag(a,b);
+#else
+    return (*s->lame_set_bWriteVbrTag)(a,b);
+#endif
+}
+
+int CDECL MythMP3::lame_set_quality(lame_global_flags *a, int b)
+{
+#ifndef CONFIG_DLOPEN_LIBMP3LAME
+    return ::lame_set_quality(a,b);
+#else
+    return (*s->lame_set_quality)(a,b);
+#endif
+}
+
+int CDECL MythMP3::lame_set_compression_ratio(lame_global_flags *a, float b)
+{
+#ifndef CONFIG_DLOPEN_LIBMP3LAME
+    return ::lame_set_compression_ratio(a,b);
+#else
+    return (*s->lame_set_compression_ratio)(a,b);
+#endif
+}
+
+int CDECL MythMP3::lame_set_mode(lame_global_flags *a, MPEG_mode b)
+{
+#ifndef CONFIG_DLOPEN_LIBMP3LAME
+    return ::lame_set_mode(a,b);
+#else
+    return (*s->lame_set_mode)(a,b);
+#endif
+}
+
+int CDECL MythMP3::lame_set_num_channels(lame_global_flags *a, int b)
+{
+#ifndef CONFIG_DLOPEN_LIBMP3LAME
+    return ::lame_set_num_channels(a,b);
+#else
+    return (*s->lame_set_num_channels)(a,b);
+#endif
+}
+
+int CDECL MythMP3::lame_set_in_samplerate(lame_global_flags *a , int b)
+{
+#ifndef CONFIG_DLOPEN_LIBMP3LAME
+    return ::lame_set_in_samplerate(a,b);
+#else
+    return (*s->lame_set_in_samplerate)(a,b);
+#endif
+}
+
+int CDECL MythMP3::lame_init_params(lame_global_flags *a)
+{
+#ifndef CONFIG_DLOPEN_LIBMP3LAME
+    return ::lame_init_params(a);
+#else
+    return (*s->lame_init_params)(a);
+#endif
+}
+
+int CDECL MythMP3::lame_encode_buffer_interleaved(
+        lame_global_flags*  gfp,
+        short int           pcm[],
+        int                 num_samples,
+        unsigned char*      mp3buf,
+        int                 mp3buf_size)
+{
+#ifndef CONFIG_DLOPEN_LIBMP3LAME
+    return ::lame_encode_buffer_interleaved(gfp,pcm,num_samples,mp3buf,
+                                            mp3buf_size);
+#else
+    return (*s->lame_encode_buffer_interleaved)(gfp,pcm,num_samples,mp3buf,
+                                                mp3buf_size);
+#endif
+}
+
+int CDECL MythMP3::lame_encode_buffer (
+        lame_global_flags*  gfp,
+        const short int     buffer_l [],
+        const short int     buffer_r [],
+        const int           nsamples,
+        unsigned char*      mp3buf,
+        const int           mp3buf_size)
+{
+#ifndef CONFIG_DLOPEN_LIBMP3LAME
+    return ::lame_encode_buffer(gfp,buffer_l,buffer_r,nsamples,mp3buf,
+                                mp3buf_size);
+#else
+    return (*s->lame_encode_buffer)(gfp,buffer_l,buffer_r,nsamples,mp3buf,
+                                    mp3buf_size);
+#endif
+}
+
+int CDECL MythMP3::lame_encode_flush_nogap(
+        lame_global_flags *  gfp,
+        unsigned char*       mp3buf,
+        int                  size)
+{
+#ifndef CONFIG_DLOPEN_LIBMP3LAME
+    return ::lame_encode_flush_nogap(gfp,mp3buf,size);
+#else
+    return (*s->lame_encode_flush_nogap)(gfp,mp3buf,size);
+#endif
+}
--- a/libs/libmythtv/NuppelVideoRecorder.h
+++ b/libs/libmythtv/NuppelVideoRecorder.h
@@ -35,6 +35,8 @@
 
 #include "mythexp.h"
 
+#include "myth_mp3.h"
+
 struct video_audio;
 struct VBIData;
 struct cc;
@@ -287,6 +289,8 @@
 
     bool go7007;
     bool resetcapture;
+
+    MythMP3 myth_mp3;
 };
 
 #endif
