00001 #include <unistd.h>
00002 #include <stdlib.h>
00003
00004 #include "mythconfig.h"
00005
00006 #include "dvdringbuffer.h"
00007 #include "mythcontext.h"
00008 #include "mythmediamonitor.h"
00009 #include "iso639.h"
00010
00011 #include "mythdvdplayer.h"
00012 #include "compat.h"
00013 #include "mythlogging.h"
00014 #include "mythuihelper.h"
00015
00016 #define LOC QString("DVDRB: ")
00017
00018 #define IncrementButtonVersion \
00019 if (++m_buttonVersion > 1024) \
00020 m_buttonVersion = 1;
00021
00022 #define DVD_DRIVE_SPEED 1
00023
00024 static const char *dvdnav_menu_table[] =
00025 {
00026 NULL,
00027 NULL,
00028 "Title",
00029 "Root",
00030 "Subpicture",
00031 "Audio",
00032 "Angle",
00033 "Part",
00034 };
00035
00036 DVDInfo::DVDInfo(const QString &filename)
00037 : m_nav(NULL), m_name(NULL), m_serialnumber(NULL)
00038 {
00039 LOG(VB_PLAYBACK, LOG_INFO, QString("DVDInfo: Trying %1").arg(filename));
00040 QString name = filename;
00041 if (name.left(6) == "dvd://")
00042 name.remove(0,5);
00043 else if (name.left(5) == "dvd:/")
00044 name.remove(0,4);
00045 else if (name.left(4) == "dvd:")
00046 name.remove(0,4);
00047
00048 QByteArray fname = name.toLocal8Bit();
00049 dvdnav_status_t res = dvdnav_open(&m_nav, fname.constData());
00050 if (res == DVDNAV_STATUS_ERR)
00051 {
00052 LOG(VB_GENERAL, LOG_ERR, QString("DVDInfo: Failed to open device at %1")
00053 .arg(fname.constData()));
00054 return;
00055 }
00056
00057 res = dvdnav_get_title_string(m_nav, &m_name);
00058 if (res == DVDNAV_STATUS_ERR)
00059 LOG(VB_GENERAL, LOG_ERR, "DVDInfo: Failed to get name.");
00060 res = dvdnav_get_serial_string(m_nav, &m_serialnumber);
00061 if (res == DVDNAV_STATUS_ERR)
00062 LOG(VB_GENERAL, LOG_ERR, "DVDInfo: Failed to get serial number.");
00063 }
00064
00065 DVDInfo::~DVDInfo(void)
00066 {
00067 if (m_nav)
00068 dvdnav_close(m_nav);
00069 LOG(VB_PLAYBACK, LOG_INFO, QString("DVDInfo: Finishing."));
00070 }
00071
00072 bool DVDInfo::GetNameAndSerialNum(QString &name, QString &serial)
00073 {
00074 name = QString(m_name);
00075 serial = QString(m_serialnumber);
00076 if (name.isEmpty() && serial.isEmpty())
00077 return false;
00078 return true;
00079 }
00080
00081 DVDRingBuffer::DVDRingBuffer(const QString &lfilename) :
00082 RingBuffer(kRingBuffer_DVD),
00083 m_dvdnav(NULL), m_dvdBlockReadBuf(NULL),
00084 m_dvdBlockRPos(0), m_dvdBlockWPos(0),
00085 m_pgLength(0), m_pgcLength(0),
00086 m_cellStart(0), m_cellChanged(false),
00087 m_pgcLengthChanged(false), m_pgStart(0),
00088 m_currentpos(0),
00089 m_lastNav(NULL), m_part(0), m_lastPart(0),
00090 m_title(0), m_lastTitle(0), m_playerWait(false),
00091 m_titleParts(0), m_gotStop(false), m_currentAngle(0),
00092 m_currentTitleAngleCount(0), m_newSequence(false),
00093 m_still(0), m_lastStill(0),
00094 m_audioStreamsChanged(false),
00095 m_dvdWaiting(false),
00096 m_titleLength(0),
00097
00098 m_skipstillorwait(true),
00099 m_cellstartPos(0), m_buttonSelected(false),
00100 m_buttonExists(false), m_cellid(0),
00101 m_lastcellid(0), m_vobid(0),
00102 m_lastvobid(0), m_cellRepeated(false),
00103
00104 m_curAudioTrack(0),
00105 m_curSubtitleTrack(0),
00106 m_autoselectsubtitle(true),
00107 m_dvdname(NULL), m_serialnumber(NULL),
00108 m_seeking(false), m_seektime(0),
00109 m_currentTime(0),
00110 m_parent(NULL),
00111 m_forcedAspect(-1.0f),
00112
00113
00114 m_inMenu(false), m_buttonVersion(1), m_buttonStreamID(0),
00115 m_hl_button(0, 0, 0, 0), m_menuSpuPkt(0), m_menuBuflength(0)
00116 {
00117 memset(&m_dvdMenuButton, 0, sizeof(AVSubtitle));
00118 memset(m_dvdBlockWriteBuf, 0, sizeof(char) * DVD_BLOCK_SIZE);
00119 memset(m_clut, 0, sizeof(uint32_t) * 16);
00120 memset(m_button_color, 0, sizeof(uint8_t) * 4);
00121 memset(m_button_alpha, 0, sizeof(uint8_t) * 4);
00122 uint def[8] = { 3, 5, 10, 20, 30, 60, 120, 180 };
00123 uint seekValues[8] = { 1, 2, 4, 8, 10, 15, 20, 60 };
00124
00125 for (uint i = 0; i < 8; i++)
00126 m_seekSpeedMap.insert(def[i], seekValues[i]);
00127
00128 OpenFile(lfilename);
00129 }
00130
00131 DVDRingBuffer::~DVDRingBuffer()
00132 {
00133 CloseDVD();
00134 m_menuBtnLock.lock();
00135 ClearMenuSPUParameters();
00136 m_menuBtnLock.unlock();
00137 ClearChapterCache();
00138 }
00139
00140 void DVDRingBuffer::CloseDVD(void)
00141 {
00142 rwlock.lockForWrite();
00143 if (m_dvdnav)
00144 {
00145 SetDVDSpeed(-1);
00146 dvdnav_close(m_dvdnav);
00147 m_dvdnav = NULL;
00148 }
00149 m_gotStop = false;
00150 m_audioStreamsChanged = true;
00151 rwlock.unlock();
00152 }
00153
00154 void DVDRingBuffer::ClearChapterCache(void)
00155 {
00156 rwlock.lockForWrite();
00157 foreach (QList<uint64_t> chapters, m_chapterMap)
00158 chapters.clear();
00159 m_chapterMap.clear();
00160 rwlock.unlock();
00161 }
00162
00163 long long DVDRingBuffer::Seek(long long pos, int whence, bool has_lock)
00164 {
00165 LOG(VB_FILE, LOG_INFO, LOC + QString("Seek(%1,%2,%3)")
00166 .arg(pos).arg((whence == SEEK_SET) ? "SEEK_SET":
00167 ((whence == SEEK_CUR) ? "SEEK_CUR" : "SEEK_END"))
00168 .arg(has_lock ? "locked" : "unlocked"));
00169
00170 long long ret = -1;
00171
00172
00173
00174 if (!has_lock)
00175 rwlock.lockForWrite();
00176
00177 poslock.lockForWrite();
00178
00179
00180 if (readaheadrunning &&
00181 ((whence == SEEK_SET && pos == readpos) ||
00182 (whence == SEEK_CUR && pos == 0)))
00183 {
00184 ret = readpos;
00185
00186 poslock.unlock();
00187 if (!has_lock)
00188 rwlock.unlock();
00189
00190 return ret;
00191 }
00192
00193
00194 long long new_pos = (SEEK_SET==whence) ? pos : readpos + pos;
00195
00196
00197
00198
00199 if ((SEEK_END == whence) ||
00200 ((SEEK_CUR == whence) && new_pos != 0))
00201 {
00202 errno = EINVAL;
00203 ret = -1;
00204 }
00205 else
00206 {
00207 NormalSeek(new_pos);
00208 ret = new_pos;
00209 }
00210
00211 if (ret >= 0)
00212 {
00213 readpos = ret;
00214
00215 ignorereadpos = -1;
00216
00217 if (readaheadrunning)
00218 ResetReadAhead(readpos);
00219
00220 readAdjust = 0;
00221 }
00222 else
00223 {
00224 QString cmd = QString("Seek(%1, %2)").arg(pos)
00225 .arg((whence == SEEK_SET) ? "SEEK_SET" :
00226 ((whence == SEEK_CUR) ? "SEEK_CUR" : "SEEK_END"));
00227 LOG(VB_GENERAL, LOG_ERR, LOC + cmd + " Failed" + ENO);
00228 }
00229
00230 poslock.unlock();
00231
00232 generalWait.wakeAll();
00233
00234 if (!has_lock)
00235 rwlock.unlock();
00236
00237 return ret;
00238 }
00239
00240 long long DVDRingBuffer::NormalSeek(long long time)
00241 {
00242 QMutexLocker lock(&m_seekLock);
00243 return Seek(time);
00244 }
00245
00246 long long DVDRingBuffer::Seek(long long time)
00247 {
00248 dvdnav_status_t dvdRet = DVDNAV_STATUS_OK;
00249
00250 int seekSpeed = 0;
00251 int ffrewSkip = 1;
00252 if (m_parent)
00253 ffrewSkip = m_parent->GetFFRewSkip();
00254
00255 if (ffrewSkip != 1 && ffrewSkip != 0 && time != 0)
00256 {
00257 QMap<uint, uint>::const_iterator it = m_seekSpeedMap.lowerBound(labs(time));
00258 if (it == m_seekSpeedMap.end())
00259 seekSpeed = *(it - 1);
00260 else
00261 seekSpeed = *it;
00262 if (time < 0)
00263 seekSpeed = -seekSpeed;
00264 dvdRet = dvdnav_relative_time_search(m_dvdnav, seekSpeed);
00265 }
00266 else
00267 {
00268 m_seektime = (uint64_t)time;
00269 dvdRet = dvdnav_absolute_time_search(m_dvdnav, m_seektime, 0);
00270 }
00271
00272 LOG(VB_PLAYBACK, LOG_DEBUG,
00273 QString("DVD Playback Seek() time: %1; seekSpeed: %2")
00274 .arg(time).arg(seekSpeed));
00275
00276 if (dvdRet == DVDNAV_STATUS_ERR)
00277 {
00278 LOG(VB_PLAYBACK, LOG_ERR, LOC +
00279 QString("Seek() to time %1 failed").arg(time));
00280 return -1;
00281 }
00282 else if (!m_inMenu)
00283 {
00284 m_gotStop = false;
00285 if (time > 0 && ffrewSkip == 1)
00286 m_seeking = true;
00287 }
00288
00289 return m_currentpos;
00290 }
00291
00292 bool DVDRingBuffer::IsBookmarkAllowed(void)
00293 {
00294 return GetTotalTimeOfTitle() >= 120;
00295 }
00296
00297 void DVDRingBuffer::GetDescForPos(QString &desc)
00298 {
00299 if (m_inMenu)
00300 {
00301 if ((m_part <= DVD_MENU_MAX) && dvdnav_menu_table[m_part] )
00302 {
00303 desc = QString("%1 Menu").arg(dvdnav_menu_table[m_part]);
00304 }
00305 }
00306 else
00307 {
00308 desc = QObject::tr("Title %1 chapter %2").arg(m_title).arg(m_part);
00309 }
00310 }
00311
00312 bool DVDRingBuffer::OpenFile(const QString &lfilename, uint retry_ms)
00313 {
00314 rwlock.lockForWrite();
00315
00316 if (m_dvdnav)
00317 {
00318 rwlock.unlock();
00319 CloseDVD();
00320 rwlock.lockForWrite();
00321 }
00322
00323 safefilename = lfilename;
00324 filename = lfilename;
00325 QByteArray fname = filename.toLocal8Bit();
00326
00327 dvdnav_status_t res = dvdnav_open(&m_dvdnav, fname.constData());
00328 if (res == DVDNAV_STATUS_ERR)
00329 {
00330 LOG(VB_GENERAL, LOG_ERR,
00331 LOC + QString("Failed to open DVD device at %1")
00332 .arg(fname.constData()));
00333 rwlock.unlock();
00334 return false;
00335 }
00336
00337 LOG(VB_GENERAL, LOG_INFO, LOC + QString("Opened DVD device at %1")
00338 .arg(fname.constData()));
00339
00340 dvdnav_set_readahead_flag(m_dvdnav, 0);
00341 dvdnav_set_PGC_positioning_flag(m_dvdnav, 1);
00342
00343 int32_t num_titles = 0;
00344 res = dvdnav_get_number_of_titles(m_dvdnav, &num_titles);
00345 if (num_titles == 0 || res == DVDNAV_STATUS_ERR)
00346 {
00347 char buf[DVD_BLOCK_SIZE * 5];
00348 LOG(VB_GENERAL, LOG_INFO,
00349 LOC + QString("Reading %1 bytes from the drive")
00350 .arg(DVD_BLOCK_SIZE * 5));
00351 safe_read(buf, DVD_BLOCK_SIZE * 5);
00352 res = dvdnav_get_number_of_titles(m_dvdnav, &num_titles);
00353 }
00354
00355 if (res == DVDNAV_STATUS_ERR)
00356 {
00357 LOG(VB_GENERAL, LOG_ERR,
00358 LOC + QString("Failed to get the number of titles on the DVD" ));
00359 }
00360 else
00361 {
00362 LOG(VB_GENERAL, LOG_INFO,
00363 LOC + QString("There are %1 titles on the disk")
00364 .arg(num_titles));
00365 }
00366
00367 dvdnav_title_play(m_dvdnav, 1);
00368
00369
00370
00371 if (dvdnav_get_next_still_flag(m_dvdnav))
00372 {
00373 LOG(VB_GENERAL, LOG_NOTICE,
00374 LOC + "The selected title is a still frame. "
00375 "Playback is likely to fail - please raise a bug report at "
00376 "http://code.mythtv.org/trac");
00377 }
00378
00379 dvdnav_current_title_info(m_dvdnav, &m_title, &m_part);
00380 dvdnav_get_title_string(m_dvdnav, &m_dvdname);
00381 dvdnav_get_serial_string(m_dvdnav, &m_serialnumber);
00382 dvdnav_get_angle_info(m_dvdnav, &m_currentAngle, &m_currentTitleAngleCount);
00383 SetDVDSpeed();
00384
00385
00386 GetChapterTimes(m_title);
00387
00388 LOG(VB_PLAYBACK, LOG_INFO, LOC +
00389 QString("DVD Serial Number %1").arg(m_serialnumber));
00390
00391 readblocksize = DVD_BLOCK_SIZE * 62;
00392 setswitchtonext = false;
00393 ateof = false;
00394 commserror = false;
00395 numfailures = 0;
00396 rawbitrate = 8000;
00397
00398 CalcReadAheadThresh();
00399
00400 rwlock.unlock();
00401
00402 return true;
00403 }
00404
00405 bool DVDRingBuffer::StartFromBeginning(void)
00406 {
00407 LOG(VB_GENERAL, LOG_INFO, LOC + "Resetting DVD device.");
00408
00409
00410
00411 if (m_gotStop)
00412 {
00413 LOG(VB_GENERAL, LOG_ERR, LOC +
00414 "DVD errored after initial scan - trying again");
00415 CloseDVD();
00416 OpenFile(filename);
00417 if (!m_dvdnav)
00418 LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to re-open DVD.");
00419 }
00420
00421 if (m_dvdnav)
00422 {
00423 QMutexLocker lock(&m_seekLock);
00424 dvdnav_first_play(m_dvdnav);
00425 m_audioStreamsChanged = true;
00426 }
00427
00428 return m_dvdnav;
00429 }
00430
00431 void DVDRingBuffer::GetChapterTimes(QList<long long> ×)
00432 {
00433 if (!m_chapterMap.contains(m_title))
00434 GetChapterTimes(m_title);
00435
00436 if (!m_chapterMap.contains(m_title))
00437 return;
00438
00439 foreach (uint64_t chapter, m_chapterMap.value(m_title))
00440 times.push_back(chapter);
00441 }
00442
00443 uint64_t DVDRingBuffer::GetChapterTimes(uint title)
00444 {
00445 if (!m_dvdnav)
00446 return 0;
00447
00448 uint64_t duration;
00449 uint64_t *chaps;
00450 uint32_t num = dvdnav_describe_title_chapters(m_dvdnav, title,
00451 &chaps, &duration);
00452
00453 if (num < 1)
00454 {
00455 LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to retrieve chapter data");
00456 return 0;
00457 }
00458
00459 QList<uint64_t> chapters;
00460
00461 chapters.append(0);
00462
00463 if (num > 1)
00464 {
00465 for (uint i = 0; i < num - 1; i++)
00466 chapters.append((chaps[i] + 45000) / 90000);
00467 }
00468
00469 if (chaps)
00470 free(chaps);
00471 m_chapterMap.insert(title, chapters);
00472 return (duration + 45000) / 90000;
00473 }
00474
00477 long long DVDRingBuffer::GetReadPosition(void) const
00478 {
00479 uint32_t pos = 0;
00480 uint32_t length = 1;
00481 if (m_dvdnav)
00482 {
00483 if (dvdnav_get_position(m_dvdnav, &pos, &length) == DVDNAV_STATUS_ERR)
00484 {
00485
00486 dvdnav_get_position(m_dvdnav, &pos, &length);
00487 }
00488 }
00489 return pos * DVD_BLOCK_SIZE;
00490 }
00491
00492 void DVDRingBuffer::WaitForPlayer(void)
00493 {
00494 if (!m_skipstillorwait)
00495 {
00496 LOG(VB_PLAYBACK, LOG_INFO,
00497 LOC + "Waiting for player's buffers to drain");
00498 m_playerWait = true;
00499 int count = 0;
00500 while (m_playerWait && count++ < 200)
00501 {
00502 rwlock.unlock();
00503 usleep(10000);
00504 rwlock.lockForWrite();
00505 }
00506
00507 if (m_playerWait)
00508 {
00509 LOG(VB_GENERAL, LOG_ERR, LOC + "Player wait state was not cleared");
00510 m_playerWait = false;
00511 }
00512 }
00513 }
00514
00515 int DVDRingBuffer::safe_read(void *data, uint sz)
00516 {
00517 dvdnav_status_t dvdStat;
00518 unsigned char *blockBuf = NULL;
00519 uint tot = 0;
00520 int32_t dvdEvent = 0;
00521 int32_t dvdEventSize = 0;
00522 int needed = sz;
00523 char *dest = (char*) data;
00524 int offset = 0;
00525
00526 if (m_gotStop)
00527 {
00528 LOG(VB_GENERAL, LOG_ERR, LOC + "safe_read: called after DVDNAV_STOP");
00529 errno = EBADF;
00530 return -1;
00531 }
00532
00533 if (readaheadrunning)
00534 LOG(VB_GENERAL, LOG_ERR, LOC + "read ahead thread running.");
00535
00536 while (needed)
00537 {
00538 blockBuf = m_dvdBlockWriteBuf;
00539
00540 dvdStat = dvdnav_get_next_cache_block(
00541 m_dvdnav, &blockBuf, &dvdEvent, &dvdEventSize);
00542
00543 if (dvdStat == DVDNAV_STATUS_ERR)
00544 {
00545 LOG(VB_GENERAL, LOG_ERR, LOC + QString("Failed to read block: %1")
00546 .arg(dvdnav_err_to_string(m_dvdnav)));
00547 errno = EIO;
00548 return -1;
00549 }
00550
00551 switch (dvdEvent)
00552 {
00553
00554 case DVDNAV_BLOCK_OK:
00555 {
00556
00557 if (!m_seeking)
00558 {
00559 memcpy(dest + offset, blockBuf, DVD_BLOCK_SIZE);
00560 tot += DVD_BLOCK_SIZE;
00561 }
00562
00563
00564 if (blockBuf != m_dvdBlockWriteBuf)
00565 dvdnav_free_cache_block(m_dvdnav, blockBuf);
00566
00567
00568 LOG(VB_PLAYBACK|VB_FILE, LOG_DEBUG, LOC + "DVDNAV_BLOCK_OK");
00569 }
00570 break;
00571
00572
00573 case DVDNAV_CELL_CHANGE:
00574 {
00575
00576 dvdnav_cell_change_event_t *cell_event =
00577 (dvdnav_cell_change_event_t*) (blockBuf);
00578
00579
00580 m_inMenu = !dvdnav_is_domain_vts(m_dvdnav);
00581
00582
00583 m_cellChanged = true;
00584 if (m_pgcLength != cell_event->pgc_length)
00585 m_pgcLengthChanged = true;
00586 m_pgLength = cell_event->pg_length;
00587 m_pgcLength = cell_event->pgc_length;
00588 m_cellStart = cell_event->cell_start;
00589 m_pgStart = cell_event->pg_start;
00590
00591
00592 m_lastTitle = m_title;
00593 m_lastPart = m_part;
00594 m_lastStill = m_still;
00595 uint32_t pos;
00596 uint32_t length;
00597 m_still = dvdnav_get_next_still_flag(m_dvdnav);
00598 dvdnav_current_title_info(m_dvdnav, &m_title, &m_part);
00599 dvdnav_get_number_of_parts(m_dvdnav, m_title, &m_titleParts);
00600 dvdnav_get_position(m_dvdnav, &pos, &length);
00601 m_titleLength = length *DVD_BLOCK_SIZE;
00602 if (!m_seeking)
00603 m_cellstartPos = GetReadPosition();
00604
00605
00606 LOG(VB_PLAYBACK, LOG_DEBUG, LOC +
00607 QString("---- DVDNAV_CELL_CHANGE - Cell "
00608 "#%1 Menu %2 Length %3")
00609 .arg(cell_event->cellN).arg(m_inMenu ? "Yes" : "No")
00610 .arg((float)cell_event->cell_length / 90000.0f,0,'f',1));
00611 QString still = m_still ? ((m_still < 0xff) ?
00612 QString("Stillframe: %1 seconds").arg(m_still) :
00613 QString("Infinite stillframe")) :
00614 QString("Length: %1 seconds")
00615 .arg((float)m_pgcLength / 90000.0f, 0, 'f', 1);
00616 if (m_title == 0)
00617 {
00618 LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("Menu #%1 %2")
00619 .arg(m_part).arg(still));
00620 }
00621 else
00622 {
00623 LOG(VB_PLAYBACK, LOG_INFO,
00624 LOC + QString("Title #%1: %2 Part %3 of %4")
00625 .arg(m_title).arg(still).arg(m_part).arg(m_titleParts));
00626 }
00627
00628
00629
00630 if (((m_still != m_lastStill) || (m_title != m_lastTitle)) &&
00631 !((m_title == 0 && m_lastTitle == 0) &&
00632 (m_part == m_lastPart)))
00633 {
00634 WaitForPlayer();
00635 }
00636
00637
00638 if (m_parent)
00639 {
00640 if (m_still && (m_still < 0xff))
00641 m_parent->ResetStillFrameTimer();
00642 else
00643 m_parent->SetStillFrameTimeout(0);
00644 }
00645
00646
00647 m_lastvobid = m_vobid;
00648 m_lastcellid = m_cellid;
00649 m_buttonSelected = false;
00650 m_vobid = m_cellid = 0;
00651 m_cellRepeated = false;
00652
00653 IncrementButtonVersion;
00654 if (m_inMenu)
00655 {
00656 m_autoselectsubtitle = true;
00657 GetMythUI()->RestoreScreensaver();
00658 }
00659 else
00660 GetMythUI()->DisableScreensaver();
00661
00662
00663 if (blockBuf != m_dvdBlockWriteBuf)
00664 dvdnav_free_cache_block(m_dvdnav, blockBuf);
00665 }
00666 break;
00667
00668
00669 case DVDNAV_SPU_CLUT_CHANGE:
00670 {
00671
00672 LOG(VB_PLAYBACK, LOG_DEBUG, LOC + "DVDNAV_SPU_CLUT_CHANGE");
00673
00674
00675 memcpy(m_clut, blockBuf, 16 * sizeof(uint32_t));
00676
00677 if (blockBuf != m_dvdBlockWriteBuf)
00678 dvdnav_free_cache_block(m_dvdnav, blockBuf);
00679 }
00680 break;
00681
00682
00683 case DVDNAV_SPU_STREAM_CHANGE:
00684 {
00685
00686 dvdnav_spu_stream_change_event_t* spu =
00687 (dvdnav_spu_stream_change_event_t*)(blockBuf);
00688
00689
00690 IncrementButtonVersion;
00691
00692
00693 if (m_inMenu || NumMenuButtons() > 0)
00694 {
00695 m_buttonStreamID = 32;
00696 int aspect = dvdnav_get_video_aspect(m_dvdnav);
00697
00698
00699
00700
00701 int physical_wide = (spu->physical_wide & 0xF);
00702
00703 if (aspect != 0 && physical_wide > 0)
00704 m_buttonStreamID += physical_wide;
00705 }
00706
00707
00708 if (m_autoselectsubtitle)
00709 m_curSubtitleTrack = dvdnav_get_active_spu_stream(m_dvdnav);
00710
00711
00712 LOG(VB_PLAYBACK, LOG_DEBUG,
00713 QString(LOC + "DVDNAV_SPU_STREAM_CHANGE: "
00714 "physicalwide %1, physicalletterbox %2, "
00715 "physicalpanscan %3, currenttrack %4")
00716 .arg(spu->physical_wide).arg(spu->physical_letterbox)
00717 .arg(spu->physical_pan_scan).arg(m_curSubtitleTrack));
00718
00719
00720 if (blockBuf != m_dvdBlockWriteBuf)
00721 dvdnav_free_cache_block(m_dvdnav, blockBuf);
00722 }
00723 break;
00724
00725
00726 case DVDNAV_AUDIO_STREAM_CHANGE:
00727 {
00728
00729 int new_track = dvdnav_get_active_audio_stream(m_dvdnav);
00730
00731
00732 LOG(VB_PLAYBACK, LOG_DEBUG, LOC +
00733 QString("DVDNAV_AUDIO_STREAM_CHANGE: old %1 new %2")
00734 .arg(new_track).arg(m_curAudioTrack));
00735
00736
00737 if (new_track != m_curAudioTrack)
00738 {
00739 m_curAudioTrack = new_track;
00740 m_audioStreamsChanged = true;
00741 }
00742
00743
00744 if (blockBuf != m_dvdBlockWriteBuf)
00745 dvdnav_free_cache_block(m_dvdnav, blockBuf);
00746 }
00747 break;
00748
00749
00750 case DVDNAV_NAV_PACKET:
00751 {
00752 QMutexLocker lock(&m_seekLock);
00753
00754
00755 m_lastNav = (dvdnav_t *)blockBuf;
00756
00757
00758 dsi_t *dsi = dvdnav_get_current_nav_dsi(m_dvdnav);
00759
00760
00761
00762 if (m_vobid == 0 && m_cellid == 0)
00763 {
00764 m_vobid = dsi->dsi_gi.vobu_vob_idn;
00765 m_cellid = dsi->dsi_gi.vobu_c_idn;
00766 if ((m_lastvobid == m_vobid) && (m_lastcellid == m_cellid)
00767 && m_inMenu)
00768 {
00769 m_cellRepeated = true;
00770 }
00771 }
00772
00773
00774 m_currentTime = (uint)dvdnav_get_current_time(m_dvdnav);
00775 m_currentpos = GetReadPosition();
00776
00777 if (m_seeking)
00778 {
00779
00780 int relativetime =
00781 (int)((m_seektime - m_currentTime)/ 90000);
00782 if (relativetime <= 1)
00783 {
00784 m_seeking = false;
00785 m_seektime = 0;
00786 }
00787 else
00788 {
00789 dvdnav_relative_time_search(m_dvdnav, relativetime * 2);
00790 }
00791 }
00792
00793
00794 LOG(VB_PLAYBACK, LOG_DEBUG, LOC + "DVDNAV_NAV_PACKET");
00795
00796
00797 if (blockBuf != m_dvdBlockWriteBuf)
00798 dvdnav_free_cache_block(m_dvdnav, blockBuf);
00799 }
00800 break;
00801
00802 case DVDNAV_HOP_CHANNEL:
00803 {
00804
00805 LOG(VB_PLAYBACK, LOG_DEBUG, LOC + "DVDNAV_HOP_CHANNEL");
00806 WaitForPlayer();
00807 }
00808 break;
00809
00810
00811 case DVDNAV_NOP:
00812 break;
00813
00814
00815 case DVDNAV_VTS_CHANGE:
00816 {
00817
00818 dvdnav_vts_change_event_t* vts =
00819 (dvdnav_vts_change_event_t*)(blockBuf);
00820
00821
00822 int aspect = dvdnav_get_video_aspect(m_dvdnav);
00823 if (aspect == 2)
00824 m_forcedAspect = 4.0f / 3.0f;
00825 else if (aspect == 3)
00826 m_forcedAspect = 16.0f / 9.0f;
00827 else
00828 m_forcedAspect = -1;
00829 int permission = dvdnav_get_video_scale_permission(m_dvdnav);
00830
00831
00832 LOG(VB_PLAYBACK, LOG_DEBUG, LOC +
00833 QString("DVDNAV_VTS_CHANGE: old_vtsN %1, new_vtsN %2, "
00834 "aspect %3, perm %4")
00835 .arg(vts->old_vtsN).arg(vts->new_vtsN)
00836 .arg(aspect).arg(permission));
00837
00838
00839 if ((vts->old_vtsN != vts->new_vtsN) ||
00840 (vts->old_domain != vts->new_domain))
00841 {
00842 m_audioStreamsChanged = true;
00843 }
00844
00845
00846 if (blockBuf != m_dvdBlockWriteBuf)
00847 dvdnav_free_cache_block(m_dvdnav, blockBuf);
00848 }
00849 break;
00850
00851
00852 case DVDNAV_HIGHLIGHT:
00853 {
00854
00855 dvdnav_highlight_event_t* hl =
00856 (dvdnav_highlight_event_t*)(blockBuf);
00857
00858
00859 m_menuBtnLock.lock();
00860 DVDButtonUpdate(false);
00861 IncrementButtonVersion;
00862 m_menuBtnLock.unlock();
00863
00864
00865 LOG(VB_PLAYBACK, LOG_DEBUG, LOC +
00866 QString("DVDNAV_HIGHLIGHT: display %1, palette %2, "
00867 "sx %3, sy %4, ex %5, ey %6, pts %7, buttonN %8")
00868 .arg(hl->display).arg(hl->palette)
00869 .arg(hl->sx).arg(hl->sy)
00870 .arg(hl->ex).arg(hl->ey)
00871 .arg(hl->pts).arg(hl->buttonN));
00872
00873
00874 if (blockBuf != m_dvdBlockWriteBuf)
00875 dvdnav_free_cache_block(m_dvdnav, blockBuf);
00876 }
00877 break;
00878
00879
00880 case DVDNAV_STILL_FRAME:
00881 {
00882
00883 dvdnav_still_event_t* still =
00884 (dvdnav_still_event_t*)(blockBuf);
00885
00886
00887 if (!m_still)
00888 LOG(VB_GENERAL, LOG_WARNING, LOC + "DVDNAV_STILL_FRAME in "
00889 "cell that is not marked as a still frame");
00890
00891 if (still->length != m_still)
00892 LOG(VB_GENERAL, LOG_WARNING, LOC + "DVDNAV_STILL_FRAME "
00893 "length does not match cell still length");
00894
00895
00896
00897 rwlock.unlock();
00898 usleep(10000);
00899 rwlock.lockForWrite();
00900
00901
00902
00903 if (m_skipstillorwait)
00904 SkipStillFrame();
00905 else if (m_parent)
00906 {
00907 if ((still->length > 0) && (still->length < 0xff))
00908 m_parent->SetStillFrameTimeout(still->length);
00909 }
00910
00911
00912 LOG(VB_PLAYBACK, LOG_DEBUG, LOC + "DVDNAV_STILL_FRAME");
00913
00914
00915 if (blockBuf != m_dvdBlockWriteBuf)
00916 dvdnav_free_cache_block(m_dvdnav, blockBuf);
00917 }
00918 break;
00919
00920
00921 case DVDNAV_WAIT:
00922 {
00923
00924 LOG(VB_PLAYBACK, LOG_DEBUG, LOC + "DVDNAV_WAIT");
00925
00926
00927 if (m_skipstillorwait)
00928 WaitSkip();
00929 else
00930 {
00931 m_dvdWaiting = true;
00932 rwlock.unlock();
00933 usleep(10000);
00934 rwlock.lockForWrite();
00935 }
00936
00937
00938 if (blockBuf != m_dvdBlockWriteBuf)
00939 dvdnav_free_cache_block(m_dvdnav, blockBuf);
00940 }
00941 break;
00942
00943
00944 case DVDNAV_STOP:
00945 {
00946 LOG(VB_GENERAL, LOG_INFO, LOC + "DVDNAV_STOP");
00947 sz = tot;
00948 m_gotStop = true;
00949
00950
00951 if (blockBuf != m_dvdBlockWriteBuf)
00952 dvdnav_free_cache_block(m_dvdnav, blockBuf);
00953 }
00954 break;
00955
00956
00957 default:
00958 {
00959 LOG(VB_GENERAL, LOG_ERR, LOC +
00960 QString("Unknown DVD event: %1").arg(dvdEvent));
00961 }
00962 break;
00963 }
00964
00965 needed = sz - tot;
00966 offset = tot;
00967 }
00968
00969 return tot;
00970 }
00971
00972 bool DVDRingBuffer::playTrack(int track)
00973 {
00974 QMutexLocker lock(&m_seekLock);
00975 if (track < 1)
00976 Seek(0);
00977 else if (track < m_titleParts)
00978 dvdnav_part_play(m_dvdnav, m_title, track);
00979 else
00980 return false;
00981 m_gotStop = false;
00982 return true;
00983 }
00984
00985 bool DVDRingBuffer::nextTrack(void)
00986 {
00987 int newPart = m_part + 1;
00988
00989 QMutexLocker lock(&m_seekLock);
00990 if (newPart < m_titleParts)
00991 {
00992 dvdnav_part_play(m_dvdnav, m_title, newPart);
00993 m_gotStop = false;
00994 return true;
00995 }
00996 return false;
00997 }
00998
00999 void DVDRingBuffer::prevTrack(void)
01000 {
01001 int newPart = m_part - 1;
01002
01003 QMutexLocker lock(&m_seekLock);
01004 if (newPart > 0)
01005 dvdnav_part_play(m_dvdnav, m_title, newPart);
01006 else
01007 Seek(0);
01008 m_gotStop = false;
01009 }
01010
01014 uint DVDRingBuffer::GetTotalTimeOfTitle(void)
01015 {
01016 return m_pgcLength / 90000;
01017 }
01018
01021 uint DVDRingBuffer::GetCellStart(void)
01022 {
01023 return m_cellStart / 90000;
01024 }
01025
01028 bool DVDRingBuffer::CellChanged(void)
01029 {
01030 bool ret = m_cellChanged;
01031 m_cellChanged = false;
01032 return ret;
01033 }
01034
01037 bool DVDRingBuffer::PGCLengthChanged(void)
01038 {
01039 bool ret = m_pgcLengthChanged;
01040 m_pgcLengthChanged = false;
01041 return ret;
01042 }
01043
01044 void DVDRingBuffer::SkipStillFrame(void)
01045 {
01046 QMutexLocker locker(&m_seekLock);
01047 LOG(VB_PLAYBACK, LOG_INFO, LOC + "Skipping still frame.");
01048 dvdnav_still_skip(m_dvdnav);
01049 }
01050
01051 void DVDRingBuffer::WaitSkip(void)
01052 {
01053 QMutexLocker locker(&m_seekLock);
01054 dvdnav_wait_skip(m_dvdnav);
01055 m_dvdWaiting = false;
01056 LOG(VB_PLAYBACK, LOG_INFO, LOC + "Exiting DVDNAV_WAIT status");
01057 }
01058
01061 bool DVDRingBuffer::GoToMenu(const QString str)
01062 {
01063 DVDMenuID_t menuid;
01064 QMutexLocker locker(&m_seekLock);
01065
01066 LOG(VB_PLAYBACK, LOG_INFO,
01067 LOC + QString("DVDRingBuf: GoToMenu %1").arg(str));
01068
01069 if (str.compare("chapter") == 0)
01070 {
01071 menuid = DVD_MENU_Part;
01072 }
01073 else if (str.compare("root") == 0)
01074 {
01075 menuid = DVD_MENU_Root;
01076 }
01077 else if (str.compare("title") == 0)
01078 menuid = DVD_MENU_Title;
01079 else
01080 return false;
01081
01082 dvdnav_status_t ret = dvdnav_menu_call(m_dvdnav, menuid);
01083 if (ret == DVDNAV_STATUS_OK)
01084 return true;
01085 return false;
01086 }
01087
01088 void DVDRingBuffer::GoToNextProgram(void)
01089 {
01090 QMutexLocker locker(&m_seekLock);
01091
01092
01093
01094 dvdnav_next_pg_search(m_dvdnav);
01095 }
01096
01097 void DVDRingBuffer::GoToPreviousProgram(void)
01098 {
01099 QMutexLocker locker(&m_seekLock);
01100
01101
01102
01103 dvdnav_prev_pg_search(m_dvdnav);
01104 }
01105
01106 bool DVDRingBuffer::HandleAction(const QStringList &actions, int64_t pts)
01107 {
01108 (void)pts;
01109
01110 if (!NumMenuButtons())
01111 return false;
01112
01113 bool handled = true;
01114 if (actions.contains(ACTION_UP) ||
01115 actions.contains(ACTION_CHANNELUP))
01116 {
01117 MoveButtonUp();
01118 }
01119 else if (actions.contains(ACTION_DOWN) ||
01120 actions.contains(ACTION_CHANNELDOWN))
01121 {
01122 MoveButtonDown();
01123 }
01124 else if (actions.contains(ACTION_LEFT) ||
01125 actions.contains(ACTION_SEEKRWND))
01126 {
01127 MoveButtonLeft();
01128 }
01129 else if (actions.contains(ACTION_RIGHT) ||
01130 actions.contains(ACTION_SEEKFFWD))
01131 {
01132 MoveButtonRight();
01133 }
01134 else if (actions.contains(ACTION_SELECT))
01135 {
01136 ActivateButton();
01137 }
01138 else
01139 handled = false;
01140
01141 return handled;
01142 }
01143
01144 void DVDRingBuffer::MoveButtonLeft(void)
01145 {
01146 if (NumMenuButtons() > 1)
01147 {
01148 pci_t *pci = dvdnav_get_current_nav_pci(m_dvdnav);
01149 dvdnav_left_button_select(m_dvdnav, pci);
01150 }
01151 }
01152
01153 void DVDRingBuffer::MoveButtonRight(void)
01154 {
01155 if (NumMenuButtons() > 1)
01156 {
01157 pci_t *pci = dvdnav_get_current_nav_pci(m_dvdnav);
01158 dvdnav_right_button_select(m_dvdnav, pci);
01159 }
01160 }
01161
01162 void DVDRingBuffer::MoveButtonUp(void)
01163 {
01164 if (NumMenuButtons() > 1)
01165 {
01166 pci_t *pci = dvdnav_get_current_nav_pci(m_dvdnav);
01167 dvdnav_upper_button_select(m_dvdnav, pci);
01168 }
01169 }
01170
01171 void DVDRingBuffer::MoveButtonDown(void)
01172 {
01173 if (NumMenuButtons() > 1)
01174 {
01175 pci_t *pci = dvdnav_get_current_nav_pci(m_dvdnav);
01176 dvdnav_lower_button_select(m_dvdnav, pci);
01177 }
01178 }
01179
01182 void DVDRingBuffer::ActivateButton(void)
01183 {
01184 if (NumMenuButtons() > 0)
01185 {
01186 IncrementButtonVersion;
01187 pci_t *pci = dvdnav_get_current_nav_pci(m_dvdnav);
01188 dvdnav_button_activate(m_dvdnav, pci);
01189 }
01190 }
01191
01194 void DVDRingBuffer::GetMenuSPUPkt(uint8_t *buf, int buf_size, int stream_id)
01195 {
01196 if (buf_size < 4)
01197 return;
01198
01199 if (m_buttonStreamID != stream_id)
01200 return;
01201
01202 QMutexLocker lock(&m_menuBtnLock);
01203
01204 ClearMenuSPUParameters();
01205 uint8_t *spu_pkt;
01206 spu_pkt = (uint8_t*)av_malloc(buf_size);
01207 memcpy(spu_pkt, buf, buf_size);
01208 m_menuSpuPkt = spu_pkt;
01209 m_menuBuflength = buf_size;
01210 if (!m_buttonSelected)
01211 {
01212 SelectDefaultButton();
01213 m_buttonSelected = true;
01214 }
01215
01216 if (DVDButtonUpdate(false))
01217 {
01218 int32_t gotbutton;
01219 m_buttonExists = DecodeSubtitles(&m_dvdMenuButton, &gotbutton,
01220 m_menuSpuPkt, m_menuBuflength);
01221 }
01222 }
01223
01227 AVSubtitle *DVDRingBuffer::GetMenuSubtitle(uint &version)
01228 {
01229
01230 m_menuBtnLock.lock();
01231
01232 if ((m_menuBuflength > 4) && m_buttonExists && (NumMenuButtons() > 0))
01233 {
01234 version = m_buttonVersion;
01235 return &(m_dvdMenuButton);
01236 }
01237
01238 return NULL;
01239 }
01240
01241
01242 void DVDRingBuffer::ReleaseMenuButton(void)
01243 {
01244 m_menuBtnLock.unlock();
01245 }
01246
01249 QRect DVDRingBuffer::GetButtonCoords(void)
01250 {
01251 QRect rect(0,0,0,0);
01252 if (!m_buttonExists)
01253 return rect;
01254
01255 rect.setRect(m_hl_button.x(), m_hl_button.y(), m_hl_button.width(),
01256 m_hl_button.height());
01257
01258 return rect;
01259 }
01260
01264 bool DVDRingBuffer::DecodeSubtitles(AVSubtitle *sub, int *gotSubtitles,
01265 const uint8_t *spu_pkt, int buf_size)
01266 {
01267 #define GETBE16(p) (((p)[0] << 8) | (p)[1])
01268
01269 int cmd_pos, pos, cmd, next_cmd_pos, offset1, offset2;
01270 int x1, x2, y1, y2;
01271 uint8_t alpha[4], palette[4];
01272 uint i;
01273 int date;
01274
01275 if (!spu_pkt)
01276 return false;
01277
01278 if (buf_size < 4)
01279 return false;
01280
01281 bool force_subtitle_display = false;
01282 sub->rects = NULL;
01283 sub->num_rects = 0;
01284 sub->start_display_time = 0;
01285 sub->end_display_time = 0;
01286
01287 cmd_pos = GETBE16(spu_pkt + 2);
01288 while ((cmd_pos + 4) < buf_size)
01289 {
01290 offset1 = -1;
01291 offset2 = -1;
01292 date = GETBE16(spu_pkt + cmd_pos);
01293 next_cmd_pos = GETBE16(spu_pkt + cmd_pos + 2);
01294 pos = cmd_pos + 4;
01295 x1 = x2 = y1 = y2 = 0;
01296 while (pos < buf_size)
01297 {
01298 cmd = spu_pkt[pos++];
01299 switch(cmd)
01300 {
01301 case 0x00:
01302 force_subtitle_display = true;
01303 break;
01304 case 0x01:
01305 sub->start_display_time = (date << 10) / 90;
01306 break;
01307 case 0x02:
01308 sub->end_display_time = (date << 10) / 90;
01309 break;
01310 case 0x03:
01311 {
01312 if ((buf_size - pos) < 2)
01313 goto fail;
01314
01315 palette[3] = spu_pkt[pos] >> 4;
01316 palette[2] = spu_pkt[pos] & 0x0f;
01317 palette[1] = spu_pkt[pos + 1] >> 4;
01318 palette[0] = spu_pkt[pos + 1] & 0x0f;
01319 pos +=2;
01320 }
01321 break;
01322 case 0x04:
01323 {
01324 if ((buf_size - pos) < 2)
01325 goto fail;
01326 alpha[3] = spu_pkt[pos] >> 4;
01327 alpha[2] = spu_pkt[pos] & 0x0f;
01328 alpha[1] = spu_pkt[pos + 1] >> 4;
01329 alpha[0] = spu_pkt[pos + 1] & 0x0f;
01330 pos +=2;
01331 }
01332 break;
01333 case 0x05:
01334 {
01335 if ((buf_size - pos) < 6)
01336 goto fail;
01337 x1 = (spu_pkt[pos] << 4) | (spu_pkt[pos + 1] >> 4);
01338 x2 = ((spu_pkt[pos + 1] & 0x0f) << 8) | spu_pkt[pos + 2];
01339 y1 = (spu_pkt[pos + 3] << 4) | (spu_pkt[pos + 4] >> 4);
01340 y2 = ((spu_pkt[pos + 4] & 0x0f) << 8) | spu_pkt[pos + 5];
01341 pos +=6;
01342 }
01343 break;
01344 case 0x06:
01345 {
01346 if ((buf_size - pos) < 4)
01347 goto fail;
01348 offset1 = GETBE16(spu_pkt + pos);
01349 offset2 = GETBE16(spu_pkt + pos + 2);
01350 pos +=4;
01351 }
01352 break;
01353 case 0xff:
01354 default:
01355 goto the_end;
01356 }
01357 }
01358 the_end:
01359 if (offset1 >= 0)
01360 {
01361 int w, h;
01362 uint8_t *bitmap;
01363 w = x2 - x1 + 1;
01364 if (w < 0)
01365 w = 0;
01366 h = y2 - y1 + 1;
01367 if (h < 0)
01368 h = 0;
01369 if (w > 0 && h > 0)
01370 {
01371 if (sub->rects != NULL)
01372 {
01373 for (i = 0; i < sub->num_rects; i++)
01374 {
01375 av_free(sub->rects[i]->pict.data[0]);
01376 av_free(sub->rects[i]->pict.data[1]);
01377 av_freep(&sub->rects[i]);
01378 }
01379 av_freep(&sub->rects);
01380 sub->num_rects = 0;
01381 }
01382
01383 bitmap = (uint8_t*) av_malloc(w * h);
01384 sub->num_rects = (NumMenuButtons() > 0) ? 2 : 1;
01385 sub->rects = (AVSubtitleRect **)
01386 av_mallocz(sizeof(AVSubtitleRect*) * sub->num_rects);
01387 for (i = 0; i < sub->num_rects; i++)
01388 {
01389 sub->rects[i] = (AVSubtitleRect *) av_mallocz(sizeof(AVSubtitleRect));
01390 }
01391 sub->rects[0]->pict.data[1] = (uint8_t*)av_mallocz(4 * 4);
01392 decode_rle(bitmap, w * 2, w, (h + 1) / 2,
01393 spu_pkt, offset1 * 2, buf_size);
01394 decode_rle(bitmap + w, w * 2, w, h / 2,
01395 spu_pkt, offset2 * 2, buf_size);
01396 guess_palette((uint32_t*)sub->rects[0]->pict.data[1], palette, alpha);
01397 sub->rects[0]->pict.data[0] = bitmap;
01398 sub->rects[0]->x = x1;
01399 sub->rects[0]->y = y1;
01400 sub->rects[0]->w = w;
01401 sub->rects[0]->h = h;
01402 sub->rects[0]->type = SUBTITLE_BITMAP;
01403 sub->rects[0]->nb_colors = 4;
01404 sub->rects[0]->pict.linesize[0] = w;
01405 if (NumMenuButtons() > 0)
01406 {
01407 sub->rects[1]->type = SUBTITLE_BITMAP;
01408 sub->rects[1]->pict.data[1] = (uint8_t*)av_malloc(4 *4);
01409 guess_palette((uint32_t*)sub->rects[1]->pict.data[1],
01410 m_button_color, m_button_alpha);
01411 }
01412 else
01413 find_smallest_bounding_rectangle(sub);
01414 *gotSubtitles = 1;
01415 }
01416 }
01417 if (next_cmd_pos == cmd_pos)
01418 break;
01419 cmd_pos = next_cmd_pos;
01420 }
01421 if (sub->num_rects > 0)
01422 {
01423 if (force_subtitle_display)
01424 {
01425 sub->forced = 1;
01426 LOG(VB_PLAYBACK, LOG_INFO, LOC + "Decoded forced subtitle");
01427 }
01428 return true;
01429 }
01430 fail:
01431 return false;
01432 }
01433
01437 bool DVDRingBuffer::DVDButtonUpdate(bool b_mode)
01438 {
01439 if (!m_parent)
01440 return false;
01441
01442 QSize video_disp_dim = m_parent->GetVideoSize();
01443 int videoheight = video_disp_dim.height();
01444 int videowidth = video_disp_dim.width();
01445
01446 int32_t button;
01447 pci_t *pci;
01448 dvdnav_status_t dvdRet;
01449 dvdnav_highlight_area_t hl;
01450 dvdnav_get_current_highlight(m_dvdnav, &button);
01451 pci = dvdnav_get_current_nav_pci(m_dvdnav);
01452 dvdRet = dvdnav_get_highlight_area(pci, button, b_mode, &hl);
01453
01454 if (dvdRet == DVDNAV_STATUS_ERR)
01455 return false;
01456
01457 for (uint i = 0 ; i < 4 ; i++)
01458 {
01459 m_button_alpha[i] = 0xf & (hl.palette >> (4 * i ));
01460 m_button_color[i] = 0xf & (hl.palette >> (16+4 *i ));
01461 }
01462
01463 m_hl_button.setCoords(hl.sx, hl.sy, hl.ex, hl.ey);
01464
01465 if (((hl.sx + hl.sy) > 0) &&
01466 (hl.sx < videowidth && hl.sy < videoheight))
01467 return true;
01468
01469 return false;
01470 }
01471
01474 void DVDRingBuffer::ClearMenuButton(void)
01475 {
01476 if (m_buttonExists || m_dvdMenuButton.rects)
01477 {
01478 for (uint i = 0; i < m_dvdMenuButton.num_rects; i++)
01479 {
01480 AVSubtitleRect* rect = m_dvdMenuButton.rects[i];
01481 av_free(rect->pict.data[0]);
01482 av_free(rect->pict.data[1]);
01483 av_free(rect);
01484 }
01485 av_free(m_dvdMenuButton.rects);
01486 m_dvdMenuButton.rects = NULL;
01487 m_dvdMenuButton.num_rects = 0;
01488 m_buttonExists = false;
01489 }
01490 }
01491
01495 void DVDRingBuffer::ClearMenuSPUParameters(void)
01496 {
01497 if (m_menuBuflength == 0)
01498 return;
01499
01500 LOG(VB_PLAYBACK, LOG_INFO, LOC + "Clearing Menu SPU Packet" );
01501
01502 ClearMenuButton();
01503
01504 av_free(m_menuSpuPkt);
01505 m_menuBuflength = 0;
01506 m_hl_button.setRect(0, 0, 0, 0);
01507 }
01508
01509 int DVDRingBuffer::NumMenuButtons(void) const
01510 {
01511 pci_t *pci = dvdnav_get_current_nav_pci(m_dvdnav);
01512 int numButtons = pci->hli.hl_gi.btn_ns;
01513 if (numButtons > 0 && numButtons < 36)
01514 return numButtons;
01515 else
01516 return 0;
01517 }
01518
01521 uint DVDRingBuffer::GetAudioLanguage(int id)
01522 {
01523 uint16_t lang = dvdnav_audio_stream_to_lang(m_dvdnav, id);
01524 LOG(VB_PLAYBACK, LOG_INFO, LOC +
01525 QString("StreamID: %1; lang: %2").arg(id).arg(lang));
01526 return ConvertLangCode(lang);
01527 }
01528
01532 int DVDRingBuffer::GetAudioTrackNum(uint stream_id)
01533 {
01534 return dvdnav_get_audio_logical_stream(m_dvdnav, stream_id);
01535 }
01536
01537 int DVDRingBuffer::GetAudioTrackType(uint stream_id)
01538 {
01539 AudioTrackType ret = kAudioTypeNormal;
01540 audio_attr_t attributes;
01541 int logicalStreamId = dvdnav_get_audio_logical_stream(m_dvdnav, stream_id);
01542 if (dvdnav_get_audio_attr(m_dvdnav, logicalStreamId, &attributes) >= 1)
01543 {
01544 LOG(VB_AUDIO, LOG_INFO, QString("DVD Audio Track #%1 Language "
01545 "Extension Code - %2")
01546 .arg(stream_id)
01547 .arg(attributes.code_extension));
01548 switch (attributes.code_extension)
01549 {
01550 case 1:
01551 ret = kAudioTypeNormal;
01552 break;
01553 case 2:
01554 ret = kAudioTypeAudioDescription;
01555 break;
01556 case 3: case 4:
01557 ret = kAudioTypeCommentary;
01558 break;
01559 case 0: default:
01560 break;
01561 }
01562 }
01563
01564 return (int)ret;
01565 }
01566
01569 uint DVDRingBuffer::GetSubtitleLanguage(int id)
01570 {
01571 uint16_t lang = dvdnav_spu_stream_to_lang(m_dvdnav, id);
01572 LOG(VB_PLAYBACK, LOG_INFO, LOC +
01573 QString("StreamID: %1; lang: %2").arg(id).arg(lang));
01574 return ConvertLangCode(lang);
01575 }
01576
01579 uint DVDRingBuffer::ConvertLangCode(uint16_t code)
01580 {
01581 if (code == 0)
01582 return 0;
01583
01584 QChar str2[2];
01585 str2[0] = QChar(code >> 8);
01586 str2[1] = QChar(code & 0xff);
01587 QString str3 = iso639_str2_to_str3(QString(str2, 2));
01588
01589 LOG(VB_PLAYBACK, LOG_INFO, LOC +
01590 QString("code: %1; iso639: %2").arg(code).arg(str3));
01591
01592 if (!str3.isEmpty())
01593 return iso639_str3_to_key(str3);
01594 return 0;
01595 }
01596
01600 void DVDRingBuffer::SelectDefaultButton(void)
01601 {
01602 pci_t *pci = dvdnav_get_current_nav_pci(m_dvdnav);
01603 int32_t button = pci->hli.hl_gi.fosl_btnn;
01604 if (button > 0 && !m_cellRepeated)
01605 {
01606 dvdnav_button_select(m_dvdnav,pci,button);
01607 return;
01608 }
01609 dvdnav_get_current_highlight(m_dvdnav,&button);
01610 if (button > 0 && button <= NumMenuButtons())
01611 dvdnav_button_select(m_dvdnav,pci,button);
01612 else
01613 dvdnav_button_select(m_dvdnav,pci,1);
01614 }
01615
01620 void DVDRingBuffer::SetTrack(uint type, int trackNo)
01621 {
01622 if (type == kTrackTypeSubtitle)
01623 {
01624 m_curSubtitleTrack = trackNo;
01625 if (trackNo < 0)
01626 m_autoselectsubtitle = true;
01627 else
01628 m_autoselectsubtitle = false;
01629 }
01630 else if (type == kTrackTypeAudio)
01631 {
01632 m_curAudioTrack = trackNo;
01633 dvdnav_set_active_audio_stream(m_dvdnav, trackNo);
01634 }
01635 }
01636
01642 int DVDRingBuffer::GetTrack(uint type)
01643 {
01644 if (type == kTrackTypeSubtitle)
01645 return m_curSubtitleTrack;
01646 else if (type == kTrackTypeAudio)
01647 return m_curAudioTrack;
01648
01649 return 0;
01650 }
01651
01652 uint8_t DVDRingBuffer::GetNumAudioChannels(int id)
01653 {
01654 unsigned char channels = dvdnav_audio_stream_channels(m_dvdnav, id);
01655 if (channels == 0xff)
01656 return 0;
01657 return (uint8_t)channels;
01658 }
01659
01662 bool DVDRingBuffer::GetNameAndSerialNum(QString& _name, QString& _serial)
01663 {
01664 _name = QString(m_dvdname);
01665 _serial = QString(m_serialnumber);
01666 if (_name.isEmpty() && _serial.isEmpty())
01667 return false;
01668 return true;
01669 }
01670
01676 double DVDRingBuffer::GetFrameRate(void)
01677 {
01678 double dvdfps = 0;
01679 int format = dvdnav_get_video_format(m_dvdnav);
01680
01681 dvdfps = (format == 1)? 25.00 : 29.97;
01682 LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("DVD Frame Rate %1").arg(dvdfps));
01683 return dvdfps;
01684 }
01685
01689 void DVDRingBuffer::SetDVDSpeed(void)
01690 {
01691 QMutexLocker lock(&m_seekLock);
01692 SetDVDSpeed(DVD_DRIVE_SPEED);
01693 }
01694
01697 void DVDRingBuffer::SetDVDSpeed(int speed)
01698 {
01699 if (filename.startsWith("/"))
01700 MediaMonitor::SetCDSpeed(filename.toLocal8Bit().constData(), speed);
01701 }
01702
01705 uint DVDRingBuffer::TitleTimeLeft(void)
01706 {
01707 return (GetTotalTimeOfTitle() - GetCurrentTime());
01708 }
01709
01712 void DVDRingBuffer::guess_palette(uint32_t *rgba_palette,uint8_t *palette,
01713 uint8_t *alpha)
01714 {
01715 int i,r,g,b,y,cr,cb;
01716 uint32_t yuv;
01717
01718 memset(rgba_palette, 0, 16);
01719
01720 for (i=0 ; i < 4 ; i++)
01721 {
01722 yuv = m_clut[palette[i]];
01723 y = ((yuv >> 16) & 0xff);
01724 cr = ((yuv >> 8) & 0xff);
01725 cb = ((yuv >> 0) & 0xff);
01726 r = int(y + 1.4022 * (cr - 128));
01727 b = int(y + 1.7710 * (cb - 128));
01728 g = int(1.7047 * y - (0.1952 * b) - (0.5647 * r)) ;
01729 if (r < 0) r = 0;
01730 if (g < 0) g = 0;
01731 if (b < 0) b = 0;
01732 if (r > 0xff) r = 0xff;
01733 if (g > 0xff) g = 0xff;
01734 if (b > 0xff) b = 0xff;
01735 rgba_palette[i] = ((alpha[i] * 17) << 24) | (r << 16 )| (g << 8) | b;
01736 }
01737 }
01738
01742 int DVDRingBuffer::decode_rle(uint8_t *bitmap, int linesize, int w, int h,
01743 const uint8_t *buf, int nibble_offset, int buf_size)
01744 {
01745 unsigned int v;
01746 int x, y, len, color, nibble_end;
01747 uint8_t *d;
01748
01749 nibble_end = buf_size * 2;
01750 x = 0;
01751 y = 0;
01752 d = bitmap;
01753 for(;;) {
01754 if (nibble_offset >= nibble_end)
01755 return -1;
01756 v = get_nibble(buf, nibble_offset++);
01757 if (v < 0x4) {
01758 v = (v << 4) | get_nibble(buf, nibble_offset++);
01759 if (v < 0x10) {
01760 v = (v << 4) | get_nibble(buf, nibble_offset++);
01761 if (v < 0x040) {
01762 v = (v << 4) | get_nibble(buf, nibble_offset++);
01763 if (v < 4) {
01764 v |= (w - x) << 2;
01765 }
01766 }
01767 }
01768 }
01769 len = v >> 2;
01770 if (len > (w - x))
01771 len = (w - x);
01772 color = v & 0x03;
01773 memset(d + x, color, len);
01774 x += len;
01775 if (x >= w) {
01776 y++;
01777 if (y >= h)
01778 break;
01779 d += linesize;
01780 x = 0;
01781 nibble_offset += (nibble_offset & 1);
01782 }
01783 }
01784 return 0;
01785 }
01786
01789 int DVDRingBuffer::get_nibble(const uint8_t *buf, int nibble_offset)
01790 {
01791 return (buf[nibble_offset >> 1] >> ((1 - (nibble_offset & 1)) << 2)) & 0xf;
01792 }
01793
01798 int DVDRingBuffer::is_transp(const uint8_t *buf, int pitch, int n,
01799 const uint8_t *transp_color)
01800 {
01801 int i;
01802 for (i = 0; i < n; i++)
01803 {
01804 if (!transp_color[*buf])
01805 return 0;
01806 buf += pitch;
01807 }
01808 return 1;
01809 }
01810
01816 int DVDRingBuffer::find_smallest_bounding_rectangle(AVSubtitle *s)
01817 {
01818 uint8_t transp_color[256];
01819 int y1, y2, x1, x2, y, w, h, i;
01820 uint8_t *bitmap;
01821
01822 if (s->num_rects == 0 || s->rects == NULL ||
01823 s->rects[0]->w <= 0 || s->rects[0]->h <= 0)
01824 {
01825 return 0;
01826 }
01827
01828 memset(transp_color, 0, 256);
01829 for (i = 0; i < s->rects[0]->nb_colors * 4; i+=4)
01830 {
01831 if ((s->rects[0]->pict.data[1][i] >> 24) == 0)
01832 transp_color[i] = 1;
01833 }
01834
01835 y1 = 0;
01836 while (y1 < s->rects[0]->h &&
01837 is_transp(s->rects[0]->pict.data[0] + y1 * s->rects[0]->pict.linesize[0],
01838 1, s->rects[0]->w, transp_color))
01839 {
01840 y1++;
01841 }
01842
01843 if (y1 == s->rects[0]->h)
01844 {
01845 av_freep(&s->rects[0]->pict.data[0]);
01846 s->rects[0]->w = s->rects[0]->h = 0;
01847 return 0;
01848 }
01849
01850 y2 = s->rects[0]->h - 1;
01851 while (y2 > 0 &&
01852 is_transp(s->rects[0]->pict.data[0] + y2 * s->rects[0]->pict.linesize[0], 1,
01853 s->rects[0]->w, transp_color))
01854 {
01855 y2--;
01856 }
01857
01858 x1 = 0;
01859 while (x1 < (s->rects[0]->w - 1) &&
01860 is_transp(s->rects[0]->pict.data[0] + x1, s->rects[0]->pict.linesize[0],
01861 s->rects[0]->h, transp_color))
01862 {
01863 x1++;
01864 }
01865
01866 x2 = s->rects[0]->w - 1;
01867 while (x2 > 0 &&
01868 is_transp(s->rects[0]->pict.data[0] + x2, s->rects[0]->pict.linesize[0],
01869 s->rects[0]->h, transp_color))
01870 {
01871 x2--;
01872 }
01873
01874 w = x2 - x1 + 1;
01875 h = y2 - y1 + 1;
01876 bitmap = (uint8_t*) av_malloc(w * h);
01877 if (!bitmap)
01878 return 1;
01879
01880 for(y = 0; y < h; y++)
01881 {
01882 memcpy(bitmap + w * y, s->rects[0]->pict.data[0] + x1 +
01883 (y1 + y) * s->rects[0]->pict.linesize[0], w);
01884 }
01885
01886 av_freep(&s->rects[0]->pict.data[0]);
01887 s->rects[0]->pict.data[0] = bitmap;
01888 s->rects[0]->pict.linesize[0] = w;
01889 s->rects[0]->w = w;
01890 s->rects[0]->h = h;
01891 s->rects[0]->x += x1;
01892 s->rects[0]->y += y1;
01893 return 1;
01894 }
01895
01896 bool DVDRingBuffer::SwitchAngle(uint angle)
01897 {
01898 if (!m_dvdnav)
01899 return false;
01900
01901 LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("Switching to Angle %1...")
01902 .arg(angle));
01903 dvdnav_status_t status = dvdnav_angle_change(m_dvdnav, (int32_t)angle);
01904 if (status == DVDNAV_STATUS_OK)
01905 {
01906 m_currentAngle = angle;
01907 return true;
01908 }
01909 return false;
01910 }
01911
01912 bool DVDRingBuffer::NewSequence(bool new_sequence)
01913 {
01914 bool result = false;
01915 if (new_sequence)
01916 {
01917 LOG(VB_PLAYBACK, LOG_INFO, LOC + "New sequence");
01918 m_newSequence = true;
01919 return result;
01920 }
01921
01922 result = m_newSequence && m_inMenu;
01923 m_newSequence = false;
01924 if (result)
01925 LOG(VB_PLAYBACK, LOG_INFO, LOC + "Asking for still frame");
01926 return result;
01927 }