00001
00002
00003
00004 #include <unistd.h>
00005
00006 #include "mythconfig.h"
00007
00008 #include "mythcontext.h"
00009 #include "videobuffers.h"
00010 extern "C" {
00011 #include "libavcodec/avcodec.h"
00012 }
00013 #include "fourcc.h"
00014 #include "compat.h"
00015 #include "mythlogging.h"
00016
00017 #define TRY_LOCK_SPINS 100
00018 #define TRY_LOCK_SPINS_BEFORE_WARNING 10
00019 #define TRY_LOCK_SPIN_WAIT 100
00020
00021 int next_dbg_str = 0;
00022
00023 YUVInfo::YUVInfo(uint w, uint h, uint sz, const int *p, const int *o)
00024 : width(w), height(h), size(sz)
00025 {
00026 if (p)
00027 {
00028 memcpy(pitches, p, 3 * sizeof(int));
00029 }
00030 else
00031 {
00032 pitches[0] = width;
00033 pitches[1] = pitches[2] = width >> 1;
00034 }
00035
00036 if (o)
00037 {
00038 memcpy(offsets, o, 3 * sizeof(int));
00039 }
00040 else
00041 {
00042 offsets[0] = 0;
00043 offsets[1] = width * height;
00044 offsets[2] = offsets[1] + (offsets[1] >> 2);
00045 }
00046 }
00047
00121 VideoBuffers::VideoBuffers()
00122 : needfreeframes(0), needprebufferframes(0),
00123 needprebufferframes_normal(0), needprebufferframes_small(0),
00124 keepprebufferframes(0), createdpauseframe(false), rpos(0), vpos(0),
00125 global_lock(QMutex::Recursive)
00126 {
00127 }
00128
00129 VideoBuffers::~VideoBuffers()
00130 {
00131 DeleteBuffers();
00132 }
00133
00155 void VideoBuffers::Init(uint numdecode, bool extra_for_pause,
00156 uint need_free, uint needprebuffer_normal,
00157 uint needprebuffer_small, uint keepprebuffer)
00158 {
00159 QMutexLocker locker(&global_lock);
00160
00161 Reset();
00162
00163 uint numcreate = numdecode + ((extra_for_pause) ? 1 : 0);
00164
00165
00166
00167 buffers.reserve(max(numcreate, (uint)128));
00168
00169 buffers.resize(numcreate);
00170 for (uint i = 0; i < numcreate; i++)
00171 {
00172 memset(at(i), 0, sizeof(VideoFrame));
00173 at(i)->codec = FMT_NONE;
00174 at(i)->interlaced_frame = -1;
00175 at(i)->top_field_first = +1;
00176 vbufferMap[at(i)] = i;
00177 }
00178
00179 needfreeframes = need_free;
00180 needprebufferframes = needprebuffer_normal;
00181 needprebufferframes_normal = needprebuffer_normal;
00182 needprebufferframes_small = needprebuffer_small;
00183 keepprebufferframes = keepprebuffer;
00184 createdpauseframe = extra_for_pause;
00185
00186 if (createdpauseframe)
00187 enqueue(kVideoBuffer_pause, at(numcreate - 1));
00188
00189 for (uint i = 0; i < numdecode; i++)
00190 enqueue(kVideoBuffer_avail, at(i));
00191 }
00192
00197 void VideoBuffers::Reset()
00198 {
00199 QMutexLocker locker(&global_lock);
00200
00201
00202
00203 frame_vector_t::iterator it = buffers.begin();
00204 for (;it != buffers.end(); ++it)
00205 {
00206 if (it->qscale_table)
00207 {
00208 delete [] it->qscale_table;
00209 it->qscale_table = NULL;
00210 }
00211 }
00212
00213 available.clear();
00214 used.clear();
00215 limbo.clear();
00216 finished.clear();
00217 decode.clear();
00218 pause.clear();
00219 displayed.clear();
00220 vbufferMap.clear();
00221 }
00222
00227 void VideoBuffers::SetPrebuffering(bool normal)
00228 {
00229 QMutexLocker locker(&global_lock);
00230 needprebufferframes = (normal) ?
00231 needprebufferframes_normal : needprebufferframes_small;
00232 }
00233
00234 VideoFrame *VideoBuffers::GetNextFreeFrameInternal(BufferType enqueue_to)
00235 {
00236 QMutexLocker locker(&global_lock);
00237 VideoFrame *frame = NULL;
00238
00239
00240 for (uint i = 0; i < available.size(); i++)
00241 {
00242 frame = available.dequeue();
00243 if (decode.contains(frame))
00244 available.enqueue(frame);
00245 else
00246 break;
00247 }
00248
00249 while (frame && used.contains(frame))
00250 {
00251 LOG(VB_PLAYBACK, LOG_NOTICE,
00252 QString("GetNextFreeFrame() served a busy frame %1. Dropping. %2")
00253 .arg(DebugString(frame, true)).arg(GetStatus()));
00254 frame = available.dequeue();
00255 }
00256
00257 if (frame)
00258 safeEnqueue(enqueue_to, frame);
00259
00260 return frame;
00261 }
00262
00269 VideoFrame *VideoBuffers::GetNextFreeFrame(BufferType enqueue_to)
00270 {
00271 for (uint tries = 1; true; tries++)
00272 {
00273 VideoFrame *frame = VideoBuffers::GetNextFreeFrameInternal(enqueue_to);
00274
00275 if (frame)
00276 return frame;
00277
00278 if (tries >= TRY_LOCK_SPINS)
00279 {
00280 LOG(VB_GENERAL, LOG_ERR,
00281 QString("GetNextFreeFrame() unable to "
00282 "lock frame %1 times. Discarding Frames.")
00283 .arg(TRY_LOCK_SPINS));
00284 DiscardFrames(true);
00285 continue;
00286 }
00287
00288 if (tries && !(tries % TRY_LOCK_SPINS_BEFORE_WARNING))
00289 {
00290 LOG(VB_PLAYBACK, LOG_NOTICE,
00291 QString("GetNextFreeFrame() TryLock has "
00292 "spun %1 times, this is a lot.").arg(tries));
00293 }
00294 usleep(TRY_LOCK_SPIN_WAIT);
00295 }
00296
00297 return NULL;
00298 }
00299
00306 void VideoBuffers::ReleaseFrame(VideoFrame *frame)
00307 {
00308 QMutexLocker locker(&global_lock);
00309
00310 vpos = vbufferMap[frame];
00311 limbo.remove(frame);
00312 decode.enqueue(frame);
00313 used.enqueue(frame);
00314 }
00315
00321 void VideoBuffers::DeLimboFrame(VideoFrame *frame)
00322 {
00323 QMutexLocker locker(&global_lock);
00324 if (limbo.contains(frame))
00325 limbo.remove(frame);
00326
00327
00328
00329 if (!decode.contains(frame))
00330 safeEnqueue(kVideoBuffer_avail, frame);
00331
00332
00333 while (decode.contains(frame))
00334 decode.remove(frame);
00335 }
00336
00341 void VideoBuffers::StartDisplayingFrame(void)
00342 {
00343 QMutexLocker locker(&global_lock);
00344 rpos = vbufferMap[used.head()];
00345 }
00346
00351 void VideoBuffers::DoneDisplayingFrame(VideoFrame *frame)
00352 {
00353 QMutexLocker locker(&global_lock);
00354
00355 if(used.contains(frame))
00356 remove(kVideoBuffer_used, frame);
00357
00358 enqueue(kVideoBuffer_finished, frame);
00359
00360
00361 frame_queue_t ula(finished);
00362 frame_queue_t::iterator it = ula.begin();
00363 for (; it != ula.end(); ++it)
00364 {
00365 if (!decode.contains(*it))
00366 {
00367 remove(kVideoBuffer_finished, *it);
00368 enqueue(kVideoBuffer_avail, *it);
00369 }
00370 }
00371 }
00372
00378 void VideoBuffers::DiscardFrame(VideoFrame *frame)
00379 {
00380 QMutexLocker locker(&global_lock);
00381 safeEnqueue(kVideoBuffer_avail, frame);
00382 }
00383
00384 frame_queue_t *VideoBuffers::queue(BufferType type)
00385 {
00386 QMutexLocker locker(&global_lock);
00387
00388 frame_queue_t *q = NULL;
00389
00390 if (type == kVideoBuffer_avail)
00391 q = &available;
00392 else if (type == kVideoBuffer_used)
00393 q = &used;
00394 else if (type == kVideoBuffer_displayed)
00395 q = &displayed;
00396 else if (type == kVideoBuffer_limbo)
00397 q = &limbo;
00398 else if (type == kVideoBuffer_pause)
00399 q = &pause;
00400 else if (type == kVideoBuffer_decode)
00401 q = &decode;
00402 else if (type == kVideoBuffer_finished)
00403 q = &finished;
00404
00405 return q;
00406 }
00407
00408 const frame_queue_t *VideoBuffers::queue(BufferType type) const
00409 {
00410 QMutexLocker locker(&global_lock);
00411
00412 const frame_queue_t *q = NULL;
00413
00414 if (type == kVideoBuffer_avail)
00415 q = &available;
00416 else if (type == kVideoBuffer_used)
00417 q = &used;
00418 else if (type == kVideoBuffer_displayed)
00419 q = &displayed;
00420 else if (type == kVideoBuffer_limbo)
00421 q = &limbo;
00422 else if (type == kVideoBuffer_pause)
00423 q = &pause;
00424 else if (type == kVideoBuffer_decode)
00425 q = &decode;
00426 else if (type == kVideoBuffer_finished)
00427 q = &finished;
00428
00429 return q;
00430 }
00431
00432 VideoFrame *VideoBuffers::dequeue(BufferType type)
00433 {
00434 QMutexLocker locker(&global_lock);
00435
00436 frame_queue_t *q = queue(type);
00437
00438 if (!q)
00439 return NULL;
00440
00441 return q->dequeue();
00442 }
00443
00444 VideoFrame *VideoBuffers::head(BufferType type)
00445 {
00446 QMutexLocker locker(&global_lock);
00447
00448 frame_queue_t *q = queue(type);
00449
00450 if (!q)
00451 return NULL;
00452
00453 if (q->size())
00454 return q->head();
00455
00456 return NULL;
00457 }
00458
00459 VideoFrame *VideoBuffers::tail(BufferType type)
00460 {
00461 QMutexLocker locker(&global_lock);
00462
00463 frame_queue_t *q = queue(type);
00464
00465 if (!q)
00466 return NULL;
00467
00468 if (q->size())
00469 return q->tail();
00470
00471 return NULL;
00472 }
00473
00474 void VideoBuffers::enqueue(BufferType type, VideoFrame *frame)
00475 {
00476 if (!frame)
00477 return;
00478
00479 frame_queue_t *q = queue(type);
00480 if (!q)
00481 return;
00482
00483 global_lock.lock();
00484 q->remove(frame);
00485 q->enqueue(frame);
00486 global_lock.unlock();
00487
00488 return;
00489 }
00490
00491 void VideoBuffers::remove(BufferType type, VideoFrame *frame)
00492 {
00493 if (!frame)
00494 return;
00495
00496 QMutexLocker locker(&global_lock);
00497
00498 if ((type & kVideoBuffer_avail) == kVideoBuffer_avail)
00499 available.remove(frame);
00500 if ((type & kVideoBuffer_used) == kVideoBuffer_used)
00501 used.remove(frame);
00502 if ((type & kVideoBuffer_displayed) == kVideoBuffer_displayed)
00503 displayed.remove(frame);
00504 if ((type & kVideoBuffer_limbo) == kVideoBuffer_limbo)
00505 limbo.remove(frame);
00506 if ((type & kVideoBuffer_pause) == kVideoBuffer_pause)
00507 pause.remove(frame);
00508 if ((type & kVideoBuffer_decode) == kVideoBuffer_decode)
00509 decode.remove(frame);
00510 if ((type & kVideoBuffer_finished) == kVideoBuffer_finished)
00511 finished.remove(frame);
00512 }
00513
00514 void VideoBuffers::requeue(BufferType dst, BufferType src, int num)
00515 {
00516 QMutexLocker locker(&global_lock);
00517
00518 num = (num <= 0) ? size(src) : num;
00519 for (uint i=0; i<(uint)num; i++)
00520 {
00521 VideoFrame *frame = dequeue(src);
00522 if (frame)
00523 enqueue(dst, frame);
00524 }
00525 }
00526
00527 void VideoBuffers::safeEnqueue(BufferType dst, VideoFrame* frame)
00528 {
00529 if (!frame)
00530 return;
00531
00532 QMutexLocker locker(&global_lock);
00533
00534 remove(kVideoBuffer_all, frame);
00535 enqueue(dst, frame);
00536 }
00537
00538 frame_queue_t::iterator VideoBuffers::begin_lock(BufferType type)
00539 {
00540 global_lock.lock();
00541 frame_queue_t *q = queue(type);
00542 if (q)
00543 return q->begin();
00544 else
00545 return available.begin();
00546 }
00547
00548 frame_queue_t::iterator VideoBuffers::end(BufferType type)
00549 {
00550 QMutexLocker locker(&global_lock);
00551
00552 frame_queue_t::iterator it;
00553 frame_queue_t *q = queue(type);
00554 if (q)
00555 it = q->end();
00556 else
00557 it = available.end();
00558
00559 return it;
00560 }
00561
00562 uint VideoBuffers::size(BufferType type) const
00563 {
00564 QMutexLocker locker(&global_lock);
00565
00566 const frame_queue_t *q = queue(type);
00567 if (q)
00568 return q->size();
00569
00570 return 0;
00571 }
00572
00573 bool VideoBuffers::contains(BufferType type, VideoFrame *frame) const
00574 {
00575 QMutexLocker locker(&global_lock);
00576
00577 const frame_queue_t *q = queue(type);
00578 if (q)
00579 return q->contains(frame);
00580
00581 return false;
00582 }
00583
00584 VideoFrame *VideoBuffers::GetScratchFrame(void)
00585 {
00586 if (!createdpauseframe || !head(kVideoBuffer_pause))
00587 {
00588 LOG(VB_GENERAL, LOG_ERR, "GetScratchFrame() called, but not allocated");
00589 }
00590
00591 QMutexLocker locker(&global_lock);
00592 return head(kVideoBuffer_pause);
00593 }
00594
00595 void VideoBuffers::SetLastShownFrameToScratch(void)
00596 {
00597 if (!createdpauseframe || !head(kVideoBuffer_pause))
00598 {
00599 LOG(VB_GENERAL, LOG_ERR,
00600 "SetLastShownFrameToScratch() called but no pause frame");
00601 return;
00602 }
00603
00604 VideoFrame *pause = head(kVideoBuffer_pause);
00605 rpos = vbufferMap[pause];
00606 }
00607
00612 void VideoBuffers::DiscardFrames(bool next_frame_keyframe)
00613 {
00614 QMutexLocker locker(&global_lock);
00615 LOG(VB_PLAYBACK, LOG_INFO, QString("VideoBuffers::DiscardFrames(%1): %2")
00616 .arg(next_frame_keyframe).arg(GetStatus()));
00617
00618 if (!next_frame_keyframe)
00619 {
00620 frame_queue_t ula(used);
00621 frame_queue_t::iterator it = ula.begin();
00622 for (; it != ula.end(); ++it)
00623 DiscardFrame(*it);
00624 LOG(VB_PLAYBACK, LOG_INFO,
00625 QString("VideoBuffers::DiscardFrames(%1): %2 -- done")
00626 .arg(next_frame_keyframe).arg(GetStatus()));
00627 return;
00628 }
00629
00630
00631 frame_queue_t ula(used);
00632 ula.insert(ula.end(), limbo.begin(), limbo.end());
00633 ula.insert(ula.end(), available.begin(), available.end());
00634 ula.insert(ula.end(), finished.begin(), finished.end());
00635 frame_queue_t::iterator it;
00636
00637
00638 frame_queue_t discards(used);
00639 discards.insert(discards.end(), limbo.begin(), limbo.end());
00640 discards.insert(discards.end(), finished.begin(), finished.end());
00641 for (it = discards.begin(); it != discards.end(); ++it)
00642 DiscardFrame(*it);
00643
00644
00645 if (available.count() + pause.count() + displayed.count() != Size())
00646 {
00647 for (uint i=0; i < Size(); i++)
00648 {
00649 if (!available.contains(at(i)) &&
00650 !pause.contains(at(i)) &&
00651 !displayed.contains(at(i)))
00652 {
00653 LOG(VB_GENERAL, LOG_ERR,
00654 QString("VideoBuffers::DiscardFrames(): ERROR, %1 (%2) not "
00655 "in available, pause, or displayed %3")
00656 .arg(DebugString(at(i), true)).arg((long long)at(i))
00657 .arg(GetStatus()));
00658 DiscardFrame(at(i));
00659 }
00660 }
00661 }
00662
00663
00664
00665 for (it = decode.begin(); it != decode.end(); ++it)
00666 remove(kVideoBuffer_all, *it);
00667 for (it = decode.begin(); it != decode.end(); ++it)
00668 available.enqueue(*it);
00669 decode.clear();
00670
00671 LOG(VB_PLAYBACK, LOG_INFO,
00672 QString("VideoBuffers::DiscardFrames(%1): %2 -- done")
00673 .arg(next_frame_keyframe).arg(GetStatus()));
00674 }
00675
00676 void VideoBuffers::ClearAfterSeek(void)
00677 {
00678 {
00679 QMutexLocker locker(&global_lock);
00680
00681 for (uint i = 0; i < Size(); i++)
00682 at(i)->timecode = 0;
00683
00684 while (used.count() > 1)
00685 {
00686 VideoFrame *buffer = used.dequeue();
00687 available.enqueue(buffer);
00688 }
00689
00690 if (used.count() > 0)
00691 {
00692 VideoFrame *buffer = used.dequeue();
00693 available.enqueue(buffer);
00694 vpos = vbufferMap[buffer];
00695 rpos = vpos;
00696 }
00697 else
00698 {
00699 vpos = rpos = 0;
00700 }
00701 }
00702 }
00703
00704 bool VideoBuffers::CreateBuffers(VideoFrameType type, int width, int height)
00705 {
00706 vector<unsigned char*> bufs;
00707 vector<YUVInfo> yuvinfo;
00708 return CreateBuffers(type, width, height, bufs, yuvinfo);
00709 }
00710
00711 bool VideoBuffers::CreateBuffers(VideoFrameType type, int width, int height,
00712 vector<unsigned char*> bufs,
00713 vector<YUVInfo> yuvinfo)
00714 {
00715 if ((FMT_YV12 != type) && (FMT_YUY2 != type))
00716 return false;
00717
00718 bool ok = true;
00719 uint buf_size = buffersize(type, width, height);
00720
00721 while (bufs.size() < Size())
00722 {
00723 unsigned char *data = (unsigned char*)av_malloc(buf_size + 64);
00724 if (!data)
00725 {
00726 LOG(VB_GENERAL, LOG_ERR, "Failed to allocate memory for frame.");
00727 return false;
00728 }
00729
00730 bufs.push_back(data);
00731 yuvinfo.push_back(YUVInfo(width, height, buf_size, NULL, NULL));
00732 allocated_arrays.push_back(data);
00733 }
00734
00735 for (uint i = 0; i < Size(); i++)
00736 {
00737 init(&buffers[i],
00738 type, bufs[i], yuvinfo[i].width, yuvinfo[i].height,
00739 max(buf_size, yuvinfo[i].size),
00740 (const int*) yuvinfo[i].pitches, (const int*) yuvinfo[i].offsets);
00741
00742 ok &= (bufs[i] != NULL);
00743 }
00744
00745 Clear();
00746
00747 return ok;
00748 }
00749
00750 static unsigned char *ffmpeg_hack = (unsigned char*)
00751 "avlib should not use this private data";
00752
00753 bool VideoBuffers::CreateBuffer(int width, int height, uint num, void* data,
00754 VideoFrameType fmt)
00755 {
00756 if (num >= Size())
00757 return false;
00758
00759 init(&buffers[num], fmt, (unsigned char*)data, width, height, 0);
00760 buffers[num].priv[0] = ffmpeg_hack;
00761 buffers[num].priv[1] = ffmpeg_hack;
00762 return true;
00763 }
00764
00765 uint VideoBuffers::AddBuffer(int width, int height, void* data,
00766 VideoFrameType fmt)
00767 {
00768 QMutexLocker lock(&global_lock);
00769
00770 uint num = Size();
00771 buffers.resize(num + 1);
00772 memset(&buffers[num], 0, sizeof(VideoFrame));
00773 buffers[num].interlaced_frame = -1;
00774 buffers[num].top_field_first = 1;
00775 vbufferMap[at(num)] = num;
00776 init(&buffers[num], fmt, (unsigned char*)data, width, height, 0);
00777 buffers[num].priv[0] = ffmpeg_hack;
00778 buffers[num].priv[1] = ffmpeg_hack;
00779 enqueue(kVideoBuffer_avail, at(num));
00780
00781 return Size();
00782 }
00783
00784 void VideoBuffers::DeleteBuffers()
00785 {
00786 next_dbg_str = 0;
00787 for (uint i = 0; i < Size(); i++)
00788 {
00789 buffers[i].buf = NULL;
00790
00791 if (buffers[i].qscale_table)
00792 {
00793 delete [] buffers[i].qscale_table;
00794 buffers[i].qscale_table = NULL;
00795 }
00796 }
00797
00798 for (uint i = 0; i < allocated_arrays.size(); i++)
00799 av_free(allocated_arrays[i]);
00800 allocated_arrays.clear();
00801 }
00802
00803 static unsigned long long to_bitmap(const frame_queue_t& list);
00804 QString VideoBuffers::GetStatus(int n) const
00805 {
00806 if (n <= 0)
00807 n = Size();
00808
00809 QString str("");
00810 if (global_lock.tryLock())
00811 {
00812 unsigned long long a = to_bitmap(available);
00813 unsigned long long u = to_bitmap(used);
00814 unsigned long long d = to_bitmap(displayed);
00815 unsigned long long l = to_bitmap(limbo);
00816 unsigned long long p = to_bitmap(pause);
00817 unsigned long long f = to_bitmap(finished);
00818 unsigned long long x = to_bitmap(decode);
00819 for (uint i=0; i<(uint)n; i++)
00820 {
00821 unsigned long long mask = 1<<i;
00822 QString tmp("");
00823 if (a & mask)
00824 tmp += (x & mask) ? "a" : "A";
00825 if (u & mask)
00826 tmp += (x & mask) ? "u" : "U";
00827 if (d & mask)
00828 tmp += (x & mask) ? "d" : "D";
00829 if (l & mask)
00830 tmp += (x & mask) ? "l" : "L";
00831 if (p & mask)
00832 tmp += (x & mask) ? "p" : "P";
00833 if (f & mask)
00834 tmp += (x & mask) ? "f" : "F";
00835
00836 if (0 == tmp.length())
00837 str += " ";
00838 else if (1 == tmp.length())
00839 str += tmp;
00840 else
00841 str += "(" + tmp + ")";
00842 }
00843 global_lock.unlock();
00844 }
00845 else
00846 {
00847 for (uint i=0; i<(uint)n; i++)
00848 str += " ";
00849 }
00850 return str;
00851 }
00852
00853 void VideoBuffers::Clear(uint i)
00854 {
00855 clear(at(i));
00856 }
00857
00858 void VideoBuffers::Clear(void)
00859 {
00860 for (uint i = 0; i < Size(); i++)
00861 Clear(i);
00862 }
00863
00864
00865
00866
00867
00868 #define DBG_STR_ARR_SIZE 40
00869 QString dbg_str_arr[DBG_STR_ARR_SIZE] =
00870 {
00871 "A ", " B ", " C ", " D ",
00872 " E ", " F ", " G ", " H",
00873 "a ", " b ", " c ", " d ",
00874 " e ", " f ", " g ", " h",
00875 "0 ", " 1 ", " 2 ", " 3 ",
00876 " 4 ", " 5 ", " 6 ", " 7",
00877 "I ", " J ", " K ", " L ",
00878 " M ", " N ", " O ", " P",
00879 "i ", " j ", " k ", " l ",
00880 " m ", " n ", " o ", " p",
00881 };
00882 QString dbg_str_arr_short[DBG_STR_ARR_SIZE] =
00883 {
00884 "A","B","C","D","E","F","G","H",
00885 "a","b","c","d","e","f","g","h",
00886 "0","1","2","3","4","5","6","7",
00887 "I","J","K","L","M","N","O","P",
00888 "i","j","k","l","m","n","o","p",
00889 };
00890
00891 map<const VideoFrame *, int> dbg_str;
00892
00893 static int DebugNum(const VideoFrame *frame)
00894 {
00895 map<const VideoFrame *, int>::iterator it = dbg_str.find(frame);
00896 if (it == dbg_str.end())
00897 {
00898 dbg_str[frame] = next_dbg_str;
00899 next_dbg_str = (next_dbg_str+1) % DBG_STR_ARR_SIZE;
00900 }
00901 return dbg_str[frame];
00902 }
00903
00904 const QString& DebugString(const VideoFrame *frame, bool short_str)
00905 {
00906 if (short_str)
00907 return dbg_str_arr_short[DebugNum(frame)];
00908 else
00909 return dbg_str_arr[DebugNum(frame)];
00910 }
00911
00912 const QString& DebugString(uint i, bool short_str)
00913 {
00914 return ((short_str) ? dbg_str_arr_short : dbg_str_arr)[i];
00915 }
00916
00917 static unsigned long long to_bitmap(const frame_queue_t& list)
00918 {
00919 unsigned long long bitmap = 0;
00920 frame_queue_t::const_iterator it = list.begin();
00921 for (; it != list.end(); ++it)
00922 {
00923 int shift = DebugNum(*it);
00924 bitmap |= 1<<shift;
00925 }
00926 return bitmap;
00927 }
00928
00929 static QString bitmap_to_string(unsigned long long bitmap)
00930 {
00931 QString str("");
00932 for (int i=0; i<8; i++)
00933 str += ((bitmap>>i)&1) ? DebugString(i, true) : " ";
00934 return str;
00935 }
00936
00937 const QString DebugString(const frame_queue_t& list)
00938 {
00939 return bitmap_to_string(to_bitmap(list));
00940 }
00941
00942 const QString DebugString(const vector<const VideoFrame*>& list)
00943 {
00944
00945 unsigned long long bitmap = 0;
00946 vector<const VideoFrame*>::const_iterator it = list.begin();
00947 for (; it != list.end(); ++it)
00948 {
00949 int shift = DebugNum(*it);
00950 bitmap |= 1<<shift;
00951 }
00952
00953 return bitmap_to_string(bitmap);
00954 }