00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #define USE_QT_ONLY 1
00022
00023 #ifndef USE_QT_ONLY
00024
00025 #include <klocale.h>
00026 #include <kurl.h>
00027 #include <kstandarddirs.h>
00028 #include <kdebug.h>
00029 #include <kmessagebox.h>
00030 #include <kapplication.h>
00031
00032 #else
00033
00034 #include <qmessagebox.h>
00035 #include <qapplication.h>
00036
00037 #endif
00038
00039 #include <qdir.h>
00040 #include <qcursor.h>
00041 #include <qimage.h>
00042
00043 #include <string.h>
00044 #include <stdlib.h>
00045 #include <xine/xineutils.h>
00046
00047 #include "convert.h"
00048 #include "qxinewidget.h"
00049
00050 #ifndef USE_QT_ONLY
00051 #include "qxinewidget.moc"
00052 #endif
00053
00054 #include <X11/keysym.h>
00055 #ifdef HAVE_XTEST
00056 #include <X11/extensions/XTest.h>
00057 #endif
00058
00059
00060 #define TIMER_EVENT_PLAYBACK_FINISHED 100
00061 #define TIMER_EVENT_NEW_CHANNELS 101
00062 #define TIMER_EVENT_NEW_TITLE 102
00063 #define TIMER_EVENT_NEW_INFO 103
00064 #define TIMER_EVENT_NEW_PROGRESS_INFO 104
00065 #define TIMER_EVENT_CHANGE_CURSOR 105
00066 #define TIMER_EVENT_GRAB_KEYBOARD 106
00067 #define TIMER_EVENT_NEW_MRL_REFERENCE 107
00068 #define TIMER_EVENT_NEW_XINE_MESSAGE 108
00069 #define TIMER_EVENT_RESTART_PLAYBACK 200
00070 #define TIMER_EVENT_RESIZE_PARENT 300
00071
00072
00073 QXineWidget::QXineWidget(QWidget *parent, const char *name, const QString& prefAudio, const QString& prefVideo, bool verbose, bool startManual)
00074 : QWidget(parent,name), QThread()
00075 {
00076 xineEngine = NULL; xineStream = NULL; audioDriver = NULL; videoDriver = NULL;
00077 eventQueue = NULL; xinePost = NULL; xineRunning = false;
00078 xineDisplay = NULL; eventThread = 0; currentZoom = 100;
00079 startXineManual = startManual;
00080 visualPluginName = QString::null;
00081 devicePath = QString::null;
00082 xineVerbose = verbose;
00083 autoresizeEnabled = false; videoFrameWidth = 0; videoFrameHeight = 0;
00084
00085 preferedAudio = prefAudio;
00086 preferedVideo = prefVideo;
00087
00088 setPaletteBackgroundColor(QColor(0,0,0));
00089
00090 playMode = NORMAL_PLAY;
00091
00092 connect(&posTimer, SIGNAL(timeout()), this, SLOT(slotGetPosition()));
00093 connect(&lengthInfoTimer, SIGNAL(timeout()), this, SLOT(slotEmitLengthInfo()));
00094 connect(&screensaverTimer, SIGNAL(timeout()), this, SLOT(slotFakeKeyEvent()));
00095 connect(&mouseHideTimer, SIGNAL(timeout()), this, SLOT(slotHideMouse()));
00096
00097 setMouseTracking( true );
00098 setUpdatesEnabled( false );
00099 }
00100
00101 QXineWidget::~QXineWidget()
00102 {
00103
00104
00105 xineRunning = false;
00106
00107
00108 posTimer.stop();
00109 screensaverTimer.stop();
00110 mouseHideTimer.stop();
00111
00112 if (xineStream)
00113 {
00114 xine_close(xineStream);
00115 }
00116
00117 if (running())
00118 {
00119
00120 XEvent ev;
00121 ev.type = Expose;
00122 ev.xexpose.display = xineDisplay;
00123 ev.xexpose.window = winId();
00124 ev.xexpose.x = x();
00125 ev.xexpose.y = y();
00126 ev.xexpose.width = width();
00127 ev.xexpose.height = height();
00128 ev.xexpose.count = 0;
00129
00130 XSendEvent( x11Display(), winId(), False, ExposureMask, &ev );
00131 XFlush( x11Display() );
00132
00133 if( !wait(1000) )
00134 {
00135 warningOut("XEvent thread don't exit. Terminating it...");
00136 terminate();
00137 }
00138 }
00139
00140 debugOut("Shut down xine engine\n");
00141
00142 if (xineDisplay)
00143 XLockDisplay( xineDisplay );
00144
00145 if (xinePost)
00146 {
00147 debugOut(QString("Dispose visual plugin: %1").arg(visualPluginName));
00148 postAudioSource = xine_get_audio_source (xineStream);
00149 xine_post_wire_audio_port (postAudioSource, audioDriver);
00150 xine_post_dispose (xineEngine, xinePost);
00151 }
00152 if (eventQueue)
00153 xine_event_dispose_queue(eventQueue);
00154 if (xineStream)
00155 xine_dispose(xineStream);
00156 if (audioDriver)
00157 xine_close_audio_driver(xineEngine, audioDriver);
00158 if (videoDriver)
00159 xine_close_video_driver(xineEngine, videoDriver);
00160 if (xineEngine)
00161 xine_exit(xineEngine);
00162 xineEngine = NULL;
00163
00164 if (xineDisplay)
00165 XUnlockDisplay( xineDisplay );
00166
00167
00168
00169
00170
00171
00172
00173
00174 xineDisplay = NULL;
00175
00176 debugOut("xine closed\n");
00177 }
00178
00179
00180 QString QXineWidget::i18n(const char *text)
00181 {
00182 #ifdef USE_QT_ONLY
00183 return tr (text);
00184 #else
00185 return ::i18n(text);
00186 #endif
00187 }
00188
00189 void QXineWidget::debugOut (QString qsDebug)
00190 {
00191 #ifdef USE_QT_ONLY
00192 QString qsDebugging = QString ("Debug: ") + qsDebug;
00193 printf ((const char *)qsDebugging);
00194 #else
00195 kdDebug(555) << (const char *)qsDebug << "\n";
00196 #endif
00197 }
00198 void QXineWidget::errorOut (QString qsError)
00199 {
00200 #ifdef USE_QT_ONLY
00201 QString qsErroring = QString ("Error: ") + qsError;
00202 printf ((const char *)qsErroring);
00203 #else
00204 kdError(555) << (const char *)qsError << "\n";
00205 #endif
00206 }
00207 void QXineWidget::warningOut (QString qsWarning)
00208 {
00209 #ifdef USE_QT_ONLY
00210 QString qsWarninging = QString ("Warning: ") + qsWarning;
00211 printf ((const char *)qsWarninging);
00212 #else
00213 kdWarning(555) << (const char *)qsWarning << "\n";
00214 #endif
00215 }
00216
00217 void QXineWidget::postEvent(QObject *pObject,QEvent *pEvent)
00218 {
00219 #ifdef USE_QT_ONLY
00220 QApplication::postEvent (pObject, pEvent);
00221 #else
00222 KApplication::kApplication()->postEvent(pObject, pEvent);
00223 #endif
00224 }
00225
00226 void QXineWidget::messageBoxError(QWidget *pWidget, QString qsMessage)
00227 {
00228 #ifdef USE_QT_ONLY
00229 QMessageBox::about(pWidget, qsMessage, qsMessage);
00230 #else
00231 KMessageBox::error(pWidget, qsMessage);
00232 #endif
00233 }
00234
00235
00236 void QXineWidget::SaveXineConfig()
00237 {
00238 if (!devicePath.isNull())
00239 {
00240 debugOut("Set CD/VCD/DVD path back");
00241 xine_cfg_entry_t config;
00242
00243 xine_config_lookup_entry (xineEngine, "input.cdda_device", &config);
00244 if ( devicePath == config.str_value )
00245 {
00246 config.str_value = (char*)cachedCDPath.latin1();
00247 xine_config_update_entry (xineEngine, &config);
00248 }
00249
00250 xine_config_lookup_entry (xineEngine, "input.vcd_device", &config);
00251 if ( devicePath == config.str_value )
00252 {
00253 config.str_value = (char*)cachedVCDPath.latin1();
00254 xine_config_update_entry (xineEngine, &config);
00255 }
00256
00257 xine_config_lookup_entry (xineEngine, "input.dvd_device", &config);
00258 if ( devicePath == config.str_value )
00259 {
00260 config.str_value = (char*)cachedDVDPath.latin1();
00261 xine_config_update_entry (xineEngine, &config);
00262 }
00263 }
00264
00265 debugOut(QString("Save %1\n").arg(configFile));
00266 xine_config_save(xineEngine, configFile);
00267 }
00268
00269
00270
00271
00272
00273
00274 void QXineWidget::DestSizeCallback(void* p, int , int , double ,
00275 int* dest_width, int* dest_height, double* dest_aspect)
00276
00277 {
00278 if (p == NULL) return;
00279 QXineWidget* vw = (QXineWidget*) p;
00280
00281 *dest_width = vw->width();
00282 *dest_height = vw->height();
00283 *dest_aspect = vw->displayRatio;
00284 }
00285
00286 void QXineWidget::FrameOutputCallback(void* p, int video_width, int video_height, double video_aspect,
00287 int* dest_x, int* dest_y, int* dest_width, int* dest_height,
00288 double* dest_aspect, int* win_x, int* win_y)
00289
00290 {
00291 if (p == NULL) return;
00292 QXineWidget* vw = (QXineWidget*) p;
00293
00294 *dest_x = 0;
00295 *dest_y = 0 ;
00296 *dest_width = vw->width();
00297 *dest_height = vw->height();
00298 *win_x = vw->globX;
00299 *win_y = vw->globY;
00300 *dest_aspect = vw->displayRatio;
00301
00302
00303 if (video_aspect >= vw->displayRatio)
00304 video_width = (int) ( (double) (video_width * video_aspect / vw->displayRatio + 0.5) );
00305 else
00306 video_height = (int) ( (double) (video_height * vw->displayRatio / video_aspect) + 0.5);
00307
00308
00309 if (vw->autoresizeEnabled)
00310 {
00311 if ( (video_width != vw->videoFrameWidth) || (video_height != vw->videoFrameHeight) )
00312 {
00313 if ( (vw->parentWidget()) && (!vw->parentWidget()->isFullScreen()) && (vw->posTimer.isActive()) && (video_width > 0) && (video_height > 0) )
00314 {
00315 vw->videoFrameWidth = video_width;
00316 vw->videoFrameHeight = video_height;
00317
00318 vw->newParentSize = vw->parentWidget()->size() - QSize((vw->width() - video_width), vw->height() - video_height);
00319 debugOut (QString("Resize video window to: %1x%2 ...").arg(vw->newParentSize.width()).arg(vw->newParentSize.height()));
00320 debugOut(QString("...with video frame: %1x%2, video aspect ratio: %3").arg(video_width).arg(video_height).arg(video_aspect));
00321
00322
00323
00324 vw->postEvent( vw, new QTimerEvent( TIMER_EVENT_RESIZE_PARENT ) );
00325 }
00326 }
00327 }
00328 }
00329
00330
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340 void QXineWidget::XineEventListener(void *p, const xine_event_t* xineEvent)
00341 {
00342
00343 if (p == NULL) return;
00344 QXineWidget* vw = (QXineWidget*) p;
00345
00346
00347
00348 switch (xineEvent->type)
00349 {
00350 case XINE_EVENT_UI_PLAYBACK_FINISHED:
00351 {
00352 debugOut("xine event: playback finished");
00353 vw->postEvent( vw, new QTimerEvent( TIMER_EVENT_PLAYBACK_FINISHED ) );
00354 break;
00355 }
00356 case XINE_EVENT_UI_CHANNELS_CHANGED:
00357 {
00358 debugOut("xine event: channels changed");
00359 int i,j,channels;
00360 char* lang = new char[128];
00361 QString num;
00362
00363 vw->audioCh.clear();
00364 vw->subCh.clear();
00365
00366
00367 channels = QMAX(6, xine_get_stream_info(vw->xineStream, XINE_STREAM_INFO_MAX_AUDIO_CHANNEL));
00368 for(i = 0; i < channels; i++)
00369 {
00370 if (xine_get_audio_lang(vw->xineStream, i, lang))
00371 vw->audioCh << lang;
00372 else
00373 vw->audioCh << vw->i18n("Ch ") + num.setNum(i+1);
00374 }
00375
00376
00377
00378 channels = QMAX(6, xine_get_stream_info(vw->xineStream, XINE_STREAM_INFO_MAX_SPU_CHANNEL));
00379 for(j = 0; j < channels; j++)
00380 {
00381 if (xine_get_spu_lang(vw->xineStream, j, lang))
00382 vw->subCh << lang;
00383 else
00384 vw->subCh << vw->i18n("Ch ") + num.setNum(j+1);
00385 }
00386
00387 delete lang;
00388
00389 vw->currentAudio = xine_get_param(vw->xineStream, XINE_PARAM_AUDIO_CHANNEL_LOGICAL);
00390 vw->currentSub = xine_get_param(vw->xineStream, XINE_PARAM_SPU_CHANNEL);
00391
00392 if (vw->currentAudio > (i-1))
00393 {
00394 vw->slotSetAudioChannel(0);
00395 vw->currentAudio = -1;
00396 }
00397
00398 if (vw->currentSub > (j-1))
00399 {
00400 vw->slotSetSubtitleChannel(0);
00401 vw->currentSub = -1;
00402 }
00403
00404 vw->postEvent( vw, new QTimerEvent( TIMER_EVENT_NEW_CHANNELS ) );
00405 break;
00406 }
00407 case XINE_EVENT_UI_SET_TITLE:
00408 {
00409 debugOut("xine event: ui set title");
00410 xine_ui_data_t* xd = (xine_ui_data_t*)xineEvent->data;
00411 vw->currentTitle = QString::fromLocal8Bit( (char*)xd->str );
00412 vw->trackInfoRow = vw->currentTitle + " ** " + vw->GetStreamInfo() + vw->extraInfo;
00413
00414 vw->postEvent( vw, new QTimerEvent( TIMER_EVENT_NEW_TITLE ) );
00415 vw->postEvent( vw, new QTimerEvent( TIMER_EVENT_NEW_INFO ) );
00416 break;
00417 }
00418 case XINE_EVENT_PROGRESS:
00419 {
00420 debugOut("xine event: progress info");
00421 xine_progress_data_t* pd = (xine_progress_data_t*)xineEvent->data;
00422
00423 QString perc;
00424 perc.setNum(pd->percent);
00425 perc.append(" %");
00426
00427 vw->currentProgress = pd->description;
00428 vw->currentProgress.append(" ");
00429 vw->currentProgress.append(perc);
00430
00431 if (pd->percent != 100)
00432 vw->postEvent( vw, new QTimerEvent( TIMER_EVENT_NEW_PROGRESS_INFO ) );
00433 else
00434 vw->postEvent( vw, new QTimerEvent( TIMER_EVENT_NEW_INFO ) );
00435
00436 break;
00437 }
00438 case XINE_EVENT_DROPPED_FRAMES:
00439 {
00440 debugOut("xine event: dropped frames");
00441 xine_dropped_frames_t* dropped = (xine_dropped_frames_t*)xineEvent->data;
00442
00443 warningOut(QString("skipped frames: %1% discarded frames: %2%").arg( dropped->skipped_frames/10).arg(dropped->discarded_frames/10));
00444
00445 break;
00446 }
00447 case XINE_EVENT_SPU_BUTTON:
00448 {
00449 debugOut("xine event: spu button");
00450 xine_spu_button_t* button = (xine_spu_button_t*)xineEvent->data;
00451
00452 if (button->direction == 1)
00453 {
00454 debugOut("DVD Menu: Mouse entered button");
00455 vw->DVDButtonEntered = true;
00456 }
00457 else
00458 {
00459 debugOut("DVD Menu: Mouse leaved button");
00460 vw->DVDButtonEntered = false;
00461 }
00462
00463 vw->postEvent( vw, new QTimerEvent( TIMER_EVENT_CHANGE_CURSOR ) );
00464 break;
00465 }
00466 case XINE_EVENT_UI_NUM_BUTTONS:
00467 {
00468 debugOut("xine event: ui num buttons");
00469 xine_ui_data_t *buttons = (xine_ui_data_t *)xineEvent->data;
00470 if(buttons->num_buttons >= 1)
00471 vw->DVDMenuEntered = true;
00472 else
00473 vw->DVDMenuEntered = false;
00474
00475 debugOut(QString("DVD Menu: Num buttons=%1").arg(buttons->num_buttons));
00476 vw->postEvent( vw, new QTimerEvent( TIMER_EVENT_GRAB_KEYBOARD ) );
00477 break;
00478 }
00479 case XINE_EVENT_MRL_REFERENCE:
00480 {
00481 debugOut("xine event: mrl reference");
00482 xine_mrl_reference_data_t* mrldata = (xine_mrl_reference_data_t*)xineEvent->data;
00483 vw->newMrlReference = mrldata->mrl;
00484
00485 vw->postEvent( vw, new QTimerEvent( TIMER_EVENT_NEW_MRL_REFERENCE ) );
00486 break;
00487 }
00488 case XINE_EVENT_UI_MESSAGE:
00489 {
00490 debugOut("xine event: xine message");
00491
00492 xine_ui_message_data_t *data = (xine_ui_message_data_t *)xineEvent->data;
00493 QString message;
00494
00495
00496 switch(data->type)
00497 {
00498 case XINE_MSG_NO_ERROR:
00499 {
00500
00501 char* s = data->messages;
00502 char* d = new char[2000];
00503
00504 while(s && (*s != '\0') && ((*s + 1) != '\0'))
00505 {
00506 switch(*s)
00507 {
00508 case '\0':
00509 {
00510 *d = '\n';
00511 break;
00512 }
00513 default:
00514 {
00515 *d = *s;
00516 break;
00517 }
00518 }
00519 s++;
00520 d++;
00521 }
00522 *++d = '\0';
00523
00524 message = d;
00525 delete d;
00526 break;
00527 }
00528 case XINE_MSG_GENERAL_WARNING:
00529 {
00530 message = vw->i18n("General Warning: \n");
00531
00532 if(data->explanation)
00533 message = message + ((char *) data + data->explanation) + " " + ((char *) data + data->parameters);
00534 else
00535 message = message + vw->i18n("No Informations available.");
00536
00537 break;
00538 }
00539 case XINE_MSG_UNKNOWN_HOST:
00540 {
00541 message = vw->i18n("The host you're trying to connect is unknown.\nCheck the validity of the specified hostname. ");
00542 if(data->explanation)
00543 message = message + "(" + ((char *) data + data->parameters) + ")";
00544 break;
00545 }
00546 case XINE_MSG_UNKNOWN_DEVICE:
00547 {
00548 message = vw->i18n("The device name you specified seems invalid. ");
00549 if(data->explanation)
00550 message = message + "(" + ((char *) data + data->parameters) + ")";
00551 break;
00552 }
00553 case XINE_MSG_NETWORK_UNREACHABLE:
00554 {
00555 message = vw->i18n("The network looks unreachable.\nCheck your network setup and the server name. ");
00556 if(data->explanation)
00557 message = message + "(" + ((char *) data + data->parameters) + ")";
00558 break;
00559 }
00560 case XINE_MSG_CONNECTION_REFUSED:
00561 {
00562 message = vw->i18n("The connection was refused.\nCheck the host name. ");
00563 if(data->explanation)
00564 message = message + "(" + ((char *) data + data->parameters) + ")";
00565 break;
00566 }
00567 case XINE_MSG_FILE_NOT_FOUND:
00568 {
00569 message = vw->i18n("The specified file or url was not found. Please check it. ");
00570 if(data->explanation)
00571 message = message + "(" + ((char *) data + data->parameters) + ")";
00572 break;
00573 }
00574 case XINE_MSG_READ_ERROR:
00575 {
00576 message = vw->i18n("The source can't be read.\nMaybe you don't have enough rights for this, or source doesn't contain data (e.g: no disc in drive). ");
00577 if(data->explanation)
00578 message = message + "(" + ((char *) data + data->parameters) + ")";
00579 break;
00580 }
00581 case XINE_MSG_LIBRARY_LOAD_ERROR:
00582 {
00583 message = vw->i18n("A problem occur while loading a library or a decoder: ");
00584 if(data->explanation)
00585 message = message + ((char *) data + data->parameters);
00586 break;
00587 }
00588 case XINE_MSG_ENCRYPTED_SOURCE:
00589 {
00590 message = vw->i18n("The source seems encrypted, and can't be read. ");
00591 if (vw->currentMRL.contains("dvd:/"))
00592 message = message + vw->i18n("\nYour DVD is probably crypted. According to your country laws, you can or can't use libdvdcss to be able to read this disc. ");
00593 if(data->explanation)
00594 message = message + "(" + ((char *) data + data->parameters) + ")";
00595 break;
00596 }
00597 default:
00598 {
00599 message = vw->i18n("Unkown error: \n");
00600 if(data->explanation)
00601 message = message + ((char *) data + data->explanation) + " " + ((char *) data + data->parameters);
00602 break;
00603 }
00604 }
00605
00606 vw->xineMessage = message;
00607 vw->postEvent( vw, new QTimerEvent( TIMER_EVENT_NEW_XINE_MESSAGE ) );
00608 break;
00609 }
00610 default:
00611 {
00612
00613 break;
00614 }
00615 }
00616
00617
00618 }
00619
00620
00621 void QXineWidget::timerEvent( QTimerEvent* tevent )
00622 {
00623 switch ( tevent->timerId() )
00624 {
00625 case TIMER_EVENT_PLAYBACK_FINISHED:
00626 {
00627 emit signalPlaybackFinished();
00628 break;
00629 }
00630 case TIMER_EVENT_NEW_CHANNELS:
00631 {
00632 emit signalNewChannels( audioCh, subCh, currentAudio, currentSub);
00633 break;
00634 }
00635 case TIMER_EVENT_NEW_TITLE:
00636 {
00637 emit signalNewTitle( currentTitle );
00638 break;
00639 }
00640 case TIMER_EVENT_NEW_INFO:
00641 {
00642 emit signalNewInfo( trackInfoRow );
00643 break;
00644 }
00645 case TIMER_EVENT_NEW_PROGRESS_INFO:
00646 {
00647 emit signalNewInfo( currentProgress );
00648 break;
00649 }
00650 case TIMER_EVENT_CHANGE_CURSOR:
00651 {
00652 if (DVDButtonEntered)
00653 setCursor(QCursor(Qt::PointingHandCursor));
00654 else
00655 setCursor(QCursor(Qt::ArrowCursor));
00656 break;
00657 }
00658 case TIMER_EVENT_GRAB_KEYBOARD:
00659 {
00660 if (DVDMenuEntered)
00661 grabKeyboard();
00662 else
00663 releaseKeyboard();
00664 break;
00665 }
00666 case TIMER_EVENT_NEW_MRL_REFERENCE:
00667 {
00668 emit signalNewMrlReference( newMrlReference );
00669 break;
00670 }
00671 case TIMER_EVENT_NEW_XINE_MESSAGE:
00672 {
00673 emit signalNewXineMessage();
00674 break;
00675 }
00676 case TIMER_EVENT_RESTART_PLAYBACK:
00677 {
00678 PlayMRL( currentMRL, currentTitle, false );
00679 slotChangePosition( savedPos );
00680 break;
00681 }
00682 case TIMER_EVENT_RESIZE_PARENT:
00683 {
00684 parentWidget()->resize( newParentSize );
00685 break;
00686 }
00687 default: break;
00688 }
00689 }
00690
00691
00692
00693
00694 void QXineWidget::VideoDriverChangedCallback(void* p, xine_cfg_entry_t* entry)
00695 {
00696 if (p == NULL) return;
00697 QXineWidget* vw = (QXineWidget*) p;
00698
00699 int pos, time, length;
00700
00701 debugOut(QString("New video driver: %1").arg(entry->enum_values[entry->num_value]));
00702
00703 bool playing = false;
00704 if (xine_get_status(vw->xineStream) == XINE_STATUS_PLAY)
00705 {
00706 playing = true;
00707 vw->savedPos = 0;
00708 if ( xine_get_pos_length(vw->xineStream, &pos, &time, &length) )
00709 vw->savedPos = pos;
00710 }
00711
00712 xine_close(vw->xineStream);
00713
00714 if (vw->xinePost)
00715 {
00716 debugOut(QString("Dispose visual plugin: %1").arg(vw->visualPluginName));
00717 vw->postAudioSource = xine_get_audio_source (vw->xineStream);
00718 xine_post_wire_audio_port (vw->postAudioSource, vw->audioDriver);
00719 xine_post_dispose (vw->xineEngine, vw->xinePost);
00720 vw->xinePost = NULL;
00721 }
00722
00723 xine_event_dispose_queue(vw->eventQueue);
00724 xine_dispose(vw->xineStream);
00725 xine_close_video_driver(vw->xineEngine, vw->videoDriver);
00726 vw->videoDriver = NULL;
00727
00728 vw->videoDriver = xine_open_video_driver(vw->xineEngine,
00729 entry->enum_values[entry->num_value], XINE_VISUAL_TYPE_X11,
00730 (void *) &(vw->visual));
00731
00732
00733 if (!vw->videoDriver)
00734 {
00735 QApplication::beep();
00736 vw->trackInfoRow = vw->i18n("Error: Can't init new Video Driver %1 - using %2!").arg(entry->enum_values[entry->num_value]).arg(vw->videoDriverName);
00737 vw->postEvent( vw, new QTimerEvent( TIMER_EVENT_NEW_INFO ) );
00738 playing = false;
00739 vw->videoDriver = xine_open_video_driver(vw->xineEngine,
00740 vw->videoDriverName, XINE_VISUAL_TYPE_X11,
00741 (void *) &(vw->visual));
00742 }
00743 else
00744 {
00745 vw->videoDriverName = entry->enum_values[entry->num_value];
00746 vw->trackInfoRow = vw->i18n("Using Video Driver: ") + vw->videoDriverName;
00747 vw->postEvent( vw, new QTimerEvent( TIMER_EVENT_NEW_INFO ) );
00748 }
00749
00750 vw->xineStream = xine_stream_new(vw->xineEngine, vw->audioDriver, vw->videoDriver);
00751 vw->eventQueue = xine_event_new_queue (vw->xineStream);
00752 xine_event_create_listener_thread(vw->eventQueue, &QXineWidget::XineEventListener, p);
00753
00754 if (playing)
00755 vw->postEvent( vw, new QTimerEvent( TIMER_EVENT_RESTART_PLAYBACK ) );
00756 }
00757
00758
00759
00760
00761 void QXineWidget::AudioDriverChangedCallback(void* p, xine_cfg_entry_t* entry)
00762 {
00763 if (p == NULL) return;
00764 QXineWidget* vw = (QXineWidget*) p;
00765
00766 int pos, time, length;
00767
00768 debugOut(QString("New audio driver: %1").arg(entry->enum_values[entry->num_value]));
00769
00770 bool playing = false;
00771 if (xine_get_status(vw->xineStream) == XINE_STATUS_PLAY)
00772 {
00773 playing = true;
00774 vw->savedPos = 0;
00775 if ( xine_get_pos_length(vw->xineStream, &pos, &time, &length) )
00776 vw->savedPos = pos;
00777 }
00778
00779 xine_close(vw->xineStream);
00780
00781 if (vw->xinePost)
00782 {
00783 debugOut(QString("Dispose visual plugin: %1").arg(vw->visualPluginName));
00784 vw->postAudioSource = xine_get_audio_source (vw->xineStream);
00785 xine_post_wire_audio_port (vw->postAudioSource, vw->audioDriver);
00786 xine_post_dispose (vw->xineEngine, vw->xinePost);
00787 vw->xinePost = NULL;
00788 }
00789
00790 xine_event_dispose_queue(vw->eventQueue);
00791 xine_dispose(vw->xineStream);
00792 xine_close_audio_driver(vw->xineEngine, vw->audioDriver);
00793 vw->audioDriver = NULL;
00794
00795 vw->audioDriver = xine_open_audio_driver(vw->xineEngine, entry->enum_values[entry->num_value], NULL);
00796
00797 if (!vw->audioDriver)
00798 {
00799 QApplication::beep();
00800 vw->trackInfoRow = vw->i18n("Error: Can't init new Audio Driver %1 - using %2!").arg(entry->enum_values[entry->num_value]).arg(vw->audioDriverName);
00801 vw->postEvent( vw, new QTimerEvent( TIMER_EVENT_NEW_INFO ) );
00802 playing = false;
00803 vw->audioDriver = xine_open_audio_driver(vw->xineEngine, vw->audioDriverName, NULL);
00804 }
00805 else
00806 {
00807 vw->audioDriverName = entry->enum_values[entry->num_value];
00808 vw->trackInfoRow = vw->i18n("Using Audio Driver: ") + vw->audioDriverName;
00809 vw->postEvent( vw, new QTimerEvent( TIMER_EVENT_NEW_INFO ) );
00810 }
00811
00812 vw->xineStream = xine_stream_new(vw->xineEngine, vw->audioDriver, vw->videoDriver);
00813 vw->eventQueue = xine_event_new_queue (vw->xineStream);
00814 xine_event_create_listener_thread(vw->eventQueue, &QXineWidget::XineEventListener, p);
00815
00816 if (playing)
00817 vw->postEvent( vw, new QTimerEvent( TIMER_EVENT_RESTART_PLAYBACK ) );
00818 }
00819
00820
00821
00822
00823
00824
00825 void QXineWidget::run()
00826 {
00827 debugOut("Start event loop...\n");
00828
00829 XEvent event;
00830
00831 while( xineRunning )
00832 {
00833 XNextEvent ( xineDisplay, &event );
00834 XLockDisplay( xineDisplay );
00835
00836 if (event.type == Expose)
00837 {
00838 if (event.xexpose.count == 0)
00839 {
00840 xine_gui_send_vo_data (xineStream, XINE_GUI_SEND_EXPOSE_EVENT, &event);
00841 }
00842 }
00843
00844 XUnlockDisplay( xineDisplay );
00845 }
00846
00847 debugOut("Exiting event loop...\n");
00848 }
00849
00850
00851
00852
00853
00854
00855
00856 void QXineWidget::polish()
00857 {
00858 if (!startXineManual)
00859 {
00860 if (!InitXine()) emit signalQuit();
00861 }
00862 }
00863
00864 bool QXineWidget::InitXine()
00865 {
00866 if (xineRunning) return true;
00867
00868 bool cmdlAudioEnum = false, cmdlVideoEnum = false;
00869
00870 GlobalPosChanged();
00871
00872
00873
00874 if (!XInitThreads ())
00875 {
00876 QApplication::beep();
00877 messageBoxError(0, i18n("XInitThreads failed!"));
00878 return false;
00879 }
00880
00881 xineDisplay = XOpenDisplay( getenv("DISPLAY") );
00882
00883 if (!xineDisplay)
00884 {
00885 QApplication::beep();
00886 messageBoxError(0, i18n("Failed to connect to X-Server!"));
00887 return false;
00888 }
00889
00890 xineScreen = DefaultScreen( xineDisplay );
00891 xineWindow = winId();
00892
00893 XLockDisplay( xineDisplay );
00894
00895 XSelectInput( xineDisplay, xineWindow, ExposureMask );
00896
00897
00898
00899 double resHor = DisplayWidth( xineDisplay, xineScreen )*1000 / DisplayWidthMM( xineDisplay, xineScreen );
00900 double resVer = DisplayHeight( xineDisplay, xineScreen )*1000 / DisplayHeightMM( xineDisplay, xineScreen );
00901
00902 displayRatio = resVer / resHor;
00903
00904
00905 debugOut(QString("Display aspect ratio (v/h): %1").arg(displayRatio));
00906
00907 XUnlockDisplay( xineDisplay );
00908
00909
00910
00911 debugOut(QString("Using xine version %1\n").arg(xine_get_version_string()));
00912
00913 xineEngine = xine_new();
00914 if (!xineEngine)
00915 {
00916 QApplication::beep();
00917 messageBoxError(0, i18n("Can't init xine Engine!"));
00918 return false;
00919 }
00920
00921 if (xineVerbose)
00922 xine_engine_set_param( xineEngine, XINE_ENGINE_PARAM_VERBOSITY, 99 );
00923
00924
00925
00926 configFile = QDir::homeDirPath();
00927 configFile.append("/.kaffeine/config");
00928
00929 if (QFile::exists(configFile))
00930 xine_config_load (xineEngine, configFile);
00931 else
00932 warningOut("No config file found, will create one...\n");
00933
00934
00935 debugOut("Post-init xine engine\n");
00936 xine_init(xineEngine);
00937
00940 const char* const* drivers = NULL;
00941 char** audioChoices = NULL;
00942 int i = 0;
00943
00944 drivers = xine_list_audio_output_plugins (xineEngine);
00945 audioChoices = new char*[15];
00946 for(i = 0; i < 15; i++) audioChoices[i] = new char[10];
00947 audioChoices[0] = const_cast<char*>("auto");
00948 i = 0;
00949 while(drivers[i])
00950 {
00951 audioChoices[i+1] = (char*)drivers[i];
00952 if (preferedAudio == drivers[i]) cmdlAudioEnum = true;
00953 i++;
00954 }
00955 audioChoices[i+1] = NULL;
00956 if (preferedAudio == "auto") cmdlAudioEnum = true;
00957
00958 char* audioInfo = new char[200];
00959 strcpy(audioInfo, i18n("Audiodriver to use (default: auto)").local8Bit() );
00960 i = xine_config_register_enum(xineEngine, "gui.audiodriver", 0,
00961 audioChoices, audioInfo, NULL, 10, &QXineWidget::AudioDriverChangedCallback, this);
00962
00963 if (cmdlAudioEnum)
00964 audioDriverName = preferedAudio;
00965 else
00966 audioDriverName = audioChoices[i];
00967
00968 debugOut(QString("Use audio driver %1\n").arg(audioDriverName));
00969
00970 i = 0;
00971 char** videoChoices = NULL;
00972 drivers = xine_list_video_output_plugins (xineEngine);
00973 videoChoices = new char*[15];
00974 for(i = 0; i < 15; i++) videoChoices[i] = new char[10];
00975 i = 0;
00976 videoChoices[0] = const_cast<char*>("auto");
00977 while(drivers[i])
00978 {
00979 videoChoices[i+1] = (char*)drivers[i];
00980 if (preferedVideo == drivers[i]) cmdlVideoEnum = true;
00981 i++;
00982 }
00983 videoChoices[i+1] = NULL;
00984 if (preferedVideo == "auto") cmdlVideoEnum = true;
00985
00986 char* videoInfo = new char[200];
00987 strcpy( videoInfo, i18n("Videodriver to use (default: auto)").local8Bit() );
00988 i = xine_config_register_enum(xineEngine, "gui.videodriver", 0,
00989 videoChoices, videoInfo, NULL, 10, &QXineWidget::VideoDriverChangedCallback, this);
00990
00991 if (cmdlVideoEnum)
00992 videoDriverName = preferedVideo;
00993 else
00994 videoDriverName = videoChoices[i];
00995
00996 debugOut(QString("Use video driver %1\n").arg(videoDriverName));
00997
00998
00999
01000
01001 visual.display = xineDisplay;
01002 visual.screen = xineScreen;
01003 visual.d = xineWindow;
01004 visual.dest_size_cb = &QXineWidget::DestSizeCallback;
01005 visual.frame_output_cb = &QXineWidget::FrameOutputCallback;
01006 visual.user_data = (void*)this;
01007
01008 debugOut("Init video driver\n");
01009
01010 videoDriver = xine_open_video_driver(xineEngine,
01011 videoDriverName, XINE_VISUAL_TYPE_X11,
01012 (void *) &(visual));
01013 if (!videoDriver)
01014 {
01015 QApplication::beep();
01016 messageBoxError(0, i18n("Can't init Video Driver!") + " (" + videoDriverName + ")");
01017 return false;
01018 }
01019
01020
01021 debugOut("Init audio driver\n");
01022
01023 audioDriver = xine_open_audio_driver (xineEngine, audioDriverName, NULL);
01024 if (!audioDriver)
01025 {
01026 QApplication::beep();
01027 messageBoxError(0, i18n("Can't init Audio Driver!")+ " (" + audioDriverName + ")");
01028 return false;
01029 }
01030
01031
01032
01033 xineStream = xine_stream_new(xineEngine, audioDriver, videoDriver);
01034 if (!xineStream)
01035 {
01036 QApplication::beep();
01037 messageBoxError(0, i18n("Can't create a new xine Stream!"));
01038 return false;
01039 }
01040
01043 eventQueue = xine_event_new_queue (xineStream);
01044 xine_event_create_listener_thread(eventQueue, &QXineWidget::XineEventListener, (void*)this);
01045
01046
01047 setLogoFile();
01048
01051 #ifdef HAVE_XTEST
01052 int a,b,c,d;
01053 haveXTest = XTestQueryExtension(x11Display(), &a, &b, &c, &d);
01054 if (haveXTest)
01055 xTestKeycode = XKeysymToKeycode(x11Display(), XK_Shift_L);
01056
01057 #endif
01058
01059
01060 debugOut("xine init successful\n");
01061 xineRunning = true;
01062
01064 start();
01065
01066 parentWidget()->polish();
01067
01068 return true;
01069 }
01070
01071 void QXineWidget::setLogoFile()
01072 {
01073
01074 }
01075
01076
01077
01078
01079
01080
01081 bool QXineWidget::PlayMRL(const QString& mrl, const QString& title, bool returnInfo)
01082 {
01083 lengthInfoTimer.stop();
01084
01085
01086
01087
01088 emit signalNewInfo(i18n("Opening..."));
01089 setCursor(QCursor(Qt::WaitCursor));
01090
01091 currentMRL = mrl;
01092
01093
01094 extraInfo = QString::null;
01095 QString ref;
01096
01097 for (int i = 1; i <= mrl.contains('#'); i++)
01098 {
01099 ref = mrl.section('#', i, i);
01100 if (ref.section(':', 0, 0) == "subtitle")
01101 extraInfo = extraInfo + " ** " + i18n("Subtitles: ") + ref.section(':', 1);
01102 if (ref.section(':', 0, 0) == "save")
01103 extraInfo = extraInfo + " ** " + i18n("Save as: ") + ref.section(':', 1);
01104 }
01105
01106 debugOut(QString("Playing: %1").arg(currentMRL.local8Bit()));
01107
01108 if (!xine_open(xineStream, currentMRL.local8Bit() ))
01109 {
01110 SendXineError( returnInfo );
01111 setCursor(QCursor(Qt::ArrowCursor));
01112 return false;
01113 }
01114
01115
01116
01117 if ( (xine_get_stream_info (xineStream, XINE_STREAM_INFO_HAS_AUDIO)) &&
01118 (!xine_get_stream_info (xineStream, XINE_STREAM_INFO_HAS_VIDEO)) )
01119 {
01120
01121 if (visualPluginName && (!xinePost))
01122 {
01123 debugOut(QString("Init visual plugin: %1").arg(visualPluginName));
01124 xinePost = xine_post_init (xineEngine, visualPluginName, 0,
01125 &audioDriver,
01126 &videoDriver);
01127
01128 postAudioSource = xine_get_audio_source (xineStream);
01129 postInput = (xine_post_in_t*)xine_post_input (xinePost, const_cast<char*>("audio in"));
01130 xine_post_wire (postAudioSource, postInput);
01131 }
01132 }
01133 else
01134 {
01135 if (xinePost)
01136 {
01137 debugOut(QString("Dispose visual plugin: %1").arg(visualPluginName));
01138 postAudioSource = xine_get_audio_source (xineStream);
01139 xine_post_wire_audio_port (postAudioSource, audioDriver);
01140 xine_post_dispose (xineEngine, xinePost);
01141 xinePost = NULL;
01142 }
01143 }
01144
01145
01146
01147 if (!xine_play(xineStream, 0,0))
01148 {
01149 SendXineError( returnInfo );
01150 setCursor(QCursor(Qt::ArrowCursor));
01151 return false;
01152 }
01153
01154
01155 if (xine_get_stream_info(xineStream, XINE_STREAM_INFO_HAS_CHAPTERS))
01156 emit signalHasChapters(true);
01157 else
01158 emit signalHasChapters(false);
01159
01160
01163 currentTitle = title;
01164
01165 if ( (title.contains('.')) || (title.contains(":/")) )
01166 {
01167 QString metaTitle = QString::fromLocal8Bit( xine_get_meta_info(xineStream, XINE_META_INFO_TITLE) );
01168 if ( (metaTitle) && (!metaTitle.isEmpty()) )
01169 {
01170 QString metaArtist = QString::fromLocal8Bit(xine_get_meta_info(xineStream, XINE_META_INFO_ARTIST));
01171 QString metaAlbum = QString::fromLocal8Bit(xine_get_meta_info(xineStream, XINE_META_INFO_ALBUM));
01172 QString metaTrack = "";
01173 QString metaInfo = metaString;
01174 metaInfo.replace( "artist", metaArtist );
01175 metaInfo.replace( "title", metaTitle );
01176 metaInfo.replace( "album", metaAlbum );
01177 metaInfo.replace( "track", metaTrack );;
01178 currentTitle = metaInfo;
01179 if ((metaInfo != title) && (returnInfo))
01180 {
01181 emit signalMetaInfo(metaInfo);
01182 }
01183 }
01184 if (returnInfo)
01185 {
01186 QString length = GetLengthInfo();
01187 if (!length.isNull())
01188 emit signalLengthInfo( length );
01189 else
01190 lengthInfoTimer.start( 1000 );
01191 }
01192 }
01193
01194 trackInfoRow = currentTitle;
01195
01196 QString streamInfo = GetStreamInfo();
01197 if (returnInfo)
01198 {
01199 emit signalStreamInfo(streamInfo);
01200 }
01201
01202 streamInfo = streamInfo + extraInfo;
01203
01204 trackInfoRow.append( streamInfo.prepend(" ** ") );
01205 emit signalNewInfo(trackInfoRow);
01206
01207 slotSetAudioChannel(0);
01208
01209 posTimer.start(500);
01210
01211 setCursor(QCursor(Qt::ArrowCursor));
01212
01213 emit signalShowOSD(currentTitle);
01214
01215 return true;
01216 }
01217
01218
01219
01220
01221 void QXineWidget::SendXineError( bool returnInfo )
01222 {
01223 QString error;
01224 int errCode = xine_get_error(xineStream);
01225
01226 switch (errCode)
01227 {
01228 case XINE_ERROR_NO_INPUT_PLUGIN:
01229 case XINE_ERROR_NO_DEMUX_PLUGIN:
01230 {
01231 error = i18n("No plugin found to handle this resource");
01232 break;
01233 }
01234 case XINE_ERROR_DEMUX_FAILED:
01235 {
01236 error = i18n("Resource seems to be broken");
01237 break;
01238 }
01239 case XINE_ERROR_MALFORMED_MRL:
01240 {
01241 error = i18n("Requested resource does not exist");
01242 break;
01243 }
01244 case XINE_ERROR_INPUT_FAILED:
01245 {
01246 error = i18n("Resource can not be opened");
01247 break;
01248 }
01249 default:
01250 {
01251 error = i18n("Generic error");
01252 break;
01253 }
01254 }
01255
01256 emit signalNewInfo( i18n("Error: ") + error );
01257
01258 if (returnInfo)
01259 {
01260 emit signalStreamInfo( error );
01261 emit signalLengthInfo( i18n("*Error*") );
01262 }
01263 }
01264
01265
01266
01267
01268
01269 void QXineWidget::GetVisualPlugins(QStringList& visuals) const
01270 {
01271 const char* const* plugins = xine_list_post_plugins_typed(xineEngine, XINE_POST_TYPE_AUDIO_VISUALIZATION);
01272
01273 for (int i = 0; plugins[i]; i++)
01274 {
01275 visuals << plugins[i];
01276 }
01277 }
01278
01279
01280
01281
01282 void QXineWidget::SetVisualPlugin(const QString& visual)
01283 {
01284 if ( visualPluginName == visual ) return;
01285
01286 debugOut(QString("New visualization plugin: %1").arg(visual));
01287
01288 if (visual == "none")
01289 visualPluginName = QString::null;
01290 else
01291 visualPluginName = visual;
01292
01293 if (xinePost)
01294 {
01295 xine_post_out_t *pp;
01296
01297 pp = xine_get_audio_source (xineStream);
01298 xine_post_wire_audio_port (pp, audioDriver);
01299 xine_post_dispose (xineEngine, xinePost);
01300 xinePost = NULL;
01301 }
01302
01303
01304
01305 if ( (xine_get_status( xineStream ) == XINE_STATUS_PLAY)
01306 && (!xine_get_stream_info(xineStream, XINE_STREAM_INFO_HAS_VIDEO)) && (visualPluginName) )
01307 {
01308
01309 xinePost = xine_post_init (xineEngine, visualPluginName, 0, &audioDriver, &videoDriver);
01310 postAudioSource = xine_get_audio_source(xineStream);
01311 postInput = (xine_post_in_t*)xine_post_input(xinePost, const_cast<char*>("audio in"));
01312 xine_post_wire( postAudioSource, postInput );
01313 }
01314 }
01315
01316
01317
01318
01319
01320 void QXineWidget::GetAutoplayPlugins(QStringList& autoPlayList) const
01321 {
01322 char** pluginIds = NULL;
01323 int i = 0;
01324
01325 pluginIds = (char**)xine_get_autoplay_input_plugin_ids(xineEngine);
01326
01327 while(pluginIds[i])
01328 {
01329 autoPlayList << pluginIds[i];
01330
01331 autoPlayList << xine_get_input_plugin_description(xineEngine, pluginIds[i]);
01332 i++;
01333 }
01334 }
01335
01336
01337 bool QXineWidget::GetAutoplayPluginMrl(const QString& plugin, QStringList& list)
01338 {
01339 char** mrls = NULL;
01340 int num;
01341 int i = 0;
01342
01343 mrls = xine_get_autoplay_mrls(xineEngine, plugin, &num);
01344
01345 if (mrls)
01346 {
01347 while (mrls[i])
01348 {
01349 list << mrls[i];
01350 i++;
01351 }
01352
01353 return true;
01354 }
01355 else
01356 {
01357 QString error(i18n("Error: No "));
01358 error.append(plugin);
01359 error.append(i18n(", or wrong path to device."));
01360 signalNewInfo(error);
01361 return false;
01362 }
01363 }
01364
01365
01366 void QXineWidget::slotSetVolume(int vol)
01367 {
01368 xine_set_param(xineStream, XINE_PARAM_AUDIO_VOLUME, -vol);
01369 }
01370
01371
01372 void QXineWidget::mouseMoveEvent(QMouseEvent* mev)
01373 {
01374 if (!xineRunning) return;
01375
01376
01377
01378 if (cursor().shape() == Qt::BlankCursor)
01379 {
01380 setCursor(QCursor(Qt::ArrowCursor));
01381 }
01382
01383 x11_rectangle_t rect;
01384 xine_event_t event;
01385 xine_input_data_t input;
01386
01387 rect.x = mev->x();
01388 rect.y = mev->y();
01389 rect.w = 0;
01390 rect.h = 0;
01391
01392 xine_gui_send_vo_data (xineStream,
01393 XINE_GUI_SEND_TRANSLATE_GUI_TO_VIDEO,
01394 (void*)&rect);
01395
01396 event.type = XINE_EVENT_INPUT_MOUSE_MOVE;
01397 event.data = &input;
01398 event.data_length = sizeof(input);
01399 input.button = 0;
01400 input.x = rect.x;
01401 input.y = rect.y;
01402 xine_event_send (xineStream, &event);
01403 }
01404
01405
01406 void QXineWidget::mousePressEvent(QMouseEvent* mev)
01407 {
01408 if (!xineRunning) return;
01409 int cur = cursor().shape();
01410
01411
01412
01413 if (mev->button() == Qt::MidButton)
01414 emit signalToggleFullscreen();
01415
01416 if (mev->button() == Qt::RightButton)
01417 {
01418 if ( (cur == Qt::ArrowCursor) || (cur == Qt::BlankCursor) )
01419 {
01420 emit signalShowContextMenu(mev->globalPos());
01421 return;
01422 }
01423 }
01424
01425 if (mev->button() == Qt::LeftButton)
01426 {
01427 if ( (cur == Qt::ArrowCursor) || (cur == Qt::BlankCursor) )
01428 {
01429 emit signalShowFullscreenPanel(mev->globalPos());
01430 return;
01431 }
01432
01433 x11_rectangle_t rect;
01434 xine_event_t event;
01435 xine_input_data_t input;
01436
01437 rect.x = mev->x();
01438 rect.y = mev->y();
01439 rect.w = 0;
01440 rect.h = 0;
01441
01442 xine_gui_send_vo_data (xineStream,
01443 XINE_GUI_SEND_TRANSLATE_GUI_TO_VIDEO,
01444 (void*)&rect);
01445
01446 event.type = XINE_EVENT_INPUT_MOUSE_BUTTON;
01447 event.data = &input;
01448 event.data_length = sizeof(input);
01449 input.button = 1;
01450 input.x = rect.x;
01451 input.y = rect.y;
01452 xine_event_send (xineStream, &event);
01453 }
01454 }
01455
01456
01457 void QXineWidget::PlayNextChapter() const
01458 {
01459
01460 xine_event_t xev;
01461
01462 xev.type = XINE_EVENT_INPUT_NEXT;
01463 xev.data = NULL;
01464 xev.data_length = 0;
01465
01466 xine_event_send(xineStream, &xev);
01467 }
01468
01469
01470 void QXineWidget::PlayPreviousChapter() const
01471 {
01472
01473 xine_event_t xev;
01474
01475 xev.type = XINE_EVENT_INPUT_PREVIOUS;
01476 xev.data = NULL;
01477 xev.data_length = 0;
01478
01479 xine_event_send(xineStream, &xev);
01480 }
01481
01482
01483 void QXineWidget::slotStopPlayback()
01484 {
01485 posTimer.stop();
01486 }
01487
01488
01489 void QXineWidget::SetDevice(const QString& device)
01490 {
01491 debugOut(QString("Set CD/VCD/DVD device to %1\n").arg(device));
01492 devicePath = device;
01493
01494 xine_cfg_entry_t config;
01495
01496 xine_config_lookup_entry (xineEngine, "input.cdda_device", &config);
01497 cachedCDPath = config.str_value;
01498 config.str_value = (char*)device.latin1();
01499 xine_config_update_entry (xineEngine, &config);
01500
01501 xine_config_lookup_entry (xineEngine, "input.vcd_device", &config);
01502 cachedVCDPath = config.str_value;
01503 config.str_value = (char*)device.latin1();
01504 xine_config_update_entry (xineEngine, &config);
01505
01506 xine_config_lookup_entry (xineEngine, "input.dvd_device", &config);
01507 cachedDVDPath = config.str_value;
01508 config.str_value = (char*)device.latin1();
01509 xine_config_update_entry (xineEngine, &config);
01510 }
01511
01512
01513 void QXineWidget::SetStreamSaveDir(const QString& dir)
01514 {
01515 xine_cfg_entry_t config;
01516
01517 if (!xine_config_lookup_entry (xineEngine, "misc.save_dir", &config)) return;
01518
01519 debugOut(QString("Set misc.save_dir to: %1").arg(dir));
01520 config.str_value = (char*)dir.latin1();
01521 xine_config_update_entry (xineEngine, &config);
01522 }
01523
01524
01525 const QString QXineWidget::GetStreamSaveDir()
01526 {
01527 xine_cfg_entry_t config;
01528
01529 if (!xine_config_lookup_entry (xineEngine, "misc.save_dir", &config)) return QString::null;
01530
01531 return QString( config.str_value );
01532 }
01533
01534
01535 void QXineWidget::SetBroadcasterPort(const uint port)
01536 {
01537 debugOut(QString("Set broadcaster port to ").arg(port));
01538 xine_set_param(xineStream, XINE_PARAM_BROADCASTER_PORT, port);
01539 }
01540
01541
01542 void QXineWidget::slotSpeedPause()
01543 {
01544 xine_set_param(xineStream, XINE_PARAM_SPEED, XINE_SPEED_PAUSE);
01545 posTimer.stop();
01546 signalNewInfo("Pause.");
01547 }
01548
01549
01550 void QXineWidget::slotSpeedNormal()
01551 {
01552 xine_set_param(xineStream, XINE_PARAM_SPEED, XINE_SPEED_NORMAL);
01553 posTimer.start(500);
01554 signalNewInfo(trackInfoRow);
01555 }
01556
01557
01558 QString QXineWidget::GetSupportedExtensions() const
01559 {
01560 return xine_get_file_extensions( xineEngine );
01561 }
01562
01563
01564 void QXineWidget::slotSetAudioChannel(int ch)
01565 {
01566 xine_set_param(xineStream, XINE_PARAM_AUDIO_CHANNEL_LOGICAL, ch-1);
01567 }
01568
01569
01570 void QXineWidget::slotSetSubtitleChannel(int ch)
01571 {
01572 xine_set_param(xineStream, XINE_PARAM_SPU_CHANNEL, ch-1);
01573 }
01574
01575
01576 void QXineWidget::slotSetFileSubtitles(QString newMRL)
01577 {
01578 int pos;
01579 int time;
01580 int length;
01581
01582 QString oldMRL = currentMRL;
01583
01584 if ( !xine_get_pos_length(xineStream, &pos, &time, &length) )
01585 {
01586 debugOut("No valid stream position information");
01587 return;
01588 }
01589
01590 if (xine_get_status(xineStream) == XINE_STATUS_PLAY)
01591 xine_stop(xineStream);
01592
01593 posTimer.stop();
01594
01595 if(!PlayMRL(newMRL, currentTitle, true))
01596 PlayMRL(oldMRL, currentTitle, true);
01597
01598 slotChangePosition(pos);
01599 }
01600
01601
01602 void QXineWidget::slotTogglePlayMode()
01603 {
01604 switch (playMode)
01605 {
01606 case NORMAL_PLAY:
01607 {
01608 playMode = REPEAT_PLAY;
01609 break;
01610 }
01611 case REPEAT_PLAY:
01612 {
01613 playMode = PERCENT_PLAY;
01614 break;
01615 }
01616 case PERCENT_PLAY:
01617 {
01618 playMode = NORMAL_PLAY;
01619 break;
01620 }
01621 }
01622 }
01623
01624
01625 void QXineWidget::slotGetPosition()
01626 {
01627 if (!xineRunning) return;
01628
01629 int pos;
01630 int time;
01631 int length;
01632
01633 double perc;
01634
01635 QString t;
01636
01637 if ( !xine_get_pos_length(xineStream, &pos, &time, &length) )
01638 {
01639 debugOut("No valid stream position information");
01640 return;
01641 }
01642
01643 switch (playMode)
01644 {
01645 case PERCENT_PLAY:
01646 {
01647 perc = pos/655,35;
01648 time = (int) (perc);
01649 if ( (time < 0) || (time > 100) )
01650 {
01651 emit signalNewPosition( pos , " --% " );
01652 return;
01653 }
01654 t = t.setNum(time);
01655 t = QString(" %1%2 ").arg(t).arg("%");
01656 emit signalNewPosition( pos, t );
01657 break;
01658 }
01659 case REPEAT_PLAY:
01660 {
01661 time = length - time;
01662 }
01663 case NORMAL_PLAY:
01664 {
01665 if (time < 0)
01666 {
01667 emit signalNewPosition( pos , "-:--:--" );
01668 return;
01669 }
01670 emit signalNewPosition( pos, msToTimeString(time) );
01671 break;
01672 }
01673 }
01674 }
01675
01676
01677 void QXineWidget::slotChangePosition(int pos)
01678 {
01679 if (!xineRunning) return;
01680
01681 int pause = !xine_get_param(xineStream, XINE_PARAM_SPEED);
01682 if ( (xine_get_status(xineStream) == XINE_STATUS_PLAY) && (xine_get_stream_info(xineStream, XINE_STREAM_INFO_SEEKABLE)) )
01683 {
01684 posTimer.stop();
01685 xine_play(xineStream, pos, 0);
01686 posTimer.start(500,false);
01687 }
01688
01689 if (pause)
01690 slotSpeedPause();
01691 }
01692
01693
01694 void QXineWidget::slotEject()
01695 {
01696 xine_eject(xineStream);
01697 }
01698
01699 void QXineWidget::slotEnableAutoresize(bool enable)
01700 {
01701 autoresizeEnabled = enable;
01702 if (!autoresizeEnabled)
01703 {
01704 videoFrameHeight = 0;
01705 videoFrameWidth = 0;
01706 }
01707 }
01708
01709
01710 void QXineWidget::slotToggleDeinterlace()
01711 {
01712 if (xine_get_param(xineStream, XINE_PARAM_VO_DEINTERLACE))
01713 xine_set_param(xineStream, XINE_PARAM_VO_DEINTERLACE, false);
01714 else
01715 xine_set_param(xineStream, XINE_PARAM_VO_DEINTERLACE, true);
01716 }
01717
01718
01719 void QXineWidget::slotAspectRatioAuto()
01720 {
01721 xine_set_param(xineStream, XINE_PARAM_VO_ASPECT_RATIO, XINE_VO_ASPECT_AUTO);
01722 }
01723
01724
01725 void QXineWidget::slotAspectRatio4_3()
01726 {
01727 xine_set_param(xineStream, XINE_PARAM_VO_ASPECT_RATIO, XINE_VO_ASPECT_4_3);
01728 }
01729
01730
01731 void QXineWidget::slotAspectRatio16_9()
01732 {
01733 xine_set_param(xineStream, XINE_PARAM_VO_ASPECT_RATIO, XINE_VO_ASPECT_ANAMORPHIC);
01734 }
01735
01736
01737 void QXineWidget::slotAspectRatioSquare()
01738 {
01739 xine_set_param(xineStream, XINE_PARAM_VO_ASPECT_RATIO, XINE_VO_ASPECT_SQUARE);
01740 }
01741
01742
01743 void QXineWidget::slotZoomOut()
01744 {
01745 if ((currentZoom - 5) >= 100)
01746 {
01747 currentZoom -= 5;
01748 xine_set_param(xineStream, XINE_PARAM_VO_ZOOM_X, currentZoom);
01749 xine_set_param(xineStream, XINE_PARAM_VO_ZOOM_Y, currentZoom);
01750 }
01751 }
01752
01753
01754 void QXineWidget::slotZoomIn()
01755 {
01756 if ((currentZoom + 5) <= XINE_VO_ZOOM_MAX)
01757 {
01758 currentZoom += 5;
01759 xine_set_param(xineStream, XINE_PARAM_VO_ZOOM_X, currentZoom);
01760 xine_set_param(xineStream, XINE_PARAM_VO_ZOOM_Y, currentZoom);
01761 }
01762 }
01763
01764
01765 void QXineWidget::slotZoomOff()
01766 {
01767 xine_set_param(xineStream, XINE_PARAM_VO_ZOOM_X, 100);
01768 xine_set_param(xineStream, XINE_PARAM_VO_ZOOM_Y, 100);
01769 currentZoom = 100;
01770 }
01771
01772
01773 QString QXineWidget::GetStreamInfo()
01774 {
01775 QString streamInfo;
01776
01777 streamInfo = streamInfo + "(" + xine_get_meta_info(xineStream, XINE_META_INFO_INPUT_PLUGIN) + ") ";
01778
01779 if (xine_get_stream_info(xineStream, XINE_STREAM_INFO_HAS_VIDEO))
01780 {
01781 streamInfo.append(xine_get_meta_info(xineStream, XINE_META_INFO_VIDEOCODEC));
01782 streamInfo.append(" (");
01783 streamInfo.append( QString::number(xine_get_stream_info(xineStream, XINE_STREAM_INFO_VIDEO_WIDTH)) );
01784 streamInfo.append("x");
01785 streamInfo.append( QString::number(xine_get_stream_info(xineStream, XINE_STREAM_INFO_VIDEO_HEIGHT)) );
01786 streamInfo.append(") ");
01787 }
01788
01789 if (xine_get_stream_info(xineStream, XINE_STREAM_INFO_HAS_AUDIO))
01790 {
01791 streamInfo.append(xine_get_meta_info(xineStream, XINE_META_INFO_AUDIOCODEC));
01792 streamInfo.append(" (");
01793 streamInfo.append( QString::number(xine_get_stream_info(xineStream, XINE_STREAM_INFO_AUDIO_BITRATE)/1000) );
01794 streamInfo.append("kb)");
01795 }
01796
01797 return streamInfo;
01798 }
01799
01800
01801 QString QXineWidget::GetLengthInfo()
01802 {
01803 int pos, time, length;
01804
01805 bool ok = xine_get_pos_length(xineStream, &pos, &time, &length);
01806
01807 if ( (ok) && (length > 0) )
01808 {
01809 return msToTimeString(length);
01810 }
01811
01812 return QString::null;
01813 }
01814
01815
01816 void QXineWidget::slotEmitLengthInfo()
01817 {
01818 QString length = GetLengthInfo();
01819 if (!length.isNull())
01820 {
01821 lengthInfoTimer.stop();
01822 emit signalLengthInfo( length );
01823 }
01824 }
01825
01826
01827 void QXineWidget::slotSetScreensaverTimeout( int ssTimeout )
01828 {
01829 screensaverTimeout = ssTimeout;
01830
01831 #ifdef HAVE_XTEST
01832 if (screensaverTimeout > 0)
01833 screensaverTimer.start(screensaverTimeout* 60000);
01834 else
01835 screensaverTimer.stop();
01836 #endif
01837 }
01838
01839
01840 int QXineWidget::GetScreensaverTimeout() const
01841 {
01842 return screensaverTimeout;
01843 }
01844
01845
01846 void QXineWidget::GlobalPosChanged()
01847 {
01848 QPoint g = mapToGlobal(QPoint(0,0));
01849 globX = g.x();
01850 globY = g.y();
01851
01852 }
01853
01854
01855 void QXineWidget::slotFakeKeyEvent()
01856 {
01857 #ifdef HAVE_XTEST
01858
01859
01860
01861 if (haveXTest)
01862 {
01863 XTestFakeKeyEvent(x11Display(), xTestKeycode, true, CurrentTime);
01864 XTestFakeKeyEvent(x11Display(), xTestKeycode, false, CurrentTime);
01865 XSync(x11Display(), false);
01866 }
01867
01868 #endif
01869
01870 }
01871
01872
01873 const xine_t* const QXineWidget::GetXineEngine()const
01874 {
01875 return xineEngine;
01876 }
01877
01878
01879
01880
01881 void QXineWidget::GetVideoSettings(int& hue, int& sat, int& contrast, int& bright,
01882 int& audioAmp, int& avOffset, int& spuOffset) const
01883 {
01884 hue = xine_get_param(xineStream, XINE_PARAM_VO_HUE);
01885 sat = xine_get_param(xineStream, XINE_PARAM_VO_SATURATION);
01886 contrast = xine_get_param(xineStream, XINE_PARAM_VO_CONTRAST);
01887 bright = xine_get_param(xineStream, XINE_PARAM_VO_BRIGHTNESS);
01888
01889 audioAmp = xine_get_param(xineStream, XINE_PARAM_AUDIO_AMP_LEVEL);
01890 avOffset = xine_get_param(xineStream, XINE_PARAM_AV_OFFSET);
01891 spuOffset = xine_get_param(xineStream, XINE_PARAM_SPU_OFFSET);
01892 }
01893
01894
01895 void QXineWidget::slotSetHue(int hue)
01896 {
01897 xine_set_param(xineStream, XINE_PARAM_VO_HUE, hue);
01898 }
01899
01900
01901 void QXineWidget::slotSetSaturation(int sat)
01902 {
01903 xine_set_param(xineStream, XINE_PARAM_VO_SATURATION, sat);
01904 }
01905
01906
01907 void QXineWidget::slotSetContrast(int contrast)
01908 {
01909 xine_set_param(xineStream, XINE_PARAM_VO_CONTRAST, contrast);
01910 }
01911
01912
01913 void QXineWidget::slotSetBrightness(int bright)
01914 {
01915 xine_set_param(xineStream, XINE_PARAM_VO_BRIGHTNESS, bright);
01916 }
01917
01918
01919 void QXineWidget::slotSetAudioAmp(int amp)
01920 {
01921 xine_set_param(xineStream, XINE_PARAM_AUDIO_AMP_LEVEL, amp);
01922 }
01923
01924
01925 void QXineWidget::slotSetAVOffset(int av)
01926 {
01927 xine_set_param(xineStream, XINE_PARAM_AV_OFFSET, av);
01928 }
01929
01930
01931 void QXineWidget::slotSetSpuOffset(int spu)
01932 {
01933 xine_set_param(xineStream, XINE_PARAM_SPU_OFFSET, spu);
01934 }
01935
01936
01937
01938
01939
01940 void QXineWidget::slotSetEq30(int val)
01941 {
01942 xine_set_param(xineStream, XINE_PARAM_EQ_30HZ, -val);
01943 }
01944
01945
01946 void QXineWidget::slotSetEq60(int val)
01947 {
01948 xine_set_param(xineStream, XINE_PARAM_EQ_60HZ, -val);
01949 }
01950
01951
01952 void QXineWidget::slotSetEq125(int val)
01953 {
01954 xine_set_param(xineStream, XINE_PARAM_EQ_125HZ, -val);
01955 }
01956
01957
01958 void QXineWidget::slotSetEq250(int val)
01959 {
01960 xine_set_param(xineStream, XINE_PARAM_EQ_250HZ, -val);
01961 }
01962
01963
01964 void QXineWidget::slotSetEq500(int val)
01965 {
01966 xine_set_param(xineStream, XINE_PARAM_EQ_500HZ, -val);
01967 }
01968
01969
01970 void QXineWidget::slotSetEq1k(int val)
01971 {
01972 xine_set_param(xineStream, XINE_PARAM_EQ_1000HZ, -val);
01973 }
01974
01975
01976 void QXineWidget::slotSetEq2k(int val)
01977 {
01978 xine_set_param(xineStream, XINE_PARAM_EQ_2000HZ, -val);
01979 }
01980
01981
01982 void QXineWidget::slotSetEq4k(int val)
01983 {
01984 xine_set_param(xineStream, XINE_PARAM_EQ_4000HZ, -val);
01985 }
01986
01987
01988 void QXineWidget::slotSetEq8k(int val)
01989 {
01990 xine_set_param(xineStream, XINE_PARAM_EQ_8000HZ, -val);
01991 }
01992
01993
01994 void QXineWidget::slotSetEq16k(int val)
01995 {
01996 xine_set_param(xineStream, XINE_PARAM_EQ_16000HZ, -val);
01997 }
01998
01999
02000
02001 void QXineWidget::slotMenu1()
02002 {
02003 xine_event_t xev;
02004 xev.type = XINE_EVENT_INPUT_MENU1;
02005 xev.data = NULL;
02006 xev.data_length = 0;
02007
02008 xine_event_send(xineStream, &xev);
02009 }
02010
02011
02012 void QXineWidget::slotMenu2()
02013 {
02014 xine_event_t xev;
02015 xev.type = XINE_EVENT_INPUT_MENU2;
02016 xev.data = NULL;
02017 xev.data_length = 0;
02018
02019 xine_event_send(xineStream, &xev);
02020
02021 }
02022
02023
02024 void QXineWidget::slotMenu3()
02025 {
02026 xine_event_t xev;
02027 xev.type = XINE_EVENT_INPUT_MENU3;
02028 xev.data = NULL;
02029 xev.data_length = 0;
02030
02031 xine_event_send(xineStream, &xev);
02032 }
02033
02034
02035 void QXineWidget::slotMenu4()
02036 {
02037 xine_event_t xev;
02038 xev.type = XINE_EVENT_INPUT_MENU4;
02039 xev.data = NULL;
02040 xev.data_length = 0;
02041
02042 xine_event_send(xineStream, &xev);
02043 }
02044
02045
02046 void QXineWidget::slotMenu5()
02047 {
02048 xine_event_t xev;
02049 xev.type = XINE_EVENT_INPUT_MENU5;
02050 xev.data = NULL;
02051 xev.data_length = 0;
02052
02053 xine_event_send(xineStream, &xev);
02054 }
02055
02056
02057 void QXineWidget::slotMenu6()
02058 {
02059 xine_event_t xev;
02060 xev.type = XINE_EVENT_INPUT_MENU6;
02061 xev.data = NULL;
02062 xev.data_length = 0;
02063
02064 xine_event_send(xineStream, &xev);
02065 }
02066
02067
02068 void QXineWidget::slotMenu7()
02069 {
02070 xine_event_t xev;
02071 xev.type = XINE_EVENT_INPUT_MENU7;
02072 xev.data = NULL;
02073 xev.data_length = 0;
02074
02075 xine_event_send(xineStream, &xev);
02076 }
02077
02078
02079 void QXineWidget::keyPressEvent(QKeyEvent *e)
02080 {
02081 if (keyboardGrabber() == this)
02082 {
02083 xine_event_t xev;
02084 xev.data = NULL;
02085 xev.data_length = 0;
02086
02087 switch(e->key())
02088 {
02089 case Qt::Key_Up:
02090 xev.type = XINE_EVENT_INPUT_UP;
02091 break;
02092 case Qt::Key_Down:
02093 xev.type = XINE_EVENT_INPUT_DOWN;
02094 break;
02095 case Qt::Key_Left:
02096 xev.type = XINE_EVENT_INPUT_LEFT;
02097 break;
02098 case Qt::Key_Right:
02099 xev.type = XINE_EVENT_INPUT_RIGHT;
02100 break;
02101 case Qt::Key_Return:
02102 xev.type = XINE_EVENT_INPUT_SELECT;
02103 break;
02104 default:
02105 break;
02106 }
02107 xine_event_send(xineStream, &xev);
02108
02109 e->accept();
02110 return;
02111 }
02112 e->ignore();
02113 }
02114
02115
02116
02117
02118
02119
02120 void QXineWidget::StartMouseHideTimer()
02121 {
02122 mouseHideTimer.start(5000);
02123 }
02124
02125
02126 void QXineWidget::StopMouseHideTimer()
02127 {
02128 mouseHideTimer.stop();
02129 }
02130
02131
02132 void QXineWidget::slotHideMouse()
02133 {
02134 if (cursor().shape() == Qt::ArrowCursor)
02135 {
02136 setCursor(QCursor(Qt::BlankCursor));
02137 }
02138 }
02139
02140
02141
02142
02143
02144
02145
02146 void QXineWidget::GetScreenshot(uchar*& rgb32BitData, int& videoWidth, int& videoHeight, double& scaleFactor) const
02147 {
02148
02149 uint8_t *yuv = NULL, *y = NULL, *u = NULL, *v =NULL;
02150
02151 int width, height, ratio, format;
02152 double desired_ratio, image_ratio;
02153
02154 if (!xine_get_current_frame (xineStream, &width, &height, &ratio, &format, NULL))
02155 return;
02156
02157 yuv = new uint8_t[((width+8) * (height+1) * 2)];
02158 if (yuv == NULL)
02159 {
02160 errorOut("Not enough memory to make screenshot!");
02161 return;
02162 }
02163
02164 xine_get_current_frame (xineStream, &width, &height, &ratio, &format, yuv);
02165
02166 videoWidth = width;
02167 videoHeight = height;
02168
02169
02170
02171
02172
02173 switch (format) {
02174 case XINE_IMGFMT_YUY2:
02175 {
02176 uint8_t *yuy2 = yuv;
02177
02178 yuv = new uint8_t[(width * height * 2)];
02179 if (yuv == NULL)
02180 {
02181
02182 return;
02183 }
02184 y = yuv;
02185 u = yuv + width * height;
02186 v = yuv + width * height * 5 / 4;
02187
02188 yuy2Toyv12 (y, u, v, yuy2, width, height);
02189
02190 delete [] yuy2;
02191 }
02192 break;
02193 case XINE_IMGFMT_YV12:
02194 y = yuv;
02195 u = yuv + width * height;
02196 v = yuv + width * height * 5 / 4;
02197
02198 break;
02199 default:
02200 {
02201 warningOut(QString("Screenshot: Format %1 not supported!\n").arg((char*)&format));
02202 delete [] yuv;
02203 return;
02204 }
02205 }
02206
02207
02208
02209
02210
02211 rgb32BitData = yv12ToRgb (y, u, v, width, height);
02212
02213
02214 image_ratio = (double) width / (double) height;
02215
02216
02217 switch (ratio) {
02218 case XINE_VO_ASPECT_ANAMORPHIC:
02219
02220 desired_ratio = 16.0 /9.0;
02221 break;
02222 case XINE_VO_ASPECT_DVB:
02223 desired_ratio = 2.11/1.0;
02224 break;
02225 case XINE_VO_ASPECT_SQUARE:
02226
02227 desired_ratio = image_ratio;
02228 break;
02229 default:
02230 warningOut(QString("Screenshot: Unknown aspect ratio: %1 - using 4:3").arg(ratio));
02231 case XINE_VO_ASPECT_4_3:
02232 desired_ratio = 4.0 / 3.0;
02233 break;
02234 }
02235
02236 scaleFactor = desired_ratio / image_ratio;
02237
02238 delete [] yuv;
02239 }
02240
02241
02242
02243
02244
02245
02246
02247
02248
02249
02250
02251
02252
02253