1 Index: libs/libmythtv/avformatdecoder.cpp
2 ===================================================================
3 --- libs/libmythtv/avformatdecoder.cpp.orig 2010-01-02 15:05:30.000000000 -0800
4 +++ libs/libmythtv/avformatdecoder.cpp 2010-01-02 15:26:03.000000000 -0800
20 #include "mythconfig.h"
21 #include "avformatdecoder.h"
24 #include "../libmythmpeg2/mpeg2.h"
25 #include "ivtv_myth.h"
26 +#include "libavformat/riff.h"
29 #define LOC QString("AFD: ")
32 typedef MythDeque<AVFrame*> avframe_q;
42 +} __attribute__((__packed__));
48 + VD_HAS_BIH = 0x10000,
49 + VD_VERSION_MASK = 0xFFFF,
51 +#include "timeout_sem.c"
52 +#include <sys/mman.h>
61 + struct vd_struct *vd;
66 * Management of libmpeg2 decoding
68 class AvFormatDecoderPrivate
71 - AvFormatDecoderPrivate(bool allow_libmpeg2)
72 - : mpeg2dec(NULL), dvdvdec(NULL), allow_mpeg2dec(allow_libmpeg2) { ; }
73 - ~AvFormatDecoderPrivate() { DestroyMPEG2(); }
74 + AvFormatDecoderPrivate(bool allow_libmpeg2, bool allow_directshow)
75 + : mpeg2dec(NULL), dvdvdec(NULL), allow_mpeg2dec(allow_libmpeg2),
76 + ds_mpi(NULL), allow_dshow(allow_directshow) { ; }
77 + ~AvFormatDecoderPrivate() { DestroyMPEG2(); DestroyDirectShow();}
79 bool InitMPEG2(const QString &dec);
80 bool HasMPEG2Dec(void) const { return (bool)(mpeg2dec); }
81 bool HasDVDVDec(void) const { return (bool)(dvdvdec); }
82 bool HasDecoder(void) const { return HasMPEG2Dec() || HasDVDVDec(); }
84 + bool InitDirectShow(AVCodecContext *enc);
85 + bool HasDirectShow() const { return (bool)(ds_mpi); }
89 int DecodeMPEG2Video(AVCodecContext *avctx, AVFrame *picture,
90 @@ -205,13 +245,252 @@
91 bool SetVideoSize(const QSize &video_dim);
92 DVDV *GetDVDVDecoder(void) { return dvdvdec; }
94 + void DestroyDirectShow();
95 + void ResetDirectShow();
96 + int DecodeDirectShowVideo(AVCodecContext *avctx, AVFrame *picture,
97 + int *got_picture_ptr, uint8_t *buf, int buf_size,
101 mpeg2dec_t *mpeg2dec;
106 avframe_q partialFrames;
109 +bool AvFormatDecoderPrivate::InitDirectShow(AVCodecContext *enc)
117 + unsigned int codec_tag;
118 + const struct AVCodecTag *bmp_taglists[] = {ff_codec_bmp_tags, 0};
120 + codec_tag = av_codec_get_tag(bmp_taglists, enc->codec_id);
121 + VERBOSE(VB_IMPORTANT, LOC + QString("Trying DirectShow for FOURCC 0x%1")
122 + .arg(codec_tag, 8, 16));
125 + DestroyDirectShow();
126 + if (codec_tag == 0) {
127 + allow_dshow = false;
130 +// QString dec = gContext->GetSetting("UseDirectShowVideoDecoder", "no");
131 + QString dec = "yes";
135 + bool found = false;
137 + GUID guid = {0, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0}};
138 + QString codec_file = QDir::homePath() +
139 + QString("/.mythtv/dshowcodecs");
140 + if (! QFileInfo(codec_file).isFile()) {
141 + allow_dshow = false;
145 + AVCodec *avc = avcodec_find_decoder(enc->codec_id);
147 + allow_dshow = false;
150 + videotype = avc->name;
151 + QFile fh (codec_file);
153 + fh.open(QIODevice::ReadOnly);
154 + while (! fh.atEnd() && ! found) {
155 + QStringList fourc, guidlist;
156 + line = fh.readLine(1024);
157 + codec = line.section(':', 0, 0).simplified();
158 + fourc = line.section(':', 1, 1).split(",");
159 + guidlist = line.section(':', 2, 2).split(",");
160 + if (guidlist.count() != 11)
162 + for (QStringList::Iterator it = fourc.begin();
163 + it != fourc.end(); it++)
165 + if ((*it).simplified() == videotype)
167 + guid.f1 = guidlist[0].toUInt(0, 0);
168 + guid.f2 = guidlist[1].toUShort(0, 0);
169 + guid.f3 = guidlist[2].toUShort(0, 0);
170 + for (int i = 0; i < 8; i++)
171 + guid.f4[i] = guidlist[i + 3].toUShort(0, 0);
181 + char cmd[255], shm[80];
185 + //out_fmt = 0x30323449; bpp = 12; //I420 12bpp
186 + out_fmt = 0x32595559; bpp = 16; //YUY2 16bpp
187 + snprintf(cmd, 255, "dshowserver --codec %s --size %dx%d "
188 + "--guid %08x-%04x-%04x-%02x%02x%02x%02x%02x%02x%02x%02x "
189 + "--fourc 0x%08x --bits %d --outfmt 0x%08x --pid %d --id %x "
191 + codec.toAscii().constData(), enc->width, enc->height,
192 + guid.f1, guid.f2, guid.f3,
193 + guid.f4[0], guid.f4[1], guid.f4[2], guid.f4[3],
194 + guid.f4[4], guid.f4[5], guid.f4[6], guid.f4[7],
195 + codec_tag, bpp, out_fmt, getpid(), *(int *)pthread_self(), port,
196 + ((print_verbose_messages & VB_PLAYBACK) == VB_PLAYBACK ?
198 + ds_mpi = new ds_mpi_t;
199 + snprintf(shm, 80, "/dshow_shm.%x", *(int *)pthread_self());
200 + ds_mpi->fd = shm_open(shm, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
202 + ds_mpi->picsize = enc->width * enc->height * bpp / 8;
204 + if (enc->height % 16)
205 + extra = (16 - enc->height % 16) * bpp / 8;
206 + int memsize = sizeof(struct vd_struct) + enc->width * enc->height +
207 + ds_mpi->picsize + extra;
208 + ftruncate(ds_mpi->fd, memsize);
209 + ds_mpi->mem = mmap(NULL, memsize, PROT_READ | PROT_WRITE,
210 + MAP_SHARED, ds_mpi->fd, 0);
211 + if(ds_mpi->mem == MAP_FAILED) {
213 + allow_dshow = false;
216 + memset((char *)ds_mpi->mem, 0, sizeof(struct vd_struct));
219 + memset((char *)ds_mpi->mem + (memsize - extra), 0, extra);
220 + ds_mpi->vd = (struct vd_struct *)ds_mpi->mem;
221 + ds_mpi->data = ((char *)ds_mpi->mem) + sizeof(struct vd_struct);
222 + ds_mpi->picture = ds_mpi->data + enc->width * enc->height;
224 + //Create read/write semaphores in locked state
225 + ds_mpi->sem = timed_seminit(DS_SOCKET, &port, 1);
226 + //ds_mpi->sem = timed_seminit(DS_SEMAPHORE, *(int *)pthread_self(), 1);
229 + ret = timed_semwait(ds_mpi->sem, 10);
232 + VERBOSE(VB_IMPORTANT, LOC + "DirectShow filter failed");
234 + VERBOSE(VB_IMPORTANT, LOC + "Found DirectShow filter");
239 + allow_dshow = false;
243 +void AvFormatDecoderPrivate::DestroyDirectShow()
247 + VERBOSE(VB_PLAYBACK, LOC + "Destroying filter");
248 + ds_mpi->vd->cmd = VD_END; //'1' is cmd for terminating
249 + timed_sempost(ds_mpi->sem);
251 + timed_semdelete(ds_mpi->sem);
257 +void AvFormatDecoderPrivate::ResetDirectShow()
260 + ds_mpi->vd->cmd = VD_SEEK; //'3' is cmd for seek
261 + timed_sempost(ds_mpi->sem);
262 + timed_semwait(ds_mpi->sem, 10);
266 +void yuy2i420(AVFrame *dst, char *src, int w, int l)
268 + uint8_t *y, *u, *v;
273 + for(i=0; i < l; i++) {
274 + for(j=0; j < w; j+=2) {
281 + for(j=0; j < w; j+=2) {
290 +int AvFormatDecoderPrivate::DecodeDirectShowVideo(AVCodecContext *avctx,
292 + int *got_picture_ptr,
293 + uint8_t *buf, int buf_size,
297 + ds_mpi->vd->cmd = VD_DECODE; //'1' is cmd for decoding
298 + memcpy(ds_mpi->data, buf, buf_size);
299 + ds_mpi->vd->buflen = buf_size;
300 + ds_mpi->vd->pts = (uint64_t)*pts;
301 + timed_sempost(ds_mpi->sem);
302 + ret = timed_semwait(ds_mpi->sem, 10);
303 + if (ret == 1 && ds_mpi->vd->ret && ! (ds_mpi->vd->ret & (1<<31))) {
304 + *got_picture_ptr = 1;
305 + if (ds_mpi->vd->pts) {
306 + *pts = (long long)ds_mpi->vd->pts;
308 + picture->interlaced_frame = (ds_mpi->vd->ret & 10) ? true : false;
309 + avctx->get_buffer(avctx, picture);
311 + if(avctx->height & 0x0f) {
312 + unsigned long pos, pos1, siz = avctx->height * avctx->width;
313 + memcpy(picture->data[0], ds_mpi->picture, siz);
315 + pos1 = siz + avctx->width * (16 - avctx->height % 16);
317 + memcpy(picture->data[0]+pos1, ds_mpi->picture+pos, siz);
319 + pos1+=siz + avctx->width * ( 16 - avctx->height % 16) / 4;
320 + memcpy(picture->data[0]+pos1, ds_mpi->picture+pos, siz);
322 + memcpy(picture->data[0], ds_mpi->picture, ds_mpi->picsize);
325 + //YUY2 is a packed format so padding is easier
327 + //if(avctx->height % 16)
328 + //extra = (16 - avctx->height % 16);
329 + yuy2i420(picture, ds_mpi->picture,
330 + avctx->width, avctx->height);
333 + *got_picture_ptr = 0;
338 +/*************************************************/
341 * \brief Initialise either libmpeg2, or DVDV (Mac HW accel), to do decoding
345 bool no_hardware_decode)
346 : DecoderBase(parent, pginfo),
347 - d(new AvFormatDecoderPrivate(allow_libmpeg2)),
348 + d(new AvFormatDecoderPrivate(allow_libmpeg2, true)),
349 is_db_ignored(gContext->IsDatabaseIgnored()),
350 m_h264_parser(new H264Parser()),
353 avcodec_flush_buffers(enc);
356 + d->ResetDirectShow();
359 // Discard all the queued up decoded frames
360 @@ -1673,6 +1953,9 @@
364 + if (CODEC_ID_H264 == enc->codec_id)
368 mcid = VideoOutputXv::GetBestSupportedCodec(
369 /* disp dim */ width, height,
370 @@ -1754,6 +2037,7 @@
373 // Initialize alternate decoders when needed...
374 + if (! d->InitDirectShow(enc))
375 if ((dec == "libmpeg2") &&
376 (CODEC_IS_MPEG(enc->codec_id)))
378 @@ -3905,7 +4189,21 @@
382 - if (d->HasDecoder())
383 +/* printf("Trying: %d\n",len);
385 + static int fnum = 0;
388 + sprintf(str,"enc%d", fnum++);;
389 + fh = open(str, 01101,00777);
390 + write(fh, ptr, len);
394 + if (d->HasDirectShow())
395 + ret = d->DecodeDirectShowVideo(context, &mpa_pic,
396 + &gotpicture, ptr, len, &pts);
397 + else if (d->HasDecoder())
399 if (decodeStillFrame)
401 Index: libs/libmythtv/libmythtv.pro
402 ===================================================================
403 --- libs/libmythtv/libmythtv.pro.orig 2010-01-02 15:05:30.000000000 -0800
404 +++ libs/libmythtv/libmythtv.pro 2010-01-02 15:06:01.000000000 -0800
406 using_hdhomerun: LIBS += -L../libmythhdhomerun -lmythhdhomerun-$$LIBVERSION
407 using_backend: LIBS += -lmp3lame
408 LIBS += -lz $$EXTRA_LIBS $$QMAKE_LIBS_DYNLOAD
411 TARGETDEPS += ../libmyth/libmyth-$${MYTH_SHLIB_EXT}
412 TARGETDEPS += ../libavutil/libmythavutil-$${MYTH_SHLIB_EXT}
413 Index: libs/libmythtv/timeout_sem.c
414 ===================================================================
415 --- /dev/null 1970-01-01 00:00:00.000000000 +0000
416 +++ libs/libmythtv/timeout_sem.c 2010-01-02 15:07:56.000000000 -0800
427 + #include <netinet/in.h>
428 + #include <sys/socket.h>
429 + #include <arpa/inet.h>
430 + #include <sys/wait.h>
432 + #define DS_EINPROGRESS EINPROGRESS
433 + #define DS_ETIMEDOUT ETIMEDOUT
434 + #define DS_EWOULDBLOCK EWOULDBLOCK
436 + #define _WIN32_WINNT 0x0501
437 + #include <windows.h>
438 + #include <winsock2.h>
439 + #include <ws2tcpip.h>
441 + #define DS_EINPROGRESS WSAEINPROGRESS
442 + #define DS_ETIMEDOUT WSAETIMEDOUT
443 + #define DS_EWOULDBLOCK WSAEWOULDBLOCK
446 +#include "timeout_sem.h"
448 + #undef DS_SEMAPHORE
453 +#include <semaphore.h>
467 +#endif /*DS_SEMAPHORE*/
472 + void ALRMhandler(int sig) {
474 + int sem_twait(sem_t *sem, int t) {
477 + ret = sem_wait(sem);
478 + printf("twait complete\n");
481 + void init_twait() {
483 + struct sigaction sa;
484 + sigemptyset(&none);
485 + sigprocmask(SIG_SETMASK, &none, 0);
487 + sa.sa_handler = ALRMhandler;
489 + sigemptyset(&sa.sa_mask);
490 + sigaction(SIGALRM, &sa, 0);
493 + int sem_twait(sem_t *sem, int t) {
494 + struct timespec ts;
495 + clock_gettime(CLOCK_REALTIME, &ts);
497 + return(sem_timedwait(sem, &ts));
499 + void init_twait() {}
501 +#endif /*DS_SEMAPHORE */
503 +int setblocking(int sock, int block)
505 + unsigned long opts;
507 + opts = fcntl(sock,F_GETFL);
509 + perror("fcntl(F_GETFL)");
510 + exit(EXIT_FAILURE);
512 + opts = block ? (opts & ~O_NONBLOCK)
513 + : (opts | O_NONBLOCK);
514 + if (fcntl(sock,F_SETFL,opts) < 0) {
515 + perror("fcntl(F_SETFL)");
516 + exit(EXIT_FAILURE);
520 + if ( ioctlsocket( sock, FIONBIO, &opts ) == SOCKET_ERROR )
522 + perror("ioctlsocket");
523 + exit(EXIT_FAILURE);
529 +int timed_connect(int sockfd, const struct sockaddr *serv_addr,
530 + socklen_t addrlen, int secs) {
531 + //Socket should already be non-blocking
538 + // Trying to connect with timeout
539 + res = connect(sockfd, serv_addr, addrlen);
541 + if (errno == DS_EINPROGRESS || errno == DS_EWOULDBLOCK || errno == 0) {
542 + fprintf(stderr, "EINPROGRESS in connect() - selecting\n");
547 + FD_SET(sockfd, &myset);
548 + res = select(sockfd+1, NULL, &myset, &myset, &tv);
549 + if (res < 0 && errno != EINTR) {
550 + fprintf(stderr, "Error connecting (select) %d - %s\n", errno, strerror(errno));
553 + else if (res > 0) {
554 + // Socket selected for write
556 + if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (void*)(&valopt), &lon) < 0) {
557 + fprintf(stderr, "Error in getsockopt() %d - %s\n", errno, strerror(errno));
560 + // Check the value returned...
562 + fprintf(stderr, "Error in delayed connection() %d - %s\n", valopt, strerror(valopt)
569 + fprintf(stderr, "Timeout in select() - Cancelling!\n");
575 + fprintf(stderr, "Error connecting (connect) %d - %s\n", errno, strerror(errno));
579 + // I hope that is all
582 +int timed_accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen, int secs) {
583 + //Socket should already be non-blocking
591 + FD_SET(sockfd, &myset);
592 + res = select(sockfd+1, &myset, NULL, NULL, &tv);
593 + if (res < 0 && errno != EINTR) {
594 + fprintf(stderr, "Error accepting %d - %s\n", errno, strerror(errno));
597 + else if (res > 0) {
598 + // Socket selected for read
599 + return accept(sockfd, NULL, NULL);
601 + errno = DS_ETIMEDOUT;
604 +int timed_recv(int sockfd, void *buf, size_t len, int flags, int secs) {
605 + //Socket should already be non-blocking
613 + FD_SET(sockfd, &myset);
614 + res = select(sockfd+1, &myset, NULL, NULL, &tv);
615 + if (res < 0 && errno != EINTR) {
616 + fprintf(stderr, "Error accepting %d - %s\n", errno, strerror(errno));
619 + else if (res > 0) {
620 + // Socket selected for read
621 + return recv(sockfd, buf, len, flags);
623 + errno = DS_ETIMEDOUT;
627 +int timed_sockinit(int *port, int is_server)
629 + int sockfd; // listen on sock_fd
630 + struct sockaddr_in my_addr;
631 + socklen_t peer_addr_size = sizeof(struct sockaddr_in);
636 + if(WSAStartup(MAKEWORD(2, 2), &wsaData) !=0) {
637 + printf("WSAStartup failed\n");
642 + memset(&my_addr, 0, sizeof(my_addr));
643 + my_addr.sin_family = AF_INET;
644 + my_addr.sin_addr.s_addr=INADDR_ANY;
645 + my_addr.sin_port = *port;
646 + if ((sockfd = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
647 + perror("server: socket");
651 + setblocking(sockfd, 0);
653 + if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (const char *)&yes,
654 + sizeof(int)) == -1) {
655 + perror("setsockopt");
659 + if (bind(sockfd, (struct sockaddr *) &my_addr, sizeof(struct sockaddr_in)) == -1) {
661 + perror("server: bind");
664 + if (listen(sockfd, 1) == -1) {
668 + if (getsockname(sockfd, (struct sockaddr *)&my_addr, &peer_addr_size) == -1) {
669 + perror("getsockname");
672 + if(my_addr.sin_port == 0) {
673 + printf("Failed to get port\n");
676 + *port = my_addr.sin_port;
678 + if (timed_connect(sockfd, (struct sockaddr *) &my_addr, sizeof(struct sockaddr_in), 10) == -1)
681 + perror("client: connect");
689 +int timed_semwait(void *_sem, int secs) {
690 + struct sem *sem = (struct sem *)_sem;
692 + if(sem->type == DS_SOCKET) {
693 + if(! sem->initialized) {
694 + ok = timed_accept(sem->sockfd, NULL, NULL, secs);
696 + sem->listenfd = sem->sockfd;
699 + sem->initialized = 1;
702 + ok = (timed_recv(sem->sockfd, sem->mutex_rx, 1, 0, secs) == 1);
706 + else if(sem->type == DS_SEMAPHORE) {
707 + ok = (sem_twait(sem->sem_rd, secs) == 0);
708 + if(! sem->initialized) {
709 + timed_semclean(sem);
710 + sem->initialized = 1;
714 + if(!ok && errno == DS_ETIMEDOUT) {
720 +void timed_sempost(void *_sem) {
721 + struct sem *sem = (struct sem *)_sem;
722 + if(sem->type == DS_SOCKET) {
723 + send(sem->sockfd, sem->mutex_tx, 1, 0);
726 + else if(sem->type == DS_SEMAPHORE) {
727 + sem_post(sem->sem_wr);
732 +void timed_semclean(void * _sem) {
734 + struct sem *sem = (struct sem *) _sem;
735 + if(sem->type == DS_SEMAPHORE) {
736 + char sem1[80], sem2[80];
737 + snprintf(sem1, 80, "/dshow_sem1.%s", (char *)sem->id);
738 + snprintf(sem2, 80, "/dshow_sem2.%s", (char *)sem->id);
745 +void *timed_seminit(unsigned int semtype, void *id, int is_host) {
747 + sem = (struct sem *)malloc(sizeof(struct sem));
748 + memset(sem, 0, sizeof(struct sem));
749 + sem->type = semtype;
751 + sem->initialized = !(is_host);
752 + if(semtype == DS_SOCKET) {
753 + sem->listenfd = -1;
754 + sem->sockfd = timed_sockinit((int *)id, is_host);
755 + if(sem->sockfd == -1) {
756 + perror("sock_init");
761 + else if(semtype == DS_SEMAPHORE) {
762 + char semrd[80], semwr[80];
764 + snprintf(semrd, 80, "/dshow_sem%d.%s", is_host ? 2 : 1, (char *)id);
765 + snprintf(semwr, 80, "/dshow_sem%d.%s", is_host ? 1 : 2, (char *)id);
767 + sem->sem_rd = sem_open(semrd, O_CREAT, 0644, 0);
768 + sem->sem_wr = sem_open(semwr, O_CREAT, 0644, 0);
770 + sem->sem_rd = sem_open(semrd, 0);
771 + sem->sem_wr = sem_open(semwr, 0);
775 + if(sem->sem_rd == SEM_FAILED) {
776 + timed_semclean(sem);
777 + perror("sem_open(1)");
780 + if(sem->sem_wr == SEM_FAILED) {
781 + timed_semclean(sem);
782 + perror("sem_open(2)");
785 + //tell calling procedure that we are awake;
787 + sem_post(sem->sem_wr);
790 +#endif /*DS_SEMAPHORE*/
792 + fprintf(stderr, "Unknown type specified: %d\n", semtype);
798 +void timed_semdelete(void *_sem) {
799 + struct sem *sem = (struct sem *) _sem;
800 + if(sem->type == DS_SOCKET) {
801 + close(sem->sockfd);
802 + if(sem->listenfd != -1)
803 + close(sem->listenfd);
805 + } else if(sem->type == DS_SEMAPHORE) {
806 + if(! sem->initialized)
807 + timed_semclean(sem);
808 + sem_close(sem->sem_wr);
809 + sem_close(sem->sem_rd);
815 Index: libs/libmythtv/timeout_sem.h
816 ===================================================================
817 --- /dev/null 1970-01-01 00:00:00.000000000 +0000
818 +++ libs/libmythtv/timeout_sem.h 2010-01-02 15:07:59.000000000 -0800
820 +#define DS_SOCKET 0x01
821 +#define DS_SEMAPHORE 0x02
823 +#define DS_TIMEOUT -1
825 +void *timed_seminit(unsigned int semtype, void *id, int is_host);
826 +void timed_semclean(void *_sem);
827 +void timed_sempost(void *_sem);
828 +int timed_semwait(void *_sem, int secs);
829 +void timed_semdelete(void *_sem);