| | 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 | |