| 211 | static int sem_twait(sem_t *sem, int t) { |
| 212 | struct timespec ts; |
| 213 | clock_gettime(CLOCK_REALTIME, &ts); |
| 214 | ts.tv_sec += t; |
| 215 | return(sem_timedwait(sem, &ts)); |
| 216 | } |
| 217 | bool AvFormatDecoderPrivate::InitDirectShow(AVCodecContext *enc) |
| 218 | { |
| 219 | typedef struct { |
| 220 | uint32_t f1; |
| 221 | uint16_t f2; |
| 222 | uint16_t f3; |
| 223 | uint8_t f4[8]; |
| 224 | } GUID; |
| 225 | |
| 226 | const struct AVCodecTag *bmp_taglists[] = {codec_bmp_tags, 0}; |
| 227 | |
| 228 | if(enc->codec_tag == 0) |
| 229 | enc->codec_tag = av_codec_get_tag(bmp_taglists, enc->codec_id); |
| 230 | // VERBOSE(VB_IMPORTANT, QString("Trying DirectShow for FOURCC 0x%1") |
| 231 | // .arg(enc->codec_tag, 8, 16, 0)); |
| 232 | if (!allow_dshow) |
| 233 | return false; |
| 234 | DestroyDirectShow(); |
| 235 | if (enc->codec_tag == 0) { |
| 236 | allow_dshow = false; |
| 237 | return false; |
| 238 | } |
| 239 | // QString dec = gContext->GetSetting("UseDirectShowVideoDecoder", "no"); |
| 240 | QString dec = "yes"; |
| 241 | |
| 242 | if (dec == "yes") |
| 243 | { |
| 244 | bool found = false; |
| 245 | QString codec; |
| 246 | GUID guid = {0, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0}}; |
| 247 | QString codec_file = QDir::homeDirPath() + |
| 248 | QString("/.mythtv/dshowcodecs"); |
| 249 | if (! QFileInfo(codec_file).isFile()) { |
| 250 | allow_dshow = false; |
| 251 | return false; |
| 252 | } |
| 253 | QString videotype; |
| 254 | AVCodec *avc = avcodec_find_decoder(enc->codec_id); |
| 255 | if (! avc) { |
| 256 | allow_dshow = false; |
| 257 | return false; |
| 258 | } |
| 259 | videotype = avc->name; |
| 260 | QFile fh (codec_file); |
| 261 | QString line; |
| 262 | fh.open(IO_ReadOnly); |
| 263 | while (! fh.atEnd() && ! found) { |
| 264 | QStringList fourc, guidlist; |
| 265 | QTextStream filein(&fh); |
| 266 | line = filein.readLine(1024); |
| 267 | codec = line.section(':', 0, 0).stripWhiteSpace(); |
| 268 | fourc = QStringList::split(",",line.section(':', 1, 1)); |
| 269 | guidlist = QStringList::split(",",line.section(':', 2, 2)); |
| 270 | if (guidlist.count() != 11) |
| 271 | continue; |
| 272 | for (QStringList::Iterator it = fourc.begin(); |
| 273 | it != fourc.end(); it++) |
| 274 | { |
| 275 | if ((*it).stripWhiteSpace() == videotype) |
| 276 | { |
| 277 | guid.f1 = guidlist[0].toUInt(0, 0); |
| 278 | guid.f2 = guidlist[1].toUShort(0, 0); |
| 279 | guid.f3 = guidlist[2].toUShort(0, 0); |
| 280 | for (int i = 0; i < 8; i++) |
| 281 | guid.f4[i] = guidlist[i + 3].toUShort(0, 0); |
| 282 | found = true; |
| 283 | } |
| 284 | } |
| 285 | if (found) |
| 286 | break; |
| 287 | } |
| 288 | fh.close(); |
| 289 | if (found) { |
| 290 | int ret; |
| 291 | char cmd[255], shm[80], sem1[80], sem2[80]; |
| 292 | uint32_t out_fmt; |
| 293 | int bpp; |
| 294 | //out_fmt = 0x30323449; bpp = 12; //I420 12bpp |
| 295 | out_fmt = 0x32595559; bpp = 16; //YUY2 16bpp |
| 296 | snprintf(cmd, 255, "dshowserver -c %s -s %dx%d " |
| 297 | "-g %08x-%04x-%04x-%02x%02x%02x%02x%02x%02x%02x%02x " |
| 298 | "-f 0x%08x -b %d -o 0x%08x -p %d -i %x %s&", |
| 299 | codec.ascii(), enc->width, enc->height, |
| 300 | guid.f1, guid.f2, guid.f3, |
| 301 | guid.f4[0], guid.f4[1], guid.f4[2], guid.f4[3], |
| 302 | guid.f4[4], guid.f4[5], guid.f4[6], guid.f4[7], |
| 303 | enc->codec_tag, bpp, out_fmt, getpid(), *(int *)pthread_self(), |
| 304 | ((print_verbose_messages & VB_PLAYBACK == VB_PLAYBACK) ? |
| 305 | "-d" : "")); |
| 306 | ds_mpi = new ds_mpi_t; |
| 307 | snprintf(shm, 80, "/dshow_shm.%x", *(int *)pthread_self()); |
| 308 | snprintf(sem1, 80, "/dshow_sem1.%x", *(int *)pthread_self()); |
| 309 | snprintf(sem2, 80, "/dshow_sem2.%x", *(int *)pthread_self()); |
| 310 | ds_mpi->fd = shm_open(shm, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR); |
| 311 | ds_mpi->picsize = enc->width * enc->height * bpp / 8; |
| 312 | int extra = 0; |
| 313 | if (enc->height % 16) |
| 314 | extra = (16 - enc->height % 16) * bpp / 8; |
| 315 | int memsize = sizeof(struct vd_struct) + enc->width * enc->height + |
| 316 | ds_mpi->picsize + extra; |
| 317 | ftruncate(ds_mpi->fd, memsize); |
| 318 | ds_mpi->mem = mmap(NULL, memsize, PROT_READ | PROT_WRITE, |
| 319 | MAP_SHARED, ds_mpi->fd, 0); |
| 320 | if(ds_mpi->mem == MAP_FAILED) { |
| 321 | perror("mmap"); |
| 322 | allow_dshow = false; |
| 323 | return false; |
| 324 | } |
| 325 | memset((char *)ds_mpi->mem, 0, sizeof(struct vd_struct)); |
| 326 | |
| 327 | if (extra) |
| 328 | memset((char *)ds_mpi->mem + (memsize - extra), 0, extra); |
| 329 | ds_mpi->vd = (struct vd_struct *)ds_mpi->mem; |
| 330 | ds_mpi->data = ((char *)ds_mpi->mem) + sizeof(struct vd_struct); |
| 331 | ds_mpi->picture = ds_mpi->data + enc->width * enc->height; |
| 332 | //Create read/write semaphores in locked state |
| 333 | ds_mpi->sem_wr = sem_open(sem1, O_CREAT, 0644, 0); |
| 334 | ds_mpi->sem_rd = sem_open(sem2, O_CREAT, 0644, 0); |
| 335 | system(cmd); |
| 336 | ret = sem_twait(ds_mpi->sem_rd, 10); |
| 337 | shm_unlink(shm); |
| 338 | sem_unlink(sem1); |
| 339 | sem_unlink(sem2); |
| 340 | if(ret != 0) { |
| 341 | VERBOSE(VB_IMPORTANT, LOC + "DirectShow filter failed"); |
| 342 | } else { |
| 343 | VERBOSE(VB_IMPORTANT, LOC + "Found DirectShow filter"); |
| 344 | return true; |
| 345 | } |
| 346 | } |
| 347 | } |
| 348 | allow_dshow = false; |
| 349 | return false; |
| 350 | } |
| 351 | |
| 352 | void AvFormatDecoderPrivate::DestroyDirectShow() |
| 353 | { |
| 354 | if (ds_mpi) |
| 355 | { |
| 356 | VERBOSE(VB_PLAYBACK, LOC + "Destroying filter"); |
| 357 | ds_mpi->vd->cmd = VD_END; //'1' is cmd for terminating |
| 358 | sem_post(ds_mpi->sem_wr); |
| 359 | close(ds_mpi->fd); |
| 360 | sem_close(ds_mpi->sem_wr); |
| 361 | sem_close(ds_mpi->sem_rd); |
| 362 | delete ds_mpi; |
| 363 | ds_mpi = NULL; |
| 364 | } |
| 365 | } |
| 366 | |
| 367 | void AvFormatDecoderPrivate::ResetDirectShow() |
| 368 | { |
| 369 | } |
| 370 | |
| 371 | void yuy2i420(AVFrame *dst, char *src, int w, int l) |
| 372 | { |
| 373 | int count; |
| 374 | uint8_t *y, *u, *v; |
| 375 | y = dst->data[0]; |
| 376 | u = dst->data[1]; |
| 377 | v = dst->data[2]; |
| 378 | int i,j; |
| 379 | for(i=0; i < l; i++) { |
| 380 | for(j=0; j < w; j+=2) { |
| 381 | *(y++) = *(src++); |
| 382 | *(u++) = *(src++); |
| 383 | *(y++) = *(src++); |
| 384 | *(v++) = *(src++); |
| 385 | } |
| 386 | i++; |
| 387 | for(j=0; j < w; j+=2) { |
| 388 | *(y++) = *src; |
| 389 | src+=2; |
| 390 | *(y++) = *src; |
| 391 | src+=2; |
| 392 | } |
| 393 | } |
| 394 | } |
| 395 | |
| 396 | int AvFormatDecoderPrivate::DecodeDirectShowVideo(AVCodecContext *avctx, |
| 397 | AVFrame *picture, |
| 398 | int *got_picture_ptr, |
| 399 | uint8_t *buf, int buf_size) |
| 400 | { |
| 401 | int ret; |
| 402 | ds_mpi->vd->cmd = VD_DECODE; //'1' is cmd for decoding |
| 403 | memcpy(ds_mpi->data, buf, buf_size); |
| 404 | ds_mpi->vd->buflen = buf_size; |
| 405 | sem_post(ds_mpi->sem_wr); |
| 406 | ret = sem_twait(ds_mpi->sem_rd, 10); |
| 407 | if(ret == 0 && ds_mpi->vd->ret && ! (ds_mpi->vd->ret & (1<<31))) { |
| 408 | *got_picture_ptr = 1; |
| 409 | picture->interlaced_frame = (ds_mpi->vd->ret & 10) ? true : false; |
| 410 | avctx->get_buffer(avctx, picture); |
| 411 | #if 0 //Using YV12 |
| 412 | if(avctx->height & 0x0f) { |
| 413 | unsigned long pos, pos1, siz = avctx->height * avctx->width; |
| 414 | memcpy(picture->data[0], ds_mpi->picture, siz); |
| 415 | pos = siz; |
| 416 | pos1 = siz + avctx->width * (16 - avctx->height % 16); |
| 417 | siz /= 4; |
| 418 | memcpy(picture->data[0]+pos1, ds_mpi->picture+pos, siz); |
| 419 | pos+=siz; |
| 420 | pos1+=siz + avctx->width * ( 16 - avctx->height % 16) / 4; |
| 421 | memcpy(picture->data[0]+pos1, ds_mpi->picture+pos, siz); |
| 422 | } else { |
| 423 | memcpy(picture->data[0], ds_mpi->picture, ds_mpi->picsize); |
| 424 | } |
| 425 | #else //Using YUY2 |
| 426 | //YUY2 is a packed format so padding is easier |
| 427 | //int extra = 0; |
| 428 | //if(avctx->height % 16) |
| 429 | //extra = (16 - avctx->height % 16); |
| 430 | yuy2i420(picture, ds_mpi->picture, |
| 431 | avctx->width, avctx->height); |
| 432 | #endif |
| 433 | } else { |
| 434 | *got_picture_ptr = 0; |
| 435 | } |
| 436 | return buf_size; |
| 437 | } |
| 438 | |
| 439 | /*************************************************/ |
| 440 | |