Ticket #1871: 1871-v2.patch
File 1871-v2.patch, 19.3 KB (added by , 18 years ago) |
---|
-
libs/libmythtv/videobuffers.h
137 137 private: 138 138 frame_queue_t *queue(BufferType type); 139 139 const frame_queue_t *queue(BufferType type) const; 140 VideoFrame *GetNextFreeFrameInternal( 141 bool with_lock, bool allow_unsafe, BufferType enqueue_to); 140 142 141 143 frame_queue_t available, used, limbo, pause, displayed, decode; 142 144 vbuffer_map_t vbufferMap; // videobuffers to buffer's index … … 160 162 uint vpos; 161 163 162 164 mutable QMutex global_lock; 163 QMutex inheritence_lock;164 165 165 166 bool use_frame_locks; 166 167 QMutex frame_lock; -
libs/libmythtv/videobuffers.cpp
84 84 : numbuffers(0), needfreeframes(0), needprebufferframes(0), 85 85 needprebufferframes_normal(0), needprebufferframes_small(0), 86 86 keepprebufferframes(0), need_extra_for_pause(false), rpos(0), vpos(0), 87 global_lock(true), inheritence_lock(false),use_frame_locks(true),87 global_lock(true), use_frame_locks(true), 88 88 frame_lock(true) 89 89 { 90 90 } … … 123 123 uint needprebuffer_small, uint keepprebuffer, 124 124 bool enable_frame_locking) 125 125 { 126 global_lock.lock();126 QMutexLocker locker(&global_lock); 127 127 128 128 Reset(); 129 129 … … 154 154 155 155 for (uint i = 0; i < numdecode; i++) 156 156 enqueue(kVideoBuffer_avail, at(i)); 157 158 global_lock.unlock();159 157 } 160 158 161 159 /** … … 164 162 */ 165 163 void VideoBuffers::Reset() 166 164 { 167 global_lock.lock();165 QMutexLocker locker(&global_lock); 168 166 169 167 // Delete ffmpeg VideoFrames so we can create 170 168 // a different number of buffers below … … 185 183 displayed.clear(); 186 184 parents.clear(); 187 185 children.clear(); 188 189 186 vbufferMap.clear(); 190 191 global_lock.unlock();192 187 } 193 188 194 189 /** … … 197 192 */ 198 193 void VideoBuffers::SetPrebuffering(bool normal) 199 194 { 200 global_lock.lock(); 201 195 QMutexLocker locker(&global_lock); 202 196 needprebufferframes = (normal) ? 203 197 needprebufferframes_normal : needprebufferframes_small; 204 205 global_lock.unlock();206 198 }; 207 199 200 VideoFrame *VideoBuffers::GetNextFreeFrameInternal( 201 bool with_lock, bool allow_unsafe, BufferType enqueue_to) 202 { 203 QMutexLocker locker(&global_lock); 204 VideoFrame *frame = available.dequeue(); 205 206 // Try to get a frame not being used by the decoder 207 for (uint i = 0; i <= available.size() && decode.contains(frame); i++) 208 { 209 if (!available.contains(frame)) 210 available.enqueue(frame); 211 frame = available.dequeue(); 212 } 213 214 while (frame && used.contains(frame)) 215 { 216 VERBOSE(VB_IMPORTANT, 217 QString("GetNextFreeFrame() served a busy frame %1. " 218 "Dropping. %2") 219 .arg(DebugString(frame, true)).arg(GetStatus())); 220 frame = available.dequeue(); 221 } 222 223 // only way this should be triggered if we're in unsafe mode 224 if (!frame && allow_unsafe) 225 { 226 VERBOSE(VB_PLAYBACK, 227 QString("GetNextFreeFrame() is getting a busy frame %1. " 228 " %2") 229 .arg(DebugString(frame, true)).arg(GetStatus())); 230 frame = used.dequeue(); 231 if (EnoughFreeFrames()) 232 available_wait.wakeAll(); 233 } 234 235 if (frame) 236 { 237 safeEnqueue(enqueue_to, frame); 238 239 bool success = true; 240 if (with_lock) 241 success = TryLockFrame(frame, "GetNextFreeFrame"); 242 243 if (!success) 244 { 245 safeEnqueue(kVideoBuffer_avail, frame); 246 VERBOSE(VB_IMPORTANT, 247 QString("GetNextFreeFrame() unable to lock frame %1. " 248 "Dropping %2. w/lock(%3) unsafe(%4)") 249 .arg(DebugString(frame)).arg(GetStatus()) 250 .arg(with_lock).arg(allow_unsafe)); 251 DiscardFrame(frame); 252 frame = NULL; 253 } 254 } 255 256 return frame; 257 } 258 208 259 /** 209 260 * \fn VideoBuffers::GetNextFreeFrame(bool,bool,BufferType) 210 261 * Gets a frame from available buffers list. … … 219 270 bool allow_unsafe, 220 271 BufferType enqueue_to) 221 272 { 222 VideoFrame *frame = NULL; 223 uint tries = 0; 224 bool success = false; 225 while (!success) 273 for (uint tries = 1; true; tries++) 226 274 { 227 success = false; 228 global_lock.lock(); 229 frame = available.dequeue(); 275 VideoFrame *frame = VideoBuffers::GetNextFreeFrameInternal( 276 with_lock, allow_unsafe, enqueue_to); 230 277 231 // Try to get a frame not being used by the decoder 232 for (uint i = 0; i <= available.size() && decode.contains(frame); i++) 233 { 234 if (!available.contains(frame)) 235 available.enqueue(frame); 236 frame = available.dequeue(); 237 } 278 if (frame) 279 return frame; 238 280 239 while (frame && used.contains(frame))281 if (tries >= TRY_LOCK_SPINS) 240 282 { 241 VERBOSE(VB_IMPORTANT, 242 QString("GetNextFreeFrame() served a busy frame %1. " 243 "Dropping. %2") 244 .arg(DebugString(frame, true)).arg(GetStatus())); 245 frame = available.dequeue(); 283 VERBOSE(VB_IMPORTANT, 284 QString("GetNextFreeFrame() unable to " 285 "lock frame %1 times. Discarding Frames.") 286 .arg(TRY_LOCK_SPINS)); 287 DiscardFrames(true); 288 continue; 246 289 } 247 290 248 // only way this should be triggered if we're in unsafe mode 249 if (!frame && allow_unsafe) 291 if (tries && !(tries % TRY_LOCK_SPINS_BEFORE_WARNING)) 250 292 { 251 293 VERBOSE(VB_PLAYBACK, 252 QString("GetNextFreeFrame() is getting a busy frame %1. " 253 " %2") 254 .arg(DebugString(frame, true)).arg(GetStatus())); 255 frame = used.dequeue(); 256 if (EnoughFreeFrames()) 257 available_wait.wakeAll(); 294 QString("GetNextFreeFrame() TryLock has " 295 "spun %1 times, this is a lot.").arg(tries)); 258 296 } 259 if (frame) 260 { 261 safeEnqueue(enqueue_to, frame); 262 263 success = true; 264 if (with_lock) 265 success = TryLockFrame(frame, "GetNextFreeFrame"); 266 if (!success) 267 safeEnqueue(kVideoBuffer_avail, frame); 268 } 269 270 global_lock.unlock(); 271 272 if (!success) 273 { 274 if (frame) 275 { 276 VERBOSE(VB_IMPORTANT, 277 QString("GetNextFreeFrame() unable to lock frame %1. " 278 "Dropping %2. w/lock(%3) unsafe(%4)") 279 .arg(DebugString(frame)).arg(GetStatus()) 280 .arg(with_lock).arg(allow_unsafe)); 281 DiscardFrame(frame); 282 } 283 ++tries; 284 if (tries<TRY_LOCK_SPINS) 285 { 286 if (tries && !(tries % TRY_LOCK_SPINS_BEFORE_WARNING)) 287 VERBOSE(VB_PLAYBACK, "GetNextFreeFrame() TryLock has " 288 "spun "<<tries<<" times, this is a lot."); 289 usleep(TRY_LOCK_SPIN_WAIT); 290 } 291 else 292 { 293 VERBOSE(VB_IMPORTANT, 294 QString("GetNextFreeFrame() unable to " 295 "lock frame %1 times. Discarding Frames.") 296 .arg(TRY_LOCK_SPINS)); 297 DiscardFrames(true); 298 } 299 } 297 usleep(TRY_LOCK_SPIN_WAIT); 300 298 } 301 299 302 return frame;300 return NULL; 303 301 } 304 302 305 303 /** … … 310 308 */ 311 309 void VideoBuffers::ReleaseFrame(VideoFrame *frame) 312 310 { 313 global_lock.lock(); 311 QMutexLocker locker(&global_lock); 312 314 313 vpos = vbufferMap[frame]; 315 314 limbo.remove(frame); 316 315 decode.enqueue(frame); 317 316 used.enqueue(frame); 318 global_lock.unlock();319 317 } 320 318 321 319 /** … … 325 323 */ 326 324 void VideoBuffers::DeLimboFrame(VideoFrame *frame) 327 325 { 328 global_lock.lock();326 QMutexLocker locker(&global_lock); 329 327 if (limbo.contains(frame)) 330 328 { 331 329 limbo.remove(frame); 332 330 available.enqueue(frame); 333 331 } 334 332 decode.remove(frame); 335 global_lock.unlock();336 333 } 337 334 338 335 /** … … 341 338 */ 342 339 void VideoBuffers::StartDisplayingFrame(void) 343 340 { 344 global_lock.lock();341 QMutexLocker locker(&global_lock); 345 342 rpos = vbufferMap[used.head()]; 346 global_lock.unlock();347 343 } 348 344 349 345 /** … … 352 348 */ 353 349 void VideoBuffers::DoneDisplayingFrame(void) 354 350 { 355 global_lock.lock();351 QMutexLocker locker(&global_lock); 356 352 357 353 VideoFrame *buf = used.dequeue(); 358 354 if (buf) … … 361 357 if (EnoughFreeFrames()) 362 358 available_wait.wakeAll(); 363 359 } 364 365 global_lock.unlock();366 360 } 367 361 368 362 /** … … 372 366 */ 373 367 void VideoBuffers::DiscardFrame(VideoFrame *frame) 374 368 { 375 global_lock.lock(); 369 QMutexLocker locker(&global_lock); 370 376 371 bool ok = TryLockFrame(frame, "DiscardFrame A"); 377 372 for (uint i=0; i<5 && !ok; i++) 378 373 { … … 393 388 "Unable to obtain lock on %1, %2") 394 389 .arg(DebugString(frame, true)).arg(GetStatus())); 395 390 } 396 global_lock.unlock();397 391 } 398 392 399 393 frame_queue_t *VideoBuffers::queue(BufferType type) 400 394 { 395 QMutexLocker locker(&global_lock); 396 401 397 frame_queue_t *q = NULL; 402 398 403 global_lock.lock();404 399 if (type == kVideoBuffer_avail) 405 400 q = &available; 406 401 else if (type == kVideoBuffer_used) … … 413 408 q = &pause; 414 409 else if (type == kVideoBuffer_decode) 415 410 q = &decode; 416 global_lock.unlock();417 411 418 412 return q; 419 413 } 420 414 421 415 const frame_queue_t *VideoBuffers::queue(BufferType type) const 422 416 { 417 QMutexLocker locker(&global_lock); 418 423 419 const frame_queue_t *q = NULL; 424 420 425 global_lock.lock();426 421 if (type == kVideoBuffer_avail) 427 422 q = &available; 428 423 else if (type == kVideoBuffer_used) … … 435 430 q = &pause; 436 431 else if (type == kVideoBuffer_decode) 437 432 q = &decode; 438 global_lock.unlock();439 433 440 434 return q; 441 435 } 442 436 443 437 VideoFrame *VideoBuffers::dequeue(BufferType type) 444 438 { 439 QMutexLocker locker(&global_lock); 440 445 441 frame_queue_t *q = queue(type); 446 if (q) 447 { 448 global_lock.lock(); 449 VideoFrame *frame = q->dequeue(); 450 global_lock.unlock(); 451 return frame; 452 } 453 return NULL; 442 443 if (!q) 444 return NULL; 445 446 return q->dequeue(); 454 447 } 455 448 456 449 VideoFrame *VideoBuffers::head(BufferType type) 457 450 { 451 QMutexLocker locker(&global_lock); 452 458 453 frame_queue_t *q = queue(type); 459 if (q) 460 { 461 QMutexLocker locker(&global_lock); 462 if (q->size()) 463 return q->head(); 464 } 454 455 if (!q) 456 return NULL; 457 458 if (q->size()) 459 return q->head(); 460 465 461 return NULL; 466 462 } 467 463 468 464 VideoFrame *VideoBuffers::tail(BufferType type) 469 465 { 466 QMutexLocker locker(&global_lock); 467 470 468 frame_queue_t *q = queue(type); 471 if (q) 472 { 473 QMutexLocker locker(&global_lock); 474 if (q->size()) 475 return q->tail(); 476 } 469 470 if (!q) 471 return NULL; 472 473 if (q->size()) 474 return q->tail(); 475 477 476 return NULL; 478 477 } 479 478 480 479 void VideoBuffers::enqueue(BufferType type, VideoFrame *frame) 481 480 { 482 if (frame) 483 { 484 frame_queue_t *q = queue(type); 485 if (q) 486 { 487 global_lock.lock(); 488 q->remove(frame); 489 q->enqueue(frame); 490 global_lock.unlock(); 491 if (q == &available && EnoughFreeFrames()) 492 available_wait.wakeAll(); 493 } 494 } 481 if (!frame) 482 return; 483 484 frame_queue_t *q = queue(type); 485 if (!q) 486 return; 487 488 global_lock.lock(); 489 q->remove(frame); 490 q->enqueue(frame); 491 global_lock.unlock(); 492 493 if (q == &available && EnoughFreeFrames()) 494 available_wait.wakeAll(); 495 496 return; 495 497 } 496 498 497 499 void VideoBuffers::remove(BufferType type, VideoFrame *frame) 498 500 { 499 if ( frame)500 {501 global_lock.lock(); 502 if ((type & kVideoBuffer_avail) == kVideoBuffer_avail)503 available.remove(frame); 504 if ((type & kVideoBuffer_used) == kVideoBuffer_used)505 used.remove(frame);506 if ((type & kVideoBuffer_displayed) == kVideoBuffer_displayed)507 displayed.remove(frame);508 if ((type & kVideoBuffer_limbo) == kVideoBuffer_limbo)509 limbo.remove(frame);510 if ((type & kVideoBuffer_pause) == kVideoBuffer_pause)511 pause.remove(frame);512 if ((type & kVideoBuffer_decode) == kVideoBuffer_decode)513 decode.remove(frame);514 global_lock.unlock();515 }501 if (!frame) 502 return; 503 504 QMutexLocker locker(&global_lock); 505 506 if ((type & kVideoBuffer_avail) == kVideoBuffer_avail) 507 available.remove(frame); 508 if ((type & kVideoBuffer_used) == kVideoBuffer_used) 509 used.remove(frame); 510 if ((type & kVideoBuffer_displayed) == kVideoBuffer_displayed) 511 displayed.remove(frame); 512 if ((type & kVideoBuffer_limbo) == kVideoBuffer_limbo) 513 limbo.remove(frame); 514 if ((type & kVideoBuffer_pause) == kVideoBuffer_pause) 515 pause.remove(frame); 516 if ((type & kVideoBuffer_decode) == kVideoBuffer_decode) 517 decode.remove(frame); 516 518 } 517 519 518 520 void VideoBuffers::requeue(BufferType dst, BufferType src, int num) 519 521 { 520 global_lock.lock(); 522 QMutexLocker locker(&global_lock); 523 521 524 num = (num <= 0) ? size(src) : num; 522 525 for (uint i=0; i<(uint)num; i++) 523 526 { … … 525 528 if (frame) 526 529 enqueue(dst, frame); 527 530 } 528 global_lock.unlock();529 531 } 530 532 531 533 void VideoBuffers::safeEnqueue(BufferType dst, VideoFrame* frame) 532 534 { 533 if ( frame)534 {535 global_lock.lock(); 536 remove(kVideoBuffer_all, frame);537 enqueue(dst, frame); 538 global_lock.unlock();539 }535 if (!frame) 536 return; 537 538 QMutexLocker locker(&global_lock); 539 540 remove(kVideoBuffer_all, frame); 541 enqueue(dst, frame); 540 542 } 541 543 542 544 frame_queue_t::iterator VideoBuffers::begin_lock(BufferType type) … … 551 553 552 554 frame_queue_t::iterator VideoBuffers::end(BufferType type) 553 555 { 554 global_lock.lock(); 556 QMutexLocker locker(&global_lock); 557 555 558 frame_queue_t::iterator it; 556 559 frame_queue_t *q = queue(type); 557 560 if (q) 558 561 it = q->end(); 559 562 else 560 563 it = available.end(); 561 global_lock.unlock(); 564 562 565 return it; 563 566 } 564 567 565 568 uint VideoBuffers::size(BufferType type) const 566 569 { 567 uint s = 0; 570 QMutexLocker locker(&global_lock); 571 568 572 const frame_queue_t *q = queue(type); 569 573 if (q) 570 { 571 global_lock.lock(); 572 s = q->size(); 573 global_lock.unlock(); 574 } 575 return s; 574 return q->size(); 575 576 return 0; 576 577 } 577 578 578 579 bool VideoBuffers::contains(BufferType type, VideoFrame *frame) const 579 580 { 580 bool c = false; 581 QMutexLocker locker(&global_lock); 582 581 583 const frame_queue_t *q = queue(type); 582 584 if (q) 583 { 584 global_lock.lock(); 585 c = q->contains(frame); 586 global_lock.unlock(); 587 } 588 return c; 585 return q->contains(frame); 586 587 return false; 589 588 } 590 589 591 590 VideoFrame *VideoBuffers::GetScratchFrame(void) … … 595 594 VERBOSE(VB_IMPORTANT, 596 595 "GetScratchFrame() called, but not allocated"); 597 596 } 597 598 QMutexLocker locker(&global_lock); 598 599 return at(allocSize()-1); 599 600 } 600 601 … … 605 606 VERBOSE(VB_IMPORTANT, 606 607 "GetScratchFrame() called, but not allocated"); 607 608 } 609 610 QMutexLocker locker(&global_lock); 608 611 return at(allocSize()-1); 609 612 } 610 613 … … 692 695 693 696 void VideoBuffers::ClearAfterSeek(void) 694 697 { 695 global_lock.lock(); 698 { 699 QMutexLocker locker(&global_lock); 696 700 697 for (uint i = 0; i < size(); i++)698 at(i)->timecode = 0;701 for (uint i = 0; i < size(); i++) 702 at(i)->timecode = 0; 699 703 700 while (used.count() > 1)701 {702 VideoFrame *buffer = used.dequeue();703 available.enqueue(buffer);704 }704 while (used.count() > 1) 705 { 706 VideoFrame *buffer = used.dequeue(); 707 available.enqueue(buffer); 708 } 705 709 706 if (used.count() > 0) 707 { 708 VideoFrame *buffer = used.dequeue(); 709 available.enqueue(buffer); 710 vpos = vbufferMap[buffer]; 711 rpos = vpos; 710 if (used.count() > 0) 711 { 712 VideoFrame *buffer = used.dequeue(); 713 available.enqueue(buffer); 714 vpos = vbufferMap[buffer]; 715 rpos = vpos; 716 } 717 else 718 { 719 vpos = rpos = 0; 720 } 712 721 } 713 else714 {715 vpos = rpos = 0;716 }717 722 718 723 if (EnoughFreeFrames()) 719 724 available_wait.wakeAll(); 720 725 721 global_lock.unlock();722 726 } 723 727 724 728 void VideoBuffers::LockFrame(const VideoFrame *frame, const char* owner) … … 865 869 { 866 870 (void)frame; 867 871 #ifdef USING_XVMC 868 inheritence_lock.lock();872 QMutexLocker locker(&global_lock); 869 873 870 874 frame_map_t::iterator it = parents.find(frame); 871 875 if (it == parents.end()) … … 909 913 for (; it != new_parents.end(); ++it) 910 914 children[*it].push_back((VideoFrame*)frame); 911 915 } 912 913 inheritence_lock.unlock();914 916 #endif // USING_XVMC 915 917 } 916 918 917 919 void VideoBuffers::RemoveInheritence(const VideoFrame *frame) 918 920 { 919 inheritence_lock.lock();921 QMutexLocker locker(&global_lock); 920 922 921 923 frame_map_t::iterator it = parents.find(frame); 922 924 if (it == parents.end()) 923 {924 inheritence_lock.unlock();925 925 return; 926 }927 926 928 927 frame_queue_t new_parents; 929 928 frame_queue_t &p = it->second; … … 952 951 VERBOSE(VB_IMPORTANT, QString("Parent #%1: %2") 953 952 .arg(i).arg(DebugString(*pit))); 954 953 } 955 956 inheritence_lock.unlock();957 954 } 958 955 959 956 frame_queue_t VideoBuffers::Children(const VideoFrame *frame) 960 957 { 958 QMutexLocker locker(&global_lock); 959 961 960 frame_queue_t c; 962 961 frame_map_t::iterator it = children.find(frame); 963 962 if (it != children.end()) … … 967 966 968 967 bool VideoBuffers::HasChildren(const VideoFrame *frame) 969 968 { 969 QMutexLocker locker(&global_lock); 970 970 971 frame_map_t::iterator it = children.find(frame); 971 972 if (it != children.end()) 972 973 return !(it->second.empty()); … … 1033 1034 1034 1035 void VideoBuffers::SetOSDFrame(VideoFrame *frame, VideoFrame *osd) 1035 1036 { 1036 if (frame ==osd)1037 if (frame == osd) 1037 1038 { 1038 1039 VERBOSE(VB_IMPORTANT, QString("SetOSDFrame() -- frame==osd %1") 1039 1040 .arg(GetStatus())); … … 1044 1045 xvmc_render_state_t* r = GetRender(frame); 1045 1046 if (r) 1046 1047 { 1047 global_lock.lock();1048 QMutexLocker locker(&global_lock); 1048 1049 1049 1050 VideoFrame* old_osd = (VideoFrame*) r->p_osd_target_surface_render; 1050 1051 if (old_osd) … … 1054 1055 1055 1056 if (osd) 1056 1057 xvmc_osd_parent[osd] = frame; 1057 1058 global_lock.unlock();1059 1058 } 1059 1060 1060 UnlockFrame(frame, "SetOSDFrame"); 1061 1061 } 1062 1062 1063 1063 VideoFrame* VideoBuffers::GetOSDParent(const VideoFrame *osd) 1064 1064 { 1065 global_lock.lock(); 1066 VideoFrame *parent = xvmc_osd_parent[osd]; 1067 global_lock.unlock(); 1068 return parent; 1065 QMutexLocker locker(&global_lock); 1066 return xvmc_osd_parent[osd]; 1069 1067 } 1070 1068 1071 1069 #endif