|
|
|
//
|
|
|
|
// C++ Implementation: k9plaympeg2
|
|
|
|
//
|
|
|
|
// Description:
|
|
|
|
//
|
|
|
|
//
|
|
|
|
// Author: Jean-Michel PETIT <k9copy@free.fr>, (C) 2006
|
|
|
|
//
|
|
|
|
// Copyright: See COPYING file that comes with this distribution
|
|
|
|
//
|
|
|
|
//
|
|
|
|
#include "k9plaympeg2.h"
|
|
|
|
#include "kdecmpeg2.h"
|
|
|
|
#include "dvdnav.h"
|
|
|
|
|
|
|
|
#include <klocale.h>
|
|
|
|
#include <tqapplication.h>
|
|
|
|
|
|
|
|
k9PlayMPEG2::k9PlayMPEG2()
|
|
|
|
{
|
|
|
|
m_title=NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
k9PlayMPEG2::~k9PlayMPEG2()
|
|
|
|
{
|
|
|
|
stop();
|
|
|
|
}
|
|
|
|
|
|
|
|
void k9PlayMPEG2::updatePos( uint32_t _position) {
|
|
|
|
m_idxLect=_position;
|
|
|
|
m_decoder.clear();
|
|
|
|
m_decoder.getDecoder()->restart();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#define DVD_LANGUAGE "en"
|
|
|
|
#define DVD_READ_CACHE 1
|
|
|
|
|
|
|
|
void k9PlayMPEG2::playTitle() {
|
|
|
|
dvdnav_t *dvdnav;
|
|
|
|
uint8_t mem[DVD_VIDEO_LB_LEN];
|
|
|
|
int finished = 0;
|
|
|
|
int32_t tt = 0,ptt=0;
|
|
|
|
uint32_t pos, lgr;
|
|
|
|
int title=m_title->getnumTitle();
|
|
|
|
|
|
|
|
|
|
|
|
/* open dvdnav handle */
|
|
|
|
if (dvdnav_open(&dvdnav, m_device,m_dvd) != DVDNAV_STATUS_OK) {
|
|
|
|
setError("ERR:Error on dvdnav_open\n");
|
|
|
|
return ;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* set read ahead cache usage */
|
|
|
|
if (dvdnav_set_readahead_flag(dvdnav, DVD_READ_CACHE) != DVDNAV_STATUS_OK) {
|
|
|
|
setError(TQString("ERR:Error on dvdnav_set_readahead_flag: %1\n").arg(dvdnav_err_to_string(dvdnav)));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* set the language */
|
|
|
|
if (dvdnav_menu_language_select(dvdnav, DVD_LANGUAGE) != DVDNAV_STATUS_OK ||
|
|
|
|
dvdnav_audio_language_select(dvdnav, DVD_LANGUAGE) != DVDNAV_STATUS_OK ||
|
|
|
|
dvdnav_spu_language_select(dvdnav, DVD_LANGUAGE) != DVDNAV_STATUS_OK) {
|
|
|
|
setError(TQString("ERR:Error on setting languages: %1\n").arg(dvdnav_err_to_string(dvdnav)));
|
|
|
|
return ;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* set the PGC positioning flag to have position information relatively to the
|
|
|
|
* whole feature instead of just relatively to the current chapter */
|
|
|
|
if (dvdnav_set_PGC_positioning_flag(dvdnav, 1) != DVDNAV_STATUS_OK) {
|
|
|
|
setError(TQString("ERR:Error on dvdnav_set_PGC_positioning_flag: %1\n").arg(dvdnav_err_to_string(dvdnav)));
|
|
|
|
return ;
|
|
|
|
}
|
|
|
|
|
|
|
|
int32_t parts;
|
|
|
|
dvdnav_get_number_of_parts(dvdnav , title, &parts);
|
|
|
|
|
|
|
|
if (m_chapter==0)
|
|
|
|
dvdnav_title_play(dvdnav , title);
|
|
|
|
else
|
|
|
|
dvdnav_part_play(dvdnav , title,m_chapter);
|
|
|
|
/* the read loop which regularly calls dvdnav_get_next_block
|
|
|
|
* and handles the returned events */
|
|
|
|
|
|
|
|
while (!finished && !m_stopped && tqApp!=NULL) {
|
|
|
|
int result, event, len;
|
|
|
|
uint8_t *buf = mem;
|
|
|
|
|
|
|
|
if (m_idxLect !=0xFFFFFFFF) {
|
|
|
|
dvdnav_sector_search(dvdnav, m_idxLect,SEEK_SET);
|
|
|
|
m_idxLect=0xFFFFFFFF;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* the main reading function */
|
|
|
|
#ifdef DVD_READ_CACHE
|
|
|
|
|
|
|
|
result = dvdnav_get_next_cache_block(dvdnav, &buf, &event, &len);
|
|
|
|
#else
|
|
|
|
|
|
|
|
result = dvdnav_get_next_block(dvdnav, buf, &event, &len);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
if (result == DVDNAV_STATUS_ERR) {
|
|
|
|
setError(TQString("ERR:Error getting next block: %1\n").arg(dvdnav_err_to_string(dvdnav)));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (event) {
|
|
|
|
case DVDNAV_NAV_PACKET:
|
|
|
|
{
|
|
|
|
dvdnav_current_title_info(dvdnav, &tt, &ptt);
|
|
|
|
dvdnav_get_position(dvdnav, &pos, &lgr);
|
|
|
|
|
|
|
|
if (tt != title)
|
|
|
|
finished=1;
|
|
|
|
|
|
|
|
if (finished==0 && buf[17]==0xE0) {
|
|
|
|
m_decoder.addData( buf,len);
|
|
|
|
}
|
|
|
|
if (tqApp->tryLock()) {
|
|
|
|
emit setPosition( pos);
|
|
|
|
tqApp->unlock();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
//removed break --> save
|
|
|
|
case DVDNAV_BLOCK_OK:
|
|
|
|
/* We have received a regular block of the currently playing MPEG stream.*/
|
|
|
|
m_decoder.addData( buf,len);
|
|
|
|
break;
|
|
|
|
case DVDNAV_NOP:
|
|
|
|
/* Nothing to do here. */
|
|
|
|
break;
|
|
|
|
case DVDNAV_STILL_FRAME:
|
|
|
|
/* We have reached a still frame. A real player application would wait
|
|
|
|
* the amount of time specified by the still's length while still handling
|
|
|
|
* user input to make menus and other interactive stills work.
|
|
|
|
* A length of 0xff means an indefinite still which has to be skipped
|
|
|
|
* indirectly by some user interaction. */
|
|
|
|
{
|
|
|
|
dvdnav_still_event_t *still_event = (dvdnav_still_event_t *)buf;
|
|
|
|
dvdnav_still_skip(dvdnav);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case DVDNAV_WAIT:
|
|
|
|
/* We have reached a point in DVD playback, where timing is critical.
|
|
|
|
* Player application with internal fifos can introduce state
|
|
|
|
* inconsistencies, because libdvdnav is always the fifo's length
|
|
|
|
* ahead in the stream compared to what the application sees.
|
|
|
|
* Such applications should wait until their fifos are empty
|
|
|
|
* when they receive this type of event. */
|
|
|
|
dvdnav_wait_skip(dvdnav);
|
|
|
|
break;
|
|
|
|
case DVDNAV_SPU_CLUT_CHANGE:
|
|
|
|
/* Player applications should pass the new colour lookup table to their
|
|
|
|
* SPU decoder */
|
|
|
|
break;
|
|
|
|
case DVDNAV_SPU_STREAM_CHANGE:
|
|
|
|
/* Player applications should inform their SPU decoder to switch channels */
|
|
|
|
break;
|
|
|
|
case DVDNAV_AUDIO_STREAM_CHANGE:
|
|
|
|
/* Player applications should inform their audio decoder to switch channels */
|
|
|
|
break;
|
|
|
|
case DVDNAV_HIGHLIGHT:
|
|
|
|
/* Player applications should inform their overlay engine to highlight the
|
|
|
|
* given button */
|
|
|
|
{
|
|
|
|
dvdnav_highlight_event_t *highlight_event = (dvdnav_highlight_event_t *)buf;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case DVDNAV_VTS_CHANGE:
|
|
|
|
/* Some status information like video aspect and video scale permissions do
|
|
|
|
* not change inside a VTS. Therefore this event can be used to query such
|
|
|
|
* information only when necessary and update the decoding/displaying
|
|
|
|
* accordingly. */
|
|
|
|
break;
|
|
|
|
case DVDNAV_CELL_CHANGE:
|
|
|
|
// dvdnav_get_position(dvdnav, &pos, &lgr);
|
|
|
|
break;
|
|
|
|
case DVDNAV_HOP_CHANNEL:
|
|
|
|
/* This event is issued whenever a non-seamless operation has been executed.
|
|
|
|
* Applications with fifos should drop the fifos content to speed up responsiveness. */
|
|
|
|
break;
|
|
|
|
case DVDNAV_STOP:
|
|
|
|
/* Playback should end here. */
|
|
|
|
{
|
|
|
|
finished = 1;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
finished = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef DVD_READ_CACHE
|
|
|
|
dvdnav_free_cache_block(dvdnav, buf);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
}
|
|
|
|
m_decoder.setNoData();
|
|
|
|
/* destroy dvdnav handle */
|
|
|
|
dvdnav_close(dvdnav);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void k9PlayMPEG2::run() {
|
|
|
|
m_stopped=false;
|
|
|
|
|
|
|
|
m_idxLect=m_startSector;
|
|
|
|
playTitle();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void k9PlayMPEG2::stop() {
|
|
|
|
m_stopped=TRUE;
|
|
|
|
|
|
|
|
m_decoder.setNoData();
|
|
|
|
m_decoder.clear();
|
|
|
|
m_decoder.wait();
|
|
|
|
wait();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void k9PlayMPEG2::play() {
|
|
|
|
if (m_stopped && m_title!=NULL)
|
|
|
|
open(m_dvd,m_device,m_title,m_chapter);
|
|
|
|
}
|
|
|
|
|
|
|
|
kDecMPEG2 *k9PlayMPEG2::getDecoder() {
|
|
|
|
return m_decoder.getDecoder() ;
|
|
|
|
}
|
|
|
|
|
|
|
|
void k9PlayMPEG2::open (dvd_reader_t *dvd,const TQString & device,k9DVDTitle * title,int chapter=0) {
|
|
|
|
m_dvd=dvd;
|
|
|
|
m_chapter=chapter;
|
|
|
|
int ret = 0;
|
|
|
|
struct stat dvd_stat;
|
|
|
|
TQString c;
|
|
|
|
m_idxLect=0xFFFFFFFF;
|
|
|
|
|
|
|
|
stop();
|
|
|
|
|
|
|
|
m_title=title;
|
|
|
|
m_device=device;
|
|
|
|
|
|
|
|
m_startSector=0;
|
|
|
|
m_lastSector=0;
|
|
|
|
ret = stat(device.utf8(), &dvd_stat);
|
|
|
|
/* if ( ret < 0 ) {
|
|
|
|
c=i18n("Can't find device %1\n").arg(device.latin1());
|
|
|
|
setError(c);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
m_title=title;
|
|
|
|
|
|
|
|
m_startSector=m_title->getChapter( 0)->getstartSector();
|
|
|
|
m_lastSector= m_startSector + m_title->getsectors(); //m_title->getChapter(m_title->getchapterCount()-1)->getendSector();
|
|
|
|
|
|
|
|
emit setPosition( m_startSector);
|
|
|
|
emit setMax( m_lastSector);
|
|
|
|
emit setMin( m_startSector);
|
|
|
|
|
|
|
|
m_decoder.start(TQThread::LowPriority);
|
|
|
|
|
|
|
|
start();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#include "k9plaympeg2.moc"
|