Index: libs/libmythtv/avformatdecoder.cpp
===================================================================
--- libs/libmythtv/avformatdecoder.cpp	(revision 17449)
+++ libs/libmythtv/avformatdecoder.cpp	(working copy)
@@ -1,6 +1,7 @@
 // C headers
 #include <cassert>
 #include <unistd.h>
+#include <fcntl.h>
 
 // C++ headers
 #include <algorithm>
@@ -8,6 +9,7 @@
 using namespace std;
 
 #include <q3tl.h>
+#include <qdir.h>
 
 // MythTV headers
 #include "mythconfig.h"
@@ -43,6 +45,7 @@
 #include "../libavcodec/ac3_parser.h"
 #include "../libmythmpeg2/mpeg2.h"
 #include "ivtv_myth.h"
+#include "libavformat/riff.h"
 // from libavcodec
 extern const uint8_t *ff_find_start_code(const uint8_t * restrict p, const uint8_t *end, uint32_t * restrict state);
 }
@@ -132,21 +135,56 @@
 
 typedef MythDeque<AVFrame*> avframe_q;
 
+struct vd_struct {
+  union {
+    uint32_t ret;
+    uint32_t cmd;
+  };
+  uint32_t buflen;
+  uint64_t pts;
+  uint32_t unused[8];
+} __attribute__((__packed__));
+
+enum {
+  VD_END = 1,
+  VD_DECODE = 2,
+  VD_SEEK = 3,
+  VD_HAS_BIH = 0x10000,
+  VD_VERSION_MASK = 0xFFFF,
+};
+
+#include <semaphore.h>
+#include <sys/mman.h>
+typedef struct {
+    int fd;
+    void *mem;
+    char *data;
+    char *picture;
+    int picsize;
+    sem_t *sem_rd;
+    sem_t *sem_wr;
+    struct vd_struct *vd;
+} ds_mpi_t;
+
 /**
  * Management of libmpeg2 decoding
  */
 class AvFormatDecoderPrivate
 {
   public:
-    AvFormatDecoderPrivate(bool allow_libmpeg2)
-        : mpeg2dec(NULL), dvdvdec(NULL), allow_mpeg2dec(allow_libmpeg2) { ; }
-   ~AvFormatDecoderPrivate() { DestroyMPEG2(); }
+    AvFormatDecoderPrivate(bool allow_libmpeg2, bool allow_directshow)
+        : mpeg2dec(NULL), dvdvdec(NULL), allow_mpeg2dec(allow_libmpeg2),
+          ds_mpi(NULL), allow_dshow(allow_directshow) { ; }
+   ~AvFormatDecoderPrivate() { DestroyMPEG2(); DestroyDirectShow();}
     
     bool InitMPEG2(const QString &dec);
     bool HasMPEG2Dec(void) const { return (bool)(mpeg2dec); }
     bool HasDVDVDec(void) const { return (bool)(dvdvdec); }
     bool HasDecoder(void) const { return HasMPEG2Dec() || HasDVDVDec(); }
 
+    bool InitDirectShow(AVCodecContext *enc);
+    bool HasDirectShow() const { return (bool)(ds_mpi); }
+
     void DestroyMPEG2();
     void ResetMPEG2();
     int DecodeMPEG2Video(AVCodecContext *avctx, AVFrame *picture,
@@ -156,13 +194,250 @@
     bool SetVideoSize(const QSize &video_dim);
     DVDV *GetDVDVDecoder(void) { return dvdvdec; }
 
+    void DestroyDirectShow();
+    void ResetDirectShow();
+    int DecodeDirectShowVideo(AVCodecContext *avctx, AVFrame *picture,
+                         int *got_picture_ptr, uint8_t *buf, int buf_size);
+
   private:
     mpeg2dec_t *mpeg2dec;
     DVDV       *dvdvdec;
     bool        allow_mpeg2dec;
+    ds_mpi_t   *ds_mpi;
+    bool        allow_dshow;
     avframe_q   partialFrames;
 };
 
+static int sem_twait(sem_t *sem, int t) {
+    struct timespec ts;
+    clock_gettime(CLOCK_REALTIME, &ts);
+    ts.tv_sec += t;
+    return(sem_timedwait(sem, &ts));
+}
+bool AvFormatDecoderPrivate::InitDirectShow(AVCodecContext *enc)
+{
+    typedef struct {
+        uint32_t f1;
+        uint16_t f2;
+        uint16_t f3;
+        uint8_t  f4[8];
+    } GUID;
+
+    const struct AVCodecTag *bmp_taglists[] = {codec_bmp_tags, 0};
+
+    if(enc->codec_tag == 0)
+        enc->codec_tag = av_codec_get_tag(bmp_taglists, enc->codec_id);
+//    VERBOSE(VB_IMPORTANT, QString("Trying DirectShow for FOURCC 0x%1")
+//            .arg(enc->codec_tag, 8, 16, 0));
+    if (!allow_dshow)
+        return false;
+    DestroyDirectShow();
+    if (enc->codec_tag == 0) {
+        allow_dshow = false;
+        return false;
+    }
+//    QString dec = gContext->GetSetting("UseDirectShowVideoDecoder", "no");
+    QString dec = "yes";
+
+    if (dec == "yes")
+    {
+        bool found = false;
+        QString codec;
+        GUID guid = {0, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0}};
+        QString codec_file = QDir::homeDirPath() +
+                            QString("/.mythtv/dshowcodecs");
+        if (! QFileInfo(codec_file).isFile()) {
+            allow_dshow = false;
+            return false;
+        }
+        QString videotype;
+        AVCodec *avc = avcodec_find_decoder(enc->codec_id);
+        if (! avc) {
+           allow_dshow = false;
+           return false;
+        }
+        videotype = avc->name;
+        QFile fh (codec_file);
+        QString line;
+        fh.open(IO_ReadOnly);
+        while (! fh.atEnd() && ! found) {
+            QStringList fourc, guidlist;
+            QTextStream filein(&fh);
+            line = filein.readLine(1024);
+            codec = line.section(':', 0, 0).stripWhiteSpace();
+            fourc = QStringList::split(",",line.section(':', 1, 1));
+            guidlist  = QStringList::split(",",line.section(':', 2, 2));
+            if (guidlist.count() != 11)
+                continue;
+            for (QStringList::Iterator it = fourc.begin();
+                 it != fourc.end(); it++)
+            {
+                if ((*it).stripWhiteSpace() == videotype)
+                {
+                    guid.f1 = guidlist[0].toUInt(0, 0);
+                    guid.f2 = guidlist[1].toUShort(0, 0);
+                    guid.f3 = guidlist[2].toUShort(0, 0);
+                    for (int i = 0; i < 8; i++)
+                        guid.f4[i] = guidlist[i + 3].toUShort(0, 0);
+                    found = true;
+                }
+            }
+            if (found)
+                break;
+        }
+        fh.close();
+        if (found) {
+            int ret;
+            char cmd[255], shm[80], sem1[80], sem2[80];
+            uint32_t out_fmt;
+            int bpp;
+            //out_fmt = 0x30323449; bpp = 12; //I420 12bpp
+            out_fmt = 0x32595559; bpp = 16; //YUY2 16bpp
+            snprintf(cmd, 255, "dshowserver -c %s -s %dx%d "
+                     "-g %08x-%04x-%04x-%02x%02x%02x%02x%02x%02x%02x%02x "
+                     "-f 0x%08x -b %d -o 0x%08x -p %d -i %x %s&",
+                codec.ascii(), enc->width, enc->height,
+                guid.f1, guid.f2, guid.f3,
+                      guid.f4[0], guid.f4[1], guid.f4[2], guid.f4[3],
+                      guid.f4[4], guid.f4[5], guid.f4[6], guid.f4[7],
+                enc->codec_tag, bpp, out_fmt, getpid(), *(int *)pthread_self(),
+                ((print_verbose_messages & VB_PLAYBACK == VB_PLAYBACK) ?
+                            "-d" : ""));
+            ds_mpi = new ds_mpi_t;
+            snprintf(shm, 80, "/dshow_shm.%x", *(int *)pthread_self());
+            snprintf(sem1, 80, "/dshow_sem1.%x", *(int *)pthread_self());
+            snprintf(sem2, 80, "/dshow_sem2.%x", *(int *)pthread_self());
+            ds_mpi->fd = shm_open(shm, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
+            ds_mpi->picsize =  enc->width * enc->height * bpp / 8;
+            int extra = 0;
+            if (enc->height % 16)
+                extra = (16 - enc->height % 16) * bpp / 8;
+            int memsize = sizeof(struct vd_struct) + enc->width * enc->height +
+                          ds_mpi->picsize + extra;
+            ftruncate(ds_mpi->fd, memsize);
+            ds_mpi->mem = mmap(NULL, memsize, PROT_READ | PROT_WRITE,
+                               MAP_SHARED, ds_mpi->fd, 0);
+            if(ds_mpi->mem == MAP_FAILED) {
+              perror("mmap");
+              allow_dshow = false;
+              return false;
+            }
+            memset((char *)ds_mpi->mem, 0, sizeof(struct vd_struct));
+
+            if (extra)
+                memset((char *)ds_mpi->mem + (memsize - extra), 0, extra);
+            ds_mpi->vd = (struct vd_struct *)ds_mpi->mem;
+            ds_mpi->data = ((char *)ds_mpi->mem) + sizeof(struct vd_struct);
+            ds_mpi->picture = ds_mpi->data + enc->width * enc->height;
+            //Create read/write semaphores in locked state
+            ds_mpi->sem_wr = sem_open(sem1, O_CREAT, 0644, 0);
+            ds_mpi->sem_rd = sem_open(sem2, O_CREAT, 0644, 0);
+            system(cmd);
+            ret = sem_twait(ds_mpi->sem_rd, 10);
+            shm_unlink(shm);
+            sem_unlink(sem1);
+            sem_unlink(sem2);
+            if(ret != 0) {
+                VERBOSE(VB_IMPORTANT, LOC + "DirectShow filter failed");
+            } else {
+                VERBOSE(VB_IMPORTANT, LOC + "Found DirectShow filter");
+                return true;
+            }
+       }
+    }
+    allow_dshow = false;
+    return false;
+}
+
+void AvFormatDecoderPrivate::DestroyDirectShow()
+{
+    if (ds_mpi)
+    {
+        VERBOSE(VB_PLAYBACK, LOC + "Destroying filter");
+        ds_mpi->vd->cmd = VD_END; //'1' is cmd for terminating
+        sem_post(ds_mpi->sem_wr);
+        close(ds_mpi->fd);
+        sem_close(ds_mpi->sem_wr);
+        sem_close(ds_mpi->sem_rd);
+        delete ds_mpi;
+        ds_mpi = NULL;
+    }
+}
+
+void AvFormatDecoderPrivate::ResetDirectShow()
+{
+}
+
+void yuy2i420(AVFrame *dst, char *src, int w, int l)
+{
+    int count;
+  uint8_t *y, *u, *v;
+  y = dst->data[0];
+  u = dst->data[1];
+  v = dst->data[2];
+  int i,j;
+  for(i=0; i < l; i++) {
+    for(j=0; j < w; j+=2) {
+      *(y++) = *(src++);
+      *(u++) = *(src++);
+      *(y++) = *(src++);
+      *(v++) = *(src++);
+    }
+    i++;
+    for(j=0; j < w; j+=2) {
+      *(y++) = *src;
+      src+=2;
+      *(y++) = *src;
+      src+=2;
+   }
+  }
+}
+
+int AvFormatDecoderPrivate::DecodeDirectShowVideo(AVCodecContext *avctx,
+                                             AVFrame *picture,
+                                             int *got_picture_ptr,
+                                             uint8_t *buf, int buf_size)
+{
+    int ret;
+    ds_mpi->vd->cmd = VD_DECODE; //'1' is cmd for decoding
+    memcpy(ds_mpi->data, buf, buf_size);
+    ds_mpi->vd->buflen = buf_size;
+    sem_post(ds_mpi->sem_wr);
+    ret = sem_twait(ds_mpi->sem_rd, 10);
+    if(ret == 0 && ds_mpi->vd->ret && ! (ds_mpi->vd->ret & (1<<31))) {
+        *got_picture_ptr = 1;
+        picture->interlaced_frame = (ds_mpi->vd->ret & 10) ? true : false;
+        avctx->get_buffer(avctx, picture);
+#if 0  //Using YV12
+        if(avctx->height & 0x0f) {
+           unsigned long pos, pos1, siz = avctx->height * avctx->width;
+           memcpy(picture->data[0], ds_mpi->picture, siz);
+           pos = siz;
+           pos1 = siz + avctx->width * (16 - avctx->height % 16);
+           siz /= 4;
+           memcpy(picture->data[0]+pos1, ds_mpi->picture+pos, siz);
+           pos+=siz;
+           pos1+=siz + avctx->width * ( 16 - avctx->height % 16) / 4;
+           memcpy(picture->data[0]+pos1, ds_mpi->picture+pos, siz);
+        } else {
+          memcpy(picture->data[0], ds_mpi->picture, ds_mpi->picsize);
+        }
+#else //Using YUY2
+        //YUY2 is a packed format so padding is easier
+        //int extra = 0;
+        //if(avctx->height % 16)
+            //extra = (16 - avctx->height % 16);
+        yuy2i420(picture, ds_mpi->picture,
+                 avctx->width, avctx->height);
+#endif
+    } else {
+      *got_picture_ptr = 0;
+    }
+    return buf_size;
+}
+
+/*************************************************/
+
 /**
  * \brief Initialise either libmpeg2, or DVDV (Mac HW accel), to do decoding
  *
@@ -384,7 +659,7 @@
                                  bool use_null_videoout,
                                  bool allow_libmpeg2)
     : DecoderBase(parent, pginfo),
-      d(new AvFormatDecoderPrivate(allow_libmpeg2)),
+      d(new AvFormatDecoderPrivate(allow_libmpeg2, true)),
       is_db_ignored(gContext->IsDatabaseIgnored()),
       h264_kf_seq(new H264::KeyframeSequencer()),
       ic(NULL),
@@ -1532,6 +1807,9 @@
                         }
                     }
 
+                    if (CODEC_ID_H264 == enc->codec_id)
+                      force_xv = true;
+
                     MythCodecID mcid;
                     mcid = VideoOutputXv::GetBestSupportedCodec(
                         /* disp dim     */ width, height,
@@ -1541,6 +1819,7 @@
                         /* test surface */ kCodec_NORMAL_END > video_codec_id,
                         /* force_xv     */ force_xv);
                     bool vcd, idct, mc;
+
                     enc->codec_id = (CodecID)
                         myth2av_codecid(mcid, vcd, idct, mc);
 
@@ -1596,6 +1875,7 @@
                 }
 
                 // Initialize alternate decoders when needed...
+              if (! d->InitDirectShow(enc))
                 if (((dec == "libmpeg2") &&
                      (CODEC_ID_MPEG1VIDEO == enc->codec_id ||
                       CODEC_ID_MPEG2VIDEO == enc->codec_id)) ||
@@ -3589,7 +3869,21 @@
                     int gotpicture = 0;
 
                     avcodeclock.lock();
-                    if (d->HasDecoder())
+/*                    printf("Trying: %d\n",len);
+                    if (0) {
+                      static int fnum = 0;
+                      char str[80];
+                      int fh;
+                      sprintf(str,"enc%d", fnum++);;
+                      fh = open(str, 01101,00777);
+                      write(fh, ptr, len);
+                      close(fh);
+                    }
+*/
+                    if (d->HasDirectShow())
+                        ret = d->DecodeDirectShowVideo(context, &mpa_pic,
+                                                  &gotpicture, ptr, len);
+                    else if (d->HasDecoder())
                     {
                         if (decodeStillFrame)
                         {
Index: libs/libmythtv/libmythtv.pro
===================================================================
--- libs/libmythtv/libmythtv.pro	(revision 17449)
+++ libs/libmythtv/libmythtv.pro	(working copy)
@@ -37,6 +37,7 @@
 LIBS += -lmythmpeg2-$$LIBVERSION    -lmythdvdnav-$$LIBVERSION
 LIBS += -lmythfreemheg-$$LIBVERSION -lmythlivemedia-$$LIBVERSION
 LIBS += -lz $$EXTRA_LIBS
+LIBS += -lrt
 
 TARGETDEPS += ../libmyth/libmyth-$${MYTH_SHLIB_EXT}
 TARGETDEPS += ../libavutil/libmythavutil-$${MYTH_SHLIB_EXT}

