]>
Commit | Line | Data |
---|---|---|
765b517e | 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 | |
5 | @@ -2,12 +2,16 @@ | |
6 | #include <cassert> | |
7 | #include <unistd.h> | |
8 | #include <cmath> | |
9 | +#include <fcntl.h> | |
10 | ||
11 | // C++ headers | |
12 | #include <algorithm> | |
13 | #include <iostream> | |
14 | using namespace std; | |
15 | ||
16 | +// QT headers | |
17 | +#include "qdir.h" | |
18 | + | |
19 | // MythTV headers | |
20 | #include "mythconfig.h" | |
21 | #include "avformatdecoder.h" | |
22 | @@ -53,6 +57,7 @@ | |
23 | #include "avio.h" | |
24 | #include "../libmythmpeg2/mpeg2.h" | |
25 | #include "ivtv_myth.h" | |
26 | +#include "libavformat/riff.h" | |
27 | } | |
28 | ||
29 | #define LOC QString("AFD: ") | |
30 | @@ -181,21 +186,56 @@ | |
31 | ||
32 | typedef MythDeque<AVFrame*> avframe_q; | |
33 | ||
34 | +struct vd_struct { | |
35 | + union { | |
36 | + uint32_t ret; | |
37 | + uint32_t cmd; | |
38 | + }; | |
39 | + uint32_t buflen; | |
40 | + uint64_t pts; | |
41 | + uint32_t unused[8]; | |
42 | +} __attribute__((__packed__)); | |
43 | + | |
44 | +enum { | |
45 | + VD_END = 1, | |
46 | + VD_DECODE = 2, | |
47 | + VD_SEEK = 3, | |
48 | + VD_HAS_BIH = 0x10000, | |
49 | + VD_VERSION_MASK = 0xFFFF, | |
50 | +}; | |
51 | +#include "timeout_sem.c" | |
52 | +#include <sys/mman.h> | |
53 | + | |
54 | +typedef struct { | |
55 | + int fd; | |
56 | + void *mem; | |
57 | + char *data; | |
58 | + char *picture; | |
59 | + int picsize; | |
60 | + void *sem; | |
61 | + struct vd_struct *vd; | |
62 | +} ds_mpi_t; | |
63 | + | |
64 | + | |
65 | /** | |
66 | * Management of libmpeg2 decoding | |
67 | */ | |
68 | class AvFormatDecoderPrivate | |
69 | { | |
70 | public: | |
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();} | |
78 | ||
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(); } | |
83 | ||
84 | + bool InitDirectShow(AVCodecContext *enc); | |
85 | + bool HasDirectShow() const { return (bool)(ds_mpi); } | |
86 | + | |
87 | void DestroyMPEG2(); | |
88 | void ResetMPEG2(); | |
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; } | |
93 | ||
94 | + void DestroyDirectShow(); | |
95 | + void ResetDirectShow(); | |
96 | + int DecodeDirectShowVideo(AVCodecContext *avctx, AVFrame *picture, | |
97 | + int *got_picture_ptr, uint8_t *buf, int buf_size, | |
98 | + long long *pts); | |
99 | + | |
100 | private: | |
101 | mpeg2dec_t *mpeg2dec; | |
102 | DVDV *dvdvdec; | |
103 | bool allow_mpeg2dec; | |
104 | + ds_mpi_t *ds_mpi; | |
105 | + bool allow_dshow; | |
106 | avframe_q partialFrames; | |
107 | }; | |
108 | ||
109 | +bool AvFormatDecoderPrivate::InitDirectShow(AVCodecContext *enc) | |
110 | +{ | |
111 | + typedef struct { | |
112 | + uint32_t f1; | |
113 | + uint16_t f2; | |
114 | + uint16_t f3; | |
115 | + uint8_t f4[8]; | |
116 | + } GUID; | |
117 | + unsigned int codec_tag; | |
118 | + const struct AVCodecTag *bmp_taglists[] = {ff_codec_bmp_tags, 0}; | |
119 | + | |
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)); | |
123 | + if (!allow_dshow) | |
124 | + return false; | |
125 | + DestroyDirectShow(); | |
126 | + if (codec_tag == 0) { | |
127 | + allow_dshow = false; | |
128 | + return false; | |
129 | + } | |
130 | +// QString dec = gContext->GetSetting("UseDirectShowVideoDecoder", "no"); | |
131 | + QString dec = "yes"; | |
132 | + | |
133 | + if (dec == "yes") | |
134 | + { | |
135 | + bool found = false; | |
136 | + QString codec; | |
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; | |
142 | + return false; | |
143 | + } | |
144 | + QString videotype; | |
145 | + AVCodec *avc = avcodec_find_decoder(enc->codec_id); | |
146 | + if (! avc) { | |
147 | + allow_dshow = false; | |
148 | + return false; | |
149 | + } | |
150 | + videotype = avc->name; | |
151 | + QFile fh (codec_file); | |
152 | + QString line; | |
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) | |
161 | + continue; | |
162 | + for (QStringList::Iterator it = fourc.begin(); | |
163 | + it != fourc.end(); it++) | |
164 | + { | |
165 | + if ((*it).simplified() == videotype) | |
166 | + { | |
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); | |
172 | + found = true; | |
173 | + } | |
174 | + } | |
175 | + if (found) | |
176 | + break; | |
177 | + } | |
178 | + fh.close(); | |
179 | + if (found) { | |
180 | + int ret; | |
181 | + char cmd[255], shm[80]; | |
182 | + uint32_t out_fmt; | |
183 | + int bpp; | |
184 | + int port = 0; | |
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 " | |
190 | + "--port %d %s&", | |
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 ? | |
197 | + "-d" : "")); | |
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); | |
201 | + | |
202 | + ds_mpi->picsize = enc->width * enc->height * bpp / 8; | |
203 | + int extra = 0; | |
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) { | |
212 | + perror("mmap"); | |
213 | + allow_dshow = false; | |
214 | + return false; | |
215 | + } | |
216 | + memset((char *)ds_mpi->mem, 0, sizeof(struct vd_struct)); | |
217 | + | |
218 | + if (extra) | |
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; | |
223 | + | |
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); | |
227 | + | |
228 | + myth_system(cmd); | |
229 | + ret = timed_semwait(ds_mpi->sem, 10); | |
230 | + shm_unlink(shm); | |
231 | + if(ret <= 0) { | |
232 | + VERBOSE(VB_IMPORTANT, LOC + "DirectShow filter failed"); | |
233 | + } else { | |
234 | + VERBOSE(VB_IMPORTANT, LOC + "Found DirectShow filter"); | |
235 | + return true; | |
236 | + } | |
237 | + } | |
238 | + } | |
239 | + allow_dshow = false; | |
240 | + return false; | |
241 | +} | |
242 | + | |
243 | +void AvFormatDecoderPrivate::DestroyDirectShow() | |
244 | +{ | |
245 | + if (ds_mpi) | |
246 | + { | |
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); | |
250 | + close(ds_mpi->fd); | |
251 | + timed_semdelete(ds_mpi->sem); | |
252 | + delete ds_mpi; | |
253 | + ds_mpi = NULL; | |
254 | + } | |
255 | +} | |
256 | + | |
257 | +void AvFormatDecoderPrivate::ResetDirectShow() | |
258 | +{ | |
259 | + if (ds_mpi) { | |
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); | |
263 | + } | |
264 | +} | |
265 | + | |
266 | +void yuy2i420(AVFrame *dst, char *src, int w, int l) | |
267 | +{ | |
268 | + uint8_t *y, *u, *v; | |
269 | + y = dst->data[0]; | |
270 | + u = dst->data[1]; | |
271 | + v = dst->data[2]; | |
272 | + int i,j; | |
273 | + for(i=0; i < l; i++) { | |
274 | + for(j=0; j < w; j+=2) { | |
275 | + *(y++) = *(src++); | |
276 | + *(u++) = *(src++); | |
277 | + *(y++) = *(src++); | |
278 | + *(v++) = *(src++); | |
279 | + } | |
280 | + i++; | |
281 | + for(j=0; j < w; j+=2) { | |
282 | + *(y++) = *src; | |
283 | + src+=2; | |
284 | + *(y++) = *src; | |
285 | + src+=2; | |
286 | + } | |
287 | + } | |
288 | +} | |
289 | + | |
290 | +int AvFormatDecoderPrivate::DecodeDirectShowVideo(AVCodecContext *avctx, | |
291 | + AVFrame *picture, | |
292 | + int *got_picture_ptr, | |
293 | + uint8_t *buf, int buf_size, | |
294 | + long long *pts) | |
295 | +{ | |
296 | + int ret; | |
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; | |
307 | + } | |
308 | + picture->interlaced_frame = (ds_mpi->vd->ret & 10) ? true : false; | |
309 | + avctx->get_buffer(avctx, picture); | |
310 | +#if 0 //Using YV12 | |
311 | + if(avctx->height & 0x0f) { | |
312 | + unsigned long pos, pos1, siz = avctx->height * avctx->width; | |
313 | + memcpy(picture->data[0], ds_mpi->picture, siz); | |
314 | + pos = siz; | |
315 | + pos1 = siz + avctx->width * (16 - avctx->height % 16); | |
316 | + siz /= 4; | |
317 | + memcpy(picture->data[0]+pos1, ds_mpi->picture+pos, siz); | |
318 | + pos+=siz; | |
319 | + pos1+=siz + avctx->width * ( 16 - avctx->height % 16) / 4; | |
320 | + memcpy(picture->data[0]+pos1, ds_mpi->picture+pos, siz); | |
321 | + } else { | |
322 | + memcpy(picture->data[0], ds_mpi->picture, ds_mpi->picsize); | |
323 | + } | |
324 | +#else //Using YUY2 | |
325 | + //YUY2 is a packed format so padding is easier | |
326 | + //int extra = 0; | |
327 | + //if(avctx->height % 16) | |
328 | + //extra = (16 - avctx->height % 16); | |
329 | + yuy2i420(picture, ds_mpi->picture, | |
330 | + avctx->width, avctx->height); | |
331 | +#endif | |
332 | + } else { | |
333 | + *got_picture_ptr = 0; | |
334 | + } | |
335 | + return buf_size; | |
336 | +} | |
337 | + | |
338 | +/*************************************************/ | |
339 | + | |
340 | /** | |
341 | * \brief Initialise either libmpeg2, or DVDV (Mac HW accel), to do decoding | |
342 | * | |
343 | @@ -434,7 +713,7 @@ | |
344 | bool allow_libmpeg2, | |
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()), | |
351 | ic(NULL), | |
352 | @@ -723,6 +1002,7 @@ | |
353 | avcodec_flush_buffers(enc); | |
354 | } | |
355 | d->ResetMPEG2(); | |
356 | + d->ResetDirectShow(); | |
357 | } | |
358 | ||
359 | // Discard all the queued up decoded frames | |
360 | @@ -1673,6 +1953,9 @@ | |
361 | } | |
362 | } | |
363 | ||
364 | + if (CODEC_ID_H264 == enc->codec_id) | |
365 | + force_xv = true; | |
366 | + | |
367 | MythCodecID mcid; | |
368 | mcid = VideoOutputXv::GetBestSupportedCodec( | |
369 | /* disp dim */ width, height, | |
370 | @@ -1754,6 +2037,7 @@ | |
371 | } | |
372 | ||
373 | // Initialize alternate decoders when needed... | |
374 | + if (! d->InitDirectShow(enc)) | |
375 | if ((dec == "libmpeg2") && | |
376 | (CODEC_IS_MPEG(enc->codec_id))) | |
377 | { | |
378 | @@ -3905,7 +4189,21 @@ | |
379 | int gotpicture = 0; | |
380 | ||
381 | avcodeclock.lock(); | |
382 | - if (d->HasDecoder()) | |
383 | +/* printf("Trying: %d\n",len); | |
384 | + if (0) { | |
385 | + static int fnum = 0; | |
386 | + char str[80]; | |
387 | + int fh; | |
388 | + sprintf(str,"enc%d", fnum++);; | |
389 | + fh = open(str, 01101,00777); | |
390 | + write(fh, ptr, len); | |
391 | + close(fh); | |
392 | + } | |
393 | +*/ | |
394 | + if (d->HasDirectShow()) | |
395 | + ret = d->DecodeDirectShowVideo(context, &mpa_pic, | |
396 | + &gotpicture, ptr, len, &pts); | |
397 | + else if (d->HasDecoder()) | |
398 | { | |
399 | if (decodeStillFrame) | |
400 | { | |
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 | |
405 | @@ -55,6 +55,7 @@ | |
406 | using_hdhomerun: LIBS += -L../libmythhdhomerun -lmythhdhomerun-$$LIBVERSION | |
407 | using_backend: LIBS += -lmp3lame | |
408 | LIBS += -lz $$EXTRA_LIBS $$QMAKE_LIBS_DYNLOAD | |
409 | +LIBS += -lrt | |
410 | ||
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 | |
417 | @@ -0,0 +1,397 @@ | |
418 | +#include <stdio.h> | |
419 | +#include <stdlib.h> | |
420 | +#include <unistd.h> | |
421 | +#include <fcntl.h> | |
422 | +#include <errno.h> | |
423 | +#include <string.h> | |
424 | + | |
425 | +#ifndef __MINGW32__ | |
426 | + #include <netdb.h> | |
427 | + #include <netinet/in.h> | |
428 | + #include <sys/socket.h> | |
429 | + #include <arpa/inet.h> | |
430 | + #include <sys/wait.h> | |
431 | + | |
432 | + #define DS_EINPROGRESS EINPROGRESS | |
433 | + #define DS_ETIMEDOUT ETIMEDOUT | |
434 | + #define DS_EWOULDBLOCK EWOULDBLOCK | |
435 | +#else | |
436 | + #define _WIN32_WINNT 0x0501 | |
437 | + #include <windows.h> | |
438 | + #include <winsock2.h> | |
439 | + #include <ws2tcpip.h> | |
440 | + | |
441 | + #define DS_EINPROGRESS WSAEINPROGRESS | |
442 | + #define DS_ETIMEDOUT WSAETIMEDOUT | |
443 | + #define DS_EWOULDBLOCK WSAEWOULDBLOCK | |
444 | +#endif | |
445 | + | |
446 | +#include "timeout_sem.h" | |
447 | +#ifdef __MINGW32__ | |
448 | + #undef DS_SEMAPHORE | |
449 | +#endif | |
450 | + | |
451 | +#ifdef DS_SEMAPHORE | |
452 | +#include <time.h> | |
453 | +#include <semaphore.h> | |
454 | +#endif | |
455 | + | |
456 | +struct sem { | |
457 | + int type; | |
458 | + int initialized; | |
459 | + int sockfd; | |
460 | + int listenfd; | |
461 | + void *id; | |
462 | + char mutex_rx[1]; | |
463 | + char mutex_tx[1]; | |
464 | +#ifdef DS_SEMAPHORE | |
465 | + sem_t *sem_rd; | |
466 | + sem_t *sem_wr; | |
467 | +#endif /*DS_SEMAPHORE*/ | |
468 | +}; | |
469 | + | |
470 | +#ifdef DS_SEMAPHORE | |
471 | +#ifdef __APPLE__ | |
472 | + void ALRMhandler(int sig) { | |
473 | + } | |
474 | + int sem_twait(sem_t *sem, int t) { | |
475 | + int ret; | |
476 | + alarm(t); | |
477 | + ret = sem_wait(sem); | |
478 | + printf("twait complete\n"); | |
479 | + return ret; | |
480 | + } | |
481 | + void init_twait() { | |
482 | + sigset_t none; | |
483 | + struct sigaction sa; | |
484 | + sigemptyset(&none); | |
485 | + sigprocmask(SIG_SETMASK, &none, 0); | |
486 | + | |
487 | + sa.sa_handler = ALRMhandler; | |
488 | + sa.sa_flags = 0; | |
489 | + sigemptyset(&sa.sa_mask); | |
490 | + sigaction(SIGALRM, &sa, 0); | |
491 | + } | |
492 | +#else | |
493 | + int sem_twait(sem_t *sem, int t) { | |
494 | + struct timespec ts; | |
495 | + clock_gettime(CLOCK_REALTIME, &ts); | |
496 | + ts.tv_sec += t; | |
497 | + return(sem_timedwait(sem, &ts)); | |
498 | + } | |
499 | + void init_twait() {} | |
500 | +#endif | |
501 | +#endif /*DS_SEMAPHORE */ | |
502 | + | |
503 | +int setblocking(int sock, int block) | |
504 | +{ | |
505 | + unsigned long opts; | |
506 | +#ifndef __MINGW32__ | |
507 | + opts = fcntl(sock,F_GETFL); | |
508 | + if (opts < 0) { | |
509 | + perror("fcntl(F_GETFL)"); | |
510 | + exit(EXIT_FAILURE); | |
511 | + } | |
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); | |
517 | + } | |
518 | +#else | |
519 | + opts = !(block); | |
520 | + if ( ioctlsocket( sock, FIONBIO, &opts ) == SOCKET_ERROR ) | |
521 | + { | |
522 | + perror("ioctlsocket"); | |
523 | + exit(EXIT_FAILURE); | |
524 | + } | |
525 | +#endif | |
526 | + return 0; | |
527 | +} | |
528 | + | |
529 | +int timed_connect(int sockfd, const struct sockaddr *serv_addr, | |
530 | + socklen_t addrlen, int secs) { | |
531 | + //Socket should already be non-blocking | |
532 | + int res; | |
533 | + fd_set myset; | |
534 | + struct timeval tv; | |
535 | + int valopt; | |
536 | + socklen_t lon; | |
537 | + | |
538 | + // Trying to connect with timeout | |
539 | + res = connect(sockfd, serv_addr, addrlen); | |
540 | + if (res < 0 ) { | |
541 | + if (errno == DS_EINPROGRESS || errno == DS_EWOULDBLOCK || errno == 0) { | |
542 | + fprintf(stderr, "EINPROGRESS in connect() - selecting\n"); | |
543 | + do { | |
544 | + tv.tv_sec = secs; | |
545 | + tv.tv_usec = 0; | |
546 | + FD_ZERO(&myset); | |
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)); | |
551 | + return -1; | |
552 | + } | |
553 | + else if (res > 0) { | |
554 | + // Socket selected for write | |
555 | + lon = sizeof(int); | |
556 | + if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (void*)(&valopt), &lon) < 0) { | |
557 | + fprintf(stderr, "Error in getsockopt() %d - %s\n", errno, strerror(errno)); | |
558 | + return -1; | |
559 | + } | |
560 | + // Check the value returned... | |
561 | + if (valopt) { | |
562 | + fprintf(stderr, "Error in delayed connection() %d - %s\n", valopt, strerror(valopt) | |
563 | +); | |
564 | + return -1; | |
565 | + } | |
566 | + break; | |
567 | + } | |
568 | + else { | |
569 | + fprintf(stderr, "Timeout in select() - Cancelling!\n"); | |
570 | + return -1; | |
571 | + } | |
572 | + } while (1); | |
573 | + } | |
574 | + else { | |
575 | + fprintf(stderr, "Error connecting (connect) %d - %s\n", errno, strerror(errno)); | |
576 | + return -1; | |
577 | + } | |
578 | + } | |
579 | + // I hope that is all | |
580 | + return 0; | |
581 | +} | |
582 | +int timed_accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen, int secs) { | |
583 | + //Socket should already be non-blocking | |
584 | + int res; | |
585 | + fd_set myset; | |
586 | + struct timeval tv; | |
587 | + | |
588 | + tv.tv_sec = secs; | |
589 | + tv.tv_usec = 0; | |
590 | + FD_ZERO(&myset); | |
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)); | |
595 | + return -1; | |
596 | + } | |
597 | + else if (res > 0) { | |
598 | + // Socket selected for read | |
599 | + return accept(sockfd, NULL, NULL); | |
600 | + } | |
601 | + errno = DS_ETIMEDOUT; | |
602 | + return -1; | |
603 | +} | |
604 | +int timed_recv(int sockfd, void *buf, size_t len, int flags, int secs) { | |
605 | + //Socket should already be non-blocking | |
606 | + int res; | |
607 | + fd_set myset; | |
608 | + struct timeval tv; | |
609 | + | |
610 | + tv.tv_sec = secs; | |
611 | + tv.tv_usec = 0; | |
612 | + FD_ZERO(&myset); | |
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)); | |
617 | + return -1; | |
618 | + } | |
619 | + else if (res > 0) { | |
620 | + // Socket selected for read | |
621 | + return recv(sockfd, buf, len, flags); | |
622 | + } | |
623 | + errno = DS_ETIMEDOUT; | |
624 | + return -1; | |
625 | +} | |
626 | + | |
627 | +int timed_sockinit(int *port, int is_server) | |
628 | +{ | |
629 | + int sockfd; // listen on sock_fd | |
630 | + struct sockaddr_in my_addr; | |
631 | + socklen_t peer_addr_size = sizeof(struct sockaddr_in); | |
632 | + int yes=1; | |
633 | + | |
634 | +#ifdef __MINGW32__ | |
635 | + WSADATA wsaData; | |
636 | + if(WSAStartup(MAKEWORD(2, 2), &wsaData) !=0) { | |
637 | + printf("WSAStartup failed\n"); | |
638 | + exit(1); | |
639 | + } | |
640 | +#endif | |
641 | + | |
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"); | |
648 | + exit(1); | |
649 | + } | |
650 | + | |
651 | + setblocking(sockfd, 0); | |
652 | + if (is_server) { | |
653 | + if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (const char *)&yes, | |
654 | + sizeof(int)) == -1) { | |
655 | + perror("setsockopt"); | |
656 | + exit(1); | |
657 | + } | |
658 | + | |
659 | + if (bind(sockfd, (struct sockaddr *) &my_addr, sizeof(struct sockaddr_in)) == -1) { | |
660 | + close(sockfd); | |
661 | + perror("server: bind"); | |
662 | + exit(1); | |
663 | + } | |
664 | + if (listen(sockfd, 1) == -1) { | |
665 | + perror("listen"); | |
666 | + exit(1); | |
667 | + } | |
668 | + if (getsockname(sockfd, (struct sockaddr *)&my_addr, &peer_addr_size) == -1) { | |
669 | + perror("getsockname"); | |
670 | + exit(1); | |
671 | + } | |
672 | + if(my_addr.sin_port == 0) { | |
673 | + printf("Failed to get port\n"); | |
674 | + exit(1); | |
675 | + } | |
676 | + *port = my_addr.sin_port; | |
677 | + } else { | |
678 | + if (timed_connect(sockfd, (struct sockaddr *) &my_addr, sizeof(struct sockaddr_in), 10) == -1) | |
679 | + { | |
680 | + close(sockfd); | |
681 | + perror("client: connect"); | |
682 | + exit(1); | |
683 | + } | |
684 | + } | |
685 | + | |
686 | + return sockfd; | |
687 | +} | |
688 | + | |
689 | +int timed_semwait(void *_sem, int secs) { | |
690 | + struct sem *sem = (struct sem *)_sem; | |
691 | + int ok = -1; | |
692 | + if(sem->type == DS_SOCKET) { | |
693 | + if(! sem->initialized) { | |
694 | + ok = timed_accept(sem->sockfd, NULL, NULL, secs); | |
695 | + if(ok != -1) { | |
696 | + sem->listenfd = sem->sockfd; | |
697 | + sem->sockfd = ok; | |
698 | + ok = 1; | |
699 | + sem->initialized = 1; | |
700 | + } | |
701 | + } else { | |
702 | + ok = (timed_recv(sem->sockfd, sem->mutex_rx, 1, 0, secs) == 1); | |
703 | + } | |
704 | + } | |
705 | +#ifdef DS_SEMAPHORE | |
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; | |
711 | + } | |
712 | + } | |
713 | +#endif | |
714 | + if(!ok && errno == DS_ETIMEDOUT) { | |
715 | + ok = DS_TIMEOUT; | |
716 | + } | |
717 | + return ok; | |
718 | +} | |
719 | + | |
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); | |
724 | + } | |
725 | +#ifdef DS_SEMAPHORE | |
726 | + else if(sem->type == DS_SEMAPHORE) { | |
727 | + sem_post(sem->sem_wr); | |
728 | + } | |
729 | +#endif | |
730 | +} | |
731 | + | |
732 | +void timed_semclean(void * _sem) { | |
733 | +#ifdef DS_SEMAPHORE | |
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); | |
739 | + sem_unlink(sem1); | |
740 | + sem_unlink(sem2); | |
741 | + } | |
742 | +#endif | |
743 | +} | |
744 | + | |
745 | +void *timed_seminit(unsigned int semtype, void *id, int is_host) { | |
746 | + struct sem *sem; | |
747 | + sem = (struct sem *)malloc(sizeof(struct sem)); | |
748 | + memset(sem, 0, sizeof(struct sem)); | |
749 | + sem->type = semtype; | |
750 | + sem->id = id; | |
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"); | |
757 | + exit(1); | |
758 | + } | |
759 | + } | |
760 | +#ifdef DS_SEMAPHORE | |
761 | + else if(semtype == DS_SEMAPHORE) { | |
762 | + char semrd[80], semwr[80]; | |
763 | + init_twait(); | |
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); | |
766 | + if(is_host) { | |
767 | + sem->sem_rd = sem_open(semrd, O_CREAT, 0644, 0); | |
768 | + sem->sem_wr = sem_open(semwr, O_CREAT, 0644, 0); | |
769 | + } else { | |
770 | + sem->sem_rd = sem_open(semrd, 0); | |
771 | + sem->sem_wr = sem_open(semwr, 0); | |
772 | + sem_unlink(semwr); | |
773 | + sem_unlink(semrd); | |
774 | + } | |
775 | + if(sem->sem_rd == SEM_FAILED) { | |
776 | + timed_semclean(sem); | |
777 | + perror("sem_open(1)"); | |
778 | + exit(1); | |
779 | + } | |
780 | + if(sem->sem_wr == SEM_FAILED) { | |
781 | + timed_semclean(sem); | |
782 | + perror("sem_open(2)"); | |
783 | + exit(1); | |
784 | + } | |
785 | + //tell calling procedure that we are awake; | |
786 | + if(! is_host) { | |
787 | + sem_post(sem->sem_wr); | |
788 | + } | |
789 | + } | |
790 | +#endif /*DS_SEMAPHORE*/ | |
791 | + else { | |
792 | + fprintf(stderr, "Unknown type specified: %d\n", semtype); | |
793 | + exit(1); | |
794 | + } | |
795 | + return sem; | |
796 | +} | |
797 | + | |
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); | |
804 | +#ifdef DS_SEMAPHORE | |
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); | |
810 | +#endif | |
811 | + } | |
812 | + free(sem); | |
813 | +} | |
814 | + | |
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 | |
819 | @@ -0,0 +1,10 @@ | |
820 | +#define DS_SOCKET 0x01 | |
821 | +#define DS_SEMAPHORE 0x02 | |
822 | + | |
823 | +#define DS_TIMEOUT -1 | |
824 | + | |
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); |