00001 #include <unistd.h>
00002 #include <stdlib.h>
00003
00004 #include "DVDRingBuffer.h"
00005 #include "mythcontext.h"
00006 #include "mythmediamonitor.h"
00007 #include "iso639.h"
00008
00009 #include "NuppelVideoPlayer.h"
00010 #include "compat.h"
00011
00012 #define LOC QString("DVDRB: ")
00013 #define LOC_ERR QString("DVDRB, Error: ")
00014
00015 static const char *dvdnav_menu_table[] =
00016 {
00017 NULL,
00018 NULL,
00019 "Title",
00020 "Root",
00021 "Subpicture",
00022 "Audio",
00023 "Angle",
00024 "Part",
00025 };
00026
00027 DVDRingBufferPriv::DVDRingBufferPriv()
00028 : dvdnav(NULL), dvdBlockReadBuf(NULL),
00029 dvdFilename(NULL),
00030 dvdBlockRPos(0), dvdBlockWPos(0),
00031 pgLength(0), pgcLength(0),
00032 cellStart(0), cellChanged(false),
00033 pgcLengthChanged(false), pgStart(0),
00034 currentpos(0),
00035 lastNav(NULL), part(0),
00036 title(0), titleParts(0),
00037 gotStop(false),
00038 cellHasStillFrame(false), audioStreamsChanged(false),
00039 dvdWaiting(false),
00040 titleLength(0), hl_button(0, 0, 0, 0),
00041 menuSpuPkt(0),
00042 menuBuflength(0),
00043 skipstillorwait(true),
00044 cellstartPos(0), buttonSelected(false),
00045 buttonExists(false), cellid(0),
00046 lastcellid(0), vobid(0),
00047 lastvobid(0), cellRepeated(false),
00048 buttonstreamid(0), runningCellStart(false),
00049 runSeekCellStart(false),
00050 menupktpts(0), curAudioTrack(0),
00051 curSubtitleTrack(0), autoselectaudio(true),
00052 autoselectsubtitle(true),
00053 jumptotitle(true),
00054 seekpos(0), seekwhence(0),
00055 dvdname(NULL), serialnumber(NULL),
00056 seeking(false), seektime(0),
00057 currentTime(0),
00058 parent(0)
00059 {
00060 memset(&dvdMenuButton, 0, sizeof(AVSubtitle));
00061 memset(dvdBlockWriteBuf, 0, sizeof(char) * DVD_BLOCK_SIZE);
00062 memset(clut, 0, sizeof(uint32_t) * 16);
00063 memset(button_color, 0, sizeof(uint8_t) * 4);
00064 memset(button_alpha, 0, sizeof(uint8_t) * 4);
00065 uint def[8] = { 3, 5, 10, 20, 30, 60, 120, 180 };
00066 uint seekValues[8] = { 1, 2, 4, 8, 10, 15, 20, 60 };
00067
00068 for (uint i = 0; i < 8; i++)
00069 seekSpeedMap.insert(def[i], seekValues[i]);
00070 }
00071
00072 DVDRingBufferPriv::~DVDRingBufferPriv()
00073 {
00074 CloseDVD();
00075 ClearMenuSPUParameters();
00076 }
00077
00078 void DVDRingBufferPriv::CloseDVD(void)
00079 {
00080 if (dvdnav)
00081 {
00082 SetDVDSpeed(-1);
00083 dvdnav_close(dvdnav);
00084 dvdnav = NULL;
00085 }
00086 }
00087
00088 bool DVDRingBufferPriv::IsInMenu(void) const
00089 {
00090 if (dvdnav)
00091 return (!dvdnav_is_domain_vts(dvdnav));
00092 return true;
00093 }
00094
00095 long long DVDRingBufferPriv::NormalSeek(long long time)
00096 {
00097 QMutexLocker lock(&seekLock);
00098 return Seek(time);
00099 }
00100
00101 long long DVDRingBufferPriv::Seek(long long time)
00102 {
00103 dvdnav_status_t dvdRet = DVDNAV_STATUS_OK;
00104
00105 uint searchToCellStart = 1;
00106 int seekSpeed = 0;
00107 int ffrewSkip = 1;
00108 if (parent)
00109 ffrewSkip = parent->GetFFRewSkip();
00110
00111 if (ffrewSkip != 1 && time != 0)
00112 {
00113 QMapConstIterator<uint, uint> it = seekSpeedMap.find(labs(time));
00114 seekSpeed = it.data();
00115 if (time < 0)
00116 seekSpeed = -seekSpeed;
00117 dvdRet = dvdnav_time_search_within_cell(this->dvdnav, seekSpeed);
00118 }
00119 else
00120 {
00121 seektime = (uint64_t)time;
00122 dvdRet = dvdnav_time_search(this->dvdnav, seektime, searchToCellStart);
00123 }
00124
00125 if (dvdRet == DVDNAV_STATUS_ERR)
00126 {
00127 VERBOSE(VB_PLAYBACK, LOC_ERR +
00128 QString("Seek() to time %1 failed").arg(time));
00129 return -1;
00130 }
00131 else if (!IsInMenu() && !runningCellStart)
00132 {
00133 gotStop = false;
00134 if (time > 0 && ffrewSkip == 1)
00135 seeking = true;
00136 }
00137
00138 return currentpos;
00139 }
00140
00141 void DVDRingBufferPriv::GetDescForPos(QString &desc) const
00142 {
00143 if (IsInMenu())
00144 {
00145 if ((part <= DVD_MENU_MAX) && dvdnav_menu_table[part] )
00146 {
00147 desc = QString("%1 Menu").arg(dvdnav_menu_table[part]);
00148 }
00149 }
00150 else
00151 {
00152 desc = QObject::tr("Title %1 chapter %2").arg(title).arg(part);
00153 }
00154 }
00155
00156 bool DVDRingBufferPriv::OpenFile(const QString &filename)
00157 {
00158 dvdFilename = filename.ascii();
00159 dvdnav_status_t dvdRet = dvdnav_open(&dvdnav, filename.local8Bit());
00160 if (dvdRet == DVDNAV_STATUS_ERR)
00161 {
00162 VERBOSE(VB_IMPORTANT, QString("Failed to open DVD device at %1")
00163 .arg(filename.local8Bit()));
00164 return false;
00165 }
00166 else
00167 {
00168 VERBOSE(VB_IMPORTANT, QString("Opened DVD device at %1")
00169 .arg(filename.local8Bit()));
00170 dvdnav_set_readahead_flag(dvdnav, 1);
00171 dvdnav_set_PGC_positioning_flag(dvdnav, 1);
00172
00173 int32_t numTitles = 0;
00174 titleParts = 0;
00175 dvdnav_title_play(dvdnav, 0);
00176 dvdRet = dvdnav_get_number_of_titles(dvdnav, &numTitles);
00177 if (numTitles == 0 )
00178 {
00179 char buf[DVD_BLOCK_SIZE * 5];
00180 VERBOSE(VB_IMPORTANT, QString("Reading %1 bytes from the drive")
00181 .arg(DVD_BLOCK_SIZE * 5));
00182 safe_read(buf, DVD_BLOCK_SIZE * 5);
00183 dvdRet = dvdnav_get_number_of_titles(dvdnav, &numTitles);
00184 }
00185
00186 if ( dvdRet == DVDNAV_STATUS_ERR)
00187 {
00188 VERBOSE(VB_IMPORTANT,
00189 QString("Failed to get the number of titles on the DVD" ));
00190 }
00191 else
00192 {
00193 VERBOSE(VB_IMPORTANT, QString("There are %1 titles on the disk")
00194 .arg(numTitles));
00195
00196 for( int curTitle = 0; curTitle < numTitles; curTitle++)
00197 {
00198 dvdnav_get_number_of_parts(dvdnav, curTitle, &titleParts);
00199 VERBOSE(VB_IMPORTANT,
00200 QString("Title %1 has %2 parts.")
00201 .arg(curTitle).arg(titleParts));
00202 }
00203 }
00204
00205 const char *name;
00206 const char *serialnum;
00207 dvdnav_current_title_info(dvdnav, &title, &part);
00208 dvdnav_get_title_string(dvdnav, &name);
00209 dvdnav_get_serial_number(dvdnav, &serialnum);
00210 dvdname = QString(name);
00211 serialnumber = QString(serialnum);
00212 SetDVDSpeed();
00213 return true;
00214 }
00215 }
00216
00219 long long DVDRingBufferPriv::GetReadPosition(void)
00220 {
00221 uint32_t pos = 0;
00222 uint32_t length = 1;
00223 if (dvdnav)
00224 {
00225 if (dvdnav_get_position(dvdnav, &pos, &length) == DVDNAV_STATUS_ERR)
00226 {
00227
00228 dvdnav_get_position(dvdnav, &pos, &length);
00229 }
00230 }
00231 return pos * DVD_BLOCK_SIZE;
00232 }
00233
00234 int DVDRingBufferPriv::safe_read(void *data, unsigned sz)
00235 {
00236 dvdnav_status_t dvdStat;
00237 unsigned char *blockBuf = NULL;
00238 uint tot = 0;
00239 int32_t dvdEvent = 0;
00240 int32_t dvdEventSize = 0;
00241 int needed = sz;
00242 char *dest = (char*) data;
00243 int offset = 0;
00244
00245 if (gotStop)
00246 {
00247 VERBOSE(VB_IMPORTANT, LOC + "safe_read: called after DVDNAV_STOP");
00248 return -1;
00249 }
00250
00251 while (needed)
00252 {
00253 blockBuf = dvdBlockWriteBuf;
00254
00255 dvdStat = dvdnav_get_next_cache_block(
00256 dvdnav, &blockBuf, &dvdEvent, &dvdEventSize);
00257
00258 if (dvdStat == DVDNAV_STATUS_ERR)
00259 {
00260 VERBOSE(VB_IMPORTANT, QString("Error reading block from DVD: %1")
00261 .arg(dvdnav_err_to_string(dvdnav)));
00262 return -1;
00263 }
00264
00265 switch (dvdEvent)
00266 {
00267 case DVDNAV_BLOCK_OK:
00268 if (!seeking)
00269 {
00270 memcpy(dest + offset, blockBuf, DVD_BLOCK_SIZE);
00271 tot += DVD_BLOCK_SIZE;
00272 }
00273
00274 if (blockBuf != dvdBlockWriteBuf)
00275 {
00276 dvdnav_free_cache_block(dvdnav, blockBuf);
00277 }
00278
00279 break;
00280 case DVDNAV_CELL_CHANGE:
00281 {
00282 dvdnav_cell_change_event_t *cell_event =
00283 (dvdnav_cell_change_event_t*) (blockBuf);
00284 pgLength = cell_event->pg_length;
00285 if (pgcLength != cell_event->pgc_length)
00286 pgcLengthChanged = true;
00287 pgcLength = cell_event->pgc_length;
00288 cellStart = cell_event->cell_start;
00289 pgStart = cell_event->pg_start;
00290 cellChanged = true;
00291
00292 if (dvdnav_get_next_still_flag(dvdnav) > 0)
00293 {
00294 if (dvdnav_get_next_still_flag(dvdnav) < 0xff)
00295 stillFrameTimer.restart();
00296 }
00297
00298 part = 0;
00299 titleParts = 0;
00300 uint32_t pos;
00301 uint32_t length;
00302
00303 dvdnav_current_title_info(dvdnav, &title, &part);
00304 dvdnav_get_number_of_parts(dvdnav, title, &titleParts);
00305 dvdnav_get_position(dvdnav, &pos, &length);
00306 titleLength = length *DVD_BLOCK_SIZE;
00307 if (!seeking)
00308 cellstartPos = GetReadPosition();
00309
00310 VERBOSE(VB_PLAYBACK,
00311 QString("DVDNAV_CELL_CHANGE: "
00312 "pg_length == %1, pgc_length == %2, "
00313 "cell_start == %3, pg_start == %4, "
00314 "title == %5, part == %6 titleParts %7")
00315 .arg(pgLength).arg(pgcLength)
00316 .arg(cellStart).arg(pgStart)
00317 .arg(title).arg(part).arg(titleParts));
00318
00319 buttonSelected = false;
00320 if (runningCellStart)
00321 {
00322 lastvobid = lastcellid = 0;
00323 runningCellStart = false;
00324 }
00325 else
00326 {
00327 lastvobid = vobid;
00328 lastcellid = cellid;
00329 }
00330
00331 vobid = 0;
00332 cellid = 0;
00333 cellRepeated = false;
00334 menupktpts = 0;
00335 if (cellHasStillFrame)
00336 {
00337 gContext->DisableScreensaver();
00338 VERBOSE(VB_PLAYBACK, LOC + "Leaving DVDNAV_STILL_FRAME");
00339 }
00340 cellHasStillFrame = false;
00341
00342 if (parent && IsInMenu())
00343 {
00344 parent->HideDVDButton(true);
00345 autoselectaudio = true;
00346 autoselectsubtitle = true;
00347 }
00348
00349 if (blockBuf != dvdBlockWriteBuf)
00350 {
00351 dvdnav_free_cache_block(dvdnav, blockBuf);
00352 }
00353 }
00354 break;
00355 case DVDNAV_SPU_CLUT_CHANGE:
00356 {
00357 memcpy(clut, blockBuf, 16 * sizeof(uint32_t));
00358 VERBOSE(VB_PLAYBACK, "DVDNAV_SPU_CLUT_CHANGE happened.");
00359 }
00360 break;
00361 case DVDNAV_SPU_STREAM_CHANGE:
00362 {
00363 dvdnav_spu_stream_change_event_t* spu =
00364 (dvdnav_spu_stream_change_event_t*)(blockBuf);
00365
00366 subTrackMap.clear();
00367 uint count = dvdnav_subp_get_stream_count(dvdnav);
00368
00369
00370 if (parent)
00371 parent->HideDVDButton(true);
00372
00373 ClearSubtitlesOSD();
00374
00375 if (IsInMenu())
00376 {
00377 buttonstreamid = 32;
00378 int aspect = dvdnav_get_video_aspect(dvdnav);
00379 if (aspect != 0 && spu->physical_wide > 0)
00380 buttonstreamid += spu->physical_wide;
00381
00382 if (parent && parent->GetCaptionMode())
00383 parent->SetCaptionsEnabled(false, false);
00384 }
00385 else
00386 {
00387 int8_t id = 0;
00388
00389 for (uint i = 0; i < count; i++)
00390 {
00391 id = dvdnav_get_spu_logical_stream(dvdnav, i);
00392 if (id == -1)
00393 continue;
00394 id = 32 + id;
00395 subTrackMap.insert(id, i);
00396 }
00397 }
00398
00399 if (autoselectsubtitle)
00400 curSubtitleTrack = dvdnav_get_active_spu_stream(dvdnav);
00401
00402 VERBOSE(VB_PLAYBACK,
00403 QString("DVDNAV_SPU_STREAM_CHANGE: "
00404 "physical_wide==%1, physical_letterbox==%2, "
00405 "physical_pan_scan==%3, current_track==%4, "
00406 "total count %5")
00407 .arg(spu->physical_wide).arg(spu->physical_letterbox)
00408 .arg(spu->physical_pan_scan).arg(curSubtitleTrack)
00409 .arg(count));
00410
00411 if (blockBuf != dvdBlockWriteBuf)
00412 {
00413 dvdnav_free_cache_block(dvdnav, blockBuf);
00414 }
00415 }
00416 break;
00417 case DVDNAV_AUDIO_STREAM_CHANGE:
00418 {
00419 if (autoselectaudio)
00420 curAudioTrack = dvdnav_get_active_audio_stream(dvdnav);
00421
00422 audioTrackMap.clear();
00423 uint count = dvdnav_audio_get_stream_count(dvdnav);
00424 uint ac3StreamId = 128;
00425 uint mp2StreamId = 448;
00426 uint lpcmStreamId = 160;
00427 uint dtsStreamId = 136;
00428
00429 VERBOSE(VB_PLAYBACK,
00430 QString("DVDNAV_AUDIO_STREAM_CHANGE: "
00431 "Current Active Stream %1 Track Count %2")
00432 .arg(curAudioTrack).arg(count));
00433
00434 int8_t audio_format, id;
00435 for (uint i = 0; i < count; i++)
00436 {
00437 audio_format = dvdnav_audio_get_format(dvdnav, i);
00438 id = dvdnav_get_audio_logical_stream(dvdnav, i);
00439 if (id == -1)
00440 continue;
00441 switch (audio_format)
00442 {
00443 case 0:
00444 audioTrackMap.insert(ac3StreamId + id, i);
00445 break;
00446 case 2:
00447 audioTrackMap.insert(mp2StreamId + id, i);
00448 break;
00449 case 4:
00450 audioTrackMap.insert(lpcmStreamId + id, i);
00451 break;
00452 case 6:
00453 audioTrackMap.insert(dtsStreamId + id, i);
00454 break;
00455 default:
00456 VERBOSE(VB_PLAYBACK, LOC_ERR +
00457 QString("AUDIO_STREAM_CHANGE: "
00458 "Unhandled audio format %1")
00459 .arg(i));
00460 break;
00461 }
00462 }
00463
00464 audioStreamsChanged = true;
00465
00466 if (blockBuf != dvdBlockWriteBuf)
00467 {
00468 dvdnav_free_cache_block(dvdnav, blockBuf);
00469 }
00470 }
00471 break;
00472 case DVDNAV_NAV_PACKET:
00473 {
00474 QMutexLocker lock(&seekLock);
00475 lastNav = (dvdnav_t *)blockBuf;
00476 dsi_t *dsi = dvdnav_get_current_nav_dsi(dvdnav);
00477 if (vobid == 0 && cellid == 0)
00478 {
00479 vobid = dsi->dsi_gi.vobu_vob_idn;
00480 cellid = dsi->dsi_gi.vobu_c_idn;
00481 if ((lastvobid == vobid) && (lastcellid == cellid)
00482 && IsInMenu())
00483 {
00484 cellRepeated = true;
00485 }
00486 }
00487
00488 dvd_time_t timeFromCellStart = dsi->dsi_gi.c_eltm;
00489 currentTime = cellStart +
00490 (uint)(dvdnav_convert_time(&timeFromCellStart));
00491 currentpos = GetReadPosition();
00492
00493 if (seeking)
00494 {
00495
00496 int relativetime = (int)((seektime - currentTime)/ 90000);
00497 if (relativetime <= 1)
00498 {
00499 seeking = false;
00500 seektime = 0;
00501 }
00502 else
00503 dvdnav_time_search_within_cell(dvdnav, relativetime * 2);
00504 }
00505
00506 if (blockBuf != dvdBlockWriteBuf)
00507 {
00508 dvdnav_free_cache_block(dvdnav, blockBuf);
00509 }
00510 }
00511 break;
00512 case DVDNAV_HOP_CHANNEL:
00513 VERBOSE(VB_PLAYBACK, "DVDNAV_HOP_CHANNEL happened.");
00514 break;
00515 case DVDNAV_NOP:
00516 break;
00517 case DVDNAV_VTS_CHANGE:
00518 {
00519 dvdnav_vts_change_event_t* vts =
00520 (dvdnav_vts_change_event_t*)(blockBuf);
00521
00522 int aspect = dvdnav_get_video_aspect(dvdnav);
00523 int permission = dvdnav_get_video_scale_permission(dvdnav);
00524
00525 VERBOSE(VB_PLAYBACK, QString("DVDNAV_VTS_CHANGE: "
00526 "old_vtsN==%1, new_vtsN==%2, "
00527 "aspect: %3, perm: %4")
00528 .arg(vts->old_vtsN).arg(vts->new_vtsN)
00529 .arg(aspect).arg(permission));
00530
00531 if (parent)
00532 parent->SetForcedAspectRatio(aspect, permission);
00533
00534 if (blockBuf != dvdBlockWriteBuf)
00535 {
00536 dvdnav_free_cache_block(dvdnav, blockBuf);
00537 }
00538 }
00539 break;
00540 case DVDNAV_HIGHLIGHT:
00541 {
00542 dvdnav_highlight_event_t* hl =
00543 (dvdnav_highlight_event_t*)(blockBuf);
00544 VERBOSE(VB_PLAYBACK, QString(
00545 "DVDNAV_HIGHLIGHT: "
00546 "display==%1, palette==%2, "
00547 "sx==%3, sy==%4, ex==%5, ey==%6, "
00548 "pts==%7, buttonN==%8")
00549 .arg(hl->display).arg(hl->palette)
00550 .arg(hl->sx).arg(hl->sy)
00551 .arg(hl->ex).arg(hl->ey)
00552 .arg(hl->pts).arg(hl->buttonN));
00553
00554 menuBtnLock.lock();
00555
00556 DVDButtonUpdate(false);
00557 ClearSubtitlesOSD();
00558
00559 menuBtnLock.unlock();
00560
00561 if (parent && buttonExists)
00562 parent->HideDVDButton(false);
00563
00564 if (blockBuf != dvdBlockWriteBuf)
00565 {
00566 dvdnav_free_cache_block(dvdnav, blockBuf);
00567 }
00568 }
00569 break;
00570 case DVDNAV_STILL_FRAME:
00571 {
00572 if (!cellHasStillFrame)
00573 VERBOSE(VB_PLAYBACK, LOC + "Entering DVDNAV_STILL_FRAME");
00574 cellHasStillFrame = true;
00575 dvdnav_still_event_t* still =
00576 (dvdnav_still_event_t*)(blockBuf);
00577 usleep(10000);
00578 if (skipstillorwait)
00579 SkipStillFrame();
00580 else
00581 {
00582 int elapsedTime = 0;
00583 if (still->length < 0xff)
00584 {
00585 elapsedTime = stillFrameTimer.elapsed() / 1000;
00586 if (elapsedTime >= still->length)
00587 SkipStillFrame();
00588 }
00589 }
00590 if (blockBuf != dvdBlockWriteBuf)
00591 {
00592 dvdnav_free_cache_block(dvdnav, blockBuf);
00593 }
00594 }
00595 break;
00596 case DVDNAV_WAIT:
00597 {
00598 if (!dvdWaiting)
00599 VERBOSE(VB_PLAYBACK, LOC + "Entering DVDNAV_WAIT");
00600
00601 if (skipstillorwait)
00602 WaitSkip();
00603 else
00604 {
00605 dvdWaiting = true;
00606 usleep(10000);
00607 }
00608 }
00609 break;
00610 case DVDNAV_STOP:
00611 {
00612 VERBOSE(VB_GENERAL, "DVDNAV_STOP");
00613 sz = tot;
00614 gotStop = true;
00615 }
00616 break;
00617 default:
00618 VERBOSE(VB_IMPORTANT, "Got DVD event "<<dvdEvent);
00619 break;
00620 }
00621
00622 needed = sz - tot;
00623 offset = tot;
00624 }
00625
00626 return tot;
00627 }
00628
00629 bool DVDRingBufferPriv::nextTrack(void)
00630 {
00631 int newPart = part + 1;
00632
00633 QMutexLocker lock(&seekLock);
00634 if (newPart < titleParts)
00635 {
00636 dvdnav_part_play(dvdnav, title, newPart);
00637 gotStop = false;
00638 return true;
00639 }
00640 return false;
00641 }
00642
00643 void DVDRingBufferPriv::prevTrack(void)
00644 {
00645 int newPart = part - 1;
00646
00647 QMutexLocker lock(&seekLock);
00648 if (newPart > 0)
00649 dvdnav_part_play(dvdnav, title, newPart);
00650 else
00651 Seek(0);
00652 gotStop = false;
00653 }
00654
00658 uint DVDRingBufferPriv::GetTotalTimeOfTitle(void)
00659 {
00660 return pgcLength / 90000;
00661 }
00662
00665 uint DVDRingBufferPriv::GetCellStart(void)
00666 {
00667 return cellStart / 90000;
00668 }
00669
00672 bool DVDRingBufferPriv::CellChanged(void)
00673 {
00674 bool ret = cellChanged;
00675 cellChanged = false;
00676 return ret;
00677 }
00678
00681 bool DVDRingBufferPriv::PGCLengthChanged(void)
00682 {
00683 bool ret = pgcLengthChanged;
00684 pgcLengthChanged = false;
00685 return ret;
00686 }
00687
00688 void DVDRingBufferPriv::SkipStillFrame(void)
00689 {
00690 QMutexLocker locker(&seekLock);
00691 dvdnav_still_skip(dvdnav);
00692 }
00693
00694 void DVDRingBufferPriv::WaitSkip(void)
00695 {
00696 QMutexLocker locker(&seekLock);
00697 dvdnav_wait_skip(dvdnav);
00698 dvdWaiting = false;
00699 VERBOSE(VB_PLAYBACK, LOC + "Exiting DVDNAV_WAIT status");
00700 }
00701
00704 bool DVDRingBufferPriv::GoToMenu(const QString str)
00705 {
00706 DVDMenuID_t menuid;
00707 QMutexLocker locker(&seekLock);
00708 if (str.compare("chapter") == 0)
00709 {
00710 dvdnav_status_t partMenuSupported =
00711 dvdnav_menu_supported(dvdnav, DVD_MENU_Part);
00712 if (partMenuSupported == DVDNAV_STATUS_OK)
00713 menuid = DVD_MENU_Part;
00714 else
00715 return false;
00716 }
00717 else if (str.compare("menu") == 0)
00718 {
00719 dvdnav_status_t rootMenuSupported =
00720 dvdnav_menu_supported(dvdnav, DVD_MENU_Root);
00721 dvdnav_status_t titleMenuSupported =
00722 dvdnav_menu_supported(dvdnav, DVD_MENU_Title);
00723 if (rootMenuSupported == DVDNAV_STATUS_OK)
00724 menuid = DVD_MENU_Root;
00725 else if (titleMenuSupported == DVDNAV_STATUS_OK)
00726 menuid = DVD_MENU_Title;
00727 else
00728 return false;
00729 }
00730 else
00731 return false;
00732
00733 dvdnav_status_t ret = dvdnav_menu_call(dvdnav, menuid);
00734 if (ret == DVDNAV_STATUS_OK)
00735 return true;
00736 return false;
00737 }
00738
00739 void DVDRingBufferPriv::GoToNextProgram(void)
00740 {
00741 QMutexLocker locker(&seekLock);
00742
00743
00744 dvdnav_next_pg_search(dvdnav);
00745 }
00746
00747 void DVDRingBufferPriv::GoToPreviousProgram(void)
00748 {
00749 QMutexLocker locker(&seekLock);
00750 if (!dvdnav_is_domain_vts(dvdnav))
00751 dvdnav_prev_pg_search(dvdnav);
00752 }
00753
00754 void DVDRingBufferPriv::MoveButtonLeft(void)
00755 {
00756 if (NumMenuButtons() > 1)
00757 {
00758 pci_t *pci = dvdnav_get_current_nav_pci(dvdnav);
00759 dvdnav_left_button_select(dvdnav, pci);
00760 }
00761 }
00762
00763 void DVDRingBufferPriv::MoveButtonRight(void)
00764 {
00765 if (NumMenuButtons() > 1)
00766 {
00767 pci_t *pci = dvdnav_get_current_nav_pci(dvdnav);
00768 dvdnav_right_button_select(dvdnav, pci);
00769 }
00770 }
00771
00772 void DVDRingBufferPriv::MoveButtonUp(void)
00773 {
00774 if (NumMenuButtons() > 1)
00775 {
00776 pci_t *pci = dvdnav_get_current_nav_pci(dvdnav);
00777 dvdnav_upper_button_select(dvdnav, pci);
00778 }
00779 }
00780
00781 void DVDRingBufferPriv::MoveButtonDown(void)
00782 {
00783 if (NumMenuButtons() > 1)
00784 {
00785 pci_t *pci = dvdnav_get_current_nav_pci(dvdnav);
00786 dvdnav_lower_button_select(dvdnav, pci);
00787 }
00788 }
00789
00792 void DVDRingBufferPriv::ActivateButton(void)
00793 {
00794 if (NumMenuButtons() > 0)
00795 {
00796 pci_t *pci = dvdnav_get_current_nav_pci(dvdnav);
00797 dvdnav_button_activate(dvdnav, pci);
00798 }
00799 }
00800
00803 void DVDRingBufferPriv::GetMenuSPUPkt(uint8_t *buf, int buf_size, int stream_id)
00804 {
00805 if (buf_size < 4)
00806 return;
00807
00808 if (buttonstreamid != stream_id)
00809 return;
00810
00811 QMutexLocker lock(&menuBtnLock);
00812
00813 ClearMenuSPUParameters();
00814 uint8_t *spu_pkt;
00815 spu_pkt = (uint8_t*)av_malloc(buf_size);
00816 memcpy(spu_pkt, buf, buf_size);
00817 menuSpuPkt = spu_pkt;
00818 menuBuflength = buf_size;
00819 if (!buttonSelected)
00820 {
00821 SelectDefaultButton();
00822 buttonSelected = true;
00823 }
00824
00825 if (DVDButtonUpdate(false))
00826 {
00827 int32_t gotbutton;
00828 buttonExists = DecodeSubtitles(&dvdMenuButton, &gotbutton,
00829 menuSpuPkt, menuBuflength);
00830 }
00831 }
00832
00836 AVSubtitle *DVDRingBufferPriv::GetMenuSubtitle(void)
00837 {
00838 menuBtnLock.lock();
00839
00840 if ((menuBuflength > 4) && buttonExists &&
00841 (dvdMenuButton.rects[0].h >= hl_button.height()) &&
00842 (dvdMenuButton.rects[0].w >= hl_button.width()))
00843 {
00844 return &(dvdMenuButton);
00845 }
00846
00847 return NULL;
00848 }
00849
00850
00851 void DVDRingBufferPriv::ReleaseMenuButton(void)
00852 {
00853 menuBtnLock.unlock();
00854 }
00855
00858 QRect DVDRingBufferPriv::GetButtonCoords(void)
00859 {
00860 QRect rect(0,0,0,0);
00861 if (!buttonExists)
00862 return rect;
00863
00864 int x1, y1;
00865 int x = 0; int y = 0;
00866 x1 = dvdMenuButton.rects[0].x;
00867 y1 = dvdMenuButton.rects[0].y;
00868 if (hl_button.x() > x1)
00869 x = hl_button.x() - x1;
00870 if (hl_button.y() > y1)
00871 y = hl_button.y() - y1;
00872 rect.setRect(x, y, hl_button.width(), hl_button.height());
00873
00874 return rect;
00875 }
00876
00880 bool DVDRingBufferPriv::DecodeSubtitles(AVSubtitle *sub, int *gotSubtitles,
00881 const uint8_t *spu_pkt, int buf_size)
00882 {
00883 #define GETBE16(p) (((p)[0] << 8) | (p)[1])
00884
00885 int cmd_pos, pos, cmd, next_cmd_pos, offset1, offset2;
00886 int x1, x2, y1, y2;
00887 uint8_t alpha[4], palette[4];
00888 uint i;
00889 int date;
00890
00891 if (!spu_pkt)
00892 return false;
00893
00894 if (buf_size < 4)
00895 return false;
00896
00897 bool force_subtitle_display = false;
00898 sub->rects = NULL;
00899 sub->num_rects = 0;
00900 sub->start_display_time = 0;
00901 sub->end_display_time = 0;
00902
00903 cmd_pos = GETBE16(spu_pkt + 2);
00904 while ((cmd_pos + 4) < buf_size)
00905 {
00906 offset1 = -1;
00907 offset2 = -1;
00908 date = GETBE16(spu_pkt + cmd_pos);
00909 next_cmd_pos = GETBE16(spu_pkt + cmd_pos + 2);
00910 pos = cmd_pos + 4;
00911 x1 = x2 = y1 = y2 = 0;
00912 while (pos < buf_size)
00913 {
00914 cmd = spu_pkt[pos++];
00915 switch(cmd)
00916 {
00917 case 0x00:
00918 force_subtitle_display = true;
00919 break;
00920 case 0x01:
00921 sub->start_display_time = (date << 10) / 90;
00922 break;
00923 case 0x02:
00924 sub->end_display_time = (date << 10) / 90;
00925 break;
00926 case 0x03:
00927 {
00928 if ((buf_size - pos) < 2)
00929 goto fail;
00930
00931 palette[3] = spu_pkt[pos] >> 4;
00932 palette[2] = spu_pkt[pos] & 0x0f;
00933 palette[1] = spu_pkt[pos + 1] >> 4;
00934 palette[0] = spu_pkt[pos + 1] & 0x0f;
00935 pos +=2;
00936 }
00937 break;
00938 case 0x04:
00939 {
00940 if ((buf_size - pos) < 2)
00941 goto fail;
00942 alpha[3] = spu_pkt[pos] >> 4;
00943 alpha[2] = spu_pkt[pos] & 0x0f;
00944 alpha[1] = spu_pkt[pos + 1] >> 4;
00945 alpha[0] = spu_pkt[pos + 1] & 0x0f;
00946 pos +=2;
00947 }
00948 break;
00949 case 0x05:
00950 {
00951 if ((buf_size - pos) < 6)
00952 goto fail;
00953 x1 = (spu_pkt[pos] << 4) | (spu_pkt[pos + 1] >> 4);
00954 x2 = ((spu_pkt[pos + 1] & 0x0f) << 8) | spu_pkt[pos + 2];
00955 y1 = (spu_pkt[pos + 3] << 4) | (spu_pkt[pos + 4] >> 4);
00956 y2 = ((spu_pkt[pos + 4] & 0x0f) << 8) | spu_pkt[pos + 5];
00957 pos +=6;
00958 }
00959 break;
00960 case 0x06:
00961 {
00962 if ((buf_size - pos) < 4)
00963 goto fail;
00964 offset1 = GETBE16(spu_pkt + pos);
00965 offset2 = GETBE16(spu_pkt + pos + 2);
00966 pos +=4;
00967 }
00968 break;
00969 case 0xff:
00970 default:
00971 goto the_end;
00972 }
00973 }
00974 the_end:
00975 if (offset1 >= 0)
00976 {
00977 int w, h;
00978 uint8_t *bitmap;
00979 w = x2 - x1 + 1;
00980 if (w < 0)
00981 w = 0;
00982 h = y2 - y1 + 2;
00983 if (h < 0)
00984 h = 0;
00985 if (w > 0 && h > 0)
00986 {
00987 if (sub->rects != NULL)
00988 {
00989 for (i = 0; i < sub->num_rects; i++)
00990 {
00991 av_free(sub->rects[i].bitmap);
00992 av_free(sub->rects[i].rgba_palette);
00993 }
00994 av_freep(&sub->rects);
00995 sub->num_rects = 0;
00996 }
00997
00998 bitmap = (uint8_t*) av_malloc(w * h);
00999 sub->num_rects = (NumMenuButtons() > 0) ? 2 : 1;
01000 sub->rects = (AVSubtitleRect *)
01001 av_mallocz(sizeof(AVSubtitleRect) * sub->num_rects);
01002 sub->rects[0].rgba_palette = (uint32_t*)av_malloc(4 *4);
01003 decode_rle(bitmap, w * 2, w, (h + 1) / 2,
01004 spu_pkt, offset1 * 2, buf_size);
01005 decode_rle(bitmap + w, w * 2, w, h / 2,
01006 spu_pkt, offset2 * 2, buf_size);
01007 guess_palette(sub->rects[0].rgba_palette, palette, alpha);
01008 sub->rects[0].bitmap = bitmap;
01009 sub->rects[0].x = x1;
01010 sub->rects[0].y = y1;
01011 sub->rects[0].w = w;
01012 sub->rects[0].h = h;
01013 sub->rects[0].nb_colors = 4;
01014 sub->rects[0].linesize = w;
01015 if (NumMenuButtons() > 0)
01016 {
01017 sub->rects[1].rgba_palette = (uint32_t*)av_malloc(4 *4);
01018 guess_palette(sub->rects[1].rgba_palette,
01019 button_color, button_alpha);
01020 }
01021 else
01022 find_smallest_bounding_rectangle(sub);
01023 *gotSubtitles = 1;
01024 }
01025 }
01026 if (next_cmd_pos == cmd_pos)
01027 break;
01028 cmd_pos = next_cmd_pos;
01029 }
01030 if (sub->num_rects > 0)
01031 {
01032 if (parent && curSubtitleTrack == -1 && !IsInMenu())
01033 {
01034 uint captionmode = parent->GetCaptionMode();
01035 if (force_subtitle_display && captionmode != kDisplayAVSubtitle)
01036 parent->EnableCaptions(kDisplayAVSubtitle, false);
01037 else if (!force_subtitle_display && captionmode == kDisplayAVSubtitle)
01038 parent->DisableCaptions(kDisplayAVSubtitle, false);
01039 }
01040 return true;
01041 }
01042 fail:
01043 return false;
01044 }
01045
01049 bool DVDRingBufferPriv::DVDButtonUpdate(bool b_mode)
01050 {
01051 if (!parent)
01052 return false;
01053
01054 QSize video_disp_dim = parent->GetVideoSize();
01055 int videoheight = video_disp_dim.height();
01056 int videowidth = video_disp_dim.width();
01057
01058 int32_t button;
01059 pci_t *pci;
01060 dvdnav_status_t dvdRet;
01061 dvdnav_highlight_area_t hl;
01062 dvdnav_get_current_highlight(dvdnav, &button);
01063 pci = dvdnav_get_current_nav_pci(dvdnav);
01064 dvdRet = dvdnav_get_highlight_area(pci, button, b_mode, &hl);
01065
01066 if (dvdRet == DVDNAV_STATUS_ERR)
01067 return false;
01068
01069 for (uint i = 0 ; i < 4 ; i++)
01070 {
01071 button_alpha[i] = 0xf & (hl.palette >> (4 * i ));
01072 button_color[i] = 0xf & (hl.palette >> (16+4 *i ));
01073 }
01074
01075 hl_button.setCoords(hl.sx, hl.sy, hl.ex, hl.ey);
01076
01077 if (((hl.sx + hl.sy) > 0) &&
01078 (hl.sx < videowidth && hl.sy < videoheight))
01079 return true;
01080
01081 return false;
01082 }
01083
01086 void DVDRingBufferPriv::ClearMenuButton(void)
01087 {
01088 if (buttonExists || dvdMenuButton.rects)
01089 {
01090 for (uint i = 0; i < dvdMenuButton.num_rects; i++)
01091 {
01092 AVSubtitleRect* rect = &(dvdMenuButton.rects[i]);
01093 av_free(rect->rgba_palette);
01094 av_free(rect->bitmap);
01095 }
01096 av_free(dvdMenuButton.rects);
01097 dvdMenuButton.rects = NULL;
01098 dvdMenuButton.num_rects = 0;
01099 buttonExists = false;
01100 }
01101 }
01102
01106 void DVDRingBufferPriv::ClearMenuSPUParameters(void)
01107 {
01108 if (menuBuflength == 0)
01109 return;
01110
01111 VERBOSE(VB_PLAYBACK,LOC + "Clearing Menu SPU Packet" );
01112
01113 ClearMenuButton();
01114
01115 av_free(menuSpuPkt);
01116 menuBuflength = 0;
01117 hl_button.setRect(0, 0, 0, 0);
01118 }
01119
01120 int DVDRingBufferPriv::NumMenuButtons(void) const
01121 {
01122 pci_t *pci = dvdnav_get_current_nav_pci(dvdnav);
01123 int numButtons = pci->hli.hl_gi.btn_ns;
01124 if (numButtons > 0 && numButtons < 36)
01125 return numButtons;
01126 else
01127 return 0;
01128 }
01129
01132 uint DVDRingBufferPriv::GetAudioLanguage(int id)
01133 {
01134 uint16_t lang = dvdnav_audio_stream_to_lang(dvdnav, id);
01135 return ConvertLangCode(lang);
01136 }
01137
01142 int DVDRingBufferPriv::GetSubTrackNum(uint stream_id)
01143 {
01144 if (subTrackMap.empty())
01145 return -1;
01146 QMapConstIterator<uint, uint> it = subTrackMap.begin();
01147 for (; it != subTrackMap.end(); ++it)
01148 {
01149 if (it.key() == stream_id)
01150 return (int)it.data();
01151 }
01152 return 33;
01153 }
01154
01159 int DVDRingBufferPriv::GetAudioTrackNum(uint stream_id)
01160 {
01161 if (audioTrackMap.empty())
01162 return -1;
01163 QMapConstIterator<uint, uint> it = audioTrackMap.begin();
01164 for (; it != audioTrackMap.end(); ++it)
01165 {
01166 if (it.key() == stream_id)
01167 return (int)it.data();
01168 }
01169 return 10;
01170 }
01171
01174 uint DVDRingBufferPriv::GetSubtitleLanguage(int id)
01175 {
01176 uint16_t lang = dvdnav_spu_stream_to_lang(dvdnav, id);
01177 return ConvertLangCode(lang);
01178 }
01179
01182 uint DVDRingBufferPriv::ConvertLangCode(uint16_t code)
01183 {
01184 if (code == 0)
01185 return 0;
01186
01187 QChar str2[2];
01188 str2[0] = QChar(code >> 8);
01189 str2[1] = QChar(code & 0xff);
01190 QString str3 = iso639_str2_to_str3(QString(str2, 2));
01191 if (str3)
01192 return iso639_str3_to_key(str3);
01193 return 0;
01194 }
01195
01199 void DVDRingBufferPriv::SelectDefaultButton(void)
01200 {
01201 pci_t *pci = dvdnav_get_current_nav_pci(dvdnav);
01202 int32_t button = pci->hli.hl_gi.fosl_btnn;
01203 if (button > 0 && !cellRepeated)
01204 {
01205 dvdnav_button_select(dvdnav,pci,button);
01206 return;
01207 }
01208 dvdnav_get_current_highlight(dvdnav,&button);
01209 if (button > 0 && button <= NumMenuButtons())
01210 dvdnav_button_select(dvdnav,pci,button);
01211 else
01212 dvdnav_button_select(dvdnav,pci,1);
01213 }
01214
01219 void DVDRingBufferPriv::SetTrack(uint type, int trackNo)
01220 {
01221 if (type == kTrackTypeSubtitle)
01222 {
01223 curSubtitleTrack = trackNo;
01224 if (trackNo < 0)
01225 autoselectsubtitle = true;
01226 else
01227 autoselectsubtitle = false;
01228 }
01229 else if (type == kTrackTypeAudio)
01230 {
01231 curAudioTrack = trackNo;
01232 autoselectaudio = false;
01233 }
01234 }
01235
01241 int DVDRingBufferPriv::GetTrack(uint type)
01242 {
01243 if (type == kTrackTypeSubtitle)
01244 return curSubtitleTrack;
01245 else if (type == kTrackTypeAudio)
01246 return curAudioTrack;
01247
01248 return 0;
01249 }
01250
01251 uint8_t DVDRingBufferPriv::GetNumAudioChannels(int id)
01252 {
01253 unsigned char channels = dvdnav_audio_get_channels(dvdnav, id);
01254 if (channels == 0xff)
01255 return 0;
01256 return (uint8_t)channels + 1;
01257 }
01258
01262 void DVDRingBufferPriv::ClearSubtitlesOSD(void)
01263 {
01264 if (parent && parent->GetOSD() &&
01265 parent->GetOSD()->IsSetDisplaying("subtitles"))
01266 {
01267 parent->GetOSD()->HideSet("subtitles");
01268 parent->GetOSD()->ClearAll("subtitles");
01269 }
01270 }
01271
01274 bool DVDRingBufferPriv::GetNameAndSerialNum(QString& _name, QString& _serial)
01275 {
01276 (_name) = dvdname;
01277 (_serial) = serialnumber;
01278 if (dvdname == "" && serialnumber == "")
01279 return false;
01280 return true;
01281 }
01282
01287 double DVDRingBufferPriv::GetFrameRate(void)
01288 {
01289 float dvdfps = 0;
01290 int format = dvdnav_get_video_format(dvdnav);
01291 if (format)
01292 dvdfps = 23.97;
01293 else
01294 dvdfps = 29.97;
01295
01296 return dvdfps;
01297 }
01298
01302 bool DVDRingBufferPriv::IsSameChapter(int tmpcellid, int tmpvobid)
01303 {
01304 if ((tmpcellid == cellid) && (tmpvobid == vobid))
01305 return true;
01306
01307 return false;
01308 }
01309
01314 void DVDRingBufferPriv::RunSeekCellStart(void)
01315 {
01316 if (!runSeekCellStart)
01317 return;
01318
01319 bool ret = true;
01320 if (NumMenuButtons() > 0 && !buttonExists)
01321 ret = false;
01322
01323 if (ret)
01324 {
01325 ret = SeekCellStart();
01326 runSeekCellStart = false;
01327 }
01328 }
01329
01332 bool DVDRingBufferPriv::SeekCellStart(void)
01333 {
01334 QMutexLocker lock(&seekLock);
01335 runningCellStart = true;
01336 return (Seek(cellStart) == 0);
01337 }
01338
01342 void DVDRingBufferPriv::SetDVDSpeed(void)
01343 {
01344 QMutexLocker lock(&seekLock);
01345 int dvdDriveSpeed = gContext->GetNumSetting("DVDDriveSpeed", 12);
01346 SetDVDSpeed(dvdDriveSpeed);
01347 }
01348
01351 void DVDRingBufferPriv::SetDVDSpeed(int speed)
01352 {
01353 MediaMonitor::SetCDSpeed(dvdFilename, speed);
01354 }
01355
01358 uint DVDRingBufferPriv::TitleTimeLeft(void)
01359 {
01360 return (GetTotalTimeOfTitle() -
01361 GetCurrentTime());
01362 }
01363
01366 void DVDRingBufferPriv::guess_palette(uint32_t *rgba_palette,uint8_t *palette,
01367 uint8_t *alpha)
01368 {
01369 int i,r,g,b,y,cr,cb;
01370 uint32_t yuv;
01371
01372 for (i = 0; i < 4; i++)
01373 rgba_palette[i] = 0;
01374
01375 for (i=0 ; i < 4 ; i++)
01376 {
01377 yuv = clut[palette[i]];
01378 y = ((yuv >> 16) & 0xff);
01379 cr = ((yuv >> 8) & 0xff);
01380 cb = ((yuv >> 0) & 0xff);
01381 r = int(y + 1.4022 * (cr - 128));
01382 b = int(y + 1.7710 * (cb - 128));
01383 g = int(1.7047 * y - (0.1952 * b) - (0.5647 * r)) ;
01384 if (r < 0) r = 0;
01385 if (g < 0) g = 0;
01386 if (b < 0) b = 0;
01387 if (r > 0xff) r = 0xff;
01388 if (g > 0xff) g = 0xff;
01389 if (b > 0xff) b = 0xff;
01390 rgba_palette[i] = ((alpha[i] * 17) << 24) | (r << 16 )| (g << 8) | b;
01391 }
01392 }
01393
01397 int DVDRingBufferPriv::decode_rle(uint8_t *bitmap, int linesize, int w, int h,
01398 const uint8_t *buf, int nibble_offset, int buf_size)
01399 {
01400 unsigned int v;
01401 int x, y, len, color, nibble_end;
01402 uint8_t *d;
01403
01404 nibble_end = buf_size * 2;
01405 x = 0;
01406 y = 0;
01407 d = bitmap;
01408 for(;;) {
01409 if (nibble_offset >= nibble_end)
01410 return -1;
01411 v = get_nibble(buf, nibble_offset++);
01412 if (v < 0x4) {
01413 v = (v << 4) | get_nibble(buf, nibble_offset++);
01414 if (v < 0x10) {
01415 v = (v << 4) | get_nibble(buf, nibble_offset++);
01416 if (v < 0x040) {
01417 v = (v << 4) | get_nibble(buf, nibble_offset++);
01418 if (v < 4) {
01419 v |= (w - x) << 2;
01420 }
01421 }
01422 }
01423 }
01424 len = v >> 2;
01425 if (len > (w - x))
01426 len = (w - x);
01427 color = v & 0x03;
01428 memset(d + x, color, len);
01429 x += len;
01430 if (x >= w) {
01431 y++;
01432 if (y >= h)
01433 break;
01434 d += linesize;
01435 x = 0;
01436 nibble_offset += (nibble_offset & 1);
01437 }
01438 }
01439 return 0;
01440 }
01441
01444 int DVDRingBufferPriv::get_nibble(const uint8_t *buf, int nibble_offset)
01445 {
01446 return (buf[nibble_offset >> 1] >> ((1 - (nibble_offset & 1)) << 2)) & 0xf;
01447 }
01448
01453 int DVDRingBufferPriv::is_transp(const uint8_t *buf, int pitch, int n,
01454 const uint8_t *transp_color)
01455 {
01456 int i;
01457 for (i = 0; i < n; i++)
01458 {
01459 if (!transp_color[*buf])
01460 return 0;
01461 buf += pitch;
01462 }
01463 return 1;
01464 }
01465
01471 int DVDRingBufferPriv::find_smallest_bounding_rectangle(AVSubtitle *s)
01472 {
01473 uint8_t transp_color[256];
01474 int y1, y2, x1, x2, y, w, h, i;
01475 uint8_t *bitmap;
01476
01477 if (s->num_rects == 0 || s->rects == NULL ||
01478 s->rects[0].w <= 0 || s->rects[0].h <= 0)
01479 {
01480 return 0;
01481 }
01482
01483 memset(transp_color, 0, 256);
01484 for (i = 0; i < s->rects[0].nb_colors; i++)
01485 {
01486 if ((s->rects[0].rgba_palette[i] >> 24) == 0)
01487 transp_color[i] = 1;
01488 }
01489
01490 y1 = 0;
01491 while (y1 < s->rects[0].h &&
01492 is_transp(s->rects[0].bitmap + y1 * s->rects[0].linesize,
01493 1, s->rects[0].w, transp_color))
01494 {
01495 y1++;
01496 }
01497
01498 if (y1 == s->rects[0].h)
01499 {
01500 av_freep(&s->rects[0].bitmap);
01501 s->rects[0].w = s->rects[0].h = 0;
01502 return 0;
01503 }
01504
01505 y2 = s->rects[0].h - 1;
01506 while (y2 > 0 &&
01507 is_transp(s->rects[0].bitmap + y2 * s->rects[0].linesize, 1,
01508 s->rects[0].w, transp_color))
01509 {
01510 y2--;
01511 }
01512
01513 x1 = 0;
01514 while (x1 < (s->rects[0].w - 1) &&
01515 is_transp(s->rects[0].bitmap + x1, s->rects[0].linesize,
01516 s->rects[0].h, transp_color))
01517 {
01518 x1++;
01519 }
01520
01521 x2 = s->rects[0].w - 1;
01522 while (x2 > 0 &&
01523 is_transp(s->rects[0].bitmap + x2, s->rects[0].linesize,
01524 s->rects[0].h, transp_color))
01525 {
01526 x2--;
01527 }
01528
01529 w = x2 - x1 + 1;
01530 h = y2 - y1 + 1;
01531 bitmap = (uint8_t*) av_malloc(w * h);
01532 if (!bitmap)
01533 return 1;
01534
01535 for(y = 0; y < h; y++)
01536 {
01537 memcpy(bitmap + w * y, s->rects[0].bitmap + x1 +
01538 (y1 + y) * s->rects[0].linesize, w);
01539 }
01540
01541 av_freep(&s->rects[0].bitmap);
01542 s->rects[0].bitmap = bitmap;
01543 s->rects[0].linesize = w;
01544 s->rects[0].w = w;
01545 s->rects[0].h = h;
01546 s->rects[0].x += x1;
01547 s->rects[0].y += y1;
01548 return 1;
01549 }