]>
Commit | Line | Data |
---|---|---|
1b2ca44a | 1 | diff -urN mythtv-0.22.orig/libs/libmythtv/avformatdecoder.cpp mythtv-0.22/libs/libmythtv/avformatdecoder.cpp |
2 | --- mythtv-0.22.orig/libs/libmythtv/avformatdecoder.cpp 2009-02-17 19:57:44.000000000 +0100 | |
3 | +++ mythtv-0.22/libs/libmythtv/avformatdecoder.cpp 2009-03-02 20:04:25.000000000 +0100 | |
4 | @@ -2,12 +2,16 @@ | |
5 | #include <cassert> | |
6 | #include <unistd.h> | |
7 | #include <cmath> | |
8 | +#include <fcntl.h> | |
9 | ||
10 | // C++ headers | |
11 | #include <algorithm> | |
12 | #include <iostream> | |
13 | using namespace std; | |
14 | ||
15 | +// QT headers | |
16 | +#include "qdir.h" | |
17 | + | |
18 | // MythTV headers | |
19 | #include "mythconfig.h" | |
20 | #include "avformatdecoder.h" | |
21 | @@ -53,6 +57,7 @@ | |
22 | #include "avio.h" | |
23 | #include "../libmythmpeg2/mpeg2.h" | |
24 | #include "ivtv_myth.h" | |
25 | +#include "libavformat/riff.h" | |
26 | } | |
27 | ||
28 | #define LOC QString("AFD: ") | |
29 | @@ -149,21 +154,56 @@ | |
30 | ||
31 | typedef MythDeque<AVFrame*> avframe_q; | |
32 | ||
33 | +struct vd_struct { | |
34 | + union { | |
35 | + uint32_t ret; | |
36 | + uint32_t cmd; | |
37 | + }; | |
38 | + uint32_t buflen; | |
39 | + uint64_t pts; | |
40 | + uint32_t unused[8]; | |
41 | +} __attribute__((__packed__)); | |
42 | + | |
43 | +enum { | |
44 | + VD_END = 1, | |
45 | + VD_DECODE = 2, | |
46 | + VD_SEEK = 3, | |
47 | + VD_HAS_BIH = 0x10000, | |
48 | + VD_VERSION_MASK = 0xFFFF, | |
49 | +}; | |
50 | + | |
51 | +#include <semaphore.h> | |
52 | +#include <sys/mman.h> | |
53 | +typedef struct { | |
54 | + int fd; | |
55 | + void *mem; | |
56 | + char *data; | |
57 | + char *picture; | |
58 | + int picsize; | |
59 | + sem_t *sem_rd; | |
60 | + sem_t *sem_wr; | |
61 | + struct vd_struct *vd; | |
62 | +} ds_mpi_t; | |
63 | + | |
64 | /** | |
65 | * Management of libmpeg2 decoding | |
66 | */ | |
67 | class AvFormatDecoderPrivate | |
68 | { | |
69 | public: | |
70 | - AvFormatDecoderPrivate(bool allow_libmpeg2) | |
71 | - : mpeg2dec(NULL), dvdvdec(NULL), allow_mpeg2dec(allow_libmpeg2) { ; } | |
72 | - ~AvFormatDecoderPrivate() { DestroyMPEG2(); } | |
73 | + AvFormatDecoderPrivate(bool allow_libmpeg2, bool allow_directshow) | |
74 | + : mpeg2dec(NULL), dvdvdec(NULL), allow_mpeg2dec(allow_libmpeg2), | |
75 | + ds_mpi(NULL), allow_dshow(allow_directshow) { ; } | |
76 | + ~AvFormatDecoderPrivate() { DestroyMPEG2(); DestroyDirectShow();} | |
77 | ||
78 | bool InitMPEG2(const QString &dec); | |
79 | bool HasMPEG2Dec(void) const { return (bool)(mpeg2dec); } | |
80 | bool HasDVDVDec(void) const { return (bool)(dvdvdec); } | |
81 | bool HasDecoder(void) const { return HasMPEG2Dec() || HasDVDVDec(); } | |
82 | ||
83 | + bool InitDirectShow(AVCodecContext *enc); | |
84 | + bool HasDirectShow() const { return (bool)(ds_mpi); } | |
85 | + | |
86 | void DestroyMPEG2(); | |
87 | void ResetMPEG2(); | |
88 | int DecodeMPEG2Video(AVCodecContext *avctx, AVFrame *picture, | |
89 | @@ -173,13 +213,259 @@ | |
90 | bool SetVideoSize(const QSize &video_dim); | |
91 | DVDV *GetDVDVDecoder(void) { return dvdvdec; } | |
92 | ||
93 | + void DestroyDirectShow(); | |
94 | + void ResetDirectShow(); | |
95 | + int DecodeDirectShowVideo(AVCodecContext *avctx, AVFrame *picture, | |
96 | + int *got_picture_ptr, uint8_t *buf, int buf_size, | |
97 | + long long *pts); | |
98 | + | |
99 | private: | |
100 | mpeg2dec_t *mpeg2dec; | |
101 | DVDV *dvdvdec; | |
102 | bool allow_mpeg2dec; | |
103 | + ds_mpi_t *ds_mpi; | |
104 | + bool allow_dshow; | |
105 | avframe_q partialFrames; | |
106 | }; | |
107 | ||
108 | +static int sem_twait(sem_t *sem, int t) { | |
109 | + struct timespec ts; | |
110 | + clock_gettime(CLOCK_REALTIME, &ts); | |
111 | + ts.tv_sec += t; | |
112 | + return(sem_timedwait(sem, &ts)); | |
113 | +} | |
114 | +bool AvFormatDecoderPrivate::InitDirectShow(AVCodecContext *enc) | |
115 | +{ | |
116 | + typedef struct { | |
117 | + uint32_t f1; | |
118 | + uint16_t f2; | |
119 | + uint16_t f3; | |
120 | + uint8_t f4[8]; | |
121 | + } GUID; | |
122 | + | |
123 | + const struct AVCodecTag *bmp_taglists[] = {codec_bmp_tags, 0}; | |
124 | + | |
125 | + if(enc->codec_tag == 0) | |
126 | + enc->codec_tag = av_codec_get_tag(bmp_taglists, enc->codec_id); | |
127 | + VERBOSE(VB_IMPORTANT, LOC + QString("Trying DirectShow for FOURCC 0x%1") | |
128 | + .arg(enc->codec_tag, 8, 16)); | |
129 | + if (!allow_dshow) | |
130 | + return false; | |
131 | + DestroyDirectShow(); | |
132 | + if (enc->codec_tag == 0) { | |
133 | + allow_dshow = false; | |
134 | + return false; | |
135 | + } | |
136 | +// QString dec = gContext->GetSetting("UseDirectShowVideoDecoder", "no"); | |
137 | + QString dec = "yes"; | |
138 | + | |
139 | + if (dec == "yes") | |
140 | + { | |
141 | + bool found = false; | |
142 | + QString codec; | |
143 | + GUID guid = {0, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0}}; | |
144 | + QString codec_file = QDir::homePath() + | |
145 | + QString("/.mythtv/dshowcodecs"); | |
146 | + if (! QFileInfo(codec_file).isFile()) { | |
147 | + allow_dshow = false; | |
148 | + return false; | |
149 | + } | |
150 | + QString videotype; | |
151 | + AVCodec *avc = avcodec_find_decoder(enc->codec_id); | |
152 | + if (! avc) { | |
153 | + allow_dshow = false; | |
154 | + return false; | |
155 | + } | |
156 | + videotype = avc->name; | |
157 | + QFile fh (codec_file); | |
158 | + QString line; | |
159 | + fh.open(QIODevice::ReadOnly); | |
160 | + while (! fh.atEnd() && ! found) { | |
161 | + QStringList fourc, guidlist; | |
162 | + line = fh.readLine(1024); | |
163 | + codec = line.section(':', 0, 0).simplified(); | |
164 | + fourc = line.section(':', 1, 1).split(","); | |
165 | + guidlist = line.section(':', 2, 2).split(","); | |
166 | + if (guidlist.count() != 11) | |
167 | + continue; | |
168 | + for (QStringList::Iterator it = fourc.begin(); | |
169 | + it != fourc.end(); it++) | |
170 | + { | |
171 | + if ((*it).simplified() == videotype) | |
172 | + { | |
173 | + guid.f1 = guidlist[0].toUInt(0, 0); | |
174 | + guid.f2 = guidlist[1].toUShort(0, 0); | |
175 | + guid.f3 = guidlist[2].toUShort(0, 0); | |
176 | + for (int i = 0; i < 8; i++) | |
177 | + guid.f4[i] = guidlist[i + 3].toUShort(0, 0); | |
178 | + found = true; | |
179 | + } | |
180 | + } | |
181 | + if (found) | |
182 | + break; | |
183 | + } | |
184 | + fh.close(); | |
185 | + if (found) { | |
186 | + int ret; | |
187 | + char cmd[255], shm[80], sem1[80], sem2[80]; | |
188 | + uint32_t out_fmt; | |
189 | + int bpp; | |
190 | + //out_fmt = 0x30323449; bpp = 12; //I420 12bpp | |
191 | + out_fmt = 0x32595559; bpp = 16; //YUY2 16bpp | |
192 | + snprintf(cmd, 255, "dshowserver -c %s -s %dx%d " | |
193 | + "-g %08x-%04x-%04x-%02x%02x%02x%02x%02x%02x%02x%02x " | |
194 | + "-f 0x%08x -b %d -o 0x%08x -p %d -i %x %s&", | |
195 | + codec.toAscii().constData(), enc->width, enc->height, | |
196 | + guid.f1, guid.f2, guid.f3, | |
197 | + guid.f4[0], guid.f4[1], guid.f4[2], guid.f4[3], | |
198 | + guid.f4[4], guid.f4[5], guid.f4[6], guid.f4[7], | |
199 | + enc->codec_tag, bpp, out_fmt, getpid(), *(int *)pthread_self(), | |
200 | + ((print_verbose_messages & VB_PLAYBACK) == VB_PLAYBACK ? | |
201 | + "-d" : "")); | |
202 | + ds_mpi = new ds_mpi_t; | |
203 | + snprintf(shm, 80, "/dshow_shm.%x", *(int *)pthread_self()); | |
204 | + snprintf(sem1, 80, "/dshow_sem1.%x", *(int *)pthread_self()); | |
205 | + snprintf(sem2, 80, "/dshow_sem2.%x", *(int *)pthread_self()); | |
206 | + ds_mpi->fd = shm_open(shm, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR); | |
207 | + ds_mpi->picsize = enc->width * enc->height * bpp / 8; | |
208 | + int extra = 0; | |
209 | + if (enc->height % 16) | |
210 | + extra = (16 - enc->height % 16) * bpp / 8; | |
211 | + int memsize = sizeof(struct vd_struct) + enc->width * enc->height + | |
212 | + ds_mpi->picsize + extra; | |
213 | + ftruncate(ds_mpi->fd, memsize); | |
214 | + ds_mpi->mem = mmap(NULL, memsize, PROT_READ | PROT_WRITE, | |
215 | + MAP_SHARED, ds_mpi->fd, 0); | |
216 | + if(ds_mpi->mem == MAP_FAILED) { | |
217 | + perror("mmap"); | |
218 | + allow_dshow = false; | |
219 | + return false; | |
220 | + } | |
221 | + memset((char *)ds_mpi->mem, 0, sizeof(struct vd_struct)); | |
222 | + | |
223 | + if (extra) | |
224 | + memset((char *)ds_mpi->mem + (memsize - extra), 0, extra); | |
225 | + ds_mpi->vd = (struct vd_struct *)ds_mpi->mem; | |
226 | + ds_mpi->data = ((char *)ds_mpi->mem) + sizeof(struct vd_struct); | |
227 | + ds_mpi->picture = ds_mpi->data + enc->width * enc->height; | |
228 | + //Create read/write semaphores in locked state | |
229 | + ds_mpi->sem_wr = sem_open(sem1, O_CREAT, 0644, 0); | |
230 | + ds_mpi->sem_rd = sem_open(sem2, O_CREAT, 0644, 0); | |
231 | + myth_system(cmd); | |
232 | + ret = sem_twait(ds_mpi->sem_rd, 10); | |
233 | + shm_unlink(shm); | |
234 | + sem_unlink(sem1); | |
235 | + sem_unlink(sem2); | |
236 | + if(ret != 0) { | |
237 | + VERBOSE(VB_IMPORTANT, LOC + "DirectShow filter failed"); | |
238 | + } else { | |
239 | + VERBOSE(VB_IMPORTANT, LOC + "Found DirectShow filter"); | |
240 | + return true; | |
241 | + } | |
242 | + } | |
243 | + } | |
244 | + allow_dshow = false; | |
245 | + return false; | |
246 | +} | |
247 | + | |
248 | +void AvFormatDecoderPrivate::DestroyDirectShow() | |
249 | +{ | |
250 | + if (ds_mpi) | |
251 | + { | |
252 | + VERBOSE(VB_PLAYBACK, LOC + "Destroying filter"); | |
253 | + ds_mpi->vd->cmd = VD_END; //'1' is cmd for terminating | |
254 | + sem_post(ds_mpi->sem_wr); | |
255 | + close(ds_mpi->fd); | |
256 | + sem_close(ds_mpi->sem_wr); | |
257 | + sem_close(ds_mpi->sem_rd); | |
258 | + delete ds_mpi; | |
259 | + ds_mpi = NULL; | |
260 | + } | |
261 | +} | |
262 | + | |
263 | +void AvFormatDecoderPrivate::ResetDirectShow() | |
264 | +{ | |
265 | + if (ds_mpi) { | |
266 | + ds_mpi->vd->cmd = VD_SEEK; //'3' is cmd for seek | |
267 | + sem_post(ds_mpi->sem_wr); | |
268 | + sem_twait(ds_mpi->sem_rd, 10); | |
269 | + } | |
270 | +} | |
271 | + | |
272 | +void yuy2i420(AVFrame *dst, char *src, int w, int l) | |
273 | +{ | |
274 | + uint8_t *y, *u, *v; | |
275 | + y = dst->data[0]; | |
276 | + u = dst->data[1]; | |
277 | + v = dst->data[2]; | |
278 | + int i,j; | |
279 | + for(i=0; i < l; i++) { | |
280 | + for(j=0; j < w; j+=2) { | |
281 | + *(y++) = *(src++); | |
282 | + *(u++) = *(src++); | |
283 | + *(y++) = *(src++); | |
284 | + *(v++) = *(src++); | |
285 | + } | |
286 | + i++; | |
287 | + for(j=0; j < w; j+=2) { | |
288 | + *(y++) = *src; | |
289 | + src+=2; | |
290 | + *(y++) = *src; | |
291 | + src+=2; | |
292 | + } | |
293 | + } | |
294 | +} | |
295 | + | |
296 | +int AvFormatDecoderPrivate::DecodeDirectShowVideo(AVCodecContext *avctx, | |
297 | + AVFrame *picture, | |
298 | + int *got_picture_ptr, | |
299 | + uint8_t *buf, int buf_size, | |
300 | + long long *pts) | |
301 | +{ | |
302 | + int ret; | |
303 | + ds_mpi->vd->cmd = VD_DECODE; //'1' is cmd for decoding | |
304 | + memcpy(ds_mpi->data, buf, buf_size); | |
305 | + ds_mpi->vd->buflen = buf_size; | |
306 | + ds_mpi->vd->pts = (uint64_t)*pts; | |
307 | + sem_post(ds_mpi->sem_wr); | |
308 | + ret = sem_twait(ds_mpi->sem_rd, 10); | |
309 | + if (ret == 0 && ds_mpi->vd->ret && ! (ds_mpi->vd->ret & (1<<31))) { | |
310 | + *got_picture_ptr = 1; | |
311 | + if (ds_mpi->vd->pts) { | |
312 | + *pts = (long long)ds_mpi->vd->pts; | |
313 | + } | |
314 | + picture->interlaced_frame = (ds_mpi->vd->ret & 10) ? true : false; | |
315 | + avctx->get_buffer(avctx, picture); | |
316 | +#if 0 //Using YV12 | |
317 | + if(avctx->height & 0x0f) { | |
318 | + unsigned long pos, pos1, siz = avctx->height * avctx->width; | |
319 | + memcpy(picture->data[0], ds_mpi->picture, siz); | |
320 | + pos = siz; | |
321 | + pos1 = siz + avctx->width * (16 - avctx->height % 16); | |
322 | + siz /= 4; | |
323 | + memcpy(picture->data[0]+pos1, ds_mpi->picture+pos, siz); | |
324 | + pos+=siz; | |
325 | + pos1+=siz + avctx->width * ( 16 - avctx->height % 16) / 4; | |
326 | + memcpy(picture->data[0]+pos1, ds_mpi->picture+pos, siz); | |
327 | + } else { | |
328 | + memcpy(picture->data[0], ds_mpi->picture, ds_mpi->picsize); | |
329 | + } | |
330 | +#else //Using YUY2 | |
331 | + //YUY2 is a packed format so padding is easier | |
332 | + //int extra = 0; | |
333 | + //if(avctx->height % 16) | |
334 | + //extra = (16 - avctx->height % 16); | |
335 | + yuy2i420(picture, ds_mpi->picture, | |
336 | + avctx->width, avctx->height); | |
337 | +#endif | |
338 | + } else { | |
339 | + *got_picture_ptr = 0; | |
340 | + } | |
341 | + return buf_size; | |
342 | +} | |
343 | + | |
344 | +/*************************************************/ | |
345 | + | |
346 | /** | |
347 | * \brief Initialise either libmpeg2, or DVDV (Mac HW accel), to do decoding | |
348 | * | |
349 | @@ -401,7 +687,7 @@ | |
350 | bool use_null_videoout, | |
351 | bool allow_libmpeg2) | |
352 | : DecoderBase(parent, pginfo), | |
353 | - d(new AvFormatDecoderPrivate(allow_libmpeg2)), | |
354 | + d(new AvFormatDecoderPrivate(allow_libmpeg2, true)), | |
355 | is_db_ignored(gContext->IsDatabaseIgnored()), | |
356 | m_h264_parser(new H264Parser()), | |
357 | ic(NULL), | |
358 | @@ -684,6 +970,7 @@ | |
359 | avcodec_flush_buffers(enc); | |
360 | } | |
361 | d->ResetMPEG2(); | |
362 | + d->ResetDirectShow(); | |
363 | } | |
364 | ||
365 | // Discard all the queued up decoded frames | |
366 | @@ -1584,6 +1871,9 @@ | |
367 | } | |
368 | } | |
369 | ||
370 | + if (CODEC_ID_H264 == enc->codec_id) | |
371 | + force_xv = true; | |
372 | + | |
373 | MythCodecID mcid; | |
374 | mcid = VideoOutputXv::GetBestSupportedCodec( | |
375 | /* disp dim */ width, height, | |
376 | @@ -1593,6 +1883,7 @@ | |
377 | /* test surface */ kCodec_NORMAL_END > video_codec_id, | |
378 | /* force_xv */ force_xv); | |
379 | bool vcd, idct, mc, vdpau; | |
380 | + | |
381 | enc->codec_id = (CodecID) | |
382 | myth2av_codecid(mcid, vcd, idct, mc, vdpau); | |
383 | ||
384 | @@ -1668,6 +1959,7 @@ | |
385 | } | |
386 | ||
387 | // Initialize alternate decoders when needed... | |
388 | + if (! d->InitDirectShow(enc)) | |
389 | if (((dec == "libmpeg2") && | |
390 | (CODEC_ID_MPEG1VIDEO == enc->codec_id || | |
391 | CODEC_ID_MPEG2VIDEO == enc->codec_id)) || | |
392 | @@ -3756,7 +4048,21 @@ | |
393 | int gotpicture = 0; | |
394 | ||
395 | avcodeclock.lock(); | |
396 | - if (d->HasDecoder()) | |
397 | +/* printf("Trying: %d\n",len); | |
398 | + if (0) { | |
399 | + static int fnum = 0; | |
400 | + char str[80]; | |
401 | + int fh; | |
402 | + sprintf(str,"enc%d", fnum++);; | |
403 | + fh = open(str, 01101,00777); | |
404 | + write(fh, ptr, len); | |
405 | + close(fh); | |
406 | + } | |
407 | +*/ | |
408 | + if (d->HasDirectShow()) | |
409 | + ret = d->DecodeDirectShowVideo(context, &mpa_pic, | |
410 | + &gotpicture, ptr, len, &pts); | |
411 | + else if (d->HasDecoder()) | |
412 | { | |
413 | if (decodeStillFrame) | |
414 | { | |
415 | diff -urN mythtv-0.22.orig/libs/libmythtv/libmythtv.pro mythtv-0.22/libs/libmythtv/libmythtv.pro | |
416 | --- mythtv-0.22.orig/libs/libmythtv/libmythtv.pro 2009-02-17 19:57:44.000000000 +0100 | |
417 | +++ mythtv-0.22/libs/libmythtv/libmythtv.pro 2009-03-02 19:54:23.000000000 +0100 | |
418 | @@ -57,6 +57,7 @@ | |
419 | } | |
420 | using_backend: LIBS += -lmp3lame | |
421 | LIBS += -lz $$EXTRA_LIBS $$QMAKE_LIBS_DYNLOAD | |
422 | +LIBS += -lrt | |
423 | ||
424 | TARGETDEPS += ../libmyth/libmyth-$${MYTH_SHLIB_EXT} | |
425 | TARGETDEPS += ../libavutil/libmythavutil-$${MYTH_SHLIB_EXT} |