diff options
Diffstat (limited to 'kaffeine/src/input')
311 files changed, 56874 insertions, 0 deletions
diff --git a/kaffeine/src/input/Makefile.am b/kaffeine/src/input/Makefile.am new file mode 100644 index 0000000..75b2ab7 --- /dev/null +++ b/kaffeine/src/input/Makefile.am @@ -0,0 +1,21 @@ +noinst_LTLIBRARIES = libkaffeineinput.la + +if with_dvb + DVB_SUBDIR = dvb +endif + +SUBDIRS = . dvbclient audiobrowser disc $(DVB_SUBDIR) + +INCLUDES = -I$(top_srcdir)/kaffeine/src \ + -I$(top_srcdir)/kaffeine/src/player-parts/kaffeine-part $(all_includes) + +noinst_HEADERS = kaffeineinput.h + +METASOURCES = AUTO + +libkaffeineinput_la_SOURCES = kaffeineinput.cpp + +libkaffeineinput_la_LDFLAGS = $(KDE_RPATH) \ + $(all_libraries) + +libkaffeineinput_la_LIBADD = $(top_builddir)/kaffeine/src/player-parts/kaffeine-part/libkaffeinepart.la diff --git a/kaffeine/src/input/audiobrowser/Makefile.am b/kaffeine/src/input/audiobrowser/Makefile.am new file mode 100644 index 0000000..b743ccd --- /dev/null +++ b/kaffeine/src/input/audiobrowser/Makefile.am @@ -0,0 +1,28 @@ +METASOURCES = AUTO + +noinst_LTLIBRARIES = libkaffeineaudiobrowser.la + +INCLUDES = -I$(top_srcdir)/kaffeine/src/input/ \ + -I$(top_srcdir)/kaffeine/src/ \ + $(all_includes) \ + -I$(top_srcdir)/kaffeine/src/player-parts/kaffeine-part + +libkaffeineaudiobrowser_la_SOURCES = playlist.cpp \ + playlistitem.cpp \ + urllistview.cpp \ + googlefetcher.cpp \ + googlefetcherdialog.cpp + +KDE_CXXFLAGS = $(USE_EXCEPTIONS) + +libkaffeineaudiobrowser_la_LDFLAGS = $(KDE_RPATH) \ + $(all_libraries) \ + -L$(top_srcdir)/kaffeine/src/input + +libkaffeineaudiobrowser_la_LIBADD = $(top_builddir)/kaffeine/src/input/libkaffeineinput.la \ + $(top_builddir)/kaffeine/src/player-parts/kaffeine-part/libkaffeinepart.la \ + $(LIB_KHTML) + +# this is where the XML-GUI resource file goes +shellrcdir = $(kde_datadir)/kaffeine +shellrc_DATA = kaffeineplaylist.rc diff --git a/kaffeine/src/input/audiobrowser/googlefetcher.cpp b/kaffeine/src/input/audiobrowser/googlefetcher.cpp new file mode 100644 index 0000000..fe88d14 --- /dev/null +++ b/kaffeine/src/input/audiobrowser/googlefetcher.cpp @@ -0,0 +1,282 @@ +/* + * googlefetcher.cpp + * + * Copyright (C) 2004 Nathan Toone <nathan@toonetown.com> + * Copyright (C) 2006 Christophe Thommeret <hftom@free.fr> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include <dom/html_document.h> +#include <dom/html_misc.h> +#include <dom/html_table.h> +#include <dom/dom_exception.h> +#include <dom/dom2_traversal.h> + +#include <khtml_part.h> + +#include <klocale.h> +#include <kinputdialog.h> +#include <kurl.h> +#include <kio/netaccess.h> + +#include "googlefetcher.h" +#include "googlefetcherdialog.h" + +GoogleImage::GoogleImage(QString thumbURL, QString size) +{ + // thumbURL is in the following format - and we can regex the imageURL + // images?q=tbn:hKSEWNB8aNcJ:www.styxnet.com/deyoung/styx/stygians/cp_portrait.jpg + m_thumbURL = thumbURL.replace("\"",""); + m_imageURL = thumbURL.remove(QRegExp("^.*q=tbn:[^:]*:")).replace("\"",""); + m_size = size.replace("pixels - ", "\n(") + ")"; +} + + +GoogleFetcher::GoogleFetcher( QString artist, QString album, bool gallery ) +{ + m_artist = artist; + m_album = album; + m_searchString = artist+" "+album; + encoding = 0; + galleryImage=galleryPage=0; + galleryMode = gallery; +} + +void GoogleFetcher::slotLoadImageURLs(GoogleFetcher::ImageSize size) +{ + if(m_loadedQuery == m_searchString && m_loadedSize == size) + return; + + m_imageList.clear(); + + KURL url("http://images.google.com/images"); + if ( encoding ) + url.addQueryItem("q", m_searchString,encoding); + else + url.addQueryItem("q", m_searchString); + + switch (size) { + case XLarge: + url.addQueryItem("imgsz", "xlarge|xxlarge"); + break; + case Large: + url.addQueryItem("imgsz", "large"); + break; + case Medium: + url.addQueryItem("imgsz", "medium"); + break; + case Small: + url.addQueryItem("imgsz", "small"); + break; + case Icon: + url.addQueryItem("imgsz", "icon"); + break; + default: + break; + } + + m_loadedQuery = m_searchString; + m_loadedSize = size; + + // We don't normally like exceptions but missing DOMException will kill + // JuK rather abruptly whether we like it or not so we don't really have a + // choice if we're going to screen-scrape Google. + try { + + KHTMLPart part; + + // Create empty document. + + part.begin(); + part.end(); + + DOM::Document search = part.document(); + search.setAsync(false); // Grab the document before proceeding. + + kdDebug() << "Performing Google Search: " << url << endl; + + search.load(url.url()+QString("&start=%1&sa=N").arg(galleryPage*20) ); + + QString text = search.toString().string(); + + if ( !hasImageResults(text) ) { + kdDebug() << "Search returned no results.\n"; + emit signalNewSearch(m_imageList); + return; + } + + // Go through each of the top (table) nodes + + int pos = text.find("/imgres?imgurl"); + int tpos; + QString s, c; + while ( pos>-1 ) { + text = text.right( text.length()-pos-14 ); + tpos = text.find("&h="); + text = text.right( text.length()-tpos-3 ); + tpos = text.find("&w="); + c = "pixels - " + text.left( tpos ); + text = text.right( text.length()-tpos-3 ); + tpos = text.find("&sz="); + c = c + "x" + text.left( tpos ); + tpos = text.find("src="); + text = text.right( text.length()-tpos-4 ); + if ( (tpos=text.find("width="))==-1 ) + break; + s = text.left( tpos-1 ); + text = text.right( text.length()-tpos ); + if ( (tpos=text.find("></a>"))==-1 ) + break; + m_imageList.append(GoogleImage(s, c)); + pos = text.find("/imgres?imgurl"); + } + } // try + catch (DOM::DOMException &e) + { + kdError() << "Caught DOM Exception: " << e.code << endl; + } + catch (...) + { + kdError() << "Caught unknown exception.\n"; + } + + emit signalNewSearch(m_imageList); +} + +QImage GoogleFetcher::galleryNext( bool &end ) +{ + QString file; + QImage image; + m_loadedSize = All; + int tries = 0; + end = false; + + while ( tries<3 ) { + if( m_imageList.isEmpty() ) { + if ( tries==0 ) { + encoding = 0; + m_loadedQuery = ""; + ++tries; + displayWaitMessage(); + } + else if ( tries==1 ) { + encoding = 4; // try iso8859-1 + m_loadedQuery = ""; + ++tries; + kdDebug() << "Trying iso8859-1" << endl; + displayWaitMessage(); + } + else { + end = true; + return QImage(); + } + } + else { + if(KIO::NetAccess::download( m_imageList[galleryImage].imageURL(), file, 0)) + image = QImage(file); + else + image = QImage(); + ++galleryImage; + if ( galleryImage==(int)m_imageList.count() ) { + m_imageList.clear(); + galleryImage = 0; + ++galleryPage; + } + KIO::NetAccess::removeTempFile(file); + return image; + } + } + return QImage(); +} + +QPixmap GoogleFetcher::pixmap( bool forceFetch ) +{ + bool chosen = false; + m_loadedSize = All; + int tries = 0; + + encoding = 0; + displayWaitMessage(); + + QPixmap pixmap; + + while(!chosen) { + + if(m_imageList.isEmpty()) + switch(tries) { + case 0: + encoding = 4; // try iso8859-1 + m_loadedQuery = ""; + ++tries; + kdDebug() << "Trying iso8859-1" << endl; + displayWaitMessage(); + break; + default : + if ( forceFetch == true ) + chosen = !requestNewSearchTerms(true); + else + chosen = true; + } + else { + GoogleFetcherDialog dialog("google", m_imageList, m_artist, m_album, 0); + connect(&dialog, SIGNAL(sizeChanged(GoogleFetcher::ImageSize)), + this, SLOT(slotLoadImageURLs(GoogleFetcher::ImageSize))); + connect(this, SIGNAL(signalNewSearch(GoogleImageList &)), + &dialog, SLOT(refreshScreen(GoogleImageList &))); + dialog.exec(); + pixmap = dialog.result(); + chosen = dialog.takeIt(); + + if(dialog.newSearch()) + requestNewSearchTerms(); + } + } + return pixmap; +} + +void GoogleFetcher::displayWaitMessage() +{ + //KStatusBar *statusBar = static_cast<KMainWindow *>(kapp->mainWidget())->statusBar(); + //statusBar->message(i18n("Searching for Images. Please Wait...")); + slotLoadImageURLs(); + //statusBar->clear();*/ +} + +bool GoogleFetcher::requestNewSearchTerms(bool noResults) +{ + bool ok; + m_searchString = KInputDialog::getText(i18n("Cover Downloader"), + noResults ? + i18n("No matching images found, please enter new search terms:") : + i18n("Enter new search terms:"), + m_searchString, &ok); + if(ok && !m_searchString.isEmpty()) + displayWaitMessage(); + else + m_searchString = m_loadedQuery; + + return ok; +} + +bool GoogleFetcher::hasImageResults( QString &doc ) +{ + if ( !doc.contains( "/imgres?imgurl" ) ) + return false; + + return true; +} + +#include "googlefetcher.moc" diff --git a/kaffeine/src/input/audiobrowser/googlefetcher.h b/kaffeine/src/input/audiobrowser/googlefetcher.h new file mode 100644 index 0000000..7c90091 --- /dev/null +++ b/kaffeine/src/input/audiobrowser/googlefetcher.h @@ -0,0 +1,91 @@ +/* + * googlefetcher.h + * + * Copyright (C) 2004 Nathan Toone <nathan@toonetown.com> + * Copyright (C) 2006 Christophe Thommeret <hftom@free.fr> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef GOOGLEFETCHER_H +#define GOOGLEFETCHER_H + +#include <kdialogbase.h> + +#include <qpixmap.h> +#include <qstringlist.h> +#include <qregexp.h> + +namespace DOM { + class HTMLDocument; +} + +class KURL; + +class GoogleImage +{ +public: + GoogleImage(QString thumbURL = QString::null, QString size = QString::null); + + QString imageURL() const { return m_imageURL; } + QString thumbURL() const { return m_thumbURL; } + QString size() const { return m_size; } + +private: + QString m_imageURL; + QString m_thumbURL; + QString m_size; +}; + +typedef QValueList<GoogleImage> GoogleImageList; + +class GoogleFetcher : public QObject +{ + Q_OBJECT + +public: + enum ImageSize { All, Icon, Small, Medium, Large, XLarge }; + + GoogleFetcher( QString artist, QString album, bool gallery=false ); + QPixmap pixmap( bool forceFetch = false ); + QImage galleryNext( bool &end ); + +signals: + void signalNewSearch(GoogleImageList &images); + +private: + void displayWaitMessage(); + bool requestNewSearchTerms(bool noResults = false); + + // Returns true if there are results in the search, otherwise returns false. + bool hasImageResults( QString &doc ); + +private slots: + void slotLoadImageURLs(GoogleFetcher::ImageSize size = All); + +private: + QString m_artist, m_album; + QString m_searchString; + QString m_loadedQuery; + ImageSize m_loadedSize; + GoogleImageList m_imageList; + uint m_selectedIndex; + int encoding; + int galleryImage; + int galleryPage; + bool galleryMode; +}; + +#endif /* GOOGLEFETCHER_H */ diff --git a/kaffeine/src/input/audiobrowser/googlefetcherdialog.cpp b/kaffeine/src/input/audiobrowser/googlefetcherdialog.cpp new file mode 100644 index 0000000..bda3853 --- /dev/null +++ b/kaffeine/src/input/audiobrowser/googlefetcherdialog.cpp @@ -0,0 +1,254 @@ +/* + * googlefetcherdialog.cpp + * + * Copyright (C) 2004 Nathan Toone <nathan@toonetown.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include <kapplication.h> +#include <kio/netaccess.h> +#include <klocale.h> +#include <kdebug.h> +#include <kmessagebox.h> +#include <kcombobox.h> + +#include <qhbox.h> +#include <qimage.h> +#include <qlabel.h> +#include <qpushbutton.h> +#include <qeventloop.h> + +#include "googlefetcherdialog.h" + +GoogleFetcherDialog::GoogleFetcherDialog(const QString &name, + const GoogleImageList &imageList, + const QString &artist, + const QString &album, + QWidget *parent) : + KDialogBase(parent, name.latin1(), true, QString::null, + Ok | Cancel | User1 , NoDefault, true), + m_pixmap(QPixmap()), + m_imageList(imageList), + m_takeIt(false), + m_newSearch(false) +{ + m_artist = artist; + m_album = album; + disableResize(); + + QHBox *mainBox = new QHBox(this); + m_iconWidget = new KIconView(mainBox); + m_iconWidget->setResizeMode(QIconView::Adjust); + m_iconWidget->setSelectionMode(QIconView::Extended); + m_iconWidget->setSpacing(10); + m_iconWidget->setMode(KIconView::Execute); + m_iconWidget->setFixedSize(500,550); + m_iconWidget->arrangeItemsInGrid(); + m_iconWidget->setItemsMovable(FALSE); + + QHBox *imgSize = new QHBox(actionButton(User1)->parentWidget()); + //QLabel *label = new QLabel(imgSize); + //label->setText(i18n("Image size:")); + + KComboBox *combo = new KComboBox(imgSize); + combo->insertItem(i18n("All Sizes")); + combo->insertItem(i18n("Very Small")); + combo->insertItem(i18n("Small")); + combo->insertItem(i18n("Medium")); + combo->insertItem(i18n("Large")); + combo->insertItem(i18n("Very Large")); + combo->setCurrentItem(0); + connect(combo, SIGNAL(activated(int)), this, SLOT(imgSizeChanged(int))); + connect(m_iconWidget, SIGNAL( executed(QIconViewItem*) ), this, SLOT(slotOk())); + + imgSize->adjustSize(); + setMainWidget(mainBox); + setButtonText(User1, i18n("New Search")); +} + +GoogleFetcherDialog::~GoogleFetcherDialog() +{ + +} + +void GoogleFetcherDialog::setLayout() +{ + setCaption(QString("%1 - %2 (%3)") + .arg(m_artist) + .arg(m_album) + .arg(m_imageList.size())); + + m_iconWidget->clear(); + for(uint i = 0; i < m_imageList.size(); i++) + new CoverIconViewItem(m_iconWidget, m_imageList[i]); + + adjustSize(); +} + +void GoogleFetcherDialog::setImageList(const GoogleImageList &imageList) +{ + m_imageList=imageList; +} + +//////////////////////////////////////////////////////////////////////////////// +// public slots +//////////////////////////////////////////////////////////////////////////////// + +void GoogleFetcherDialog::refreshScreen(GoogleImageList &imageList) +{ + setImageList(imageList); + setLayout(); +} + +int GoogleFetcherDialog::exec() +{ + setLayout(); + return KDialogBase::exec(); +} + +void GoogleFetcherDialog::slotOk() +{ + uint selectedIndex = m_iconWidget->index(m_iconWidget->currentItem()); + m_pixmap = pixmapFromURL(m_imageList[selectedIndex].imageURL()); + + if(m_pixmap.isNull()) { + KMessageBox::sorry(this, + i18n("The cover you have selected is unavailable. Please select another."), + i18n("Cover Unavailable")); + QPixmap blankPix; + blankPix.resize(80, 80); + blankPix.fill(); + m_iconWidget->currentItem()->setPixmap(blankPix, true, true); + return; + } + + m_takeIt = true; + m_newSearch = false; + hide(); +} + +void GoogleFetcherDialog::slotCancel() +{ + m_takeIt = true; + m_newSearch = false; + m_pixmap = QPixmap(); + hide(); +} + +void GoogleFetcherDialog::slotUser1() +{ + m_takeIt = false; + m_newSearch = true; + m_pixmap = QPixmap(); + hide(); +} + +void GoogleFetcherDialog::imgSizeChanged(int index) +{ + GoogleFetcher::ImageSize imageSize = GoogleFetcher::All; + switch (index) { + case 1: + imageSize = GoogleFetcher::Icon; + break; + case 2: + imageSize = GoogleFetcher::Small; + break; + case 3: + imageSize = GoogleFetcher::Medium; + break; + case 4: + imageSize=GoogleFetcher::Large; + break; + case 5: + imageSize=GoogleFetcher::XLarge; + break; + default: + break; + } + emit sizeChanged(imageSize); +} + +QPixmap GoogleFetcherDialog::fetchedImage(uint index) const +{ + return (index > m_imageList.count()) ? QPixmap() : pixmapFromURL(m_imageList[index].imageURL()); +} + +QPixmap GoogleFetcherDialog::pixmapFromURL(const KURL &url) const +{ + QString file; + + if(KIO::NetAccess::download(url, file, 0)) { + QPixmap pixmap = QPixmap(file); + KIO::NetAccess::removeTempFile(file); + return pixmap; + } + KIO::NetAccess::removeTempFile(file); + return QPixmap(); +} + +//////////////////////////////////////////////////////////////////////////////// +// CoverIconViewItem +//////////////////////////////////////////////////////////////////////////////// + +CoverIconViewItem::CoverIconViewItem(QIconView *parent, const GoogleImage &image) : + QObject(parent), KIconViewItem(parent, parent->lastItem(), image.size()), m_job(0) +{ + // Set up the iconViewItem + + QPixmap mainMap; + mainMap.resize(80, 80); + mainMap.fill(); + setPixmap(mainMap, true, true); + + // Start downloading the image. + + m_job = KIO::get(image.thumbURL(), false, false); + connect(m_job, SIGNAL(result(KIO::Job *)), this, SLOT(imageResult(KIO::Job *))); + connect(m_job, SIGNAL(data(KIO::Job *, const QByteArray &)), + this, SLOT(imageData(KIO::Job *, const QByteArray &))); +} + +CoverIconViewItem::~CoverIconViewItem() +{ + if(m_job) { + m_job->kill(); + + // Drain results issued by KIO before being deleted, + // and before deleting the job. + kapp->eventLoop()->processEvents(QEventLoop::ExcludeUserInput); + + delete m_job; + } +} + +void CoverIconViewItem::imageData(KIO::Job *, const QByteArray &data) +{ + int currentSize = m_buffer.size(); + m_buffer.resize(currentSize + data.size(), QGArray::SpeedOptim); + memcpy(&(m_buffer.data()[currentSize]), data.data(), data.size()); +} + +void CoverIconViewItem::imageResult(KIO::Job *job) +{ + if(job->error()) + return; + + QPixmap iconImage(m_buffer); + iconImage = QImage(iconImage.convertToImage()).smoothScale(80, 80); + setPixmap(iconImage, true, true); +} + +#include "googlefetcherdialog.moc" diff --git a/kaffeine/src/input/audiobrowser/googlefetcherdialog.h b/kaffeine/src/input/audiobrowser/googlefetcherdialog.h new file mode 100644 index 0000000..48ec70c --- /dev/null +++ b/kaffeine/src/input/audiobrowser/googlefetcherdialog.h @@ -0,0 +1,98 @@ +/* + * googlefetcherdialog.h + * + * Copyright (C) 2004 Nathan Toone <nathan@toonetown.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef GOOGLEFETCHERDIALOG_H +#define GOOGLEFETCHERDIALOG_H + +#include <kiconview.h> +#include <kio/job.h> + +#include "googlefetcher.h" + +class KURL; + +class GoogleFetcherDialog : public KDialogBase +{ + Q_OBJECT + +public: + GoogleFetcherDialog(const QString &name, + const GoogleImageList &urlList, + const QString &artist, + const QString &album, + QWidget *parent = 0); + + virtual ~GoogleFetcherDialog(); + + QPixmap result() const { return m_pixmap; } + bool takeIt() const { return m_takeIt; } + bool newSearch() const { return m_newSearch; } + + void setLayout(); + void setImageList(const GoogleImageList &urlList); + +public slots: + int exec(); + void refreshScreen(GoogleImageList &list); + +signals: + void sizeChanged(GoogleFetcher::ImageSize); + +protected slots: + void slotOk(); + void slotCancel(); + void slotUser1(); + void imgSizeChanged(int index); + +private: + QPixmap fetchedImage(uint index) const; + QPixmap pixmapFromURL(const KURL &url) const; + + QPixmap m_pixmap; + GoogleImageList m_imageList; + KIconView *m_iconWidget; + bool m_takeIt; + bool m_newSearch; + QString m_artist, m_album; +}; + +namespace KIO +{ + class TransferJob; +} + +class CoverIconViewItem : public QObject, public KIconViewItem +{ + Q_OBJECT + +public: + CoverIconViewItem(QIconView *parent, const GoogleImage &image); + ~CoverIconViewItem(); + +private slots: + void imageData(KIO::Job *job, const QByteArray &data); + void imageResult(KIO::Job* job); + +private: + QByteArray m_buffer; + QGuardedPtr<KIO::TransferJob> m_job; +}; + +#endif /* GOOGLEFETCHERDIALOG_H */ diff --git a/kaffeine/src/input/audiobrowser/kaffeineplaylist.rc b/kaffeine/src/input/audiobrowser/kaffeineplaylist.rc new file mode 100644 index 0000000..a274d74 --- /dev/null +++ b/kaffeine/src/input/audiobrowser/kaffeineplaylist.rc @@ -0,0 +1,17 @@ +<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd"> +<kpartgui name="kaffeineplaylist" version="4"> +<MenuBar> + <Menu name="playlist"><text>Play&list</text> + <Action name="playlist_shuffle"/> + <Action name="playlist_repeat"/> + <Action name="playlist_autocover"/> + <Action name="playlist_showplayer"/> + <Separator/> + <Action name="playlist_clear"/> + <Action name="playlist_new"/> + <Action name="playlist_load"/> + <Action name="playlist_save_as"/> + <Action name="playlist_remove"/> + </Menu> +</MenuBar> +</kpartgui> diff --git a/kaffeine/src/input/audiobrowser/playlist.cpp b/kaffeine/src/input/audiobrowser/playlist.cpp new file mode 100644 index 0000000..480d70b --- /dev/null +++ b/kaffeine/src/input/audiobrowser/playlist.cpp @@ -0,0 +1,2365 @@ +/* + * playlist.cpp + * + * Copyright (C) 2003-2005 Jürgen Kofler <kaffeine@gmx.net> + * Copyright (C) 2005-2006 Christophe Thommeret <hftom@free.fr> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include <krandomsequence.h> +#include <kapplication.h> +#include <kglobalsettings.h> +#include <kiconloader.h> +#include <klocale.h> +#include <kfiledialog.h> +#include <kmessagebox.h> +#include <kmimetype.h> +#include <kstandarddirs.h> +#include <kmessagebox.h> +#include <kio/netaccess.h> +#include <kio/job.h> +#include <kprogress.h> +#include <kfilemetainfo.h> +#include <klineedit.h> +#include <kcombobox.h> +#include <kpushbutton.h> +#include <kdebug.h> +#include <kurl.h> +#include <kaccel.h> +#include <dcopref.h> +#include <ktoolbar.h> +#include <kcolordialog.h> +#include <kurlcombobox.h> +#include <kurlcompletion.h> + +#include <qlabel.h> +#include <qclipboard.h> +#include <qdragobject.h> +#include <qstringlist.h> +#include <qdom.h> +#include <qxml.h> +#include <qregexp.h> +#include <qheader.h> +#include <qlayout.h> +#include <qpixmap.h> +#include <qvbox.h> +#include <qlistbox.h> +#include <qtextcodec.h> +#include <qtooltip.h> +#include <qinputdialog.h> +#include <qtimer.h> +#include <qwhatsthis.h> +#include <qpopupmenu.h> + +#include "googlefetcher.h" +#include "mrl.h" +#include "playlistimport.h" +#include "playlistitem.h" +#include "playlist.h" +#include "playlist.moc" + + + +RollTitle::RollTitle( QWidget *parent ) : QLabel( "I", parent ) +{ + QColorGroup cg = parentWidget()->colorGroup(); + QColor base = cg.base(); + QColor selection = cg.highlight(); + int r = (base.red() + selection.red()) / 2; + int b = (base.blue() + selection.blue()) / 2; + int g = (base.green() + selection.green()) / 2; + back = QColor(r, g, b); + fore = parentWidget()->colorGroup().text(); + setPaletteBackgroundColor( back ); + setPaletteForegroundColor( fore ); + setFrameStyle( QFrame::StyledPanel | QFrame::Sunken ); + title = " ##### "; + titleOffset = 0; + setTitle( title ); + connect( &titleTimer, SIGNAL( timeout() ), this, SLOT( rollTitle() ) ); + titleTimer.start( 50 ); +} + +void RollTitle::setTitle( MRL mrl ) +{ + title = " ##### "; + QString s1 = mrl.artist().stripWhiteSpace(); + QString s2 = mrl.album().stripWhiteSpace(); + QString s3 = mrl.title().stripWhiteSpace(); + if ( !s1.isEmpty() ) + title+= s1+" - "; + if ( !s2.isEmpty() ) + title+= s2+" - "; + if ( s3.isEmpty() ) + title+= mrl.url(); + else + title+= s3; + titleOffset = 0; + setTitle( title ); +} + +void RollTitle::setTitle( QString t ) +{ + QLabel *lab = new QLabel( t, this ); + lab->setFrameStyle( QFrame::StyledPanel | QFrame::Sunken ); + lab->resize( lab->sizeHint() ); + int x = 2*lab->frameWidth(); + titlePix = QPixmap( lab->width()-x, height()-x, -1, QPixmap::BestOptim ); + delete lab; + QPainter p( &titlePix ); + p.fillRect( 0, 0, titlePix.width(), titlePix.height(), back ); + p.setPen( fore ); + p.setFont( font() ); + p.drawText( QRect(0,(titlePix.height()-QFontInfo(font()).pointSize())/2,titlePix.width(),QFontInfo(font()).pointSize()*2), Qt::AlignAuto|Qt::SingleLine, t ); + p.end(); +} + +void RollTitle::rollTitle() +{ + int w = 2*frameWidth(); + QPixmap pix( width()-w, height()-w, -1, QPixmap::BestOptim ); + QPainter p1( &pix ); + p1.fillRect( 0, 0, pix.width(), pix.height(), back ); + p1.end(); + int x = titlePix.width()-titleOffset; + bitBlt( &pix, 0, 0, &titlePix, titleOffset, 0, x, titlePix.height(), CopyROP ); + while ( x<pix.width() ) { + bitBlt( &pix, x, 0, &titlePix, 0, 0, titlePix.width(), titlePix.height(), CopyROP ); + x+= titlePix.width(); + } + ++titleOffset; + if ( titleOffset>titlePix.width() ) + titleOffset = 0; + bitBlt( this, w/2, w/2, &pix, 0, 0, width()-w, height()-w, CopyROP ); +} + +void RollTitle::paintEvent( QPaintEvent *pe ) +{ + QLabel::paintEvent( pe ); + QColorGroup cg = parentWidget()->colorGroup(); + QColor base = cg.base(); + QColor selection = cg.highlight(); + int r = (base.red() + selection.red()) / 2; + int b = (base.blue() + selection.blue()) / 2; + int g = (base.green() + selection.green()) / 2; + back=QColor(r,g,b); + setPaletteBackgroundColor( back ); + fore = parentWidget()->colorGroup().text(); + setPaletteForegroundColor( fore ); + setTitle( title ); +} + + + +struct CoverPopup : public QWidget +{ + CoverPopup(const QPixmap &image, const QPoint &p) : + QWidget(0, 0, WDestructiveClose | WX11BypassWM) + { + QHBoxLayout *layout = new QHBoxLayout(this); + QLabel *label = new QLabel(this); + + layout->addWidget(label); + label->setFrameStyle(QFrame::Box | QFrame::Raised); + label->setLineWidth(1); + label->setPixmap(image); + + setGeometry(p.x(), p.y(), label->width(), label->height()); + show(); + } + virtual void leaveEvent(QEvent *) { close(); } + virtual void mouseReleaseEvent(QMouseEvent *) { close(); } +}; + +CoverFrame::CoverFrame( QWidget *parent ) : QFrame( parent ) +{ + imagePath = ""; + QString path = locate("appdata", "nocover.png"); + if ( !path ) + path = locate("data", "kaffeine/nocover.png"); + noCoverPix.convertFromImage( QImage(path) ); + setPaletteBackgroundPixmap( noCoverPix ); +} + +CoverFrame::~CoverFrame() +{ +} + +void CoverFrame::setCoverPixmap( const QString &path ) +{ + QPixmap pix; + QImage img; + + img = QImage( path ); + if ( !img.isNull() ) { + img = img.smoothScale( 80, 80 ); + pix.convertFromImage( img ); + setPaletteBackgroundPixmap( pix ); + imagePath = path; + } + else { + setPaletteBackgroundPixmap( noCoverPix ); + imagePath = ""; + } +} + +void CoverFrame::popup( const QPixmap &pix ) const +{ + QPoint mouse = QCursor::pos(); + QRect desktop = KApplication::desktop()->screenGeometry(mouse); + int x = mouse.x(); + int y = mouse.y(); + int height = pix.height() + 4; + int width = pix.width() + 4; + + // Detect the right direction to pop up (always towards the center of the + // screen), try to pop up with the mouse pointer 10 pixels into the image in + // both directions. If we're too close to the screen border for this margin, + // show it at the screen edge, accounting for the four pixels (two on each + // side) for the window border. + + if(x - desktop.x() < desktop.width() / 2) + x = (x - desktop.x() < 10) ? desktop.x() : (x - 10); + else + x = (x - desktop.x() > desktop.width() - 10) ? desktop.width() - width +desktop.x() : (x - width + 10); + + if(y - desktop.y() < desktop.height() / 2) + y = (y - desktop.y() < 10) ? desktop.y() : (y - 10); + else + y = (y - desktop.y() > desktop.height() - 10) ? desktop.height() - height + desktop.y() : (y - height + 10); + + new CoverPopup( pix, QPoint(x, y) ); +} + +void CoverFrame::mousePressEvent( QMouseEvent *e ) +{ + int i; + QPixmap pix; + + switch ( e->button() ) { + case LeftButton: { + if ( imagePath.isEmpty() ) + break; + pix.convertFromImage( QImage( imagePath ) ); + if ( !pix.isNull() ) + popup( pix ); + break; + } + case RightButton: { + QPopupMenu pop( this ); + pop.insertItem( i18n("Choose a Cover..."), 1 ); + pop.insertItem( i18n("Gallery..."), 2 ); + i = pop.exec( QCursor::pos() ); + if ( i==1 ) + emit changeCurrentCover(); + else if ( i==2 ) + emit gallery(); + break; + } + default: + break; + } +} + + +PlayList::PlayList( QWidget* parent, QObject *objParent, const char *name ) : KaffeineInput(objParent , name), + m_playTime(0), m_playTimeVisible(0), m_countVisible(0), m_searchSelection(false), + m_metaOnLoading(true), m_sortAscending(true), m_currentEntry(NULL), m_currentRandomListEntry(-1), + m_endless(false), m_random(false), m_useAlternateEncoding(false), m_alternateEncoding("ISO 8859-1") +{ + google = NULL; + + mainWidget = new QVBox( parent ); + //mainWidget->setSizePolicy( QSizePolicy (QSizePolicy::Preferred, QSizePolicy::Preferred) ); + hSplit = new QSplitter( mainWidget ); + hSplit->setOpaqueResize( true ); + panel = new QVBox( hSplit ); + playlist = new QWidget( hSplit ); + hSplit->moveToFirst( panel ); + hSplit->setResizeMode( panel, QSplitter::KeepSize ); + + vSplit = new QSplitter( QSplitter::Vertical, panel ); + vSplit->setOpaqueResize( true ); + QWidget *vb = new QWidget( vSplit ); + KToolBar *tb = new KToolBar( vb ); + QVBoxLayout *v = new QVBoxLayout( vb, 0, 0 ); + v->addWidget( tb ); + tb->setIconSize( 16 ); + + browserComb = new KURLComboBox( KURLComboBox::Directories, true, vb ); + browserComb->setCompletionObject( new KURLCompletion( KURLCompletion::DirCompletion ) ); + browserComb->setAutoDeleteCompletionObject( true ); + browserComb->setMaxItems( 10 ); + browserComb->setFocusPolicy(QWidget::ClickFocus); + + + /* if (!m_medium) + m_combo->lineEdit()->setText( location->path() ); + else + m_combo->lineEdit()->setText( "/" );*/ + + QVBoxLayout *v1 = new QVBoxLayout( 0, 3, 3 ); + v1->addWidget( browserComb ); + fileBrowser = new KDirOperator( KURL("/"), vb ); + fileBrowser->setupMenu( KDirOperator::SortActions|KDirOperator::NavActions|KDirOperator::ViewActions ); + view = new KFileIconView( fileBrowser, "view" ); + view->setSelectionMode( KFile::Multi ); + fileBrowser->setMode( KFile::Files ); + fileBrowser->setView( view ); + fileBrowser->setViewConfig( KGlobal::config(), "PlaylistFileBrowser" ); + fileBrowser->setOnlyDoubleClickSelectsFiles( true ); + v1->addWidget( fileBrowser ); + v->addLayout( v1 ); + + KActionCollection *col = fileBrowser->actionCollection(); + col->action( "up" )->plug( tb ); + col->action( "back" )->plug( tb ); + col->action( "forward" )->plug( tb ); + col->action( "reload" )->plug( tb ); + col->action( "home" )->plug( tb ); + + vSplit->moveToFirst( vb ); + playerBox = new QVBox( vSplit ); + playerBox->setMinimumHeight( 50 ); + playerBox->setMinimumWidth( 200 ); + vSplit->moveToLast( playerBox ); + + m_playlistDirectory = locateLocal("appdata", "playlists"); + m_playlistDirectory.append("/"); + KIO::NetAccess::mkdir(m_playlistDirectory, mainWidget); + kdDebug() << "PLAYLIST" << endl; + + QGridLayout* layout = new QGridLayout( playlist, 4, 2, 3 ); + + m_list = new UrlListView(playlist); + mainWidget->setAcceptDrops(true); + m_list->setHScrollBarMode(KListView::AlwaysOff); + m_list->setItemMargin(2); + m_list->setMargin(0); + m_list->setSelectionMode(QListView::Extended); + m_list->addColumn(""); + m_list->addColumn(i18n("Title")); + m_list->addColumn(i18n("Artist")); + m_list->addColumn(i18n("Album")); + m_list->addColumn(i18n("Track")); + m_list->addColumn(i18n("Length")); + m_list->setShowToolTips(true); + m_list->setColumnWidthMode(MIME_COLUMN, QListView::Manual); + m_list->setColumnWidthMode(TITLE_COLUMN, QListView::Manual); + m_list->setColumnWidthMode(ARTIST_COLUMN, QListView::Manual); + m_list->setColumnWidthMode(ALBUM_COLUMN, QListView::Manual); + m_list->setColumnWidthMode(TRACK_COLUMN, QListView::Manual); + m_list->setColumnWidthMode(LENGTH_COLUMN, QListView::Manual); + m_list->setResizeMode(QListView::NoColumn); + KConfig* config = kapp->config(); + m_list->restoreLayout(config, "Playlist Layout"); + m_list->setFullWidth(true); + m_list->setSorting(-1); + m_list->setDragEnabled(true); + m_list->setAcceptDrops(true); + m_list->setDropVisualizer(true); + m_list->setItemsMovable(true); + m_list->setItemsRenameable(true); + m_list->setRenameable(TITLE_COLUMN); + m_list->setRenameable(ARTIST_COLUMN); + m_list->setRenameable(ALBUM_COLUMN); + m_list->setRenameable(TRACK_COLUMN); + m_list->setAllColumnsShowFocus(true); + m_list->setShowSortIndicator(true); + layout->addMultiCellWidget(m_list, 3, 3, 0, 1); + + coverFrame = new CoverFrame( playlist ); + coverFrame->setFixedWidth( 80 ); + coverFrame->setFixedHeight( 80 ); + layout->addMultiCellWidget(coverFrame, 0, 2, 0, 0); + + QHBoxLayout *h1 = new QHBoxLayout(); + searchBtn = new QToolButton( playlist ); + searchBtn->setAutoRaise( true ); + QToolTip::add( searchBtn, i18n("Search")); + searchBtn->setIconSet( KGlobal::iconLoader()->loadIconSet("locationbar_erase", KIcon::Small) ); + h1->addWidget( searchBtn ); + QLabel* filterLabel = new QLabel(i18n("Filter") + ":", playlist); + h1->addWidget(filterLabel); + m_playlistFilter = new KLineEdit(playlist); + m_playlistFilter->setFocusPolicy(QWidget::ClickFocus); + h1->addWidget(m_playlistFilter); + layout->addLayout( h1, 2, 1 ); + + QHBoxLayout *h2 = new QHBoxLayout(); + QLabel* playlistLabel = new QLabel(i18n("Playlist:"), playlist); + h2->addWidget(playlistLabel); + m_playlistSelector = new KComboBox( playlist ); + m_playlistSelector->setMinimumWidth(10); + m_playlistSelector->setSizePolicy( QSizePolicy (QSizePolicy::MinimumExpanding, QSizePolicy::Preferred) ); + m_playlistSelector->setEditable(true); + m_playlistSelector->setDuplicatesEnabled(false); + m_playlistSelector->setFocusPolicy(QWidget::ClickFocus); + QToolTip::add(m_playlistSelector, i18n("Select the active playlist. To change playlist name edit it and confirm with 'Return'.")); + h2->addWidget(m_playlistSelector); + layout->addLayout( h2, 1, 1 ); + + roller = new RollTitle( playlist ); + layout->addWidget( roller, 0, 1 ); + + KAccel* accel = new KAccel(mainWidget); + accel->insert("Delete selected", Qt::Key_Delete, this, SLOT(slotRemoveSelected())); + + m_isCurrentEntry = UserIcon("playing"); + m_cdPixmap = KGlobal::iconLoader()->loadIcon("cdtrack", KIcon::Small); + + setXMLFile("kaffeineplaylist.rc"); + setupActions(); + + QStrList formats = QImageIO::outputFormats(); + coverImageFormat = "PNG"; + for (int i=0; i<(int)formats.count(); i++ ) { + if ( QString(formats.at(i))=="JPEG" ) { + coverImageFormat = "JPEG"; + break; + } + } + + loadConfig( KGlobal::config() ); + + connect(coverFrame, SIGNAL(changeCurrentCover()), this, SLOT(chooseCurrentCover())); + connect(coverFrame, SIGNAL(gallery()), this, SLOT(showGallery())); + connect(browserComb, SIGNAL(urlActivated( const KURL& )), this, SLOT(setBrowserURL( const KURL& ))); + connect(browserComb, SIGNAL(returnPressed( const QString& )), this, SLOT(setBrowserURL( const QString& ))); + connect(fileBrowser, SIGNAL(urlEntered( const KURL& )), this, SLOT(browserURLChanged( const KURL& ))); + connect(fileBrowser, SIGNAL(fileSelected(const KFileItem*)), this, SLOT(fileSelected(const KFileItem*))); + connect(m_playlistFilter, SIGNAL(textChanged(const QString&)), this, SLOT(slotFindText(const QString&))); + connect( searchBtn, SIGNAL(clicked()), this, SLOT(resetSearch()) ); + connect(m_playlistSelector, SIGNAL(returnPressed(const QString&)), this, SLOT(slotNewPlaylistName(const QString&))); + connect(m_playlistSelector, SIGNAL(activated(int)),this, SLOT(slotPlaylistActivated(int))); + connect(m_list, SIGNAL(dropped(QDropEvent*, QListViewItem*)), this, SLOT(slotDropEvent(QDropEvent*, QListViewItem*))); + connect(m_list, SIGNAL(aboutToMove()), this, SLOT(slotPreDropEvent())); + connect(m_list, SIGNAL(doubleClicked(QListViewItem*)), this, SLOT(slotPlayDirect(QListViewItem*))); + connect(m_list, SIGNAL(returnPressed(QListViewItem*)), this, SLOT(slotPlayDirect(QListViewItem*))); + connect(m_list, SIGNAL(signalCut()), this, SLOT(slotCut())); + connect(m_list, SIGNAL(signalCopy()), this, SLOT(slotCopy())); + connect(m_list, SIGNAL(signalPaste()), this, SLOT(slotPaste())); + connect(m_list, SIGNAL(signalSelectAll()), this, SLOT(slotSelectAll())); + connect(m_list, SIGNAL(signalPlayItem(QListViewItem*)), this, SLOT(slotPlayDirect(QListViewItem*))); + connect(m_list, SIGNAL(signalPlaylistFromSelected()), this, SLOT(slotPlaylistFromSelected())); + connect(m_list, SIGNAL(signalAddToQueue(MRL)), this, SLOT(slotAddToQueue(MRL))); + connect(m_list->header(), SIGNAL(clicked(int)), this, SLOT(slotSort(int))); +} + +void PlayList::togglePanel() +{ + if ( panel->isHidden() ) + panel->show(); + else + panel->hide(); +} + +void PlayList::getTargets( QStringList &uiNames, QStringList &iconNames, QStringList &targetNames ) +{ + uiNames.append( i18n("Play Playlist") ); + iconNames.append( "view_text" ); + targetNames.append( "PLAYLIST" ); +} + +bool PlayList::execTarget( const QString &target ) +{ + if ( target=="PLAYLIST" ) { + emit showMe( this ); + QTimer::singleShot( 100, this, SLOT(startPlaylist()) ); + return true; + } + return false; +} + +void PlayList::setFileFilter( const QString& filter ) +{ + m_fileFilter = filter; + fileBrowser->setNameFilter( m_fileFilter ); +} + +PlayList::~PlayList() +{ + delete m_list; +} + +void PlayList::setupActions() +{ + m_repeat = new KToggleAction(i18n("&Repeat"), 0 , CTRL|Key_E, this, SLOT(slotRepeat()), actionCollection(),"playlist_repeat"); + m_repeat->setStatusText(i18n("Loop playlist")); + m_shuffle = new KToggleAction(i18n("Sh&uffle"), 0 , CTRL|Key_R, this, SLOT(slotShuffle()), actionCollection(),"playlist_shuffle"); + m_shuffle->setStatusText(i18n("Play items in random order")); + m_autoCover = new KToggleAction(i18n("Autodownload covers"), 0 , 0, this, SLOT(slotAutoCover()), actionCollection(),"playlist_autocover"); + m_autoCover->setStatusText(i18n("Automatic dowloading of covers")); + m_showPlayer = new KToggleAction(i18n("Don't switch to player window"), 0 , 0, this, SLOT(slotShowPlayer()), actionCollection(),"playlist_showplayer"); + m_showPlayer->setStatusText(i18n("Don't switch automatically to player window")); + new KAction(i18n("&Clear Current Playlist"), "eraser", 0, this, SLOT(slotClearList()), actionCollection(), "playlist_clear"); + new KAction(i18n("Ne&w Playlist"), "filenew", 0, this, SLOT(slotNewList()), actionCollection(), "playlist_new"); + new KAction(i18n("&Import Playlist..."), "project_open", 0, this, SLOT(slotPlaylistLoad()), actionCollection(), "playlist_load"); + new KAction(i18n("&Save Current Playlist As..."), "filesaveas", 0, this, SLOT(slotPlaylistSaveAs()), actionCollection(), "playlist_save_as"); + new KAction(i18n("Re&move Current Playlist"), "fileclose", 0, this, SLOT(slotPlaylistRemove()), actionCollection(), "playlist_remove"); +} + +void PlayList::slotClearList() +{ + clearList(); +} + +void PlayList::slotRepeat() +{ + setEndless(m_repeat->isChecked()); +} + +void PlayList::slotShuffle() +{ + setRandom(m_shuffle->isChecked()); +} + +void PlayList::slotAutoCover() +{ + m_cover = m_autoCover->isChecked(); +} + +void PlayList::slotShowPlayer() +{ +} + +void PlayList::slotToggleShuffle() +{ + m_shuffle->setChecked(!m_shuffle->isChecked()); + slotShuffle(); +} + +void PlayList::slotPlaylistLoad() +{ + QString path = KFileDialog::getOpenFileName(":kaffeine_openPlaylist", QString("*.kaffeine|") + i18n("Kaffeine Playlists") + "\n*.*|" + i18n("All Files"), 0, i18n("Open Playlist")); + if (path.isEmpty() || (!path.contains(".kaffeine", false))) + return; + + loadPlaylist(path); +} + +void PlayList::slotPlaylistSaveAs() +{ + QString startPath = ":kaffeine_savePlaylist"; + //if (!lastPlaylist.isEmpty()) startPath = lastPlaylist; + QString path = KFileDialog::getSaveFileName(startPath, + QString("*.kaffeine|") + i18n("Kaffeine Playlists") + "\n" + + QString("*.m3u|") + i18n("M3U Playlists") + "\n" + + QString("*.pls|") + i18n("PLS Playlists") + "\n" + + "*.*|" + i18n("All Files"), 0, i18n("Save Playlist")); + + if ( path.isEmpty() ) + return; + if ( path.right(4).lower() == ".m3u" ) { + exportM3UPlaylist(path); + } else if ( path.right(4).lower() == ".pls" ) { + exportPLSPlaylist(path); + } else if ( path.right(9).lower() == ".kaffeine" ) { + savePlaylist(path); + } else { + path.append(".kaffeine"); + savePlaylist(path); + } +} + +void PlayList::slotPlaylistRemove() +{ + removeCurrentPlaylist(); +} + +QWidget* PlayList::wantPlayerWindow() +{ + return playerBox; +} + +QWidget* PlayList::inputMainWidget() +{ + return mainWidget; +} + +void PlayList::loadConfig(KConfig* config) +{ + QValueList<int> sl; + bool b; + + config->setGroup("Playlist"); + b = config->readBoolEntry("Endless Mode", false); + m_repeat->setChecked(b); + setEndless(b); + b = config->readBoolEntry("Random Mode", false); + m_shuffle->setChecked(b); + setRandom(b); + b = config->readBoolEntry("AutoCover", false); + m_autoCover->setChecked(b); + m_cover = b; + b = config->readBoolEntry("DontShowPlayer", false); + m_showPlayer->setChecked(b); + + sl = config->readIntListEntry("HSplitSizes"); + if ( sl.count() ) + hSplit->setSizes( sl ); + else { + sl.append( 200 ); + sl.append( 200 ); + hSplit->setSizes( sl ); + } + vSplit->setSizes( config->readIntListEntry("VSplitSizes") ); + QStringList list; + list = config->readListEntry("Playlists"); + if (!list.count()) + { + list.append(i18n("Playlist") + "1"); + } + int lastRegularPlaylist = list.count(); + list.append(i18n("NEW")); + m_playlistSelector->insertStringList(list); + m_currentPlaylist = config->readNumEntry("Current", 0); + if (m_currentPlaylist > lastRegularPlaylist) + m_currentPlaylist = 0; + m_playlistSelector->setCurrentItem(m_currentPlaylist); + add(m_playlistDirectory + m_playlistSelector->text(m_currentPlaylist) + ".kaffeine", NULL); + m_nextPlaylistNumber = config->readNumEntry("Next Playlist", 2); + QString currentEntry = config->readEntry("Current Entry", QString()); + if ((!currentEntry.isEmpty()) && (m_list->childCount())) + { + QListViewItem* tmp = findByURL(currentEntry); + if (tmp) + setCurrentEntry(tmp, false); + } + fileBrowser->readConfig( config, "PlaylistFileBrowser" ); + fileBrowser->setURL( KURL(config->readEntry( "FileBrowserURL", "/" )), true ); + browserComb->setURL( KURL(config->readEntry( "FileBrowserURL", "/" )) ); +} + +void PlayList::saveConfig() +{ + saveConfig( KGlobal::config() ); +} + +void PlayList::saveConfig(KConfig* config) +{ + saveCurrentPlaylist(); + config->setGroup("Playlist"); + config->writeEntry("Endless Mode", m_repeat->isChecked()); + config->writeEntry("Random Mode", m_shuffle->isChecked()); + config->writeEntry("AutoCover", m_autoCover->isChecked()); + config->writeEntry("DontShowPlayer", m_showPlayer->isChecked()); + config->writeEntry( "HSplitSizes", hSplit->sizes() ); + config->writeEntry( "VSplitSizes", vSplit->sizes() ); + QStringList list; + QString text; + for (uint i=0; i < m_playlistSelector->listBox()->count(); i++) + { + text = m_playlistSelector->text(i); + if ( text != i18n("NEW") ) + list.append(text); + } + config->writeEntry("Playlists", list); + config->writeEntry("Current", m_currentPlaylist); + config->writeEntry("Next Playlist", m_nextPlaylistNumber); + config->writeEntry("Current Entry", m_currentEntryMRL.url()); + m_list->saveLayout(config, "Playlist Layout"); + fileBrowser->writeConfig( config, "PlaylistFileBrowser" ); + config->writeEntry( "FileBrowserURL", fileBrowser->url().url() ); +} + +void PlayList::closeEvent(QCloseEvent* ce) +{ + kdDebug() << "Playlist: close Event" << endl; + ce->ignore(); +} + +/****************************************** + * get the urls from playlist + ******************************************/ +void PlayList::startPlaylist() +{ + MRL mrl; + if ( trackNumber( 1, mrl ) ) + emit play( mrl, this ); +} + +bool PlayList::currentTrack( MRL &mrl ) +{ + mrl = getCurrent(); + if ( !mrl.isEmpty() ) + return true; + else + return false; +} + +MRL PlayList::getCurrent() +{ + if (isQueueMode()) + { + m_queue.clear(); + updateStatus(); + } + + if (m_random) + { + if (m_currentRandomListEntry == -1) return MRL(); + setCurrentEntry(m_randomList.at(m_currentRandomListEntry)); + return m_currentEntryMRL; + } + + if (!m_currentEntry) + if (m_list->childCount() > 0) + { + if (m_list->firstChild()->isVisible()) + setCurrentEntry(m_list->firstChild()); + else + { + if (m_list->firstChild()->itemBelow()) + setCurrentEntry(m_list->firstChild()->itemBelow()); + else + return MRL(); + } + } + else + return MRL(); + + setCurrentEntry(m_currentEntry); + return m_currentEntryMRL; +} + +bool PlayList::playbackFinished( MRL &mrl ) +{ + return nextTrack( mrl ); +} + +bool PlayList::nextTrack( MRL &mrl ) +{ + if (isQueueMode()) + { + mrl = m_queue.first(); + m_queue.remove(m_queue.begin()); + updateStatus(); + return true; + } + + if (!m_currentEntry) { + mrl = getCurrent(); + if ( !mrl.isEmpty() ) + return true; + else + return false; + } + + if (m_random) + { + if ((m_currentRandomListEntry+1) < (int)m_randomList.count()) + m_currentRandomListEntry += 1; + else + { + if (m_endless) + m_currentRandomListEntry = 0; + else + return false; + } + setCurrentEntry(m_randomList.at(m_currentRandomListEntry)); + mrl = m_currentEntryMRL; + return true; + } + + QListViewItem* tmpItem; + tmpItem = m_currentEntry->itemBelow(); + + if (tmpItem) + { + setCurrentEntry(tmpItem); + mrl = m_currentEntryMRL; + return true; + } + else + { + if (m_endless) + { + setCurrentEntry(m_list->firstChild()); + mrl = m_currentEntryMRL; + return true; + } + else + return false; + } +} + +bool PlayList::previousTrack( MRL &mrl ) +{ + if (isQueueMode()) + { + m_queue.clear(); + updateStatus(); + } + + if (!m_currentEntry) { + mrl = getCurrent(); + if ( !mrl.isEmpty() ) + return true; + else + return false; + } + + if (m_random) { + if (m_currentRandomListEntry > 0) + m_currentRandomListEntry -= 1; + else { + if (m_endless) + m_currentRandomListEntry = m_randomList.count()-1; + else + return false; + } + setCurrentEntry(m_randomList.at(m_currentRandomListEntry)); + mrl = m_currentEntryMRL; + return true; + } + + QListViewItem* tmpItem; + tmpItem = m_currentEntry->itemAbove(); + + if (tmpItem) { + setCurrentEntry(tmpItem); + mrl = m_currentEntryMRL; + return true; + } + else { + if (m_endless) { + setCurrentEntry(getLast()); + mrl = m_currentEntryMRL; + return true; + } + else + return false; + } +} + +bool PlayList::trackNumber( int number, MRL &mrl ) +{ + if (number > m_list->childCount()) + return false; + + QListViewItem * item = m_list->firstChild(); + for (int i = 1; i < number; i++) + item = item->nextSibling(); + + setCurrentEntry(item); + mrl = m_currentEntryMRL; + return true; +} + +QListViewItem* PlayList::getLast() +{ + return m_list->lastItem(); +} + +QListViewItem* PlayList::getFirst() +{ + return m_list->firstChild(); +} + +QListViewItem* PlayList::findByURL(const QString& url) +{ + QListViewItemIterator it(m_list); + while (it.current()) + { + if (dynamic_cast<PlaylistItem*>(*it)->url() == url) + { + return (*it); + } + ++it; + } + + /* fallback */ + return getFirst(); +} + +/********* set current entry (with play icon) ****************/ + +void PlayList::setCurrentEntry(QListViewItem* item, bool playIcon) +{ + PlaylistItem* newItem = dynamic_cast<PlaylistItem*>(item); + PlaylistItem* oldItem = dynamic_cast<PlaylistItem*>(m_currentEntry); + if (m_currentEntry) + { + oldItem->setPlaying(false); + m_currentEntry->setPixmap(TITLE_COLUMN, QPixmap()); + } + if (playIcon) + { + newItem->setPlaying(true); + item->setPixmap(TITLE_COLUMN, m_isCurrentEntry); + } + m_currentEntry = item; + if (m_random) + m_currentRandomListEntry = m_randomList.find(item); + m_currentEntryMRL = newItem->toMRL(); + roller->setTitle( m_currentEntryMRL ); + m_list->setCurrentItem(m_currentEntry); + + m_list->ensureVisible(10, m_list->itemPos(m_currentEntry), 10, 30); +} + +QListViewItem* PlayList::insertItem(QListViewItem* after, const MRL& m) +{ + PlaylistItem* tmp = NULL; + MRL mrl(m); + + m_list->setSorting(-1); + QListViewItemIterator it(m_list); + while (it.current()) + { + if (dynamic_cast<PlaylistItem*>(*it)->url() == mrl.url()) + { + kdDebug() << "PlayList: Source '" << mrl.url() << "' still exists. Skipped." << endl; + return after; + } + ++it; + } + + if (mrl.mime().isNull()) + { + KMimeType::Ptr mime = KMimeType::findByURL(mrl.kurl().path()); + mrl.setMime(mime->name()); + } + + tmp = new PlaylistItem(m_list, dynamic_cast<KListViewItem *>(after), mrl); + if (!tmp) return after; + + if ((mrl.mime() == "video/dvd") || (mrl.mime() == "video/vcd") || (mrl.mime() == "audio/cd")) + tmp->setPixmap(MIME_COLUMN, m_cdPixmap); + else + tmp->setPixmap(MIME_COLUMN, KMimeType::mimeType(mrl.mime())->pixmap(KIcon::Small)); + + if (tmp->length().contains(':')) + m_playTime += timeStringToMs(tmp->length()); + + if (m_searchSelection) + { + QString text = m_playlistFilter->text(); + if ((!tmp->title().contains(text, false)) && (!tmp->url().contains(text, false)) + && (!tmp->artist().contains(text, false)) && (!tmp->album().contains(text, false))) + { + tmp->setVisible(false); + } + } + + if (tmp->isVisible()) + { + if (tmp->length().contains(':')); + m_playTimeVisible += timeStringToMs(tmp->length()); + m_countVisible++; + } + + return tmp; +} + +void PlayList::fileSelected( const KFileItem *item ) +{ + if ( !item ) + return; + add( QStringList( item->url().path() ), NULL ); + QListViewItem* tmp = findByURL(item->url().path()); + if (tmp) { + setCurrentEntry(tmp); + emit play(m_currentEntryMRL, this); + } +} + +void PlayList::setBrowserURL( const QString &path ) +{ + fileBrowser->setURL( KURL(path), true ); +} + +void PlayList::setBrowserURL( const KURL &path ) +{ + fileBrowser->setURL( path, true ); +} + +void PlayList::browserURLChanged( const KURL &u ) +{ + QString url; + + if ( u.isLocalFile() ) + url = u.path(); + else + url = u.prettyURL(); + + QStringList urls = browserComb->urls(); + urls.remove( url ); // do not duplicate + urls.prepend( url ); + browserComb->setURLs( urls, KURLComboBox::RemoveBottom ); +} + +void PlayList::add(const QString& url, QListViewItem* after) +{ + add(QStringList(url), after); +} + + +void PlayList::add(const QStringList& urlList, QListViewItem* after) +{ + QListViewItem* tmp = NULL; + QStringList urls(urlList); + + QString ext; + QString subtitleURL; + QStringList subs; + KURL tmpKURL; + bool playlist; + MRL mrl; + QValueList<MRL> mrlList; + QString mediadevice=""; + + KProgressDialog* progress = NULL; + progress = new KProgressDialog(mainWidget, "importprogress", QString::null, i18n("Importing media resources...")); + progress->progressBar()->setTotalSteps(urls.count()); + progress->show(); + + kdDebug() << "PlayList: add " << urls.count() << " items to playlist" << endl; + + for (uint i = 0; i < urls.count(); i++) + { + mrl = MRL(urls[i]); + QString url(mrl.kurl().prettyURL()); + + if (mrl.kurl().protocol() == "media" || url.startsWith("system:/media/")) + { + QString mediaName; + if (url.startsWith("system:/media/")) + mediaName = url.mid(14); + else + mediaName = url.mid(7); + int slash = mediaName.find("/"); + QString filePath(mediaName.mid(slash)); + if (filePath == "/") + filePath = ""; + mediaName = mediaName.left(slash); + + DCOPRef mediamanager("kded","mediamanager"); + DCOPReply reply = mediamanager.call("properties(QString)",mediaName); + if (reply.isValid()) + { + QStringList properties = reply; + if (properties.isEmpty()) break; + url = properties[6] + filePath; + if (filePath.isEmpty()) + { + if (properties[10] == "media/audiocd") + { + mediadevice = properties[5]; + delete progress; + emit signalRequestForAudioCD(mediadevice); + return; + } + if (properties[10] == "media/dvdvideo") + { + mediadevice = properties[5]; + delete progress; + emit signalRequestForDVD(mediadevice); + return; + } + if ((properties[10] == "media/vcd") || (properties[10] == "media/svcd")) + { + mediadevice = properties[5]; + delete progress; + emit signalRequestForVCD(mediadevice); + return; + } + } + mrl = MRL(url); + } + } + + if (mrl.kurl().isLocalFile()) + { + if (!QFile::exists(mrl.kurl().path())) + continue; + mrl.setTitle(mrl.kurl().fileName()); + mrl.setURL(mrl.kurl().path()); + } + else + { + mrl.setTitle(mrl.url()); + } + + //kdDebug() << "PlayList: Check url " << mrl.url() << endl; + /*********** determine extension and mime type ************/ + + ext = mrl.kurl().fileName(); + ext = ext.remove(0 , ext.findRev('.') +1).lower(); + // kdDebug() << "Extension: " << ext << endl; + + //kdDebug() << "PlayList: Try to determine mime of: " << mrl.url() << endl; + KMimeType::Ptr mime = KMimeType::findByURL(mrl.kurl().path()); /* works only with path() (without protocol) + e.g. http://www.somafm.com/indipop.pls + path: /indipop.pls */ + //kdDebug() << "Mime: " << mime->name() << endl; + /*** check for kaffeine/noatun/pls/asx/m3u playlist ***/ + mrl.setMime(mime->name()); + + /******** some special processing for local files! *******/ + if (mrl.kurl().isLocalFile()) + { + /* playlist ? */ + if ((mime->name() == "text/plain") || (mime->name() == "text/xml") || (mime->name() == "application/x-kaffeine") + || (mime->name() == "audio/x-scpls") || (mime->name() == "audio/x-mpegurl" || (mime->name() == "audio/mpegurl") + || (ext == "asx") || (ext == "asf") || (ext == "wvx") || (ext == "wax"))) /* windows meta files */ + { + kdDebug() << "PlayList: Check for kaffeine/noatun/m3u/pls/asx playlist\n"; + + mrlList.clear(); + playlist = false; + QFile file(mrl.url()); + file.open(IO_ReadOnly); + + QTextStream stream(&file); + QString firstLine = stream.readLine(); + QString secondLine = stream.readLine(); + file.close(); + + if (secondLine.contains("kaffeine", false)) + { + kdDebug() << "PlayList: Try loading kaffeine playlist\n"; + playlist = PlaylistImport::kaffeine(mrl.url(), mrlList); + if (!playlist) + continue; + } + if (secondLine.contains("noatun", false)) + { + kdDebug() << "PlayList: Try loading noatun playlist\n"; + playlist = PlaylistImport::noatun(mrl.url(), mrlList); + } + if (firstLine.contains("asx", false)) + { + kdDebug() << "PlayList: Try loading asx playlist\n"; + playlist = PlaylistImport::asx(mrl.url(), mrlList); + } + if ( (firstLine.contains("[playlist]", false)) || (ext == "pls") ) + { + kdDebug() << "PlayList: Try loading pls playlist\n"; + playlist = PlaylistImport::pls(mrl.url(), mrlList); + } + if (ext == "m3u") //identify by extension + { + kdDebug() << "PlayList: Try loading m3u playlist\n"; + playlist = PlaylistImport::m3u(mrl.url(), mrlList); + } + if (playlist) + { + QValueList<MRL>::ConstIterator end(mrlList.end()); + for (QValueList<MRL>::ConstIterator it = mrlList.begin(); it != end; ++it) + after = insertItem(after, *it); + continue; + } + + } + + /* check for ram playlist */ + if ( (ext == "ra") || (ext == "rm") || (ext == "ram") || (ext == "lsc") || (ext == "pl") ) + { + mrlList.clear(); + kdDebug() << "PlayList: Try loading ram playlist\n"; + if (PlaylistImport::ram(mrl, mrlList, mainWidget->parentWidget())) + { + QValueList<MRL>::ConstIterator end(mrlList.end()); + for (QValueList<MRL>::ConstIterator it = mrlList.begin(); it != end; ++it) + after = insertItem(after, *it); + continue; + } + } + + /**** a directory ? ****/ + if (mime->name() == "inode/directory") + { + kdDebug() << "PlayList: Add Directory: " << mrl.url() << endl; + + QDir d(mrl.url()); + uint x; + + /* subdirs */ + QStringList entryList = d.entryList(QDir::Dirs, QDir::Name); + for (x = 0; x < entryList.count(); x++) + { + if (entryList[x][0] != '.') + { + urls.append(mrl.url() + "/" + entryList[x]); + } + } + + /* Media files */ + /* Exclude subtitles because they are examined twice : */ + /* Once for movie and once per subtitle - very annoying*/ + QString fileFilter = m_fileFilter; + fileFilter.remove("*.srt",false); + fileFilter.remove("*.ssa",false); + fileFilter.remove("*.txt",false); + fileFilter.remove("*.asc",false); + fileFilter.remove("*.smi",false); + fileFilter.remove("*.sub",false); + entryList = d.entryList(fileFilter, QDir::Files, QDir::Name ); + for (x = 0; x < entryList.count(); x++) + { + urls.append(mrl.url() + "/" + entryList[x]); + } + + progress->progressBar()->setTotalSteps(urls.count()); + continue; /* dont add directory to playlist */ + } + + /*** append subtitle files to the movie ***/ + if ((ext == "srt") || (ext == "ssa") || (ext == "txt") || + (ext == "asc") || (ext == "smi") || (ext == "sub")) + { + QStringList movies; + QString movieURL; + QListViewItemIterator it(m_list); + while (it.current()) + { + if (dynamic_cast<PlaylistItem*>(*it)->mime().contains("video")) + movies << dynamic_cast<PlaylistItem*>(*it)->url(); + ++it; + } + if (movies.count() == 1) + movieURL = movies[0]; + else if (movies.count() >= 2) + { + MovieChooser *mc = new MovieChooser(movies, mrl.url(), mainWidget); + if(mc->exec() == QDialog::Accepted) + movieURL = mc->getSelection(); + delete mc; + } + it = m_list; + while (it.current()) + { + if (dynamic_cast<PlaylistItem*>(*it)->url() == movieURL) + { + kdDebug() << "PlayList: adding subtitle to movie " << dynamic_cast<PlaylistItem*>(*it)->url() << endl; + (dynamic_cast<PlaylistItem*>(*it))->addSubtitle(mrl.url()); + break; + } + ++it; + } + continue; + } + + /*** get meta tags ****/ + if (m_metaOnLoading) + getMetaInfo(mrl, mime->name()); + + /* Get all suported subs in movie dir, clear out + * those starting with a different name than the movie, + * prompt the user to select a sub + */ + if (mime->name().contains("video")) + { + kdDebug() << "PlayList: Check for subtitle files" << endl; + subtitleURL = QString::null; + QDir *d = new QDir(mrl.url().section('/',0,-2)); + QString filename = mrl.url().section('/',-1,-1); + subs = QStringList(); + //Do a case insensitive search for subs + QStringList dirListing = d->entryList(QDir::Files|QDir::NoSymLinks); //cache directory listing + bool matches = false; + QStringList::Iterator end(dirListing.end()); + for(QStringList::Iterator it = dirListing.begin(); it != end; ++it ) + { + if(startsWith(*it, filename.section('.',0,-2), false)) //If filenames (without extensions) match + { + if( endsWith(*it, ".srt", false) || endsWith(*it, ".ssa", false) || + endsWith(*it, ".txt", false) || endsWith(*it, ".smi", false) || + endsWith(*it, ".asc", false) || endsWith(*it, ".sub", false) ) + matches = true; + + if(matches) { + subs.append(*it); //This is a subtitle for our movie + } + matches = false; + } + } + + if((subs.count() > 1)) { + subs.prepend(i18n("(no subtitles)")); + subs.append(i18n("Other subtitle...")); + subtitleURL = QString::null; + SubtitleChooser *sc = new SubtitleChooser(subs, filename, mainWidget); + + THERE: if(sc->exec() == QDialog::Accepted) + { + if((sc->getSelection() != i18n("(no subtitles)")) && (sc->getSelection() != i18n("Other subtitle..."))) + subtitleURL = d->path()+"/"+sc->getSelection(); + if((sc->getSelection() == i18n("Other subtitle..."))) + { + subtitleURL = KFileDialog::getOpenURL(d->path(), i18n("*.smi *.srt *.sub *.txt *.ssa *.asc|Subtitle Files\n*.*|All Files"), 0, i18n("Select Subtitle File")).path(); + if(subtitleURL.isEmpty()) + { + subtitleURL = QString::null; + goto THERE; + } + else //The user has selected another sub, so add this to the list + { + subs.clear(); + subs.append(subtitleURL); + } + } + } + delete sc; + subs.remove(i18n("(no subtitles)")); + subs.remove(i18n("Other subtitle...")); + } + + //Add the full path to the subtitle name + for (unsigned int i = 0; i < subs.size(); i++ ) + if(!subs[i].startsWith(d->path())) + subs[i] = d->path()+"/"+subs[i]; + + mrl.setSubtitleFiles(subs); + if ( subs.count()==1 ) + subtitleURL = subs[0]; // Use this one. + if (!subtitleURL.isNull()) + { + kdDebug() << "PlayList: Use subtitle file: " << subtitleURL << " for: " << mrl.url() << endl; + mrl.setCurrentSubtitle(subs.findIndex(subtitleURL)); + } + } + } /* if localFile() */ + + tmp = insertItem(after, mrl); + if (tmp) + after = tmp; + + if ( progress->wasCancelled() ) + break; + progress->progressBar()->setProgress(i+1); + progress->setLabel(QString::number(i+1) + " / " + QString::number(progress->progressBar()->totalSteps()) + " " + i18n("Files")); + KApplication::kApplication()->processEvents(); + } + + delete progress; + if (m_random) createRandomList(); + updateStatus(); +} + +void PlayList::add(const QValueList<MRL>& mrlList, QListViewItem* after) +{ + QValueList<MRL>::ConstIterator end(mrlList.end()); + for (QValueList<MRL>::ConstIterator it = mrlList.begin(); it != end; ++it) + after = insertItem(after, *it); + updateStatus(); + if (m_random) createRandomList(); +} + +void PlayList::slotPlayDirect(QListViewItem* item) +{ + if (!item) return; + + setCurrentEntry(item); + emit play(m_currentEntryMRL, this); +} + +void PlayList::setEndless(bool e) +{ + m_endless = e; +} + +void PlayList::setRandom(bool r) +{ + m_random = r; + if (m_random) createRandomList(); +} + +void PlayList::createRandomList() +{ + kdDebug() << "PlayList: Create a random playlist" << endl; + m_randomList.clear(); + m_currentRandomListEntry = 0; + + QListViewItem* tmpItem = NULL; + tmpItem = m_list->firstChild(); + if ( (tmpItem) && (!tmpItem->isVisible()) ) + tmpItem = tmpItem->itemBelow(); + + while (tmpItem) + { + m_randomList.append(tmpItem); + tmpItem = tmpItem->itemBelow(); + } + + if (!(m_randomList.count() > 0)) + { + m_currentRandomListEntry = -1; + return; + } + + KRandomSequence r(KApplication::random()); + r.randomize(&m_randomList); +} + +void PlayList::clearList() +{ + m_list->clear(); + m_randomList.clear(); + m_playTime = 0; + m_playTimeVisible = 0; + m_countVisible = 0; + if (m_searchSelection) + { + m_playlistFilter->clear(); + m_searchSelection = false; + } + updateStatus(); + m_currentEntry = NULL; + m_currentRandomListEntry = -1; +} + +void PlayList::slotDropEvent(QDropEvent* dev, QListViewItem* after) +{ + QStringList urls ,newurls; + + m_list->setSorting(-1); + if (QUriDrag::decodeLocalFiles(dev, urls)) + { + if (urls.count()) + { + for (uint i=0; i < urls.count() ;i++) + { + //KURL url(QUriDrag::unicodeUriToUri(urls[i])); + //newurls << url.path(-1); + //kdDebug() << "PlayList: Dropped " << url.path() << endl; + newurls << urls[i]; + kdDebug() << "PlayList: Dropped " << urls[i] << endl; + } + add(newurls, after); + } + else + { + QUriDrag::decodeToUnicodeUris(dev, urls); + if (urls.count()) + add(urls, after); + } + } + else + if (strcmp(dev->format(), "text/x-moz-url") == 0) /* for mozilla drops */ + { + QByteArray data = dev->encodedData("text/plain"); + QString md(data); + add(md, after); + } +} + +void PlayList::slotPreDropEvent() +{ + m_list->setSorting(-1); +} + +void PlayList::slotSetAlternateColor( const QColor& col ) +{ + m_list->setAlternateBackground( col ); + m_altCol = col; + m_list->triggerUpdate(); +} + +void PlayList::useAlternateEncoding(bool useEncoding) +{ + m_useAlternateEncoding = useEncoding; +} + +void PlayList::setAlternateEncoding(const QString& encoding) +{ + m_alternateEncoding = encoding; +} + + +void PlayList::getMetaInfo(MRL& mrl, const QString& mimeName) +{ + KFileMetaInfo* metaInfo = NULL; + KFileMetaInfoGroup metaGroup; + uint m, n; + + metaInfo = new KFileMetaInfo(mrl.url(), mimeName); + QStringList groups = metaInfo->groups(); + QStringList keys; + QString title; + QString artist; + QString album; + + QTextCodec *altCodec; + QTextCodec *CodecUtf8; + + altCodec = QTextCodec::codecForName(m_alternateEncoding.ascii()); + CodecUtf8 = QTextCodec::codecForName("UTF-8"); + //kdDebug() << "playlist: locale " << Codec->name << " index: " << m_alternateEncoding << endl; + + for (m = 0; m < groups.count(); m++) + { + //kdDebug() << "Metainfo-Group: " << groups[m] << endl; + metaGroup = metaInfo->group(groups[m]); + keys = metaGroup.keys(); + for (n = 0; n < keys.count(); n++) + { + //kdDebug() << "Metainfo-Key: " << keys[n] << endl; + if (keys[n] == "Length") + { + mrl.setLength(QTime().addSecs(metaGroup.item(keys[n]).value().toUInt())); + } + + if (keys[n] == "Title") + { + title = metaGroup.item(keys[n]).value().toString().simplifyWhiteSpace(); + if ((!title.isEmpty()) && (title.contains(QRegExp("\\w")) > 2) && (title.left(5).lower() != "track")) + { + if ((m_useAlternateEncoding) && (CodecUtf8->heuristicContentMatch(title.ascii(), title.length()) < 0)) + { + mrl.setTitle(altCodec->toUnicode(title.ascii())); + //kdDebug() << "playlist: Convert, locale name: " << altCodec->name() << title << endl; + } + else + { + mrl.setTitle(title); + //kdDebug() << "playlist: non Convert, locale name: " << CodecUtf8->name() << title << endl; + } + } + } + + if (keys[n] == "Artist") + { + artist = (metaGroup.item(keys[n]).value().toString().simplifyWhiteSpace()); + if (!artist.isEmpty()) + { + if ((m_useAlternateEncoding) && (CodecUtf8->heuristicContentMatch(artist.ascii(),artist.length()) < 0 )) + { + mrl.setArtist(altCodec->toUnicode(artist.ascii())); + } + else + { + mrl.setArtist(artist); + } + } + } + + if (keys[n] == "Album") + { + album = (metaGroup.item(keys[n]).value().toString().simplifyWhiteSpace()); + if (!album.isEmpty()) + { + if ((m_useAlternateEncoding) && (CodecUtf8->heuristicContentMatch(album.ascii(),album.length()) < 0 )) + { + mrl.setAlbum(altCodec->toUnicode(album.ascii())); + } + else + { + mrl.setAlbum(album); + } + } + } + + if (keys[n] == "Tracknumber") + mrl.setTrack(metaGroup.item(keys[n]).value().toString().simplifyWhiteSpace()); + if (keys[n] == "Date") + mrl.setYear(metaGroup.item(keys[n]).value().toString().simplifyWhiteSpace()); + if (keys[n] == "Genre") + mrl.setGenre(metaGroup.item(keys[n]).value().toString().simplifyWhiteSpace()); + } + } + + delete metaInfo; +} + +void PlayList::mergeMeta(const MRL& mrl) +{ + if (!m_currentEntry) return; + PlaylistItem* tmp = dynamic_cast<PlaylistItem*>(m_currentEntry); + bool addTime = (tmp->length() == QString("00:00:00")); + if ((tmp) && (tmp->url() == mrl.url())) + { + tmp->setTitle(mrl.title()); + tmp->setArtist(mrl.artist()); + tmp->setAlbum(mrl.album()); + tmp->setTrack(mrl.track()); + tmp->setYear(mrl.year()); + tmp->setGenre(mrl.genre()); + tmp->setLength(mrl.length().toString("h:mm:ss")); + tmp->setCurrentSubtitle(mrl.currentSubtitle()); + tmp->setSubtitles(mrl.subtitleFiles()); + } + if (addTime) + { + if (tmp->length().contains(':')); + { + m_playTime += timeStringToMs(tmp->length()); + if (tmp->isVisible()) + m_playTimeVisible += timeStringToMs(tmp->length()); + + updateStatus(); + } + } + + roller->setTitle( mrl ); + setCover( mrl.artist().stripWhiteSpace(), mrl.album().stripWhiteSpace() ); +} + +GalleryDialog::GalleryDialog( QWidget *parent, GoogleFetcher *goog ) + : KDialogBase( parent, QString(i18n("Gallery")).latin1(), true, QString::null, Ok, NoDefault, true ) +{ + google = goog; + hbox = new QHBox(this); + imageFrame = new QFrame( hbox ); + imageFrame->setFixedSize(500,500); + setMainWidget(hbox); + connect( &next, SIGNAL(timeout()), this, SLOT(slotNext()) ); + next.start(1000,true); +} + +void GalleryDialog::slotNext() +{ + QPixmap pix; + bool end; + + actionButton(Ok)->setEnabled(false); +loop: + QImage img = google->galleryNext( end ); + if ( end ) { + slotOk(); + return; + } + if ( !img.isNull() ) { + if ( img.width()>img.height() ) + imageFrame->setFixedSize(500, 500*img.height()/img.width()); + else + imageFrame->setFixedSize(500*img.width()/img.height(), 500); + img = img.smoothScale(imageFrame->width(),imageFrame->height()); + pix.convertFromImage( img ); + imageFrame->setPaletteBackgroundPixmap( pix ); + } + else + goto loop; + + actionButton(Ok)->setEnabled(true); + next.start(5000,true); +} + +void GalleryDialog::slotOk() +{ + if ( next.isActive() ) + next.stop(); + hide(); +} + +void PlayList::showGallery() +{ + if ( google ) + return; + QString s = getCurrent().artist().stripWhiteSpace(); + if ( s.isEmpty() ) + return; + google = new GoogleFetcher( s, "", true ); + GalleryDialog dlg( 0, google ); + dlg.exec(); + delete google; + google = NULL; +} + +void PlayList::setCover( QString s1, QString s2, bool forceFetch ) +{ + if ( s1.isEmpty() || s2.isEmpty() ) { + coverFrame->setCoverPixmap( "" ); + return; + } + QString s = locateLocal("appdata", ""); + QImage img; + QPixmap pix; + QString fname = s1+"_"+s2; + fname = fname.replace( QChar( '/' ), "_" ); + fname = fname.upper(); + fname = s+"covers/"+fname; + if ( !forceFetch && QFile( fname ).exists() ) + coverFrame->setCoverPixmap( fname ); + else { + if ( !forceFetch ) + coverFrame->setCoverPixmap( "" ); + if ( google ) + return; + if ( m_cover || forceFetch ) { + google = new GoogleFetcher( s1, s2 ); + pix = google->pixmap( forceFetch ); + delete google; + google = NULL; + } + if ( !QDir( s+"covers" ).exists() ) + QDir().mkdir( s+"covers" ); + if ( !pix.isNull() ) { + img = pix.convertToImage(); + img.save( fname, coverImageFormat.latin1() ); + MRL mrl = getCurrent(); + if ( s1==mrl.artist().stripWhiteSpace() && s2==mrl.album().stripWhiteSpace() ) + coverFrame->setCoverPixmap( fname ); + } + else if ( !forceFetch && m_cover ) { + QString path = locate("appdata", "nocover.png"); + if ( !path ) + path = locate("data", "kaffeine/nocover.png"); + KIO::file_copy( KURL::fromPathOrURL( path ), KURL::fromPathOrURL( fname ), -1, true ); + } + } +} + +void PlayList::chooseCurrentCover() +{ + MRL mrl = getCurrent(); + setCover( mrl.artist().stripWhiteSpace(), mrl.album().stripWhiteSpace(), true ); +} + +/************ sort playlist ******************/ + +void PlayList::slotSort(int section) +{ + m_list->setSorting(section, m_sortAscending); + m_list->sort(); + m_sortAscending = !m_sortAscending; +} + + +/*** remove items ***/ + +void PlayList::slotRemoveSelected() +{ + QPtrList<QListViewItem> selected; + + if (m_currentEntry) + if (m_currentEntry->isSelected()) + { + m_currentEntry = NULL; + m_currentRandomListEntry = -1; + } + + selected = m_list->selectedItems(); + PlaylistItem* item = NULL; + + for(uint i = 0; i<selected.count(); i++) + { + // kdDebug() << "Remove " << selected.at(i)->text(TITLE_COLUMN) << "\n"; + item = dynamic_cast<PlaylistItem *>(selected.at(i)); + if (item->length().contains(':')) + { + m_playTime -= timeStringToMs(item->length()); + m_playTimeVisible -= timeStringToMs(item->length()); + } + + m_countVisible--; + delete selected.at(i); + } + + if (m_random) createRandomList(); + updateStatus(); +} + +void PlayList::updateStatus() +{ + QString status; + if (isQueueMode()) + { + QTime total; + QValueList<MRL>::ConstIterator end(m_queue.end()); + for (QValueList<MRL>::ConstIterator it = m_queue.begin(); it != end; ++it) + total = total.addSecs(QTime().secsTo((*it).length())); + status = i18n("Queue: %1 Entries, Playtime: %2").arg(m_queue.count()).arg(total.toString("h:mm:ss")); + } + else + { + //status = i18n("Entries: %1, Playtime: %2 (Total: %3, %4)").arg(QString::number(m_countVisible)).arg(msToTimeString(m_playTimeVisible)).arg(QString::number(m_list->childCount())).arg(msToTimeString(m_playTime)); + + + status = i18n("Entries: %1, Playtime: %2").arg(QString::number(m_countVisible)).arg(msToTimeString(m_playTimeVisible)); + } + emit statusBarMessage(status); +} + +void PlayList::slotNewList() +{ + m_list->setSorting(-1); + saveCurrentPlaylist(); + m_playlistSelector->insertItem(i18n("Playlist") + QString::number(m_nextPlaylistNumber), 0); + m_nextPlaylistNumber++; + m_playlistSelector->setCurrentItem(0); + m_currentPlaylist = 0; + clearList(); +} + +void PlayList::setPlaylist(const QString& name, bool clear) +{ + saveCurrentPlaylist(); + if (clear) + clearList(); + int index = 0; + if (m_playlistSelector->listBox()->findItem(name)) + index = m_playlistSelector->listBox()->index(m_playlistSelector->listBox()->findItem(name)); + else + m_playlistSelector->insertItem(name, 0); + m_playlistSelector->setCurrentItem(index); + m_currentPlaylist = index; +} + +void PlayList::nextPlaylist() +{ + int nextPlaylist = m_playlistSelector->currentItem(); + QString pl = NULL; + do + { + nextPlaylist++; + if (nextPlaylist == m_playlistSelector->count()) + nextPlaylist = 0; + pl = m_playlistSelector->text(nextPlaylist); + } + while (nextPlaylist != m_playlistSelector->currentItem()); + + saveCurrentPlaylist(); + clearList(); + m_playlistSelector->setCurrentItem(nextPlaylist); + m_currentPlaylist = nextPlaylist; + add(m_playlistDirectory + pl + ".kaffeine", NULL); + if (mainWidget->parentWidget()) + mainWidget->parentWidget()->setFocus(); +} + +void PlayList::slotPlaylistActivated(int index) +{ + kdDebug() << "PlayList: Switch to playlist: " << m_playlistSelector->text(index) << endl; + QString pl = m_playlistSelector->text(index); + + saveCurrentPlaylist(); + clearList(); + m_currentPlaylist = index; + add(m_playlistDirectory + pl + ".kaffeine", NULL); + if (mainWidget->parentWidget()) + mainWidget->parentWidget()->setFocus(); + /* if (!isQueueMode()) + { + getCurrent(); + emit signalPlay(m_currentEntryMRL); + } */ +} + +void PlayList::slotNewPlaylistName(const QString& text) +{ + if ((text.isEmpty()) || (text == m_playlistSelector->text(m_currentPlaylist))) + return; + if (m_playlistSelector->listBox()->findItem(text)) + { + kdDebug() << "PlayList: Name still exists!" << endl; + return; + } + QString oldPl = m_playlistDirectory + m_playlistSelector->text(m_currentPlaylist) + ".kaffeine"; + kdDebug() << "Playlist: removing file: " << oldPl << endl; + if (!KIO::NetAccess::del(oldPl, mainWidget)) + kdError() << "Playlist: " << KIO::NetAccess::lastErrorString() << endl; + + kdDebug() << "PlayList: Set playlist name to: " << text << endl; + m_playlistSelector->changeItem(text, m_currentPlaylist); + saveCurrentPlaylist(); + if (mainWidget->parentWidget()) + mainWidget->parentWidget()->setFocus(); +} + +QString PlayList::queryCurrentPlaylist() +{ + QString pl = m_playlistSelector->text(m_currentPlaylist); + return (m_playlistDirectory + pl + ".kaffeine"); +} + +void PlayList::saveCurrentPlaylist() +{ + QString pl = m_playlistSelector->text(m_currentPlaylist); + savePlaylist(m_playlistDirectory + pl + ".kaffeine"); +} + +void PlayList::removeCurrentPlaylist() +{ + int code = KMessageBox::warningContinueCancel(0, i18n("Remove '%1' from list and from disk?").arg(m_playlistSelector->text(m_currentPlaylist)),QString::null,KStdGuiItem::del()); + if (code == KMessageBox::Continue) + { + QString pl = m_playlistDirectory + m_playlistSelector->text(m_currentPlaylist) + ".kaffeine"; + if (!KIO::NetAccess::del(pl, mainWidget)) + kdError() << "Playlist: " << KIO::NetAccess::lastErrorString() << endl; + + m_playlistSelector->removeItem(m_currentPlaylist); + m_currentPlaylist = m_playlistSelector->currentItem(); + clearList(); + add(m_playlistDirectory + m_playlistSelector->text(m_currentPlaylist) + ".kaffeine", NULL); + } +} + +void PlayList::loadPlaylist(const QString& pl) +{ + saveCurrentPlaylist(); + QString plName = KURL(pl).fileName(); + plName = plName.remove(".kaffeine", false); + if (m_playlistSelector->listBox()->findItem(plName)) + { + QString plNewName = NULL; + while (true) + { + bool ok; + plNewName = QInputDialog::getText(i18n("Playlist Name Already Exists"), + i18n("Enter different playlist name:"), QLineEdit::Normal, plName, &ok); + if ((ok) && (!plNewName.isEmpty())) + { + if (m_playlistSelector->listBox()->findItem(plNewName)) + continue; + else + break; + } + else + { + kdDebug() << "Playlist: Import aborted, playlist not added" << endl; + return; + } + } + plName = plNewName; + } + m_playlistSelector->insertItem(plName, 0); + m_playlistSelector->setCurrentItem(0); + m_currentPlaylist = 0; + clearList(); + add(pl, NULL); +} + +/****************************************** + * save xml playlist + ******************************************/ + +void PlayList::savePlaylist(const QString& pl) +{ + QDomDocument doc("playlist"); + doc.setContent(QString("<!DOCTYPE XMLPlaylist>")); + QDomElement root = doc.createElement("playlist"); + root.setAttribute("client", "kaffeine"); + doc.appendChild(root); + + QDomElement entry; + PlaylistItem * tmp = NULL; + + QListViewItemIterator it(m_list); + while (it.current()) + { + tmp = dynamic_cast<PlaylistItem *>(it.current()); + + entry = doc.createElement("entry"); + + entry.setAttribute("title", tmp->title()); + entry.setAttribute("artist", tmp->artist()); + entry.setAttribute("album", tmp->album()); + entry.setAttribute("track", tmp->track()); + entry.setAttribute("year", tmp->year()); + entry.setAttribute("genre", tmp->genre()); + entry.setAttribute("url", tmp->url()); + entry.setAttribute("mime", tmp->mime()); + entry.setAttribute("length", tmp->length()); + + if(!(tmp->subtitles().isEmpty())) + { + QString subList; + for(unsigned int i=0; i<tmp->subtitles().count(); i++) + subList += tmp->subtitles()[i] + "&"; + + entry.setAttribute("subs", subList); + } + entry.setAttribute("currentSub", QString::number(tmp->currentSubtitle())); + root.appendChild(entry); + + ++it; + } + + QFile file(pl); + if (!file.open(IO_WriteOnly)) return; + QTextStream stream(&file); + stream.setEncoding(QTextStream::UnicodeUTF8); + + stream << doc.toString(); + + file.close(); + m_list->setCleared(false); +} + +/**********************/ + +void PlayList::exportM3UPlaylist(const QString& pl) +{ + PlaylistItem * tmp = NULL; + + QListViewItemIterator it(m_list); + + int length = -1; + QString m3uList = "#EXTM3U\n"; + + while (it.current()) + { + tmp = dynamic_cast<PlaylistItem *>(it.current()); + + length = timeStringToMs(tmp->length()) / 1000; + if ( length == 0 ) + length = -1; + + m3uList.append("#EXTINF:" + QString::number(length) + "," + tmp->title()); + if (tmp->artist().isEmpty() ) + m3uList.append("\n"); + else + m3uList.append(" - " + tmp->artist() + "\n"); + m3uList.append(tmp->url() + "\n"); + ++it; + } + + QFile file(pl); + if (!file.open(IO_WriteOnly)) return; + QTextStream stream(&file); + stream.setEncoding(QTextStream::UnicodeUTF8); + + stream << m3uList; + + file.close(); +} + +void PlayList::exportPLSPlaylist(const QString& pl) +{ + PlaylistItem * tmp = NULL; + + QListViewItemIterator it(m_list); + + int counter = 0; + int length = -1; + + QString plsList = "[playlist]\n"; + + while (it.current()) + { + tmp = dynamic_cast<PlaylistItem *>(it.current()); + ++counter; + + length = timeStringToMs(tmp->length()) / 1000; + + if ( length == 0 ) { + length = -1; + } + + plsList.append("File" + QString::number(counter) + "=" + tmp->url() + "\n"); + plsList.append("Title" + QString::number(counter) + "=" + tmp->title()); + if (tmp->artist().isEmpty() ) + plsList.append("\n"); + else + plsList.append(" - " + tmp->artist() + "\n"); + plsList.append("Length" + QString::number(counter) + "=" + QString::number(length) + "\n"); + ++it; + + } + + plsList.append("NumberOfEntries=" + QString::number(counter) + "\n"); + plsList.append("Version=2"); + + QFile file(pl); + if (!file.open(IO_WriteOnly)) return; + QTextStream stream(&file); + stream.setEncoding(QTextStream::UnicodeUTF8); + + stream << plsList; + + file.close(); +} + +void PlayList::resetSearch() +{ + m_playlistFilter->clear(); + slotFindText( "" ); +} + +void PlayList::slotFindText(const QString& text) +{ + if (text == i18n("Filter")) return; + + QListViewItemIterator it(m_list); + m_playTimeVisible = 0; + m_countVisible = 0; + PlaylistItem* tmp = NULL; + while ( it.current() ) + { + tmp = dynamic_cast<PlaylistItem *>(it.current()); + if (text.isEmpty() || tmp->title().contains(text, false) || tmp->url().contains(text, false) + || tmp->artist().contains(text, false) || tmp->album().contains(text, false) ) + { + tmp->setVisible(true); + if (tmp->length().contains(':')) + m_playTimeVisible += timeStringToMs(tmp->length()); + + m_countVisible++; + } + else + { + tmp->setVisible(false); + if (tmp == m_currentEntry) + { + tmp->setPixmap(TITLE_COLUMN, QPixmap()); + m_currentEntry = NULL; + m_currentRandomListEntry = -1; + } + } + ++it; + } + + if (text.isEmpty()) + m_searchSelection = false; + else + m_searchSelection = true; + + if (m_random) createRandomList(); + updateStatus(); +} + + +/***************** cut/copy/paste *************************/ + +void PlayList::slotCut() +{ + slotCopy(); + slotRemoveSelected(); +} + +void PlayList::slotPaste() +{ + QPtrList<QListViewItem> selected; + selected = m_list->selectedItems(); + QListViewItem* lastSelected = NULL; + if (selected.count()) + lastSelected = selected.at(selected.count() - 1); + else + lastSelected = m_list->lastItem(); + + QStrList list; + + if (QUriDrag::decode(QApplication::clipboard()->data(), list)) + { + QStringList urls; + for (QStrListIterator it(list); *it; ++it) + urls.append(QUriDrag::uriToUnicodeUri(*it)); + add(urls, lastSelected); + return; + } + /** try to decode as text **/ + QString text; + if (QTextDrag::decode(QApplication::clipboard()->data(), text)) + { + add(text, lastSelected); + } +} + +void PlayList::slotCopy() +{ + QPtrList<QListViewItem> selected; + selected = m_list->selectedItems(); + + QStrList urlList; + + for (uint i=0; i<selected.count(); i++) + { + urlList.append(QUriDrag::unicodeUriToUri(dynamic_cast<PlaylistItem *>(selected.at(i))->url())); + } + + QApplication::clipboard()->setData(new QUriDrag(urlList)); +} + +void PlayList::slotSelectAll() +{ + QListViewItemIterator it(m_list); + while (it.current()) + { + if ((*it)->isVisible()) + m_list->setSelected(*it, true); + ++it; + } +} + +void PlayList::slotPlaylistFromSelected() +{ + QPtrList<QListViewItem> selected; + selected = m_list->selectedItems(); + + QValueList<MRL> mrlList; + + for (uint i=0; i<selected.count(); i++) + { + mrlList.append(dynamic_cast<PlaylistItem *>(selected.at(i))->toMRL()); + } + + if (mrlList.count()) + { + slotNewList(); + add(mrlList, NULL); + } +} + +void PlayList::slotAddToQueue(MRL mrl) +{ + m_queue.append(mrl); + updateStatus(); +} + +/**** helper ****/ + +QString PlayList::msToTimeString(int msec) +{ + /* + QTime t; + t = t.addMSecs(msec); + return t.toString("h:mm:ss"); + */ + /* can be >24h */ + int hours; + int min; + int sec; + int my_msec=msec; + QString tmp; + QString t; + + msec = msec/1000; //sec + hours = msec/3600; + my_msec -= hours*3600*1000; + t = t.setNum(hours); + t.append(":"); + + msec = msec - (hours*3600); + min = msec / 60; + my_msec -= min*60*1000; + tmp = tmp.setNum(min); + tmp = tmp.rightJustify(2, '0'); + t.append(tmp); + t.append(":"); + + sec = msec - (min*60); + my_msec -= sec*1000; + if(my_msec > 500) + sec++; + tmp = tmp.setNum(sec); + tmp = tmp.rightJustify(2, '0'); + t.append(tmp); + + return t; +} + +int PlayList::timeStringToMs(const QString& timeString) +{ + int sec = 0; + QStringList tokens = QStringList::split(':',timeString); + + bool ok = false; + sec += tokens[0].toInt(&ok)*3600; //hours + if (!ok) + return 0; + sec += tokens[1].toInt(&ok)*60; //minutes + if (!ok) + return 0; + sec += tokens[2].toInt(&ok); //secs + + if (ok) + return sec*1000; //return millisecs + else + return 0; +} + +bool PlayList::endsWith(QString s1, QString s2, bool caseSensitive ) +{ + if ( s1.isNull() || s2.isNull() ) + return false; + int startPos = s1.length() - s2.length(); + + for (unsigned int i = 0; i < s2.length(); i++ ) + { + if(caseSensitive) + { + if ( s1[startPos + i] != s2[i] ) + return false; + } + else + { + if ( s1[startPos + i].lower() != s2[i].lower() ) + return false; + } + } + + return true; +} + +bool PlayList::startsWith(QString s1, QString s2, bool caseSensitive ) +{ + if ( s1.isNull() || s2.isNull() ) + return false; + + if(s2.length() > s1.length()) + return false; + + for (unsigned int i = 0; i < s2.length(); i++ ) + { + if(caseSensitive) + { + if ( s1[i] != s2[i] ) + return false; + } + else + { + if ( s1[i].lower() != s2[i].lower() ) + return false; + } + } + + return true; +} + +SubtitleChooser::SubtitleChooser(QStringList values, QString filename,QWidget *parent, const char * name) : + KDialogBase(parent,name,true,i18n("Select Subtitle"), Ok|Cancel, Ok, true) +{ + QVBox *page = makeVBoxMainWidget(); + QLabel *label = new QLabel(page); + label->setText("<qt>" + i18n("Media file:") + " <b>" + filename + "</b></qt>"); + table = new QListBox(page); + this->setMinimumSize(300,200); + + table->setFocus(); + table->insertStringList(values); + table->setSelected(0, true); +} + +SubtitleChooser::~SubtitleChooser(){} + +QString SubtitleChooser::getSelection() +{ + return table->selectedItem()->text(); +} + +MovieChooser::MovieChooser(QStringList values, QString filename,QWidget *parent, const char * name) : + KDialogBase(parent,name,true,i18n("Select Movie"), Ok|Cancel, Ok, true) +{ + QVBox *page = makeVBoxMainWidget(); + QLabel *label = new QLabel(page); + label->setText("<qt> " + i18n("Subtitle file:") + " <b>" + filename + "</b></qt>"); + table = new QListBox(page); + this->setMinimumSize(450,200); + + table->setFocus(); + table->insertStringList(values); + table->setSelected(0, true); +} + +MovieChooser::~MovieChooser(){} + +QString MovieChooser::getSelection() +{ + return table->selectedItem()->text(); +} diff --git a/kaffeine/src/input/audiobrowser/playlist.h b/kaffeine/src/input/audiobrowser/playlist.h new file mode 100644 index 0000000..41df120 --- /dev/null +++ b/kaffeine/src/input/audiobrowser/playlist.h @@ -0,0 +1,336 @@ +/* + * playlist.h + * + * Copyright (C) 2003-2005 Jürgen Kofler <kaffeine@gmx.net> + * Copyright (C) 2005-2006 Christophe Thommeret <hftom@free.fr> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef PLAYLIST_H +#define PLAYLIST_H + +#include <kdialogbase.h> +#include <kdiroperator.h> +#include <kfileiconview.h> +#include <kaction.h> +#include <kstdaction.h> + +#include <qwidget.h> +#include <qptrlist.h> +#include <qvbox.h> +#include <qsplitter.h> +#include <qpainter.h> +#include <qtoolbutton.h> + +#include "urllistview.h" +#include "kaffeineinput.h" + +class UrlListView; +class MRL; +class KURL; +class QListViewItem; +class QString; +class QLabel; +class QColor; +class QDropEvent; +class QPixmap; +class KLineEdit; +class KComboBox; +class KURLComboBox; +class KConfig; +class KPushButton; +class GoogleFetcher; + + + +class GalleryDialog : public KDialogBase +{ + Q_OBJECT +public: + GalleryDialog( QWidget *parent, GoogleFetcher *goog ); +protected slots: + void slotOk(); + void slotNext(); +private: + QFrame *imageFrame; + GoogleFetcher *google; + QTimer next; + QHBox *hbox; +}; + + + +class RollTitle : public QLabel +{ + Q_OBJECT + +public: + RollTitle( QWidget *parent ); + void setTitle( MRL mrl ); + +private: + void setTitle( QString t ); + QTimer titleTimer; + QPixmap titlePix; + QColor back, fore; + int titleOffset; + QString title; + +protected: + void paintEvent ( QPaintEvent * ); + +private slots: + void rollTitle(); +}; + + + +class CoverFrame : public QFrame +{ + Q_OBJECT + +public: + CoverFrame( QWidget *parent ); + ~CoverFrame(); + void setCoverPixmap( const QString &path ); + +protected: + void mousePressEvent( QMouseEvent *e ); + +private: + void popup( const QPixmap &pix ) const; + QString imagePath; + QPixmap noCoverPix; + +signals: + void changeCurrentCover(); + void gallery(); +}; + + + +class PlayList : public KaffeineInput +{ + Q_OBJECT + +public: + PlayList(QWidget *parent, QObject *objParent, const char *name=0); + ~PlayList(); + + // Reimplemented from KaffeineInput +public: + QWidget *wantPlayerWindow(); + QWidget *inputMainWidget(); + void mergeMeta(const MRL&); + bool nextTrack( MRL& ); + bool previousTrack( MRL& ); + bool currentTrack( MRL& ); + bool trackNumber( int, MRL& ); + bool playbackFinished( MRL& ); + void getTargets( QStringList &uiNames, QStringList &iconNames, QStringList &targetNames ); + void togglePanel(); + bool execTarget( const QString& ); + void saveConfig(); + bool showPlayer() {return !m_showPlayer->isChecked();} + //*************************************** + +public: + MRL getCurrent(); /* get current playlist entry */ + MRL getNext(); + MRL getEntryWithNumber(int number); + void setCurrentEntry(QListViewItem*, bool playIcon = true); + + QListViewItem* getLast(); + QListViewItem* getFirst(); + QListViewItem* findByURL(const QString&); + + /* insert a KURL(list) after a specific item */ + void add(const QString& url, QListViewItem* after); + void add(const QStringList& urls, QListViewItem* after); + void add(const QValueList<MRL>&, QListViewItem* after); + + bool isQueueMode() { return m_queue.count(); } + + void setPlaylist(const QString& name, bool clear = false); + void nextPlaylist(); + void removeCurrentPlaylist(); + void saveCurrentPlaylist(); + QString queryCurrentPlaylist(); + void loadConfig(KConfig*); + void saveConfig(KConfig*); + void clearList(); + + void setEndless(bool); + void setRandom(bool); + + void useAlternateEncoding(bool); + void setAlternateEncoding(const QString&); + + void setFileFilter(const QString& filter); + void savePlaylist(const QString&); + void loadPlaylist(const QString&); + + void exportM3UPlaylist(const QString&); + void exportPLSPlaylist(const QString&); + + const bool getReadMetaOnLoading() const { return m_metaOnLoading; } + + QVBox *mainWidget; + QVBox *playerBox; + +public slots: + void slotToggleShuffle(); + +protected: + void closeEvent(QCloseEvent*); + +private slots: + void slotNewList(); + void slotSetReadMetaOnLoading(bool read) { m_metaOnLoading = read; } + void slotSetAlternateColor(const QColor&); + void slotPlayDirect(QListViewItem* item); /* doubleclick */ + void slotDropEvent(QDropEvent*, QListViewItem*); + void slotPreDropEvent(); + void slotCut(); + void slotPaste(); + void slotCopy(); + void slotSelectAll(); + void slotPlaylistFromSelected(); + void slotAddToQueue(MRL); + void slotRemoveSelected(); + void slotFindText(const QString&); + void slotSort(int); + void slotPlaylistActivated(int); + void slotNewPlaylistName(const QString&); + void slotRepeat(); + void slotShuffle(); + void slotAutoCover(); + void slotShowPlayer(); + void slotPlaylistLoad(); + void slotPlaylistSaveAs(); + void slotPlaylistRemove(); + void setCover( QString s1, QString s2, bool forceFetch=false ); + void chooseCurrentCover(); + void showGallery(); + void startPlaylist(); + void fileSelected( const KFileItem* ); + void setBrowserURL( const QString& ); + void setBrowserURL( const KURL& ); + void browserURLChanged( const KURL& ); + void slotClearList(); + void resetSearch(); + +private: + QListViewItem* insertItem(QListViewItem* after, const MRL&); + void updateStatus(); + void createRandomList(); + void getMetaInfo(MRL& mrl, const QString& mimeName); + void setupActions(); + /* helpers */ + static QString msToTimeString(int); + static int timeStringToMs(const QString&); + static bool endsWith(QString, QString, bool); + static bool startsWith(QString, QString, bool); + +private: + QColor m_altCol; + KComboBox* m_playlistSelector; + QToolButton *searchBtn; + KLineEdit* m_playlistFilter; + int m_nextPlaylistNumber; + QString m_playlistDirectory; + int m_currentPlaylist; + KURLComboBox *browserComb; + + QSplitter *hSplit, *vSplit; + QVBox *panel; + QWidget *playlist; + KDirOperator *fileBrowser; + KFileIconView *view; + CoverFrame *coverFrame; + GoogleFetcher *google; + QString coverImageFormat; + RollTitle *roller; + + KToggleAction *m_repeat, *m_shuffle, *m_autoCover, *m_showPlayer; + + QValueList<MRL> m_queue; + + uint m_playTime; + uint m_playTimeVisible; + uint m_countVisible; + + bool m_searchSelection; + bool m_metaOnLoading; + bool m_sortAscending; + + UrlListView* m_list; + QListViewItem* m_currentEntry; + MRL m_currentEntryMRL; + + QString m_fileFilter; + QString m_metaInfoString; + QString m_lastPlaylist; + + QPtrList<QListViewItem> m_randomList; + int m_currentRandomListEntry; + + QPixmap m_isCurrentEntry; + QPixmap m_cdPixmap; + + bool m_endless; + bool m_random; + bool m_cover; + + bool m_useAlternateEncoding; + QString m_alternateEncoding; + +signals: + void signalRequestForAudioCD(const QString&); + void signalRequestForDVD(const QString&); + void signalRequestForVCD(const QString&); +}; + +class QListBox; +class QStringList; + +class SubtitleChooser : public KDialogBase +{ + Q_OBJECT +public: + SubtitleChooser(QStringList, QString, QWidget *parent=0, const char *name = 0); + virtual ~SubtitleChooser(); + + QString getSelection(); + +private: + QListBox *table; +}; + +class MovieChooser : public KDialogBase +{ + Q_OBJECT +public: + MovieChooser(QStringList, QString, QWidget *parent=0, const char *name = 0); + virtual ~MovieChooser(); + + QString getSelection(); + +private: + QListBox *table; +}; + +#endif /* PLAYLIST_H */ diff --git a/kaffeine/src/input/audiobrowser/playlistitem.cpp b/kaffeine/src/input/audiobrowser/playlistitem.cpp new file mode 100644 index 0000000..3b5fc05 --- /dev/null +++ b/kaffeine/src/input/audiobrowser/playlistitem.cpp @@ -0,0 +1,268 @@ +/* + * playlistitem.cpp - a self-displayable item for kaffeine's playlist + * + * Copyright (C) 2004-2005 Giorgos Gousios + * Copyright (C) 2004-2005 Jürgen Kofler <kaffeine@gmx.net> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include <qstringlist.h> + +#include <kdebug.h> + +#include "mrl.h" +#include "playlistitem.h" + +PlaylistItem::PlaylistItem(KListView *list, KListViewItem *after, const QString& url, const QString& mime, const QString& title, + const QString& length, const QString& artist, const QString& album, const QString& year, const QString& genre, + const QString& track, const QStringList& subtitles, int currentSubtitle) : + KListViewItem(list, after, mime, title, artist, album, track, length), + m_url(url), m_year(year), m_genre(genre), m_subtitles(subtitles), m_currentSubtitle(currentSubtitle), isCurrent(false) +{} + +PlaylistItem::PlaylistItem(KListView* list, KListViewItem* after, const MRL& mrl) : + KListViewItem(list, after, mrl.mime(), mrl.title(), mrl.artist(), mrl.album(), + mrl.track(), mrl.length().toString("h:mm:ss")), m_url(mrl.url()), + m_year(mrl.year()), m_genre(mrl.genre()), + m_subtitles(mrl.subtitleFiles()), m_currentSubtitle(mrl.currentSubtitle()), isCurrent(false) +{} + +PlaylistItem::~PlaylistItem() {} + +MRL PlaylistItem::toMRL() const +{ + return MRL(url(), title(), stringToTime(length()), mime(), artist(), album(), track(), year(), genre(), QString::null, subtitles(), currentSubtitle()); +} + +const QString& PlaylistItem::url() const +{ + return m_url; +} + +QString PlaylistItem::mime() const +{ + return this->text(MIME_COLUMN); +} + +QString PlaylistItem::title() const +{ + return this->text(TITLE_COLUMN); +} + +QString PlaylistItem::artist() const +{ + return this->text(ARTIST_COLUMN); +} + +QString PlaylistItem::album() const +{ + return this->text(ALBUM_COLUMN); +} + +QString PlaylistItem::track() const +{ + return this->text(TRACK_COLUMN); +} + +QString PlaylistItem::year() const +{ + return m_year; +} + +QString PlaylistItem::genre() const +{ + return m_genre; +} + +QString PlaylistItem::length() const +{ + return this->text(LENGTH_COLUMN); +} + +const QStringList& PlaylistItem::subtitles() const +{ + return m_subtitles; +} + +int PlaylistItem::currentSubtitle() const +{ + return m_currentSubtitle; +} + +void PlaylistItem::setUrl(const QString& url) +{ + m_url = url; +} + +void PlaylistItem::setMime(const QString& mime) +{ + this->setText(MIME_COLUMN, mime); +} + +void PlaylistItem::setTitle(const QString& title) +{ + this->setText(TITLE_COLUMN, title); +} + +void PlaylistItem::setArtist(const QString& artist) +{ + this->setText(ARTIST_COLUMN, artist); +} + +void PlaylistItem::setAlbum(const QString& album) +{ + this->setText(ALBUM_COLUMN, album); +} + +void PlaylistItem::setTrack(const QString& track) +{ + this->setText(TRACK_COLUMN, track); +} + +void PlaylistItem::setYear(const QString& year) +{ + m_year = year; +} + +void PlaylistItem::setGenre(const QString& genre) +{ + m_genre = genre; +} + +void PlaylistItem::setLength(const QString& length) +{ + this->setText(LENGTH_COLUMN, length); +} + +void PlaylistItem::setSubtitles(const QStringList& subs) +{ + m_subtitles = subs; +} + +void PlaylistItem::addSubtitle(const QString& sub) +{ + /* This will add subtitle & set it to the current one */ + for (uint i=0; i < m_subtitles.count(); i++) { + if (m_subtitles[i] == sub) { + m_currentSubtitle = i; + return; + } + } + m_subtitles.append(sub); + m_currentSubtitle = m_subtitles.count()-1; +} + +void PlaylistItem::setCurrentSubtitle(int sub) +{ + m_currentSubtitle = sub; +} + +QTime PlaylistItem::stringToTime(const QString& timeString) +{ + int sec = 0; + bool ok = false; + QStringList tokens = QStringList::split(':',timeString); + + sec += tokens[0].toInt(&ok)*3600; //hours + sec += tokens[1].toInt(&ok)*60; //minutes + sec += tokens[2].toInt(&ok); //secs + + if (ok) + return QTime().addSecs(sec); + else + return QTime(); +} + +int PlaylistItem::compare(QListViewItem *i, int col, bool ascending ) const +{ + PlaylistItem* p = dynamic_cast<PlaylistItem*>(i); + if (!p) + return QListViewItem::compare(i, col, ascending); + + //if both strings are empty, sort by filename + if (text(col).isEmpty() && i->text(col).isEmpty()) + return -url().compare(p->url()); + + bool ok; + int track1, track2 = 0; + track1 = track().toInt(&ok); + if (ok) + track2 = p->track().toInt(&ok); + + if (col == TRACK_COLUMN) + { + if (ok) + return (track2 - track1); + else + return QListViewItem::compare(i, col, ascending); + } + else + { + int result = QListViewItem::compare(i, col, ascending); + + //if artists are equal, compare albums + if ((col == ARTIST_COLUMN) && (result == 0)) + { + result = QListViewItem::compare(i, ALBUM_COLUMN, ascending); + if (!ascending) + result = -result; + } + + //if strings are equal, sort by track number or filename + if (result == 0) + { + int diff; + if (ok) + diff = track1 - track2; + else + diff = url().compare(p->url()); + + if (ascending) + return diff; + else + return -diff; + } + else + return result; + } +} + +void PlaylistItem::setPlaying(bool playing) +{ + isCurrent = playing; +} + +void PlaylistItem::paintCell(QPainter *p, const QColorGroup &cg, int column, int width, int align) +{ + if (isCurrent) + { + QColorGroup colorGroup = cg; + + QColor base = colorGroup.base(); + QColor selection = colorGroup.highlight(); + + int r = (base.red() + selection.red()) / 2; + int b = (base.blue() + selection.blue()) / 2; + int g = (base.green() + selection.green()) / 2; + + QColor c(r, g, b); + + colorGroup.setColor(QColorGroup::Base, c); + QListViewItem::paintCell(p, colorGroup, column, width, align); + } + else + return KListViewItem::paintCell(p, cg, column, width, align); +} diff --git a/kaffeine/src/input/audiobrowser/playlistitem.h b/kaffeine/src/input/audiobrowser/playlistitem.h new file mode 100644 index 0000000..9b1b9f5 --- /dev/null +++ b/kaffeine/src/input/audiobrowser/playlistitem.h @@ -0,0 +1,93 @@ +/* + * playlistitem.h - a self-displayable item for kaffeine's playlist + * + * Copyright (C) 2004-2005 Giorgos Gousios + * Copyright (C) 2004-2005 Jürgen Kofler <kaffeine@gmx.net> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef PLAYLISTITEM_H +#define PLAYLISTITEM_H + +#include <klistview.h> + +#define MIME_COLUMN 0 +#define TITLE_COLUMN 1 +#define ARTIST_COLUMN 2 +#define ALBUM_COLUMN 3 +#define TRACK_COLUMN 4 +#define LENGTH_COLUMN 5 + +class QTime; +class QString; +class QStringList; +class MRL; + +class PlaylistItem : public KListViewItem +{ + +public: + PlaylistItem(KListView *list, KListViewItem *after, const QString& url, const QString& mime, const QString& title, + const QString& length = QString::null, const QString& artist = QString::null, const QString& album = QString::null, + const QString& track = QString::null, const QString& year = QString::null, const QString& genre = QString::null, + const QStringList& subtitles = QStringList(), int currentSubtitle = -1); + PlaylistItem(KListView* list, KListViewItem* after, const MRL&); + virtual ~PlaylistItem(); + + MRL toMRL() const; + + const QString& url() const; + QString mime() const; + QString title() const; + QString artist() const; + QString album() const; + QString track() const; + QString year() const; + QString genre() const; + QString length() const; + const QStringList& subtitles() const; + int currentSubtitle() const; + + void setUrl(const QString&); + void setMime(const QString&); + void setTitle(const QString&); + void setArtist(const QString&); + void setAlbum(const QString&); + void setTrack(const QString&); + void setYear(const QString&); + void setGenre(const QString&); + void setLength(const QString&); + void setSubtitles(const QStringList&); + void addSubtitle(const QString&); + void setCurrentSubtitle(int); + + //reimplement to fix track order + int compare( QListViewItem *i, int col, bool ascending ) const; + + void setPlaying(bool playing); + virtual void paintCell(QPainter *p, const QColorGroup &cg, int column, int width, int align); + +private: + static QTime stringToTime(const QString&); + QString m_url; + QString m_year; + QString m_genre; + QStringList m_subtitles; + int m_currentSubtitle; + bool isCurrent; +}; + +#endif /* PLAYLISTITEM_H */ diff --git a/kaffeine/src/input/audiobrowser/urllistview.cpp b/kaffeine/src/input/audiobrowser/urllistview.cpp new file mode 100644 index 0000000..49cfc3c --- /dev/null +++ b/kaffeine/src/input/audiobrowser/urllistview.cpp @@ -0,0 +1,347 @@ +/* + * urllistview.cpp + * + * Copyright (C) 2003-2005 Jürgen Kofler <kaffeine@gmx.net> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include <kglobal.h> +#include <kiconloader.h> +#include <klocale.h> +#include <kmessagebox.h> +#include <kdebug.h> +#include <kurl.h> +#include <kglobalsettings.h> +#include <kfiledialog.h> +#include <kpopupmenu.h> + +#include <qfontmetrics.h> +#include <qdragobject.h> + +#include "mrl.h" +#include "playlistitem.h" +#include "urllistview.h" +#include "urllistview.moc" + + +UrlListView::UrlListView(QWidget *parent, const char *name ) : KListView(parent,name), + m_listCleared(true), m_itemOfContextMenu(NULL) +{ + m_contextMenu = new KPopupMenu(this); + m_contextMenu->insertItem(KGlobal::iconLoader()->loadIconSet("player_play", KIcon::Small), i18n("Play"), this, SLOT(slotPlayItem())); + m_contextMenu->insertItem(i18n("Play Next/Add to Queue"), this, SLOT(slotPlayNext())); + m_contextMenu->insertSeparator(); + + m_contextMenu->insertItem(KGlobal::iconLoader()->loadIconSet("editcut", KIcon::Small), i18n("C&ut"), this, SIGNAL(signalCut()), CTRL+Key_X); + m_contextMenu->insertItem(KGlobal::iconLoader()->loadIconSet("editcopy", KIcon::Small), i18n("&Copy"), this, SIGNAL(signalCopy()), CTRL+Key_C); + m_contextMenu->insertItem(KGlobal::iconLoader()->loadIconSet("editpaste", KIcon::Small), i18n("&Paste"), this, SIGNAL(signalPaste()), CTRL+Key_V); + m_contextMenu->insertItem(i18n("Select &All"), this, SIGNAL(signalSelectAll()), CTRL+Key_A); + m_contextMenu->insertItem(i18n("Create Playlist From Selected"), this, SIGNAL(signalPlaylistFromSelected())); + m_contextMenu->insertSeparator(); + m_contextMenu->insertItem(KGlobal::iconLoader()->loadIconSet("indent", KIcon::Small), i18n("Add Sub&title..."), this, SLOT(slotAddSubtitle()),QKeySequence(),100 ); + m_contextMenu->insertSeparator(); + m_contextMenu->insertItem(KGlobal::iconLoader()->loadIconSet("edit", KIcon::Small), i18n("&Edit Title"), this, SLOT(slotEditTitle())); + m_contextMenu->insertItem(KGlobal::iconLoader()->loadIconSet("info", KIcon::Small), i18n("&Info"), this, SLOT(slotShowInfo())); + +/* width of the "length"-column */ + QFontMetrics met(KGlobalSettings::generalFont()); + int w1 = met.width(i18n("Length")); + int w2 = met.width("5:55:55") + 2; + + m_column5Width = w1 > w2 ? w1 : w2; + m_column5Width += 30; + +/* width of the "track"-column */ + w1 = met.width(i18n("Track")); + w2 = met.width("9999") + 2; + + m_column4Track = w1 > w2 ? w1 : w2; + m_column4Track += 36; + + connect(this, SIGNAL(contextMenuRequested(QListViewItem*, const QPoint&, int)), + this, SLOT(slotShowContextMenu(QListViewItem*, const QPoint&, int))); + connect(this, SIGNAL(currentChanged(QListViewItem*)), + this, SLOT(slotCurrentChanged(QListViewItem*))); + connect(this, SIGNAL(clicked( QListViewItem*, const QPoint&, int )), + this, SLOT(slotClicked( QListViewItem*, const QPoint&, int ))); +} + +UrlListView::~UrlListView() +{ +} + +bool UrlListView::acceptDrag(QDropEvent* event) const +{ + return QUriDrag::canDecode(event) || QTextDrag::canDecode(event) || KListView::acceptDrag(event); +} + +QDragObject* UrlListView::dragObject() +{ + // get selected items + QPtrList<QListViewItem> selected; + QStrList urlList; + + selected = selectedItems(); + for (uint i = 0; i<selected.count(); i++) + { + urlList.append(dynamic_cast<PlaylistItem*>(selected.at(i))->url().ascii()); + } + + return new QUriDrag(urlList, viewport()); +} + +void UrlListView::resizeEvent(QResizeEvent* rev) +{ + int width = contentsRect().width() - m_column5Width - m_column4Track - 69; + setColumnWidth(0, 20); /* mime */ + setColumnWidth(1, ((width * 5 / 12) + 50)); /* title */ + setColumnWidth(2, (width * 3 / 12)); /* artist */ + setColumnWidth(3, (width * 4 / 12)); /* album */ + setColumnWidth(4, m_column4Track); /* track */ + setColumnWidth(5, m_column5Width); /* width of "length" column */ + + KListView::resizeEvent(rev); +} + +void UrlListView::clear() +{ + m_listCleared = true; + m_itemOfContextMenu = NULL; + setSorting(-1); + KListView::clear(); +} + +void UrlListView::setCleared(bool cl) +{ + m_listCleared = cl; +} + +bool UrlListView::getCleared() const /* was playlist cleared ? */ +{ + return m_listCleared; +} + +/********** context menu **********/ + +void UrlListView::slotShowContextMenu(QListViewItem* item, const QPoint& pos, int) +{ + if (!item) + { + m_itemOfContextMenu = NULL; + disableSubEntry(); + } + else + { + m_itemOfContextMenu = dynamic_cast<PlaylistItem *>(item); + if (m_itemOfContextMenu->mime().contains("video")) + enableSubEntry(); + else + disableSubEntry(); + } + + m_contextMenu->popup(pos); +} + +void UrlListView::slotPlayItem() +{ + if (m_itemOfContextMenu) + emit signalPlayItem(m_itemOfContextMenu); +} + +void UrlListView::slotPlayNext() +{ + if (m_itemOfContextMenu) + emit signalAddToQueue(m_itemOfContextMenu->toMRL()); +} + +void UrlListView::slotEditTitle() +{ + if (m_itemOfContextMenu) + { + m_itemOfContextMenu->setRenameEnabled(1, true); + m_itemOfContextMenu->startRename(1); + m_itemOfContextMenu->setRenameEnabled(1, false); + } +} + +//Pretty print item info +void UrlListView::slotShowInfo() +{ + if (!m_itemOfContextMenu) + return; + + QString num; + num = num.setNum(childCount()); + QString info = "<qt><table width=\"90%\">"; + info = info + "<tr><td colspan=\"2\"><center><b>" + m_itemOfContextMenu->title() + "</b></center></td></tr>"; + info = info + "<tr><td><b>" + i18n("URL")+ ":</b></td><td>" + m_itemOfContextMenu->url() + "</td></tr>"; + info = info + "<tr><td><b>" + i18n("Artist") + ":</b></td><td>" + m_itemOfContextMenu->artist() + "</td></td>"; + info = info + "<tr><td><b>" + i18n("Album") + ":</b></td><td>" + m_itemOfContextMenu->album() + "</td></td>"; + info = info + "<tr><td><b>" + i18n("Track") + ":</b></td><td>" + m_itemOfContextMenu->track() + "</td></td>"; + info = info + "<tr><td><b>" + i18n("Year") + ":</b></td><td>" + m_itemOfContextMenu->year() + "</td></td>"; + info = info + "<tr><td><b>" + i18n("Genre") + ":</b></td><td>" + m_itemOfContextMenu->genre() + "</td></td>"; + info = info + "<tr><td><b>" + i18n("Length") + ":</b></td><td>" + m_itemOfContextMenu->length() + "</td></tr>"; + if(!m_itemOfContextMenu->subtitles().isEmpty()) + { + info = info + "<tr><td><b>" + i18n("Subtitles") + ":</b></td><td>"; + + for(uint i = 0; i < m_itemOfContextMenu->subtitles().count(); i++ ) + { + info = info + ""+m_itemOfContextMenu->subtitles()[i]; + if(m_itemOfContextMenu->currentSubtitle() == (int)i) + info = info + "<small> ("+i18n("in use")+")</small>"; + info = info + "<br>"; + } + info = info + "</ul></td></tr></table></qt>"; + } + + KMessageBox::information(this, info); +} + +void UrlListView::slotClicked(QListViewItem*, const QPoint&, int) +{ + /*if ( (item) && (col == 3) ) + { + m_itemOfContextMenu = dynamic_cast<PlaylistItem *>(item); + if (!m_itemOfContextMenu) return; + slotShowInfo(); + } */ +} + +#include <qdom.h> +#include <kio/job.h> + +void UrlListView::slotAddSubtitle() +{ + /*QDomDocument reqdoc; + + QDomElement methodCall = reqdoc.createElement( "methodCall" ); + QDomElement methodName = reqdoc.createElement( "methodName" ); + QDomText methodNameValue = reqdoc.createTextNode( "LogIn" ); + methodName.appendChild( methodNameValue ); + methodCall.appendChild( methodName ); + reqdoc.appendChild( methodCall ); + + QDomElement params = reqdoc.createElement( "params" ); + + QDomElement param1 = reqdoc.createElement( "param" ); + QDomElement value1 = reqdoc.createElement( "value" ); + QDomElement type1 = reqdoc.createElement( "string" ); + QDomText param1Value = reqdoc.createTextNode( "" ); + type1.appendChild( param1Value ); + value1.appendChild( type1 ); + param1.appendChild( value1 ); + params.appendChild( param1 ); + + QDomElement param2 = reqdoc.createElement( "param" ); + QDomElement value2 = reqdoc.createElement( "value" ); + QDomElement type2 = reqdoc.createElement( "string" ); + QDomText param2Value = reqdoc.createTextNode( "" ); + type2.appendChild( param2Value ); + value2.appendChild( type2 ); + param2.appendChild( value2 ); + params.appendChild( param2 ); + + QDomElement param3 = reqdoc.createElement( "param" ); + QDomElement value3 = reqdoc.createElement( "value" ); + QDomElement type3 = reqdoc.createElement( "string" ); + QDomText param3Value = reqdoc.createTextNode( "en" ); + type3.appendChild( param3Value ); + value3.appendChild( type3 ); + param3.appendChild( value3 ); + params.appendChild( param3 ); + + methodCall.appendChild( params ); + + const QString xmlRequest = "<?xml version=\"1.0\"?>\n" + reqdoc.toString(); + + QByteArray postData; + QDataStream stream( postData, IO_WriteOnly ); + stream.writeRawBytes( xmlRequest.utf8(), xmlRequest.utf8().length() ); + + openSubJobBuf = QByteArray(); + + openSubJob = KIO::http_post( "http://test.opensubtitles.org/xml-rpc", postData, false ); + openSubJob->addMetaData( "content-type", "Content-Type: text/xml" ); + + connect( openSubJob, SIGNAL(result(KIO::Job*)), this, SLOT(openSubResult(KIO::Job*)) ); + connect( openSubJob, SIGNAL(data(KIO::Job*,const QByteArray&) ), this, SLOT(openSubData(KIO::Job*, + const QByteArray&)) ); + + kdDebug() << "\n\n" << xmlRequest << "\n\n" << endl;*/ + + + if (!m_itemOfContextMenu) + return; + + QString openURL = m_itemOfContextMenu->url(); + QString subtitleURL = KFileDialog::getOpenURL(openURL, + i18n("*.smi *.srt *.sub *.txt *.ssa *.asc|Subtitle Files\n*.*|All Files"), + 0, i18n("Select Subtitle File")).path(); + if(!(subtitleURL.isEmpty()) && !(m_itemOfContextMenu->subtitles().contains(subtitleURL)) && QFile::exists(subtitleURL)) + { + m_itemOfContextMenu->addSubtitle(subtitleURL); + emit signalPlayItem(m_itemOfContextMenu); + } + +} + +void UrlListView::openSubResult( KIO::Job* job ) +{ + if ( openSubJob!=job ) + return; + if ( job->error() ) { + kdDebug() << "OpenSubtiltes error : " << job->error() << endl; + return; + } + + QDomDocument document; + if ( !document.setContent( openSubJobBuf ) ) { + kdDebug() << "Couldn't read similar artists response" << endl; + return; + } + kdDebug() << "\n\n" << document.toString() << "\n\n" << endl; + openSubJob = 0; +} + +void UrlListView::openSubData( KIO::Job* job, const QByteArray& data ) +{ + if ( openSubJob != job ) + return; + + unsigned int bufsize = openSubJobBuf.size(); + openSubJobBuf.resize( bufsize + data.size() ); + memcpy( openSubJobBuf.data()+bufsize, data.data(), data.size() ); +} + + +void UrlListView::slotCurrentChanged(QListViewItem * item) +{ + if(item == 0) //All items deleted + m_itemOfContextMenu = NULL; + else + m_itemOfContextMenu = dynamic_cast<PlaylistItem *>(item); +} + +void UrlListView::enableSubEntry() +{ + m_contextMenu->setItemEnabled(100, true); +} + +void UrlListView::disableSubEntry() +{ + m_contextMenu->setItemEnabled(100, false); +} diff --git a/kaffeine/src/input/audiobrowser/urllistview.h b/kaffeine/src/input/audiobrowser/urllistview.h new file mode 100644 index 0000000..964b743 --- /dev/null +++ b/kaffeine/src/input/audiobrowser/urllistview.h @@ -0,0 +1,92 @@ +/* + * urllistview.h + * + * Copyright (C) 2003-2005 Jürgen Kofler <kaffeine@gmx.net> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef URLLISTVIEW_H +#define URLLISTVIEW_H + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <klistview.h> + +class KPopupMenu; +class QWidget; +class QDragObject; +class PlaylistItem; +class MRL; +class KIO::Job; + +class UrlListView : public KListView +{ + Q_OBJECT +public: + UrlListView(QWidget *parent=0, const char *name=0); + ~UrlListView(); + + void setCleared(bool); + bool getCleared() const; /* was the playlist cleared or should we save it? */ + +public slots: + virtual void clear(); /* reimplement slot */ + +signals: + void signalPlayItem(QListViewItem* ); /* play selected in context menu */ + void signalCut(); + void signalCopy(); + void signalPaste(); + void signalSelectAll(); + void signalAddToQueue(MRL); + void signalPlaylistFromSelected(); + +private slots: + void slotShowContextMenu(QListViewItem*, const QPoint&, int); + void slotCurrentChanged(QListViewItem *); + void slotAddSubtitle(); + void slotShowInfo(); + void slotEditTitle(); + void slotPlayItem(); + void slotClicked(QListViewItem*, const QPoint&, int); + void slotPlayNext(); + void openSubResult( KIO::Job* ); + void openSubData( KIO::Job*, const QByteArray& ); + +protected: + virtual bool acceptDrag(QDropEvent* event) const; + virtual void resizeEvent(QResizeEvent*); + virtual QDragObject* dragObject(); + +private: + void enableSubEntry(); + void disableSubEntry(); + +private: + bool m_listCleared; + int m_column5Width; /* width of the fifth column */ + int m_column4Track; /* width of the fourth column */ + + PlaylistItem* m_itemOfContextMenu; + KPopupMenu* m_contextMenu; + KIO::Job *openSubJob; + QByteArray openSubJobBuf; + +}; + +#endif /* URLLISTVIEW_H */ diff --git a/kaffeine/src/input/disc/Makefile.am b/kaffeine/src/input/disc/Makefile.am new file mode 100644 index 0000000..b9827cc --- /dev/null +++ b/kaffeine/src/input/disc/Makefile.am @@ -0,0 +1,36 @@ +METASOURCES = AUTO + +SUBDIRS = plugins . + +noinst_LTLIBRARIES = libkaffeinedisc.la + +noinst_HEADERS = cddb.h \ + disc.h \ + paranoia.h + +INCLUDES = -I$(top_srcdir)/kaffeine/src/input/ \ + -I$(top_builddir)/kaffeine/src/input/ \ + -I$(top_srcdir)/kaffeine/src/ \ + -I$(top_srcdir)/kaffeine/src/player-parts/kaffeine-part \ + -I$(top_srcdir)/kaffeine/src/input/disc/plugins \ + $(all_includes) + +libkaffeinedisc_la_SOURCES = disc.cpp \ + cddb.cpp \ + paranoia.cpp \ + paranoiasettings.ui + +libkaffeinedisc_la_LDFLAGS = $(KDE_RPATH) \ + $(all_libraries) \ + -L$(top_srcdir)/kaffeine/src/input \ + -L$(top_srcdir)/kaffeine/src/input/disc/plugins + +libkaffeinedisc_la_LIBADD = $(top_builddir)/kaffeine/src/input/libkaffeineinput.la \ + $(top_builddir)/kaffeine/src/player-parts/kaffeine-part/libkaffeinepart.la \ + $(top_builddir)/kaffeine/src/input/disc/plugins/libkaffeineaudioencoder.la \ + -lcdda_interface -lcdda_paranoia + +# this is where the XML-GUI resource file goes +shellrcdir = $(kde_datadir)/kaffeine +shellrc_DATA = kaffeinedisc.rc + diff --git a/kaffeine/src/input/disc/cddb.cpp b/kaffeine/src/input/disc/cddb.cpp new file mode 100644 index 0000000..407fbbc --- /dev/null +++ b/kaffeine/src/input/disc/cddb.cpp @@ -0,0 +1,572 @@ +/* + * cddb.cpp + * + * Copyright (C) 2000 Michael Matz <matz@kde.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <errno.h> +#include <unistd.h> +#include <qdir.h> +#include <qtextstream.h> +#include <qregexp.h> +#include <qapplication.h> +#include <qstring.h> +#include <qcursor.h> +#include <kdebug.h> +#include <ksock.h> +#include <kextsock.h> +#include <klocale.h> +#include <kinputdialog.h> + +#include "cddb.h" +#include "cddb.moc" + +CDDB::CDDB() : ks(0), port(80), remote(false), save_local(false) +{ + QString s = QDir::homeDirPath()+"/.cddb"; + cddb_dirs +=s; +} + +CDDB::~CDDB() +{ + deinit(); +} + +bool CDDB::set_server(const char *hostname, unsigned short int _port) +{ + if (ks) + { + if (h_name == hostname && port == _port) + return true; + deinit(); + } + remote = (hostname != 0) && (*hostname != 0); + kdDebug(7101) << "CDDB: set_server, host=" << hostname << "port=" << _port << endl; + if (remote) + { + ks = new KExtendedSocket(hostname, _port); + if (ks->connect() < 0) + { + kdDebug(7101) << "CDDB: Can't connect!" << endl; + delete ks; + ks = 0; + return false; + } + + h_name = hostname; + port = _port; + QCString r; + readLine(r); // the server greeting + writeLine("cddb hello kde-user blubb kio_audiocd 0.4"); + readLine(r); + } + return true; +} + +bool CDDB::deinit() +{ + if (ks) + { + writeLine("quit"); + QCString r; + readLine(r); + ks->close(); + } + h_name.resize(0); + port = 0; + remote = false; + ks = 0; + return true; +} + +bool CDDB::readLine(QCString& ret) +{ + int read_length = 0; + char small_b[128]; + //fd_set set; + + ret.resize(0); + while (read_length < 40000) + { + // Look for a \n in buf + int ni = buf.find('\n'); + if (ni >= 0) + { + // Nice, so return this substring (without the \n), + // and truncate buf accordingly + ret = buf.left(ni); + if (ret.length() && ret[ret.length()-1] == '\r') + ret.resize(ret.length()); + buf.remove(0, ni+1); + kdDebug(7101) << "CDDB: got `" << ret << "'" << endl; + return true; + } + + // Try to refill the buffer + ks->waitForMore(60 * 1000); + ssize_t l = ks->readBlock(small_b, sizeof(small_b)-1); + if (l <= 0) + { + // l==0 normally means fd got closed, but we really need a lineend + return false; + } + small_b[l] = 0; + read_length += l; + buf += small_b; + } + return false; +} + +bool CDDB::writeLine(const QCString& line) +{ + const char *b = line.data(); + int l = line.length(); + kdDebug(7101) << "CDDB: send `" << line << "'" << endl; + while (l) + { + ssize_t wl = ks->writeBlock(b, l); + if (wl < 0 && errno != EINTR) + return false; + if (wl < 0) + wl = 0; + l -= wl; + b += wl; + } + l = line.length(); + if (l && line.data()[l-1] != '\n') + { + char c = '\n'; + ssize_t wl; + do { + wl = ks->writeBlock(&c, 1); + } while (wl <= 0 && errno == EINTR); + if (wl<=0 && errno != EINTR) + return false; + } + return true; +} + +unsigned int CDDB::get_discid(QValueList<int>& track_ofs) +{ + unsigned int id = 0; + int num_tracks = track_ofs.count() - 2; + + // the last two track_ofs[] are disc begin and disc end + + for (int i = num_tracks - 1; i >= 0; i--) + { + int n = track_ofs[i]; + n /= 75; + while (n > 0) + { + id += n % 10; + n /= 10; + } + } + unsigned int l = track_ofs[num_tracks + 1]; + l -= track_ofs[num_tracks]; + l /= 75; + id = ((id % 255) << 24) | (l << 8) | num_tracks; + return id; +} + +static int get_code (const QCString &s) +{ + bool ok; + int code = s.left(3).toInt(&ok); + if (!ok) + code = -1; + return code; +} + +static void parse_query_resp (const QCString& _r, QCString& catg, QCString& d_id, QCString& title) +{ + QCString r = _r.stripWhiteSpace(); + int i = r.find(' '); + if (i) + { + catg = r.left(i).stripWhiteSpace(); + r.remove(0, i+1); + r = r.stripWhiteSpace(); + } + i = r.find(' '); + if (i) + { + d_id = r.left(i).stripWhiteSpace(); + r.remove(0, i+1); + r = r.stripWhiteSpace(); + } + title = r; +} + +QString CDDB::track(int i) const +{ + if (i < 0 || i >= int(m_names.count())) + return QString(); + return m_names[i].utf8(); +} + +bool CDDB::parse_read_resp(QTextStream *stream, QTextStream *write_stream) +{ + /* Note, that m_names and m_title should be empty */ + QCString end = "."; + + /* Fill table, so we can index it below. */ + for (int i = 0; i < m_tracks; i++) + { + m_names.append(""); + } + while (1) + { + QCString r; + if (stream) + { + if (stream->atEnd()) + break; + r = stream->readLine().latin1(); + } + else + { + if (!readLine(r)) + return false; + } + /* Normally the "." is not saved into the local files, but be + tolerant about this. */ + if (r == end) + break; + if (write_stream) + *write_stream << r << endl; + r = r.stripWhiteSpace(); + if (r.isEmpty() || r[0] == '#') + continue; + if (r.left(7) == "DTITLE=") + { + r.remove(0, 7); + m_title += QString::fromLocal8Bit(r.stripWhiteSpace()); + } + else if (r.left(6) == "TTITLE") + { + r.remove(0, 6); + int e = r.find('='); + if (e) + { + bool ok; + int i = r.left(e).toInt(&ok); + if (ok && i >= 0 && i < m_tracks) + { + r.remove(0, e+1); + m_names[i] += QString::fromLocal8Bit(r); + } + } + } + } + + /* XXX We should canonicalize the strings ("\n" --> '\n' e.g.) */ + + int si = m_title.find(" / "); + if (si > 0) + { + m_artist = m_title.left(si).stripWhiteSpace(); + m_title.remove(0, si+3); + m_title = m_title.stripWhiteSpace(); + } + + if (m_title.isEmpty()) + m_title = i18n("No Title"); + /*else + m_title.replace(QRegExp("/"), "%2f");*/ + if (m_artist.isEmpty()) + m_artist = i18n("Unknown"); + /*else + m_artist.replace(QRegExp("/"), "%2f");*/ + + kdDebug(7101) << "CDDB: found Title: `" << m_title << "'" << endl; + for (int i = 0; i < m_tracks; i++) + { + if (m_names[i].isEmpty()) + m_names[i] += i18n("Track %1").arg(i); + m_names[i].replace(QRegExp("/"), "%2f"); + kdDebug(7101) << "CDDB: found Track " << i+1 << ": `" << m_names[i] + << "'" << endl; + } + return true; +} + +void CDDB::add_cddb_dirs(const QStringList& list) +{ + QString s = QDir::homeDirPath()+"/.cddb"; + + cddb_dirs = list; + if (cddb_dirs.isEmpty()) + cddb_dirs += s; +} + +/* Locates and opens the local file corresponding to that discid. + Returns TRUE, if file is found and ready for reading. + Returns FALSE, if file isn't found. In this case ret_file is initialized + with a QFile which resides in the first cddb_dir, and has a temp name + (the ID + getpid()). You can open it for writing. */ +bool CDDB::searchLocal(unsigned int id, QFile *ret_file) +{ + QDir dir; + QString filename; + filename = QString("%1").arg(id, 0, 16).rightJustify(8, '0'); + QStringList::ConstIterator it; + for (it = cddb_dirs.begin(); it != cddb_dirs.end(); ++it) + { + dir.setPath(*it); + if (!dir.exists()) + continue; + /* First look in dir directly. */ + ret_file->setName (*it + "/" + filename); + if (ret_file->exists() && ret_file->open(IO_ReadOnly)) + return true; + /* And then in the subdirs of dir (representing the categories normally). + */ + const QFileInfoList *subdirs = dir.entryInfoList (QDir::Dirs); + QFileInfoListIterator fiit(*subdirs); + QFileInfo *fi; + while ((fi = fiit.current()) != 0) + { + ret_file->setName (*it + "/" + fi->fileName() + "/" + filename); + if (ret_file->exists() && ret_file->open(IO_ReadOnly)) + return true; + ++fiit; + } + } + QString pid; + pid.setNum(::getpid()); + ret_file->setName (cddb_dirs[0] + "/" + filename + "." + pid); + /* Try to create the save location. */ + dir.setPath(cddb_dirs[0]); + if (save_local && !dir.exists()) + { + //dir = QDir::current(); + dir.mkdir(cddb_dirs[0]); + } + return false; +} + +bool CDDB::queryCD(QValueList<int>& track_ofs) +{ + int num_tracks = track_ofs.count() - 2; + if (num_tracks < 1) + return false; + unsigned int id = get_discid(track_ofs); + QFile file; + bool local; + + /* Already read this ID. */ + if (id == m_discid) + return true; + + emit cddbMessage(i18n("Searching local cddb entry ...")); + qApp->processEvents(); + + /* First look for a local file. */ + local = searchLocal (id, &file); + /* If we have no local file, and no remote connection, barf. */ + if (!local && (!remote || ks == 0)) + return false; + + m_tracks = num_tracks; + m_title = ""; + m_artist = ""; + m_names.clear(); + m_discid = id; + if (local) + { + QTextStream stream(&file); + /* XXX Hmm, what encoding is used by CDDB files? local? Unicode? + Nothing? */ + //stream.setEncoding(QTextStream::Locale); + parse_read_resp(&stream, 0); + file.close(); + return true; + } + + emit cddbMessage(i18n("Searching remote cddb entry ...")); + qApp->processEvents(); + + /* Remote CDDB query. */ + unsigned int length = track_ofs[num_tracks+1] - track_ofs[num_tracks]; + QCString q; + q.sprintf("cddb query %08x %d", id, num_tracks); + QCString num; + for (int i = 0; i < num_tracks; i++) + q += " " + num.setNum(track_ofs[i]); + q += " " + num.setNum(length / 75); + if (!writeLine(q)) + return false; + QCString r; + if (!readLine(r)) + return false; + r = r.stripWhiteSpace(); + int code = get_code(r); + if (code == 200) + { + QCString catg, d_id, title; + QDir dir; + QCString s, pid; + + emit cddbMessage(i18n("Found exact match cddb entry ...")); + qApp->processEvents(); + + /* an exact match */ + r.remove(0, 3); + parse_query_resp(r, catg, d_id, title); + kdDebug(7101) << "CDDB: found exact CD: category=" << catg << " DiscId=" + << d_id << " Title=`" << title << "'" << endl; + q = "cddb read " + catg + " " + d_id; + if (!writeLine(q)) + return false; + if (!readLine(r)) + return false; + r = r.stripWhiteSpace(); + code = get_code(r); + if (code != 210) + return false; + + pid.setNum(::getpid()); + s = cddb_dirs[0].latin1(); + //s = s + "/" +catg; // xine seems to not search in local subdirs + dir.setPath( s ); + if ( !dir.exists() ) dir.mkdir( s ); + s = s+"/"+ d_id; + file.setName( s ); + + if (save_local && file.open(IO_WriteOnly)) + { + kdDebug(7101) << "CDDB: file name to save =" << file.name() << endl; + QTextStream stream(&file); + if (!parse_read_resp(0, &stream)) + { + file.remove(); + return false; + } + file.close(); + /*QString newname (file.name()); + newname.truncate(newname.findRev('.')); + if (QDir::current().rename(file.name(), newname)) { + kdDebug(7101) << "CDDB: rename failed" << endl; + file.remove(); + } */ + } + else if (!parse_read_resp(0, 0)) + return false; + } + else if (code == 211) + { + // Found some close matches. We'll read the query response and ask the user + // which one should be fetched from the server. + QCString end = "."; + QCString catg, d_id, title; + QDir dir; + QCString s, pid, first_match; + QStringList disc_ids; + + /* some close matches */ + //XXX may be try to find marker based on r + emit cddbMessage(i18n("Found close cddb entry ...")); + qApp->processEvents(); + + int i=0; + while (1) + { + if (!readLine(r)) + return false; + r = r.stripWhiteSpace(); + if (r == end) + break; + disc_ids.append(r); + if (i == 0) + first_match = r; + i++; + } + + bool ok = false; + + // We don't want to be thinking too much, do we? + QApplication::restoreOverrideCursor(); + + // Oh, mylord, which match should I serve you? + QString _answer = KInputDialog::getItem(i18n("CDDB Matches"), i18n("Several close CDDB entries found. Choose one:"), + disc_ids, 0, false, &ok ); + QCString answer = _answer.utf8(); + + if (ok){ // Get user selected match + parse_query_resp(answer, catg, d_id, title); + } + else{ // Get first match + parse_query_resp(first_match, catg, d_id, title); + } + + // Now we can continue thinking... + QApplication::setOverrideCursor( QCursor(Qt::WaitCursor) ); + + kdDebug(7101) << "CDDB: found close CD: category=" << catg << " DiscId=" + << d_id << " Title=`" << title << "'" << endl; + + // ... and forth we go as usual + + q = "cddb read " + catg + " " + d_id; + if (!writeLine(q)) + return false; + if (!readLine(r)) + return false; + r = r.stripWhiteSpace(); + code = get_code(r); + if (code != 210) + return false; + + pid.setNum(::getpid()); + s = cddb_dirs[0].latin1(); + dir.setPath( s ); + if ( !dir.exists() ) dir.mkdir( s ); + s = s+"/"+ d_id; + file.setName( s ); + + if (save_local && file.open(IO_WriteOnly)) + { + kdDebug(7101) << "CDDB: file name to save =" << file.name() << endl; + QTextStream stream(&file); + if (!parse_read_resp(0, &stream)) + { + file.remove(); + return false; + } + file.close(); + } + else if (!parse_read_resp(0, 0)) + return false; + + } + else + { + /* 202 - no match found + 403 - Database entry corrupt + 409 - no handshake */ + kdDebug(7101) << "CDDB: query returned code " << code << endl; + return false; + } + + return true; +} diff --git a/kaffeine/src/input/disc/cddb.h b/kaffeine/src/input/disc/cddb.h new file mode 100644 index 0000000..e75eb2d --- /dev/null +++ b/kaffeine/src/input/disc/cddb.h @@ -0,0 +1,77 @@ +/* + * cddb.h + * + * Copyright (C) 2000 Michael Matz <matz@kde.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef CDDB_H +#define CDDB_H + +#include <qcstring.h> +#include <qvaluelist.h> +#include <qstringlist.h> +#include <qobject.h> + +class QFile; +class QTextStream; +class KExtendedSocket; + +class CDDB : public QObject +{ + Q_OBJECT + +public: + + CDDB(); + ~CDDB(); + bool set_server(const char *hostname = 0, unsigned short int port = 0); + void add_cddb_dirs(const QStringList& list); + void save_cddb (bool save) { save_local = save; } + unsigned int get_discid(QValueList<int>& track_ofs); + bool queryCD(QValueList<int>& track_ofs); + QString title() const { return m_title.utf8(); } + QString artist() const { return m_artist.utf8(); } + int trackCount() const { return m_tracks; } + QString track(int i) const; + +private: + + bool readLine(QCString& s); + bool writeLine(const QCString& s); + bool deinit(); + bool parse_read_resp(QTextStream*, QTextStream*); + bool searchLocal(unsigned int id, QFile *ret_file); + KExtendedSocket *ks; + QCString h_name; + unsigned short int port; + bool remote; + bool save_local; + QStringList cddb_dirs; + QCString buf; + unsigned int m_discid; + + int m_tracks; + QString m_title; + QString m_artist; + QStringList m_names; + +signals: + + void cddbMessage( QString ); +}; + +#endif /* CDDB_H */ diff --git a/kaffeine/src/input/disc/disc.cpp b/kaffeine/src/input/disc/disc.cpp new file mode 100644 index 0000000..224a270 --- /dev/null +++ b/kaffeine/src/input/disc/disc.cpp @@ -0,0 +1,767 @@ +/* + * disc.cpp + * + * Copyright (C) 2006 Christophe Thommeret <hftom@free.fr> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include <qstringlist.h> +#include <qlayout.h> +#include <qtooltip.h> +#include <qvaluelist.h> +#include <qcursor.h> +#include <qtimer.h> +#include <qfile.h> +#include <qpopupmenu.h> +#include <qapplication.h> + +#include <klocale.h> +#include <kiconloader.h> +#include <kmessagebox.h> +#include <kaction.h> +#include <kstdaction.h> +#include <kdebug.h> +#include <kinputdialog.h> +#include <dcopref.h> + +#include "cddb.h" +#include "mrl.h" +#include "disc.h" +#include "disc.moc" + +MLabel::MLabel( QWidget *parent ) : QLabel( parent ) +{ + setText("<center><font size=\"6\"><b>"+i18n("Audio CD")+"</b></font></center>"); +} + +void MLabel::paintEvent( QPaintEvent *pe ) +{ + QLabel::paintEvent( pe ); + QColorGroup cg = parentWidget()->colorGroup(); + QColor base = cg.base(); + QColor selection = cg.highlight(); + int r = (base.red() + selection.red()) / 2; + int b = (base.blue() + selection.blue()) / 2; + int g = (base.green() + selection.green()) / 2; + setPaletteBackgroundColor( QColor(r, g, b) ); +} + +MListView::MListView( QWidget *parent ) : KListView( parent ) +{ +} + +void MListView::resizeEvent( QResizeEvent *rev ) +{ + int width = contentsRect().width(); + setColumnWidth(0, 40); /* Track */ + setColumnWidth(1, width-90); /* title */ + setColumnWidth(2, 50); /* duration */ + + KListView::resizeEvent(rev); +} + +Disc::Disc( QWidget* parent, QObject *objParent, const char *name ) : KaffeineInput(objParent , name) +{ + mainWidget = new QVBox( parent ); + mainWidget->setSizePolicy( QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred) ); + split = new QSplitter( mainWidget ); + split->setOpaqueResize( true ); + widg = new QWidget( split ); + widg->setMinimumWidth( 200 ); + widg->setSizePolicy( QSizePolicy( QSizePolicy::Preferred, QSizePolicy::MinimumExpanding ) ); + QVBoxLayout *wb = new QVBoxLayout( widg, 0, 0 ); + discLab = new MLabel( widg ); + wb->addWidget( discLab ); + playerBox = new QVBox( widg ); + wb->addWidget( playerBox ); + playerBox->setMinimumWidth( 200 ); + playerBox->setSizePolicy( QSizePolicy( QSizePolicy::Preferred, QSizePolicy::MinimumExpanding ) ); + panel = new QFrame( split ); + split->moveToFirst( panel ); + panel->setSizePolicy( QSizePolicy( QSizePolicy::Preferred, QSizePolicy::MinimumExpanding ) ); + split->setResizeMode( panel, QSplitter::KeepSize ); + + QVBoxLayout *vb = new QVBoxLayout( panel, 3, 3 ); + cdBtn = new QToolButton( panel ); + cdBtn->setTextLabel( i18n("Play CD") ); + cdBtn->setTextPosition( QToolButton::Under ); + cdBtn->setUsesTextLabel( true ); + cdBtn->setSizePolicy( QSizePolicy( QSizePolicy::Preferred, QSizePolicy::Fixed ) ); + QToolTip::add( cdBtn, i18n("Play CD")); + ripBtn = new QToolButton( panel ); + ripBtn->setTextLabel( i18n("Rip CD") ); + ripBtn->setTextPosition( QToolButton::Under ); + ripBtn->setUsesTextLabel( true ); + ripBtn->setSizePolicy( QSizePolicy( QSizePolicy::Preferred, QSizePolicy::Fixed ) ); + QToolTip::add( ripBtn, i18n("Rip CD")); + + QHBoxLayout *h1 = new QHBoxLayout(); + h1->addWidget( cdBtn ); + h1->addWidget( ripBtn ); + vb->addLayout( h1 ); + + cdBtn->setIconSet( KGlobal::iconLoader()->loadIconSet("cdaudio_unmount", KIcon::Toolbar) ); + ripBtn->setIconSet( KGlobal::iconLoader()->loadIconSet("kilogram", KIcon::Toolbar) ); + + connect( cdBtn, SIGNAL(clicked()), this, SLOT(startCD()) ); + connect( ripBtn, SIGNAL(clicked()), this, SLOT(startRIP()) ); + + h1 = new QHBoxLayout(); + h1->addWidget( new QLabel( i18n("Artist:"), panel ) ); + artistLab = new QLabel( "", panel ); + artistLab->setLineWidth(1); + artistLab->setFrameStyle(QFrame::Panel|QFrame::Sunken); + artistLab->setSizePolicy( QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Preferred ) ); + h1->addWidget( artistLab ); + vb->addLayout( h1 ); + h1 = new QHBoxLayout(); + h1->addWidget( new QLabel( i18n("Album:"), panel ) ); + albumLab = new QLabel( "", panel ); + albumLab->setLineWidth(1); + albumLab->setFrameStyle(QFrame::Panel|QFrame::Sunken); + albumLab->setSizePolicy( QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Preferred ) ); + h1->addWidget( albumLab ); + vb->addLayout( h1 ); + + list = new MListView( panel ); + list->setHScrollBarMode( QListView::AlwaysOff ); + connect( list, SIGNAL(doubleClicked(QListViewItem*)), this, SLOT(trackSelected(QListViewItem*)) ); + list->addColumn( i18n("Track") ); + list->addColumn( i18n("Title") ); + list->addColumn( i18n("Duration") ); + //list->setSortColumn( -1 ); + list->setAllColumnsShowFocus( true ); + list->setSelectionMode(QListView::Extended); + list->setColumnWidthMode( 0, QListView::Manual ); + list->setColumnWidthMode( 1, QListView::Manual ); + list->setColumnWidthMode( 2, QListView::Manual ); + list->setResizeMode( QListView::NoColumn ); + vb->addWidget( list ); + + encodeWidget = new QWidget( panel ); + QGridLayout *grid = new QGridLayout( encodeWidget, 2, 2, 0, 3 ); + QLabel *lab = new QLabel( i18n("Select the tracks you want to rip and click the <b>Encode</b> button."), encodeWidget ); + grid->addMultiCellWidget( lab, 0, 1, 0, 0); + enc = new QToolButton( encodeWidget ); + grid->addMultiCellWidget( enc, 0, 0, 1, 1); + enc->setTextLabel( i18n("Encode...") ); + enc->setTextPosition( QToolButton::Under ); + enc->setUsesTextLabel( true ); + enc->setIconSet( KGlobal::iconLoader()->loadIconSet("kilogram", KIcon::Small) ); + enc->setSizePolicy( QSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed ) ); + connect( enc, SIGNAL(clicked()), this, SLOT(encode()) ); + vb->addWidget( encodeWidget ); + encodeWidget->hide(); + + progressBar = new QProgressBar( 100, panel ); + vb->addWidget( progressBar ); + progressBar->hide(); + + vb->addItem( new QSpacerItem( 1, 1, QSizePolicy::Preferred, QSizePolicy::Preferred ) ); + + artistLab->setPaletteBackgroundColor( list->paletteBackgroundColor() ); + albumLab->setPaletteBackgroundColor( list->paletteBackgroundColor() ); + + connect( &encodeTimer, SIGNAL(timeout()), this, SLOT(encodeProgress()) ); + + setXMLFile("kaffeinedisc.rc"); + setupActions(); + + loadConfig( KGlobal::config() ); + + para = NULL; + trackCurrent = 0; + currentPixmap = UserIcon("playing"); +} + +Disc::~Disc() +{ +} + +void Disc::togglePanel() +{ + if ( panel->isHidden() ) + panel->show(); + else + panel->hide(); +} + +void Disc::getTargets( QStringList &uiNames, QStringList &iconNames, QStringList &targetNames ) +{ + uiNames.append( i18n("Audio CD encoding") ); + iconNames.append( "kilogram" ); + targetNames.append( "DISC_RIP" ); + uiNames.append( i18n("Play Audio CD") ); + iconNames.append( "cdaudio_unmount" ); + targetNames.append( "DISC_CDDA" ); + uiNames.append( i18n("Play DVD") ); + iconNames.append( "dvd_unmount" ); + targetNames.append( "DISC_DVD" ); + uiNames.append( i18n("Play VCD") ); + iconNames.append( "cdrom_unmount" ); + targetNames.append( "DISC_VCD" ); +} + +bool Disc::execTarget( const QString &target ) +{ + if ( target=="DISC_CDDA" ) { + //emit showMe( this ); + QTimer::singleShot( 100, this, SLOT(startCD()) ); + return true; + } + else if ( target=="DISC_RIP" ) { + QTimer::singleShot( 100, this, SLOT(startRIP()) ); + return true; + } + else if ( target=="DISC_DVD" ) { + QTimer::singleShot( 100, this, SLOT(startDVD()) ); + return true; + } + else if ( target=="DISC_VCD" ) { + QTimer::singleShot( 100, this, SLOT(startVCD()) ); + return true; + } + return false; +} + +void Disc::loadConfig( KConfig* config ) +{ + QValueList<int> sl; + + config->setGroup("Disc"); + sl = config->readIntListEntry("SplitSizes"); + split->setSizes( sl ); +} + +void Disc::saveConfig() +{ + KConfig* config = KGlobal::config(); + + config->setGroup("Disc"); + config->writeEntry( "SplitSizes", split->sizes() ); +} + +QWidget* Disc::wantPlayerWindow() +{ + return playerBox; +} + +QWidget* Disc::inputMainWidget() +{ + return mainWidget; +} + +void Disc::setupActions() +{ + new KAction(i18n("Open &DVD"), "dvd_unmount", 0, this, SLOT(startDVD()), actionCollection(), "file_open_dvd"); + new KAction(i18n("Open &VCD"), "cdrom_unmount", 0, this, SLOT(startVCD()), actionCollection(), "file_open_vcd"); + new KAction(i18n("Open &Audio-CD"), "cdaudio_unmount", 0, this, SLOT(startCD()), actionCollection(), "file_open_audiocd"); +} + +void Disc::playerStopped() +{ + trackCurrent = 0; + if ( !list->isEnabled() ) + return; + list->clear(); + artistLab->setText( "" ); + albumLab->setText( "" ); + encodeWidget->hide(); +} + +void Disc::setEncoding( bool b ) +{ + list->setEnabled( !b ); + artistLab->setEnabled( !b ); + albumLab->setEnabled( !b ); + cdBtn->setEnabled( !b ); + ripBtn->setEnabled( !b ); + enc->setEnabled( !b ); + if ( b ) { + progressBar->setProgress( 0 ); + progressBar->show(); + } + else + progressBar->hide(); +} + +void Disc::encode() +{ + QListViewItem *it; + QStringList tracklist; + + it = list->firstChild(); + if ( !it ) + return; + tracklist.append( artistLab->text() ); + tracklist.append( albumLab->text() ); + while ( it!=0 ) { + if ( it->isSelected() ) + tracklist.append( it->text(0)+"-"+it->text(1) ); + it = it->nextSibling(); + } + if ( (int)tracklist.count()<3 ) { + KMessageBox::information( mainWidget, i18n("You must select the tracks to rip."), i18n("Warning") ); + return; + } + setEncoding( true ); + if ( trackCurrent ) + emit stop(); + para = new Paranoia(); + if ( !para->init( currentDevice ) ) { + KMessageBox::information( mainWidget, i18n("Unable to initialize cdparanoia."), i18n("Warning") ); + delete para; + para = NULL; + setEncoding( false ); + return; + } + + if ( para->encode( tracklist, mainWidget ) ) + encodeTimer.start( 1000 ); + else { + delete para; + para = NULL; + setEncoding( false ); + } +} + +void Disc::encodeProgress() +{ + if ( para->running() ) + progressBar->setProgress( para->getProgress() ); + else { + encodeTimer.stop(); + delete para; + para = NULL; + setEncoding( false ); + } + +} + +void Disc::setCurrent( int n ) +{ + QListViewItem *it; + + it = list->firstChild(); + while ( it!=0 ) { + if ( it->text(0).toInt()==n ) + it->setPixmap( 1, currentPixmap ); + else + it->setPixmap( 1, QPixmap() ); + it = it->nextSibling(); + } +} + +void Disc::trackSelected( QListViewItem *it ) +{ + if ( !it ) + return; + + MRL mrl( QString("cdda://%1/%2").arg( currentDevice ).arg( it->text(0).toInt() ) ); + mrl.setTitle( it->text(1) ); + mrl.setArtist( artistLab->text() ); + mrl.setAlbum( albumLab->text() ); + mrl.setTrack( it->text(0) ); + mrl.setMime( QString("audio/cdda") ); + trackCurrent = it->text(0).toInt(); + setCurrent( trackCurrent ); + emit play( mrl, this ); +} + +void Disc::startRIP() +{ + startCD( "", true ); +} + +void Disc::startCD( const QString &device, bool rip ) +{ + QStringList s; + bool init=false; + QValueList<int> qvl; + int i; + KListViewItem *it; + MRL mrl; + QStringList dcopList, devList; + bool ok=false; + + if ( !cdBtn->isEnabled() ) { + emit showMe( this ); + return; + } + + + if ( !device.isEmpty() ) + s.append( device ); + else { + DCOPRef mediamanager("kded","mediamanager"); + DCOPReply reply = mediamanager.call("fullList()"); + if ( reply.isValid() ) { + dcopList = reply; + i=0; + while ( i<(int)dcopList.count() ) { + //kdDebug() << dcopList[i+5] << " * " << dcopList[i+6] << " * " << dcopList[i+10] << endl; + if ( dcopList[i+10]=="media/audiocd" ) { + devList.append( dcopList[i+5] ); + } + i+=13; + } + if ( devList.count()>1 ) { + QString choice = KInputDialog::getItem( i18n("Audio CD"), i18n("Several Audio CD found. Choose one:"), + devList, 0, false, &ok ); + if ( ok ) + s.append( choice ); + else + return; + } + else if ( devList.count()==1 ) + s.append( devList[0] ); + else { + s.append( "/dev/cdrom" ); + s.append( "/dev/dvd" ); + } + } + else { + s.append( "/dev/cdrom" ); + s.append( "/dev/dvd" ); + } + } + + QApplication::setOverrideCursor( QCursor(Qt::WaitCursor) ); + qApp->processEvents(); + + para = new Paranoia(); + for ( i=0; i<(int)s.count(); i++ ) { + if ( (init = para->init( s[i] )) ) { + currentDevice = s[i]; + break; + } + } + if ( init ) { + list->clear(); + artistLab->setText( "" ); + albumLab->setText( "" ); + for ( i=0; i<para->getTracks(); i++) + qvl.append( para->trackFirstSector(i+1) + 150 ); + qvl.append( para->discFirstSector() ); + qvl.append( para->discLastSector() ); + CDDB *cddb = new CDDB(); + cddb->save_cddb( true ); + if ( cddb->queryCD(qvl) ) { + artistLab->setText( cddb->artist() ); + albumLab->setText( cddb->title() ); + for ( i=0; i<para->getTracks(); i++ ) { + it = new KListViewItem( list, QString().sprintf("%02d", i+1), cddb->track( i ), para->trackTime(i) ); + if ( i==0 ) { + mrl.setURL( QString("cdda://%1/1").arg( currentDevice ) ); + mrl.setTitle( cddb->track(i) ); + mrl.setArtist( artistLab->text() ); + mrl.setAlbum( albumLab->text() ); + mrl.setTrack( QString().sprintf("%02d", i+1) ); + } + } + } + else { + cddb->set_server( "freedb.freedb.org", 8880 ); + if ( cddb->queryCD(qvl) ) { + artistLab->setText( cddb->artist() ); + albumLab->setText( cddb->title() ); + for ( i=0; i<para->getTracks(); i++ ) { + it = new KListViewItem( list, QString().sprintf("%02d", i+1), cddb->track( i ), para->trackTime(i) ); + if ( i==0 ) { + mrl.setURL( QString("cdda://%1/1").arg( currentDevice ) ); + mrl.setTitle( cddb->track(i) ); + mrl.setArtist( artistLab->text() ); + mrl.setAlbum( albumLab->text() ); + mrl.setTrack( QString().sprintf("%02d", i+1) ); + } + } + } + else { + artistLab->setText( i18n("Unknown") ); + albumLab->setText( i18n("Unknown") ); + for ( i=0; i<para->getTracks(); i++ ) { + it = new KListViewItem( list, QString().sprintf("%02d", i+1), i18n("Track")+QString().sprintf("%02d", i+1), para->trackTime(i) ); + if ( i==0 ) { + mrl.setURL( QString("cdda://%1/1").arg( currentDevice ) ); + mrl.setTitle( i18n("Track")+QString().sprintf("%02d", i+1) ); + mrl.setArtist( artistLab->text() ); + mrl.setAlbum( albumLab->text() ); + mrl.setTrack( QString().sprintf("%02d", i+1) ); + } + } + } + } + delete cddb; + QApplication::restoreOverrideCursor(); + encodeWidget->show(); + emit showMe( this ); + if ( !rip && !mrl.isEmpty() ) { + mrl.setMime( QString("audio/cdda") ); + trackCurrent = mrl.track().toInt(); + setCurrent( trackCurrent ); + emit play( mrl, this ); + } + } + else { + QApplication::restoreOverrideCursor(); + KMessageBox::information( 0, i18n("No audio CD found."), i18n("Warning") ); + } + delete para; + para = NULL; +} + +void Disc::startDVD( const QString &device ) +{ + MRL mrl; + QStringList dcopList, devList; + int i; + bool ok=false; + + if ( !device.isEmpty() ) + mrl.setURL( QString("dvd://%1").arg(device) ); + else { + DCOPRef mediamanager("kded","mediamanager"); + DCOPReply reply = mediamanager.call("fullList()"); + if ( reply.isValid() ) { + dcopList = reply; + i=0; + while ( i<(int)dcopList.count() ) { + //kdDebug() << dcopList[i+5] << " * " << dcopList[i+6] << " * " << dcopList[i+10] << endl; + if ( dcopList[i+10]=="media/dvdvideo" ) { + devList.append( dcopList[i+5] ); + } + else if ( dcopList[i+10]=="media/cdrom_mounted" + || dcopList[i+10]=="media/cdwriter_mounted" + || dcopList[i+10]=="media/dvd_mounted" ) { + if ( QFile::exists(dcopList[i+6]+"/video_ts") || QFile::exists(dcopList[i+6]+"/VIDEO_TS") ) + devList.append( dcopList[i+5] ); + } + i+=13; + } + if ( devList.count()>1 ) { + QString choice = KInputDialog::getItem( i18n("DVD Video"), i18n("Several DVD Video found. Choose one:"), + devList, 0, false, &ok ); + if ( ok ) + mrl.setURL( QString("dvd://%1").arg(choice) ); + else + return; + } + else if ( devList.count()==1 ) + mrl.setURL( QString("dvd://%1").arg(devList[0]) ); + else { + //KMessageBox::information( 0, i18n("No DVD Video found."), i18n("Warning") ); + //return; + mrl.setURL( QString("dvd://") ); + } + } + else + mrl.setURL( QString("dvd://") ); + } + + mrl.setMime( QString("video/dvd") ); + + if ( !progressBar->isVisible() ) { + list->clear(); + artistLab->setText( "" ); + albumLab->setText( "" ); + encodeWidget->hide(); + } + trackCurrent = 0; + emit play( mrl, this ); +} + +void Disc::startVCD( const QString &device ) +{ + MRL mrl; + QStringList dcopList, devList; + int i; + bool ok=false; + + if ( !device.isEmpty() ) + mrl.setURL( QString("vcd://%1").arg(device) ); + else { + DCOPRef mediamanager("kded","mediamanager"); + DCOPReply reply = mediamanager.call("fullList()"); + if ( reply.isValid() ) { + dcopList = reply; + i=0; + while ( i<(int)dcopList.count() ) { + //kdDebug() << dcopList[i+5] << " * " << dcopList[i+6] << " * " << dcopList[i+10] << endl; + if ( dcopList[i+10]=="media/vcd" || dcopList[i+10]=="media/svcd" ) { + devList.append( dcopList[i+5] ); + } + i+=13; + } + if ( devList.count()>1 ) { + QString choice = KInputDialog::getItem( i18n("VCD-SVCD"), i18n("Several (S)VCD found. Choose one:"), + devList, 0, false, &ok ); + if ( ok ) + mrl.setURL( QString("vcd://%1").arg(choice) ); + else + return; + } + else if ( devList.count()==1 ) + mrl.setURL( QString("vcd://%1").arg(devList[0]) ); + else { + //KMessageBox::information( 0, i18n("No (S)VCD found."), i18n("Warning") ); + //return; + mrl.setURL( QString("vcd://") ); + } + } + else + mrl.setURL( QString("vcd://") ); + } + + mrl.setMime( QString("video/vcd") ); + + if ( !progressBar->isVisible() ) { + list->clear(); + artistLab->setText( "" ); + albumLab->setText( "" ); + encodeWidget->hide(); + } + trackCurrent = 0; + emit play( mrl, this ); +} + +bool Disc::currentTrack( MRL &mrl ) +{ + QListViewItem *it; + + if ( !trackCurrent ) + return false; + + it = list->firstChild(); + if ( !it ) + return false; + while ( it!=0 ) { + if ( it->text(0).toInt()==trackCurrent ) { + mrl.setURL( QString("cdda://%1/%2").arg( currentDevice ).arg( it->text(0).toInt() ) ); + mrl.setTitle( it->text(1) ); + mrl.setArtist( artistLab->text() ); + mrl.setAlbum( albumLab->text() ); + mrl.setTrack( it->text(0) ); + mrl.setMime( QString("audio/cdda") ); + setCurrent( trackCurrent ); + return true; + } + it = it->nextSibling(); + } + + return false; +} + +bool Disc::playbackFinished( MRL &mrl ) +{ + return nextTrack( mrl ); +} + +bool Disc::nextTrack( MRL &mrl ) +{ + QListViewItem *it; + + if ( !trackCurrent ) + return false; + + it = list->firstChild(); + if ( !it ) + return false; + while ( it!=0 ) { + if ( it->text(0).toInt()==trackCurrent+1 ) { + mrl.setURL( QString("cdda://%1/%2").arg( currentDevice ).arg( it->text(0).toInt() ) ); + mrl.setTitle( it->text(1) ); + mrl.setArtist( artistLab->text() ); + mrl.setAlbum( albumLab->text() ); + mrl.setTrack( it->text(0) ); + mrl.setMime( QString("audio/cdda") ); + ++trackCurrent; + setCurrent( trackCurrent ); + return true; + } + it = it->nextSibling(); + } + + it = list->firstChild(); + mrl.setURL( QString("cdda://%1/%2").arg( currentDevice ).arg( it->text(0).toInt() ) ); + mrl.setTitle( it->text(1) ); + mrl.setArtist( artistLab->text() ); + mrl.setAlbum( albumLab->text() ); + mrl.setTrack( it->text(0) ); + mrl.setMime( QString("audio/cdda") ); + trackCurrent = 1; + setCurrent( trackCurrent ); + return true; +} + +bool Disc::previousTrack( MRL &mrl ) +{ + QListViewItem *it; + + if ( !trackCurrent ) + return false; + + it = list->firstChild(); + if ( !it ) + return false; + while ( it!=0 ) { + if ( it->text(0).toInt()==trackCurrent-1 ) { + mrl.setURL( QString("cdda://%1/%2").arg( currentDevice ).arg( it->text(0).toInt() ) ); + mrl.setTitle( it->text(1) ); + mrl.setArtist( artistLab->text() ); + mrl.setAlbum( albumLab->text() ); + mrl.setTrack( it->text(0) ); + mrl.setMime( QString("audio/cdda") ); + --trackCurrent; + setCurrent( trackCurrent ); + return true; + } + it = it->nextSibling(); + } + + return false; +} + +bool Disc::trackNumber( int number, MRL &mrl ) +{ + QListViewItem *it; + + if ( !trackCurrent ) + return false; + + it = list->firstChild(); + if ( !it ) + return false; + while ( it!=0 ) { + if ( it->text(0).toInt()==number ) { + mrl.setURL( QString("cdda://%1/%2").arg( currentDevice ).arg( it->text(0).toInt() ) ); + mrl.setTitle( it->text(1) ); + mrl.setArtist( artistLab->text() ); + mrl.setAlbum( albumLab->text() ); + mrl.setTrack( it->text(0) ); + mrl.setMime( QString("audio/cdda") ); + trackCurrent=number; + setCurrent( trackCurrent ); + return true; + } + it = it->nextSibling(); + } + + return false; +} + +void Disc::mergeMeta( const MRL& ) +{ +} diff --git a/kaffeine/src/input/disc/disc.h b/kaffeine/src/input/disc/disc.h new file mode 100644 index 0000000..c62c905 --- /dev/null +++ b/kaffeine/src/input/disc/disc.h @@ -0,0 +1,140 @@ +/* + * disc.h + * + * Copyright (C) 2006 Christophe Thommeret <hftom@free.fr> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef DISC_H +#define DISC_H + +#include <kaction.h> +#include <kstdaction.h> +#include <kconfig.h> +#include <klistview.h> + +#include <qframe.h> +#include <qvbox.h> +#include <qsplitter.h> +#include <qtoolbutton.h> +#include <qlabel.h> +#include <qpixmap.h> +#include <qprogressbar.h> +#include <qguardedptr.h> + +#include "kaffeineinput.h" +#include "paranoia.h" + +class MRL; + +class MLabel : public QLabel +{ + Q_OBJECT + +public: + MLabel( QWidget *parent ); + ~MLabel() {} + +protected: + void paintEvent( QPaintEvent * ); +}; + + + +class MListView : public KListView +{ + Q_OBJECT + +public: + MListView( QWidget *parent ); + ~MListView() {} + +protected: + virtual void resizeEvent(QResizeEvent*); +}; + + + +class Disc : public KaffeineInput +{ + Q_OBJECT + +public: + Disc(QWidget *parent, QObject *objParent, const char *name=0); + ~Disc(); + + // Reimplemented from KaffeineInput +public: + QWidget *wantPlayerWindow(); + QWidget *inputMainWidget(); + void mergeMeta(const MRL&); + bool nextTrack( MRL& ); + bool previousTrack( MRL& ); + bool currentTrack( MRL& ); + bool trackNumber( int, MRL& ); + bool playbackFinished( MRL& ); + void toggleLayout( bool ); + void playerStopped(); + void getTargets( QStringList &uiNames, QStringList &iconNames, QStringList &targetNames ); + void togglePanel(); + bool execTarget( const QString& ); + void saveConfig(); + //*************************************** + +public slots: + void startCD( const QString &device="", bool rip=false ); + void startDVD( const QString &device="" ); + void startVCD( const QString &device="" ); + void startRIP(); + +public: + QVBox *mainWidget; + QVBox *playerBox; + +private: + void loadConfig( KConfig* config ); + void saveConfig( KConfig* config ); + void setCurrent( int n ); + void setupActions(); + + QLabel *artistLab, *albumLab; + QGuardedPtr<QWidget> widg; + QToolButton *ripBtn, *cdBtn; + QToolButton *enc; + QSplitter *split; + QGuardedPtr<QFrame> panel; + MLabel *discLab; + Paranoia *para; + MListView *list; + int trackCurrent; + QString currentDevice; + QPixmap currentPixmap; + QWidget *encodeWidget; + QTimer encodeTimer; + QProgressBar *progressBar; + +private slots: + void trackSelected( QListViewItem* ); + void encode(); + void encodeProgress(); + void setEncoding( bool ); + +signals: + void signalRequestForDVD(); + void signalRequestForVCD(); +}; + +#endif /* DISC_H */ diff --git a/kaffeine/src/input/disc/kaffeinedisc.rc b/kaffeine/src/input/disc/kaffeinedisc.rc new file mode 100644 index 0000000..326daee --- /dev/null +++ b/kaffeine/src/input/disc/kaffeinedisc.rc @@ -0,0 +1,24 @@ +<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd"> +<kpartgui name="kaffeineplaylist" version="9"> +<MenuBar> + <Menu name="file"> + <Separator/> + <Action name="file_open_dvd"/> + <Action name="file_open_vcd"/> + <Action name="file_open_audiocd"/> + <Separator/> + </Menu> +</MenuBar> +<ToolBar name="discToolBar" hidden="true"><text>CD Toolbar</text> + <Action name="file_open_dvd"/> + <Action name="file_open_vcd"/> + <Action name="file_open_audiocd"/> +</ToolBar> +<State name="no_media_part"> +<disable> + <Action name="file_open_dvd"/> + <Action name="file_open_vcd"/> + <Action name="file_open_audiocd"/> +</disable> +</State> +</kpartgui> diff --git a/kaffeine/src/input/disc/paranoia.cpp b/kaffeine/src/input/disc/paranoia.cpp new file mode 100644 index 0000000..60e2092 --- /dev/null +++ b/kaffeine/src/input/disc/paranoia.cpp @@ -0,0 +1,553 @@ +/* + * paranoia.cpp + * + * Copyright (C) 2002-2006 Christophe Thommeret <hftom@free.fr> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <unistd.h> +#include <math.h> + +#include <qfile.h> +#include <qslider.h> +#include <qlcdnumber.h> +#include <qdir.h> +#include <qlineedit.h> +#include <qbuttongroup.h> +#include <qtoolbutton.h> +#include <qcheckbox.h> + +#include <qcombobox.h> + +#include <kmessagebox.h> +#include <klocale.h> +#include <kdebug.h> +#include <ktrader.h> +#include <kpushbutton.h> +#include <kiconloader.h> +#include <kfiledialog.h> +#include <kparts/componentfactory.h> + +#include "paranoia.h" +#include "paranoia.moc" + +#define DEFAULT_DRIVE "/dev/cdrom" + +KiloConfig::KiloConfig( QWidget *parent, KConfig *confile, const QStringList &encoders ) : ParanoiaSettings( parent ) +{ + int i; + + KIconLoader *icon = new KIconLoader(); + okBtn->setGuiItem( KGuiItem(i18n("OK"), icon->loadIconSet("ok", KIcon::Small) ) ); + cancelBtn->setGuiItem( KGuiItem(i18n("Cancel"), icon->loadIconSet("cancel", KIcon::Small) ) ); + baseDirBtn->setIconSet( icon->loadIconSet("fileopen", KIcon::Small) ); + delete icon; + connect( baseDirBtn, SIGNAL( clicked() ), this, SLOT( setBaseDir() ) ); + Conf = confile; + Conf->setGroup( "Paranoia" ); + baseDirLineEdit->setText( Conf->readEntry( "Basedir", QDir::homeDirPath() ) ); + paranoiaGroup->setButton( Conf->readNumEntry( "Mode", 0 ) ); + normCb->setChecked( Conf->readBoolEntry( "Normalize", false ) ); + encoderComb->insertStringList( encoders ); + QString s = Conf->readEntry( "CurrentEncoder", "" ); + if ( !s.isEmpty() ) { + for ( i=0; i<(int)encoders.count(); i++ ) { + if ( encoders[i]==s ) { + encoderComb->setCurrentText( s ); + } + } + } +} + +void KiloConfig::setBaseDir() +{ + Conf->setGroup( "Paranoia" ); + QString d = Conf->readEntry( "Basedir", QDir::homeDirPath() ); + QString u = KFileDialog::getExistingDirectory( d ); + if ( u!="" ) { + baseDirLineEdit->setText( u ); + Conf->writeEntry( "Basedir", u ); + } +} + +QString KiloConfig::getEncoder() +{ + return encoderComb->currentText(); +} + +bool KiloConfig::getNormalize() +{ + return normCb->isChecked(); +} + +QString KiloConfig::getBaseDir() +{ + return baseDirLineEdit->text().stripWhiteSpace(); +} + +int KiloConfig::getParanoiaMode() +{ + return paranoiaGroup->selectedId(); +} + +void KiloConfig::accept() +{ + Conf->setGroup( "Paranoia" ); + Conf->writeEntry( "Mode", paranoiaGroup->id( paranoiaGroup->selected() ) ); + Conf->writeEntry( "CurrentEncoder", encoderComb->currentText() ); + Conf->writeEntry( "Normalize", normCb->isChecked() ); + done(Accepted); +} + +KiloConfig::~KiloConfig() +{ +} + +void paranoiaCallback( long, int ) +{ +} + +Paranoia::Paranoia() +{ + d = 0; + p = 0; + isRunning = false; +} + +bool Paranoia::init( QString dev ) +{ + QString s; + QFile f; + + if ( p!=0 ) paranoia_free( p ); + if (d!=0 ) cdda_close( d ); + nTracks = 0; + + dev = dev.stripWhiteSpace(); + f.setName( dev ); + if ( !f.exists() ) { + /*if ( !findCdrom() ) { + d = cdda_find_a_cdrom( CDDA_MESSAGE_PRINTIT, 0 ); + if ( cdda_open( d )!=0 ) + return false; + }*/ + return false; + } + else { + d = cdda_identify( dev.ascii(), CDDA_MESSAGE_PRINTIT, 0 ); + if ( cdda_open( d )!=0 ) + return false; + } + p = paranoia_init( d ); + nTracks = cdda_tracks( d ); + return true; +} + +bool Paranoia::findCdrom() +{ + QFile *f; + QString c; + QString s=""; + int pos, i; + bool stop=false; + char dev[4][4]={"","","",""}; + + f = new QFile( "/proc/sys/dev/cdrom/info" ); + if ( !f->open(IO_ReadOnly) ) + return false; + + QTextStream t( f ); + while ( !t.eof() && !stop ) { + s = t.readLine(); + if ( s.contains("drive name:") ) + stop = true; + } + if ( !stop ) + return false; + + pos = s.find(":"); + c = s.right( s.length()-pos-1 ); + sscanf( c.latin1(), "%s %s %s %s", dev[0], dev[1], dev[2], dev[3] ); + + for ( i=0; i<4; i++ ) + if ( procCdrom( dev[i] ) ) + return true; + + f->close(); + return false; +} + +bool Paranoia::procCdrom( QString name ) +{ + int pos; + + if ( name.contains("sr") ) { + pos = name.find("r"); + name = name.right( name.length()-pos-1 ); + name = "/dev/scd"+name; + d = cdda_identify( name.ascii(), CDDA_MESSAGE_PRINTIT, 0 ); + if ( cdda_open( d )==0 ) + return true; + } + else if ( name.contains("hd") ) { + name = "/dev/"+name; + d = cdda_identify( name.ascii(), CDDA_MESSAGE_PRINTIT, 0 ); + if ( cdda_open( d )==0 ) + return true; + } + return false; +} + +void Paranoia::setMode( int mode ) +{ + switch ( mode ) { + case 0 : mode = PARANOIA_MODE_DISABLE; + break; + case 1 : mode = PARANOIA_MODE_FULL^PARANOIA_MODE_NEVERSKIP; + break; + case 2 : mode = PARANOIA_MODE_FULL; + } + paranoia_modeset( p, mode ); +} + +bool Paranoia::encode( const QStringList &list, QWidget *parent ) +{ + QStringList desktop; + QStringList encoderName; + + encodingList.clear(); + encodingList = list; + myParent = parent; + + // check for encoders + KTrader::OfferList offers = KTrader::self()->query("KaffeineAudioEncoder"); + KTrader::OfferList::Iterator end(offers.end()); + for(KTrader::OfferList::Iterator it = offers.begin(); it != end; ++it) { + KService::Ptr ptr = (*it); + desktop.append( ptr->desktopEntryName() ); + encoderName.append( ptr->name() ); + } + + if ( !encoderName.count() ) { + KMessageBox::error( myParent, i18n("No audio encoders could be found."), i18n("Warning") ); + return false; + } + + KiloConfig dlg( myParent, KGlobal::config(), encoderName ); + int ret = dlg.exec(); + if ( ret!=QDialog::Accepted ) + return false; + normalize = dlg.getNormalize(); + baseDir = dlg.getBaseDir(); + paraMode = dlg.getParanoiaMode(); + + QString s = dlg.getEncoder(); + for ( ret=0; ret<(int)encoderName.count(); ++ret ) { + if ( encoderName[ret]==s ) { + encoderDesktop = desktop[ret]; + break; + } + } + + if ( !loadEncoder( myParent ) ) + return false; + + if ( !currentEncoder->options( myParent, KGlobal::config() ) ) { + unloadEncoder(); + return false; + } + + if ( !setPath( baseDir, QString(encodingList[0]).replace("/","_"), QString(encodingList[1]).replace("/","_") ) ) { + return false; + } + isRunning = true; + start(); + return true; +} + +bool Paranoia::loadEncoder( QWidget *parent ) +{ + int error = 0; + + KService::Ptr service = KService::serviceByDesktopName( encoderDesktop ); + if (!service) { + KMessageBox::error( parent, i18n("Loading of encoder '%1' failed.").arg(encoderDesktop) ); + return false; + } + + if ( service->serviceTypes().contains("KaffeineAudioEncoder") ) { + currentEncoder = KParts::ComponentFactory::createPartInstanceFromService<KaffeineAudioEncoder>(service, 0, service->name().ascii(), 0, 0, 0, &error); + if (error > 0) { + KMessageBox::error( parent, i18n("Loading of encoder '%1' failed.").arg(encoderDesktop) ); + return false; + } + else + return true; + } + else + return false; +} + +void Paranoia::unloadEncoder() +{ + //kdDebug()<<"Unload encoder ..."<<endl; + KService::Ptr service = KService::serviceByDesktopName( encoderDesktop ); + KLibLoader::self()->unloadLibrary( service->library().ascii() ); + //kdDebug()<<"... encoder unloaded."<<endl; +} + +bool Paranoia::validPath( QString path ) +{ + QDir dir; + + dir.setPath( path ); + if ( !dir.exists() ) { + if ( !dir.mkdir( path ) ) { + KMessageBox::error( 0, i18n("Unable to create folder: ")+path ); + return false; + } + } + return true; +} + +bool Paranoia::setPath( QString &path, const QString &artist, const QString &album ) +{ + QString s; + + if ( !path.endsWith("/") ) + path = path+"/"; + if ( !validPath( path ) ) + return false; + + s = artist; + if ( s!="" ) + path = path+s+"/"; + if ( !validPath( path ) ) + return false; + + s = album; + if ( s!="" ) + path = path+s+"/"; + if ( !validPath( path ) ) + return false; + return true; +} + +bool Paranoia::initTrack( int t ) +{ + currentSector = cdda_track_firstsector( d, t ); + endOfTrack = cdda_track_lastsector( d, t ); + paranoia_seek( p, currentSector, SEEK_SET ); + return true; +} + +static inline signed short paraSwap16( signed short x ) { + return ((((unsigned short)x & 0x00ffU) << 8) | + (((unsigned short )x & 0xff00U) >> 8)); +} + +void Paranoia::run() +{ + signed short *buf; + int i, n, len, retlen; + long curpos, endpos; + QFile f, fn; + float max; + float factor; + QString s; + char *encoded; + int overallSectors=0; + int sectorCount=0; + + progress = 0; + sleep(2); // give some time for the player to be stopped + + setMode( paraMode ); + for ( i=2; i<(int)encodingList.count(); ++i ) { + n = encodingList[i].left(2).toInt(); + overallSectors+= trackSectorSize( n ); + } + + fn.setName( baseDir+".temp" ); + + for ( i=2; i<(int)encodingList.count(); ++i ) { + n = encodingList[i].left(2).toInt(); + s = QString(encodingList[i]).replace("/","_")+currentEncoder->getExtension(); + f.setName( baseDir+s ); + initTrack( n ); + max = 0; + curpos = currentSector; + endpos = endOfTrack; + if ( normalize ) { + len = CD_FRAMESIZE_RAW; + fn.open( IO_ReadWrite | IO_Truncate ); + do { + buf = paranoia_read_limited( p, paranoiaCallback, 3 ); + if ( Q_BYTE_ORDER == Q_BIG_ENDIAN ) { + for ( i=0; i<len/2; i++) + buf[i] = paraSwap16(buf[i]); + } + ++curpos; + if ( len>0 ) { + for ( n=0; n<len/2; ++n ) + if ( fabs(buf[n])>max ) + max = fabs(buf[n]); + fn.writeBlock( (char*)buf, len ); + ++sectorCount; + progress = sectorCount*50/overallSectors; + } + if ( !isRunning ) + len=0; + } + while ( curpos<endpos && len!=0 ); + + factor = 32767.0/max; + buf = new signed short[CD_FRAMESIZE_RAW]; + fn.at( 0 ); + f.open( IO_ReadWrite | IO_Truncate ); + currentEncoder->start( encodingList[i].remove(0,3), encodingList[0], encodingList[1], encodingList[i].left(2) ); + encoded = currentEncoder->getHeader( len ); + if ( encoded ) + f.writeBlock( encoded, len ); + + do { + len = fn.readBlock( (char*)buf, CD_FRAMESIZE_RAW ); + if ( len>0 ) { + if ( max<32760 ) + for ( n=0; n<len/2; ++n ) + buf[n] = (float)buf[n]*factor; + encoded = currentEncoder->encode( (char*)buf, len, retlen ); + if ( encoded ) + f.writeBlock( encoded, retlen ); + ++sectorCount; + progress = sectorCount*50/overallSectors; + if ( !isRunning ) + len=0; + } + } + while ( len>0 ); + encoded = currentEncoder->stop( len ); + if ( encoded ) + f.writeBlock( encoded, len ); + delete [] buf; + fn.remove(); + } + else { + f.open( IO_ReadWrite | IO_Truncate ); + currentEncoder->start( encodingList[i].remove(0,3), encodingList[0], encodingList[1], encodingList[i].left(2) ); + encoded = currentEncoder->getHeader( len ); + if ( encoded ) + f.writeBlock( encoded, len ); + len = CD_FRAMESIZE_RAW; + do { + buf = paranoia_read_limited( p, paranoiaCallback, 3 ); + if ( Q_BYTE_ORDER == Q_BIG_ENDIAN ) { + for ( i=0; i<len/2; i++) { + buf[i] = paraSwap16(buf[i]); + } + } + ++curpos; + if ( len>0 ) { + encoded = currentEncoder->encode( (char*)buf, len, retlen ); + if ( encoded ) + f.writeBlock( encoded, retlen ); + ++sectorCount; + progress = sectorCount*100/overallSectors; + } + if ( !isRunning ) + len=0; + } + while ( curpos<endpos && len!=0 ); + encoded = currentEncoder->stop( len ); + if ( encoded ) + f.writeBlock( encoded, len ); + sleep(1); // cdparanoia seems to like that. + } + f.flush(); + f.close(); + } + + unloadEncoder(); + isRunning = false; +} + +int Paranoia::trackFirstSector( int t ) +{ + return cdda_track_firstsector( d, t ); +} + +int Paranoia::discFirstSector() +{ + return cdda_disc_firstsector( d ); +} + +int Paranoia::discLastSector() +{ + return cdda_disc_lastsector( d ); +} + +bool Paranoia::isAudio( int t ) +{ + if ( cdda_track_audiop( d, t+1 ) ) return true; + else return false; +} + +QString Paranoia::trackSize( int t ) +{ + QString s, c; + long total; + + total = CD_FRAMESIZE_RAW * (cdda_track_lastsector( d, t+1 )-cdda_track_firstsector( d, t+1 ) ); + if ( total>(1048576 ) ) s = c.setNum(total/1048576.0, 'f', 2)+" "+i18n("MB"); + else if ( total>1024 ) s = c.setNum(total/1024.0, 'f', 2)+" "+i18n("KB"); + else s = c.setNum(total*1.0, 'f', 2)+" "+i18n("Bytes"); + return s; +} + +long Paranoia::trackSectorSize( int t ) +{ + return cdda_track_lastsector( d, t )-cdda_track_firstsector( d, t ); +} + +QString Paranoia::trackTime( int t ) +{ + QString c; + long total, time; + int m, s; + + if ( t<0 ) total = CD_FRAMESIZE_RAW * (cdda_disc_lastsector( d )-cdda_disc_firstsector( d ) ); + else total = CD_FRAMESIZE_RAW * (cdda_track_lastsector( d, t+1 )-cdda_track_firstsector( d, t+1 ) ); + time = (8 * total) / (44100 * 2 * 16); + m = time/60; + s = time%60; + c.sprintf( "%.2i:%.2i", m, s ); + return c; +} + +Paranoia::~Paranoia() +{ + if ( p!=0 ) paranoia_free( p ); + if (d!=0 ) cdda_close( d ); +} + +long Paranoia::getTracks() +{ + return nTracks; +} diff --git a/kaffeine/src/input/disc/paranoia.h b/kaffeine/src/input/disc/paranoia.h new file mode 100644 index 0000000..4864b06 --- /dev/null +++ b/kaffeine/src/input/disc/paranoia.h @@ -0,0 +1,108 @@ +/* + * paranoia.h + * + * Copyright (C) 2002-2006 Christophe Thommeret <hftom@free.fr> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef PARANOIA_H +#define PARANOIA_H + +#include <qstringlist.h> +#include <qthread.h> +#include <qwidget.h> + +#include <kconfig.h> + +#include "kaffeineaudioencoder.h" +#include "paranoiasettings.h" + +extern "C" +{ +#include <cdda_interface.h> +#include <cdda_paranoia.h> +} + +class KiloConfig : public ParanoiaSettings +{ + Q_OBJECT + +public: + + KiloConfig( QWidget *parent, KConfig *confile, const QStringList &encoders ); + ~KiloConfig(); + + QString getEncoder(); + bool getNormalize(); + QString getBaseDir(); + int getParanoiaMode(); + +public slots: + + virtual void accept(); + void setBaseDir(); + +private: + + KConfig *Conf; +}; + +class Paranoia : public QThread +{ +public: + Paranoia(); + bool init( QString dev ); + ~Paranoia(); + bool encode( const QStringList&, QWidget* ); + long getTracks(); + QString trackTime( int t ); + int trackFirstSector( int t ); + int discFirstSector(); + int discLastSector(); + virtual void run(); + bool running() {return isRunning;} + int getProgress() {return progress;} + +private: + + bool findCdrom(); + bool procCdrom( QString name ); + bool initTrack( int t ); + void setMode( int mode ); + bool isAudio( int t ); + QString trackSize( int t ); + long trackSectorSize( int t ); + bool loadEncoder( QWidget* ); + void unloadEncoder(); + bool validPath( QString path ); + bool setPath( QString &path, const QString &artist, const QString &album ); + + long nTracks; + cdrom_drive *d; + cdrom_paranoia *p; + long currentSector, endOfTrack; + bool isRunning; + QStringList encodingList; + QWidget *myParent; + KaffeineAudioEncoder *currentEncoder; + QString encoderDesktop; + bool normalize; + QString baseDir; + int paraMode; + int progress; +}; + +#endif /* PARANOIA_H */ diff --git a/kaffeine/src/input/disc/paranoiasettings.ui b/kaffeine/src/input/disc/paranoiasettings.ui new file mode 100644 index 0000000..487899c --- /dev/null +++ b/kaffeine/src/input/disc/paranoiasettings.ui @@ -0,0 +1,252 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>ParanoiaSettings</class> +<widget class="QDialog"> + <property name="name"> + <cstring>ParanoiaSettings</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>295</width> + <height>338</height> + </rect> + </property> + <property name="caption"> + <string>Encoding Preferences</string> + </property> + <property name="sizeGripEnabled"> + <bool>false</bool> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLayoutWidget" row="0" column="0"> + <property name="name"> + <cstring>layout3</cstring> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QGroupBox"> + <property name="name"> + <cstring>encoderGroup</cstring> + </property> + <property name="title"> + <string>Encoder:</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QComboBox" row="0" column="0"> + <property name="name"> + <cstring>encoderComb</cstring> + </property> + </widget> + </grid> + </widget> + <widget class="QGroupBox"> + <property name="name"> + <cstring>basedirGroup</cstring> + </property> + <property name="title"> + <string>Base directory:</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>11</number> + </property> + <property name="spacing"> + <number>6</number> + </property> + <widget class="QToolButton" row="0" column="1"> + <property name="name"> + <cstring>baseDirBtn</cstring> + </property> + <property name="text"> + <string>...</string> + </property> + </widget> + <widget class="QLineEdit" row="0" column="0"> + <property name="name"> + <cstring>baseDirLineEdit</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>7</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="readOnly"> + <bool>true</bool> + </property> + </widget> + </grid> + </widget> + <widget class="QButtonGroup"> + <property name="name"> + <cstring>paranoiaGroup</cstring> + </property> + <property name="title"> + <string>Paranoia:</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>11</number> + </property> + <property name="spacing"> + <number>6</number> + </property> + <widget class="QRadioButton" row="0" column="0"> + <property name="name"> + <cstring>paranoiaRb0</cstring> + </property> + <property name="text"> + <string>Disable all checking</string> + </property> + </widget> + <widget class="QRadioButton" row="1" column="0"> + <property name="name"> + <cstring>paranoiaRb1</cstring> + </property> + <property name="text"> + <string>Normal mode</string> + </property> + </widget> + <widget class="QRadioButton" row="2" column="0"> + <property name="name"> + <cstring>paranoiaRb2</cstring> + </property> + <property name="text"> + <string>Paranoia mode</string> + </property> + </widget> + </grid> + </widget> + <widget class="QGroupBox"> + <property name="name"> + <cstring>groupBox3</cstring> + </property> + <property name="title"> + <string></string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QCheckBox" row="0" column="0"> + <property name="name"> + <cstring>normCb</cstring> + </property> + <property name="text"> + <string>Normalize</string> + </property> + </widget> + </grid> + </widget> + <spacer> + <property name="name"> + <cstring>spacer2</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>60</height> + </size> + </property> + </spacer> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout8</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <spacer> + <property name="name"> + <cstring>Horizontal Spacing2</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>152</width> + <height>20</height> + </size> + </property> + </spacer> + <widget class="KPushButton"> + <property name="name"> + <cstring>cancelBtn</cstring> + </property> + <property name="text"> + <string>&Cancel</string> + </property> + <property name="accel"> + <string></string> + </property> + <property name="autoDefault"> + <bool>true</bool> + </property> + </widget> + <widget class="KPushButton"> + <property name="name"> + <cstring>okBtn</cstring> + </property> + <property name="text"> + <string>&OK</string> + </property> + <property name="accel"> + <string></string> + </property> + <property name="autoDefault"> + <bool>true</bool> + </property> + <property name="default"> + <bool>true</bool> + </property> + </widget> + </hbox> + </widget> + </vbox> + </widget> + </grid> +</widget> +<connections> + <connection> + <sender>okBtn</sender> + <signal>clicked()</signal> + <receiver>ParanoiaSettings</receiver> + <slot>accept()</slot> + </connection> + <connection> + <sender>cancelBtn</sender> + <signal>clicked()</signal> + <receiver>ParanoiaSettings</receiver> + <slot>reject()</slot> + </connection> +</connections> +<layoutdefaults spacing="6" margin="11"/> +</UI> diff --git a/kaffeine/src/input/disc/plugins/Makefile.am b/kaffeine/src/input/disc/plugins/Makefile.am new file mode 100644 index 0000000..ee42503 --- /dev/null +++ b/kaffeine/src/input/disc/plugins/Makefile.am @@ -0,0 +1,24 @@ +if with_lame + LAME_SUBDIR = mp3lame +endif + +if with_oggvorbis + OGGVORBIS_SUBDIR = oggvorbis +endif + +lib_LTLIBRARIES = libkaffeineaudioencoder.la + +METASOURCES = AUTO + +SUBDIRS = . $(LAME_SUBDIR) $(OGGVORBIS_SUBDIR) + +INCLUDES = -I$(top_srcdir)/kaffeine/src $(all_includes) + +kaffeineincludedir = $(includedir)/kaffeine +kaffeineinclude_HEADERS = kaffeineaudioencoder.h + +libkaffeineaudioencoder_la_SOURCES = kaffeineaudioencoder.cpp +libkaffeineaudioencoder_la_LIBADD = $(LIB_KPARTS) +libkaffeineaudioencoder_la_LDFLAGS = $(all_libraries) -version-info 0:1:0 -no-undefined + +kde_servicetypes_DATA = kaffeineaudioencoder.desktop diff --git a/kaffeine/src/input/disc/plugins/kaffeineaudioencoder.cpp b/kaffeine/src/input/disc/plugins/kaffeineaudioencoder.cpp new file mode 100644 index 0000000..5198e43 --- /dev/null +++ b/kaffeine/src/input/disc/plugins/kaffeineaudioencoder.cpp @@ -0,0 +1,30 @@ +/* + * kaffeineaudioencoder.cpp + * + * Copyright (C) 2006 Christophe Thommeret <hftom@free.fr> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "kaffeineaudioencoder.h" +#include "kaffeineaudioencoder.moc" + +KaffeineAudioEncoder::KaffeineAudioEncoder(QObject* parent, const char* name) : KParts::Part( parent, name ) +{ +} + +KaffeineAudioEncoder::~KaffeineAudioEncoder() +{ +} diff --git a/kaffeine/src/input/disc/plugins/kaffeineaudioencoder.desktop b/kaffeine/src/input/disc/plugins/kaffeineaudioencoder.desktop new file mode 100644 index 0000000..821cabb --- /dev/null +++ b/kaffeine/src/input/disc/plugins/kaffeineaudioencoder.desktop @@ -0,0 +1,4 @@ +[Desktop Entry] +Encoding=UTF-8 +Type=ServiceType +X-KDE-ServiceType=KaffeineAudioEncoder diff --git a/kaffeine/src/input/disc/plugins/kaffeineaudioencoder.h b/kaffeine/src/input/disc/plugins/kaffeineaudioencoder.h new file mode 100644 index 0000000..1dc3616 --- /dev/null +++ b/kaffeine/src/input/disc/plugins/kaffeineaudioencoder.h @@ -0,0 +1,53 @@ +/* + * kaffeineaudioencoder.h + * + * Copyright (C) 2006 Christophe Thommeret <hftom@free.fr> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef KAFFEINEAUDIOENCODER_H +#define KAFFEINEAUDIOENCODER_H + +#include <kparts/part.h> +#include <kconfig.h> + +#include <qstring.h> +#include <qwidget.h> + +/* + * Base-Class for Kaffeine audio encoder plugins. + */ + +class KDE_EXPORT KaffeineAudioEncoder : public KParts::Part +{ + Q_OBJECT +public: + KaffeineAudioEncoder(QObject* parent, const char* name); + virtual ~KaffeineAudioEncoder(); + + // return false if the user's canceled. + virtual bool options( QWidget*, KConfig* ) {return false;} + + // your file extension, e.g. ".ogg" + virtual QString getExtension() {return QString();} + + virtual void start( QString/*title*/=0, QString/*artist*/=0, QString/*album*/=0, QString/*tracknumber*/=0, QString/*genre*/=0 ) {} + virtual char* getHeader( int&/*len*/ ) {return NULL;} + virtual char* encode( char*/*data*/, int /*datalen*/, int&/*len*/ ) {return NULL;} + virtual char* stop( int& /*len*/) {return NULL;} +}; + +#endif /* KAFFEINEAUDIOENCODER_H */ diff --git a/kaffeine/src/input/disc/plugins/mp3lame/Makefile.am b/kaffeine/src/input/disc/plugins/mp3lame/Makefile.am new file mode 100644 index 0000000..6a58eb9 --- /dev/null +++ b/kaffeine/src/input/disc/plugins/mp3lame/Makefile.am @@ -0,0 +1,17 @@ +kde_module_LTLIBRARIES = libkaffeinemp3lame.la + +INCLUDES = -I$(top_srcdir)/kaffeine/src/ -I$(top_srcdir)/kaffeine/src/input/disc/plugins/ $(all_includes) + +METASOURCES = AUTO + +kaffeineincludedir = $(includedir)/kaffeine + +noinst_HEADERS = klameenc.h + +libkaffeinemp3lame_la_SOURCES = klameenc.cpp lameconfig.ui +libkaffeinemp3lame_la_LIBADD = ../libkaffeineaudioencoder.la $(LIB_LAME) +libkaffeinemp3lame_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries) -avoid-version -no-undefined + +# this is where the desktop file will go +partdesktopdir = $(kde_servicesdir) +partdesktop_DATA = kaffeinemp3lame.desktop diff --git a/kaffeine/src/input/disc/plugins/mp3lame/kaffeinemp3lame.desktop b/kaffeine/src/input/disc/plugins/mp3lame/kaffeinemp3lame.desktop new file mode 100644 index 0000000..df941d8 --- /dev/null +++ b/kaffeine/src/input/disc/plugins/mp3lame/kaffeinemp3lame.desktop @@ -0,0 +1,12 @@ +[Desktop Entry] +Encoding=UTF-8 +Name=Lame mp3 +Name[af]=LAME MP3 +Name[hu]=LAME MP3 +Name[ka]=Lame-ის mp3 +Name[nb]=LAME MP3 +Name[pt]=MP3 do LAME +Name[xx]=xxLame mp3xx +ServiceTypes=KaffeineAudioEncoder +Type=Service +X-KDE-Library=libkaffeinemp3lame diff --git a/kaffeine/src/input/disc/plugins/mp3lame/klameenc.cpp b/kaffeine/src/input/disc/plugins/mp3lame/klameenc.cpp new file mode 100644 index 0000000..ddfc5c2 --- /dev/null +++ b/kaffeine/src/input/disc/plugins/mp3lame/klameenc.cpp @@ -0,0 +1,176 @@ +/* + * klameenc.cpp + * + * Copyright (C) 2006 Christophe Thommeret <hftom@free.fr> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include <qcombobox.h> +#include <qcheckbox.h> + +#include <kparts/genericfactory.h> +#include <klocale.h> +#include <kiconloader.h> +#include <kpushbutton.h> + +#include "klameenc.h" +#include "klameenc.moc" + +LameSettings::LameSettings( QWidget *parent, KConfig *confile ) : LameConfig( parent ) +{ + KIconLoader *icon = new KIconLoader(); + okBtn->setGuiItem( KGuiItem(i18n("OK"), icon->loadIconSet("ok", KIcon::Small) ) ); + cancelBtn->setGuiItem( KGuiItem(i18n("Cancel"), icon->loadIconSet("cancel", KIcon::Small) ) ); + delete icon; + brateComb->insertItem( "32" ); + brateComb->insertItem( "40" ); + brateComb->insertItem( "48" ); + brateComb->insertItem( "56" ); + brateComb->insertItem( "64" ); + brateComb->insertItem( "80" ); + brateComb->insertItem( "96" ); + brateComb->insertItem( "112" ); + brateComb->insertItem( "128" ); + brateComb->insertItem( "160" ); + brateComb->insertItem( "192" ); + brateComb->insertItem( "224" ); + brateComb->insertItem( "256" ); + brateComb->insertItem( "320" ); + Conf = confile; + Conf->setGroup("LameMp3"); + brateComb->setCurrentText( Conf->readEntry( "BitRate", "128" ) ); + vbrCb->setChecked( Conf->readBoolEntry( "VBR", false ) ); +} + +LameSettings::~LameSettings() +{ +} + +void LameSettings::accept() +{ + Conf->setGroup("LameMp3"); + Conf->writeEntry( "BitRate", brateComb->currentText() ); + Conf->writeEntry( "VBR", vbrCb->isChecked() ); + done( Accepted ); +} + +int LameSettings::getBitrate() +{ + return brateComb->currentText().toInt(); +} + +bool LameSettings::isVBR() +{ + return vbrCb->isChecked(); +} + +K_EXPORT_COMPONENT_FACTORY (libkaffeinemp3lame, KParts::GenericFactory<KLameEnc>) + +KLameEnc::KLameEnc( QWidget*, const char*, QObject* parent, const char* name, const QStringList& ) + : KaffeineAudioEncoder(parent,name) +{ + setInstance(KParts::GenericFactory<KLameEnc>::instance()); +} + +KAboutData *KLameEnc::createAboutData() +{ + KAboutData* aboutData = new KAboutData( "kaffeinemp3lame", I18N_NOOP("KaffeineMp3Lame"), + "0.1", I18N_NOOP("A Lame mp3 encoder plugin for Kaffeine."), + KAboutData::License_GPL, + "(c) 2006, Christophe Thommeret.", 0, "http://kaffeine.sourceforge.net"); + aboutData->addAuthor("Christophe Thommeret.",0, "hftom@free.fr"); + + return aboutData; +} + +QString KLameEnc::getExtension() +{ + return QString(".mp3"); +} + +bool KLameEnc::options( QWidget *parent, KConfig *conf ) +{ + LameSettings dlg( parent, conf ); + int ret = dlg.exec(); + if ( ret!=QDialog::Accepted ) + return false; + bitrate = dlg.getBitrate(); + vbr = dlg.isVBR(); + return true; +} + +void KLameEnc::start( QString title, QString artist, QString album, QString tracknumber, QString genre ) +{ + flags = lame_init(); + lame_set_mode( flags, STEREO ); + if ( vbr ) { + lame_set_VBR( flags, vbr_abr ); + lame_set_VBR_mean_bitrate_kbps( flags, bitrate ); + } + else { + lame_set_VBR( flags, vbr_off ); + lame_set_brate( flags, bitrate ); + } + lame_init_params( flags ); + + id3tag_init( flags ); + id3tag_v2_only( flags ); + if ( !title.isNull() ) + id3tag_set_title( flags, title.latin1() ); + if ( !artist.isNull() ) + id3tag_set_artist( flags, artist.latin1() ); + if ( !album.isNull() ) + id3tag_set_album( flags, album.latin1() ); + if ( !tracknumber.isNull() ) + id3tag_set_track( flags, tracknumber.latin1() ); + if ( !genre.isNull() ) + id3tag_set_genre( flags, genre.latin1() ); + id3tag_set_comment( flags, "Encoded by Kaffeine" ); + lame_init_params( flags ); +} + +char* KLameEnc::getHeader( int &len ) +{ + len = 0; + return NULL; +} + +char* KLameEnc::encode( char *data, int datalen, int &len ) +{ + len = lame_encode_buffer_interleaved( flags, (short int*)data, datalen/4, (unsigned char*)bufEncode, 8000 ); + + if ( len>0 ) + return bufEncode; + else + return NULL; +} + +char* KLameEnc::stop( int &len ) +{ + len = lame_encode_flush( flags, (unsigned char*)bufEncode, 8000 ); + + lame_close( flags ); + flags = 0; + + if ( len>0 ) + return bufEncode; + else + return NULL; +} + +KLameEnc::~KLameEnc() +{ +} diff --git a/kaffeine/src/input/disc/plugins/mp3lame/klameenc.h b/kaffeine/src/input/disc/plugins/mp3lame/klameenc.h new file mode 100644 index 0000000..0550149 --- /dev/null +++ b/kaffeine/src/input/disc/plugins/mp3lame/klameenc.h @@ -0,0 +1,76 @@ +/* + * klameenc.h + * + * Copyright (C) 2006 Christophe Thommeret <hftom@free.fr> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef KLAMEENC_H +#define KLAMEENC_H + +#include <lame/lame.h> + +#include <kconfig.h> + +#include "kaffeineaudioencoder.h" +#include "lameconfig.h" + +class LameSettings : public LameConfig +{ + Q_OBJECT +public: + LameSettings( QWidget *parent, KConfig *confile ); + ~LameSettings(); + + int getBitrate(); + bool isVBR(); + +public slots: + virtual void accept(); + +private: + KConfig *Conf; +}; + +class KLameEnc : public KaffeineAudioEncoder +{ + Q_OBJECT + +public: + + KLameEnc( QWidget*, const char*, QObject*, const char*, const QStringList& ); + ~KLameEnc(); + + // Reimplemented from KaffeineAudioEncoder + bool options( QWidget*, KConfig* ); + QString getExtension(); + void start( QString title=0, QString artist=0, QString album=0, QString tracknumber=0, QString genre=0 ); + char* getHeader( int &len ); + char* encode( char *data, int datalen, int &len ); + char* stop( int &len ); + //**************************** + + static KAboutData* createAboutData(); + +private: + + char bufEncode[8000]; + lame_global_flags *flags; + int bitrate; + bool vbr; +}; + +#endif /* KLAMEENC_H */ diff --git a/kaffeine/src/input/disc/plugins/mp3lame/lameconfig.ui b/kaffeine/src/input/disc/plugins/mp3lame/lameconfig.ui new file mode 100644 index 0000000..202040a --- /dev/null +++ b/kaffeine/src/input/disc/plugins/mp3lame/lameconfig.ui @@ -0,0 +1,195 @@ +<!DOCTYPE UI><UI version="3.2" stdsetdef="1"> +<class>LameConfig</class> +<widget class="QDialog"> + <property name="name"> + <cstring>LameConfig</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>232</width> + <height>142</height> + </rect> + </property> + <property name="caption"> + <string>Lame mp3 options</string> + </property> + <property name="sizeGripEnabled"> + <bool>false</bool> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLayoutWidget" row="0" column="0"> + <property name="name"> + <cstring>layout5</cstring> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QGroupBox"> + <property name="name"> + <cstring>groupBox1</cstring> + </property> + <property name="title"> + <string></string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QCheckBox" row="1" column="0"> + <property name="name"> + <cstring>vbrCb</cstring> + </property> + <property name="text"> + <string>VBR</string> + </property> + </widget> + <widget class="QLayoutWidget" row="0" column="0"> + <property name="name"> + <cstring>layout7</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>textLabel1</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>0</hsizetype> + <vsizetype>5</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Bitrate:</string> + </property> + </widget> + <widget class="QComboBox"> + <property name="name"> + <cstring>brateComb</cstring> + </property> + </widget> + <widget class="QLabel"> + <property name="name"> + <cstring>textLabel2</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>0</hsizetype> + <vsizetype>5</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Kb/s</string> + </property> + </widget> + </hbox> + </widget> + </grid> + </widget> + <spacer> + <property name="name"> + <cstring>spacer2</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>16</height> + </size> + </property> + </spacer> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout4</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <spacer> + <property name="name"> + <cstring>Horizontal Spacing2</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>107</width> + <height>20</height> + </size> + </property> + </spacer> + <widget class="KPushButton"> + <property name="name"> + <cstring>cancelBtn</cstring> + </property> + <property name="text"> + <string>&Cancel</string> + </property> + <property name="accel"> + <string></string> + </property> + <property name="autoDefault"> + <bool>true</bool> + </property> + </widget> + <widget class="KPushButton"> + <property name="name"> + <cstring>okBtn</cstring> + </property> + <property name="text"> + <string>&OK</string> + </property> + <property name="accel"> + <string></string> + </property> + <property name="autoDefault"> + <bool>true</bool> + </property> + <property name="default"> + <bool>true</bool> + </property> + </widget> + </hbox> + </widget> + </vbox> + </widget> + </grid> +</widget> +<connections> + <connection> + <sender>okBtn</sender> + <signal>clicked()</signal> + <receiver>LameConfig</receiver> + <slot>accept()</slot> + </connection> + <connection> + <sender>cancelBtn</sender> + <signal>clicked()</signal> + <receiver>LameConfig</receiver> + <slot>reject()</slot> + </connection> +</connections> +<layoutdefaults spacing="6" margin="11"/> +</UI> diff --git a/kaffeine/src/input/disc/plugins/oggvorbis/Makefile.am b/kaffeine/src/input/disc/plugins/oggvorbis/Makefile.am new file mode 100644 index 0000000..7ac8f45 --- /dev/null +++ b/kaffeine/src/input/disc/plugins/oggvorbis/Makefile.am @@ -0,0 +1,17 @@ +kde_module_LTLIBRARIES = libkaffeineoggvorbis.la + +INCLUDES = -I$(top_srcdir)/kaffeine/src/ -I$(top_srcdir)/kaffeine/src/input/disc/plugins/ $(all_includes) $(CFLAGS_OGGVORBIS) + +METASOURCES = AUTO + +kaffeineincludedir = $(includedir)/kaffeine + +noinst_HEADERS = koggenc.h + +libkaffeineoggvorbis_la_SOURCES = koggenc.cpp oggconfig.ui +libkaffeineoggvorbis_la_LIBADD = ../libkaffeineaudioencoder.la $(LIB_OGGVORBIS) +libkaffeineoggvorbis_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries) -avoid-version -no-undefined + +# this is where the desktop file will go +partdesktopdir = $(kde_servicesdir) +partdesktop_DATA = kaffeineoggvorbis.desktop diff --git a/kaffeine/src/input/disc/plugins/oggvorbis/kaffeineoggvorbis.desktop b/kaffeine/src/input/disc/plugins/oggvorbis/kaffeineoggvorbis.desktop new file mode 100644 index 0000000..cf51bf8 --- /dev/null +++ b/kaffeine/src/input/disc/plugins/oggvorbis/kaffeineoggvorbis.desktop @@ -0,0 +1,9 @@ +[Desktop Entry] +Encoding=UTF-8 +Name=Ogg Vorbis +Name[nb]=OGG Vorbis +Name[pa]=Ogg ਵੋਰਬਿਸ +Name[xx]=xxOgg Vorbisxx +ServiceTypes=KaffeineAudioEncoder +Type=Service +X-KDE-Library=libkaffeineoggvorbis diff --git a/kaffeine/src/input/disc/plugins/oggvorbis/koggenc.cpp b/kaffeine/src/input/disc/plugins/oggvorbis/koggenc.cpp new file mode 100644 index 0000000..f5352b8 --- /dev/null +++ b/kaffeine/src/input/disc/plugins/oggvorbis/koggenc.cpp @@ -0,0 +1,236 @@ +/* + * koggenc.cpp + * + * Copyright (C) 2002-2006 Christophe Thommeret <hftom@free.fr> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include <qslider.h> + +#include <kparts/genericfactory.h> +#include <kiconloader.h> +#include <kpushbutton.h> + +#include "koggenc.h" +#include "koggenc.moc" + +OggSettings::OggSettings( QWidget *parent, KConfig *confile ) : OggConfig( parent ) +{ + KIconLoader *icon = new KIconLoader(); + okBtn->setGuiItem( KGuiItem(i18n("OK"), icon->loadIconSet("ok", KIcon::Small) ) ); + cancelBtn->setGuiItem( KGuiItem(i18n("Cancel"), icon->loadIconSet("cancel", KIcon::Small) ) ); + delete icon; + Conf = confile; + Conf->setGroup("OggVorbis"); + oggSlid->setValue( Conf->readNumEntry( "Quality", 4 ) ); +} + +OggSettings::~OggSettings() +{ +} + +void OggSettings::accept() +{ + Conf->setGroup("OggVorbis"); + Conf->writeEntry( "Quality", oggSlid->value() ); + done( Accepted ); +} + +int OggSettings::getQuality() +{ + return oggSlid->value(); +} + +K_EXPORT_COMPONENT_FACTORY (libkaffeineoggvorbis, KParts::GenericFactory<KOggEnc>) + +KOggEnc::KOggEnc( QWidget*, const char*, QObject* parent, const char* name, const QStringList& ) + : KaffeineAudioEncoder(parent,name) +{ + setInstance(KParts::GenericFactory<KOggEnc>::instance()); + encodingQuality = 0.4; + bufEncode = new char[1]; + tmpBuf = new char[1]; +} + +KAboutData *KOggEnc::createAboutData() +{ + KAboutData* aboutData = new KAboutData( "kaffeineoggvorbis", I18N_NOOP("KaffeineOggVorbis"), + "0.1", I18N_NOOP("A Ogg Vorbis encoder plugin for Kaffeine."), + KAboutData::License_GPL, + "(c) 2006, Christophe Thommeret.", 0, "http://kaffeine.sourceforge.net"); + aboutData->addAuthor("Christophe Thommeret.",0, "hftom@free.fr"); + + return aboutData; +} + +QString KOggEnc::getExtension() +{ + return QString(".ogg"); +} + +bool KOggEnc::options( QWidget *parent, KConfig *conf ) +{ + OggSettings dlg( parent, conf ); + int ret = dlg.exec(); + if ( ret!=QDialog::Accepted ) + return false; + encodingQuality = dlg.getQuality()/10.0; + return true; +} + +void KOggEnc::start( QString title, QString artist, QString album, QString tracknumber, QString genre ) +{ + char* tag; + + vorbis_info_init( &vi ); + vorbis_encode_init_vbr( &vi, 2, 44100, encodingQuality ); + /* add a comment */ + vorbis_comment_init( &vc ); + vorbis_comment_add_tag( &vc, "description", "Encoded by Kaffeine" ); + //vorbis_comment_add_tag( &vc, "vendor", "KOggEnc (Kilogram)" ); + /* set up the analysis state and auxiliary encoding storage */ + vorbis_analysis_init( &vd, &vi ); + vorbis_block_init( &vd, &vb ); + /* set up our packet->stream encoder */ + /* pick a random serial number; that way we can more likely build + chained streams just by concatenation */ + srand( time(NULL) ); + ogg_stream_init( &os, rand() ); + if ( !title.isNull() ) { + tag = qstrdup( title.utf8() ); + vorbis_comment_add_tag( &vc, "title", tag ); + delete [] tag; + } + if ( !artist.isNull() ) { + tag = qstrdup( artist.utf8() ); + vorbis_comment_add_tag( &vc, "artist", tag ); + delete [] tag; + } + if ( !album.isNull() ) { + tag = qstrdup( album.utf8() ); + vorbis_comment_add_tag( &vc, "album", tag ); + delete [] tag; + } + if ( !tracknumber.isNull() ) { + tag = qstrdup( tracknumber.utf8() ); + vorbis_comment_add_tag( &vc, "tracknumber", tag ); + delete [] tag; + } + if ( !genre.isNull() ) { + tag = qstrdup( genre.utf8() ); + vorbis_comment_add_tag( &vc, "genre", tag ); + delete [] tag; + } +} + +char* KOggEnc::getHeader( int &len ) +{ + int buflen=0; + + vorbis_analysis_headerout( &vd, &vc, &header, &header_comm, &header_code ); + ogg_stream_packetin( &os, &header ); /* automatically placed in its own page */ + ogg_stream_packetin( &os, &header_comm ); + ogg_stream_packetin( &os, &header_code ); + + while( ogg_stream_flush( &os, &og ) ){ + delete [] bufEncode; + bufEncode = new char[ og.header_len+og.body_len+buflen ]; + //memcpy( mempcpy( mempcpy( bufEncode, tmpBuf, buflen ), og.header, og.header_len ), og.body, og.body_len ); + memcpy( (char*)memcpy( (char*)memcpy( bufEncode, tmpBuf, buflen )+buflen, og.header, og.header_len )+og.header_len, og.body, og.body_len ); + buflen+= og.header_len; + buflen+= og.body_len; + delete [] tmpBuf; + tmpBuf = new char[ buflen ]; + memcpy( tmpBuf, bufEncode, buflen ); + } + len = buflen; + return bufEncode; +} + +char* KOggEnc::encode( char *data, int datalen, int &len ) +{ + int buflen=0; + int i; + float **buffer=vorbis_analysis_buffer( &vd, datalen/4 ); + + for( i=0; i<datalen/4; i++ ){ + buffer[0][i] = ((data[i*4+1]<<8) | (0x00ff&(int)data[i*4]))/32768.f; + buffer[1][i] = ((data[i*4+3]<<8) | (0x00ff&(int)data[i*4+2]))/32768.f; + } + vorbis_analysis_wrote( &vd, i ); + + while( vorbis_analysis_blockout( &vd, &vb)==1 ) { + vorbis_analysis( &vb, NULL ); + vorbis_bitrate_addblock( &vb ); + while( vorbis_bitrate_flushpacket( &vd, &op ) ) { + ogg_stream_packetin( &os, &op ); + while( ogg_stream_pageout( &os, &og ) ) { + delete [] bufEncode; + bufEncode = new char[ og.header_len+og.body_len+buflen ]; + //memcpy( mempcpy( mempcpy( bufEncode, tmpBuf, buflen ), og.header, og.header_len ), og.body, og.body_len ); + memcpy( (char*)memcpy( (char*)memcpy( bufEncode, tmpBuf, buflen )+buflen, og.header, og.header_len )+og.header_len, og.body, og.body_len ); + buflen+= og.header_len; + buflen+= og.body_len; + delete [] tmpBuf; + tmpBuf = new char[ buflen ]; + memcpy( tmpBuf, bufEncode, buflen ); + } + } + } + len = buflen; + return bufEncode; +} + +char* KOggEnc::stop( int &len ) +{ + int buflen=0; + + vorbis_analysis_wrote( &vd, 0 ); + while( vorbis_analysis_blockout( &vd, &vb)==1 ) { + vorbis_analysis( &vb, NULL ); + vorbis_bitrate_addblock( &vb ); + while( vorbis_bitrate_flushpacket( &vd, &op ) ) { + ogg_stream_packetin( &os, &op ); + while( ogg_stream_pageout( &os, &og ) ) { + delete [] bufEncode; + bufEncode = new char[ og.header_len+og.body_len+buflen ]; + //memcpy( mempcpy( mempcpy( bufEncode, tmpBuf, buflen ), og.header, og.header_len ), og.body, og.body_len ); + memcpy( (char*)memcpy( (char*)memcpy( bufEncode, tmpBuf, buflen )+buflen, og.header, og.header_len )+og.header_len, og.body, og.body_len ); + buflen+= og.header_len; + buflen+= og.body_len; + delete [] tmpBuf; + tmpBuf = new char[ buflen ]; + memcpy( tmpBuf, bufEncode, buflen ); + } + } + } + ogg_stream_clear( &os ); + vorbis_block_clear( &vb ); + vorbis_dsp_clear( &vd ); + vorbis_comment_clear( &vc ); + vorbis_info_clear( &vi ); + len = buflen; + if ( len>0 ) + return bufEncode; + else + return NULL; +} + +KOggEnc::~KOggEnc() +{ + delete [] bufEncode; + delete [] tmpBuf; +} diff --git a/kaffeine/src/input/disc/plugins/oggvorbis/koggenc.h b/kaffeine/src/input/disc/plugins/oggvorbis/koggenc.h new file mode 100644 index 0000000..9560a53 --- /dev/null +++ b/kaffeine/src/input/disc/plugins/oggvorbis/koggenc.h @@ -0,0 +1,92 @@ +/* + * koggenc.h + * + * Copyright (C) 2002-2006 Christophe Thommeret <hftom@free.fr> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef KOGGENC_H +#define KOGGENC_H + +extern "C" +{ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <math.h> +#include <vorbis/vorbisenc.h> +} + +#include <kconfig.h> + +#include "kaffeineaudioencoder.h" +#include "oggconfig.h" + +class OggSettings : public OggConfig +{ + Q_OBJECT +public: + OggSettings( QWidget *parent, KConfig *confile ); + ~OggSettings(); + + int getQuality(); + +public slots: + virtual void accept(); + +private: + KConfig *Conf; +}; + +class KOggEnc : public KaffeineAudioEncoder +{ + Q_OBJECT + +public: + + KOggEnc( QWidget*, const char*, QObject*, const char*, const QStringList& ); + ~KOggEnc(); + + // Reimplemented from KaffeineAudioEncoder + bool options( QWidget*, KConfig* ); + QString getExtension(); + void start( QString title=0, QString artist=0, QString album=0, QString tracknumber=0, QString genre=0 ); + char* getHeader( int &len ); + char* encode( char *data, int datalen, int &len ); + char* stop( int &len ); + //**************************** + + static KAboutData* createAboutData(); + +private: + + ogg_stream_state os; /* take physical pages, weld into a logical stream of packets */ + ogg_page og; /* one Ogg bitstream page. Vorbis packets are inside */ + ogg_packet op; /* one raw packet of data for decode */ + vorbis_info vi; /* struct that stores all the static vorbis bitstream settings */ + vorbis_comment vc; /* struct that stores all the user comments */ + vorbis_dsp_state vd; /* central working state for the packet->PCM decoder */ + vorbis_block vb; /* local working space for packet->PCM decode */ + ogg_packet header; + ogg_packet header_comm; + ogg_packet header_code; + char *bufEncode; + char *tmpBuf; + float encodingQuality; +}; + +#endif /* KOGGENC_H */ diff --git a/kaffeine/src/input/disc/plugins/oggvorbis/oggconfig.ui b/kaffeine/src/input/disc/plugins/oggvorbis/oggconfig.ui new file mode 100644 index 0000000..178e938 --- /dev/null +++ b/kaffeine/src/input/disc/plugins/oggvorbis/oggconfig.ui @@ -0,0 +1,191 @@ +<!DOCTYPE UI><UI version="3.2" stdsetdef="1"> +<class>OggConfig</class> +<widget class="QDialog"> + <property name="name"> + <cstring>OggConfig</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>327</width> + <height>131</height> + </rect> + </property> + <property name="caption"> + <string>Ogg Vorbis Options</string> + </property> + <property name="sizeGripEnabled"> + <bool>false</bool> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLayoutWidget" row="0" column="0"> + <property name="name"> + <cstring>layout9</cstring> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QGroupBox"> + <property name="name"> + <cstring>GroupBox1</cstring> + </property> + <property name="title"> + <string></string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>11</number> + </property> + <property name="spacing"> + <number>6</number> + </property> + <widget class="QLCDNumber" row="1" column="1"> + <property name="name"> + <cstring>oggLCD</cstring> + </property> + <property name="frameShape"> + <enum>Box</enum> + </property> + <property name="frameShadow"> + <enum>Raised</enum> + </property> + <property name="numDigits"> + <number>3</number> + </property> + <property name="value" stdset="0"> + <number>0</number> + </property> + </widget> + <widget class="QSlider" row="1" column="0"> + <property name="name"> + <cstring>oggSlid</cstring> + </property> + <property name="minValue"> + <number>-1</number> + </property> + <property name="maxValue"> + <number>10</number> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + </widget> + <widget class="QLabel" row="0" column="0"> + <property name="name"> + <cstring>TextLabel1</cstring> + </property> + <property name="text"> + <string>Quality :</string> + </property> + </widget> + </grid> + </widget> + <spacer> + <property name="name"> + <cstring>spacer7</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>81</height> + </size> + </property> + </spacer> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout7</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <spacer> + <property name="name"> + <cstring>Horizontal Spacing2</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>157</width> + <height>20</height> + </size> + </property> + </spacer> + <widget class="KPushButton"> + <property name="name"> + <cstring>cancelBtn</cstring> + </property> + <property name="text"> + <string>&Cancel</string> + </property> + <property name="accel"> + <string></string> + </property> + <property name="autoDefault"> + <bool>true</bool> + </property> + </widget> + <widget class="KPushButton"> + <property name="name"> + <cstring>okBtn</cstring> + </property> + <property name="text"> + <string>&OK</string> + </property> + <property name="accel"> + <string></string> + </property> + <property name="autoDefault"> + <bool>true</bool> + </property> + <property name="default"> + <bool>true</bool> + </property> + </widget> + </hbox> + </widget> + </vbox> + </widget> + </grid> +</widget> +<connections> + <connection> + <sender>okBtn</sender> + <signal>clicked()</signal> + <receiver>OggConfig</receiver> + <slot>accept()</slot> + </connection> + <connection> + <sender>cancelBtn</sender> + <signal>clicked()</signal> + <receiver>OggConfig</receiver> + <slot>reject()</slot> + </connection> + <connection> + <sender>oggSlid</sender> + <signal>valueChanged(int)</signal> + <receiver>oggLCD</receiver> + <slot>display(int)</slot> + </connection> +</connections> +<layoutdefaults spacing="6" margin="11"/> +</UI> diff --git a/kaffeine/src/input/dvb/Makefile.am b/kaffeine/src/input/dvb/Makefile.am new file mode 100644 index 0000000..7b6c866 --- /dev/null +++ b/kaffeine/src/input/dvb/Makefile.am @@ -0,0 +1,81 @@ +SUBDIRS = lib plugins . + +INCLUDES = -I$(top_srcdir)/kaffeine/src/input/ \ + -I$(top_srcdir)/kaffeine/src/input/dvb/lib \ + -I$(top_srcdir)/kaffeine/src/input/dvb/plugins/stream \ + -I$(top_srcdir)/kaffeine/src/input/dvb/plugins/epg \ + -I$(top_srcdir)/kaffeine/src \ + $(all_includes) + +METASOURCES = AUTO + +noinst_LTLIBRARIES = libkaffeinedvb.la + +libkaffeinedvb_la_SOURCES = audioeditor.cpp \ + audioeditor.h \ + audioeditorui.ui \ + channeldesc.cpp \ + channeldesc.h \ + channeleditor.cpp \ + channeleditor.h \ + channeleditorui.ui \ + dvbconfig.cpp \ + dvbconfig.h \ + dvbevents.cpp \ + dvbevents.h \ + dvbout.cpp \ + dvbout.h \ + dvbpanel.cpp \ + dvbpanel.h \ + dvbsection.h \ + dvbsi.cpp \ + dvbsi.h \ + dvbstream.cpp \ + dvbstream.h \ + gdvb.h \ + kevents.cpp \ + kevents.h \ + kgradprogress.cpp \ + kgradprogress.h \ + krecord.cpp \ + krecord.h \ + ktimereditor.cpp \ + ktimereditor.h \ + scandialog.cpp \ + scandialog.h \ + scandialogui.ui \ + sender.cpp \ + sender.h \ + ts2rtp.cpp \ + ts2rtp.h \ + subeditorui.ui \ + subeditor.cpp \ + subeditor.h \ + broadcasteditorui.ui \ + broadcasteditor.cpp \ + broadcasteditor.h \ + cleaner.cpp \ + cleaner.h \ + crontimerui.ui \ + crontimer.cpp \ + crontimer.h \ + dvbcam.cpp \ + dvbcam.h + +libkaffeinedvb_la_LDFLAGS = $(KDE_RPATH) $(all_libraries) \ + -L$(top_srcdir)/kaffeine/src/input \ + -L$(top_srcdir)/kaffeine/src/input/dvb/plugins/stream \ + -L$(top_srcdir)/kaffeine/src/input/dvb/plugins/epg \ + ./lib/libdvbapi \ + ./lib/libdvben50221 \ + ./lib/libucsi + +libkaffeinedvb_la_LIBADD = \ + $(top_builddir)/kaffeine/src/input/dvb/plugins/stream/libkaffeinedvbplugin.la \ + $(top_builddir)/kaffeine/src/input/dvb/plugins/epg/libkaffeineepgplugin.la \ + $(top_builddir)/kaffeine/src/input/libkaffeineinput.la \ + ./lib/libdvbapi/libdvbapi.la ./lib/libdvben50221/libdvben50221.la ./lib/libucsi/libucsi.la + +# this is where the XML-GUI resource file goes +shellrcdir = $(kde_datadir)/kaffeine +shellrc_DATA = kaffeinedvb.rc diff --git a/kaffeine/src/input/dvb/audioeditor.cpp b/kaffeine/src/input/dvb/audioeditor.cpp new file mode 100644 index 0000000..a8d8a5f --- /dev/null +++ b/kaffeine/src/input/dvb/audioeditor.cpp @@ -0,0 +1,160 @@ +/* + * audioeditor.cpp + * + * Copyright (C) 2004-2005 Christophe Thommeret <hftom@free.fr> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include <qlistbox.h> +#include <qspinbox.h> +#include <qpushbutton.h> +#include <qlineedit.h> +#include <qcheckbox.h> + +#include <kmessagebox.h> +#include <klocale.h> + +#include "audioeditor.h" + +AudioEditor::AudioEditor( ChannelDesc *chan, QWidget *parent ) : AudioEditorUI( parent ) +{ + QString s, t; + int i; + + channel = chan; + pidList->clear(); + + for ( i=0; i<channel->napid; i++ ) insertItem( i ); + + if ( channel->napid==channel->maxapid ) newBtn->setEnabled( false ); + + connect( pidList, SIGNAL(highlighted(int)), this, SLOT(showProp(int)) ); + connect( upBtn, SIGNAL(clicked()), this, SLOT(itemUp()) ); + connect( downBtn, SIGNAL(clicked()), this, SLOT(itemDown()) ); + connect( delBtn, SIGNAL(clicked()), this, SLOT(itemDelete()) ); + connect( updateBtn, SIGNAL(clicked()), this, SLOT(itemUpdate()) ); + connect( newBtn, SIGNAL(clicked()), this, SLOT(itemNew()) ); +} + +void AudioEditor::insertItem( int index, bool updt ) +{ + QString s, t; + + s = t.setNum( channel->apid[index].pid ); + if ( !channel->apid[index].lang.isEmpty() ) s = s+"("+channel->apid[index].lang+")"; + if ( channel->apid[index].ac3 ) s = s+"(ac3)"; + if ( updt ) pidList->changeItem( s, index ); + else pidList->insertItem( s, index ); +} + +void AudioEditor::showProp( int index ) +{ + if ( index<0 ) { + pidSpin->setValue( 0 ); + langLe->setText( "" ); + ac3Cb->setChecked( false ); + } + else { + pidSpin->setValue( channel->apid[index].pid ); + langLe->setText( channel->apid[index].lang ); + ac3Cb->setChecked( channel->apid[index].ac3 ); + } +} + +void AudioEditor::itemUp() +{ + AudioPid a; + + int n = pidList->currentItem(); + + if ( n<1 ) return; + + a = channel->apid[n-1]; + channel->apid[n-1] = channel->apid[n]; + channel->apid[n] = a; + + insertItem( n, true ); + insertItem( n-1, true ); +} + +void AudioEditor::itemDown() +{ + AudioPid a; + + int n = pidList->currentItem(); + + if ( (n<0) || (n>(channel->napid-2)) ) return; + + a = channel->apid[n+1]; + channel->apid[n+1] = channel->apid[n]; + channel->apid[n] = a; + + insertItem( n, true ); + insertItem( n+1, true ); +} + +void AudioEditor::itemDelete() +{ + int n = pidList->currentItem(); + + if ( channel->napid==0 || (n<0) ) return; //for sure + + for ( int i=n; i<channel->napid-1; i++ ) channel->apid[i] = channel->apid[i+1]; + channel->napid--; + pidList->removeItem( n ); + + newBtn->setEnabled( true ); +} + +void AudioEditor::itemUpdate() +{ + int n = pidList->currentItem(); + + if ( n<0 ) return; + + channel->apid[n].pid = pidSpin->value(); + channel->apid[n].lang = langLe->text().stripWhiteSpace(); + if ( ac3Cb->isChecked() ) channel->apid[n].ac3 = 1; + else channel->apid[n].ac3 = 0; + + insertItem( n, true ); +} + +void AudioEditor::itemNew() +{ + if ( channel->napid==channel->maxapid ) { //for sure + newBtn->setEnabled( false ); + return; + } + + if ( !pidSpin->value() ) { + KMessageBox::sorry( this, i18n("Pid must be non zero!") ); + return; + } + channel->napid++; + channel->apid[channel->napid-1].pid = pidSpin->value(); + channel->apid[channel->napid-1].lang = langLe->text().stripWhiteSpace(); + if ( ac3Cb->isChecked() ) channel->apid[channel->napid-1].ac3 = 1; + else channel->apid[channel->napid-1].ac3 = 0; + insertItem( channel->napid-1 ); + if ( channel->napid==channel->maxapid ) newBtn->setEnabled( false ); +} + +AudioEditor::~AudioEditor() +{ +} + +#include "audioeditor.moc" diff --git a/kaffeine/src/input/dvb/audioeditor.h b/kaffeine/src/input/dvb/audioeditor.h new file mode 100644 index 0000000..8751505 --- /dev/null +++ b/kaffeine/src/input/dvb/audioeditor.h @@ -0,0 +1,53 @@ +/* + * audioeditor.h + * + * Copyright (C) 2004-2005 Christophe Thommeret <hftom@free.fr> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef AUDIOEDITOR_H +#define AUDIOEDITOR_H + +#include "channeldesc.h" +#include "audioeditorui.h" + +class AudioEditor : public AudioEditorUI +{ + Q_OBJECT + +public: + + AudioEditor( ChannelDesc *chan, QWidget *parent ); + ~AudioEditor(); + +private slots: + + void showProp( int index ); + void itemUp(); + void itemDown(); + void itemDelete(); + void itemUpdate(); + void itemNew(); + +private: + + void insertItem( int index, bool updt=false ); + + ChannelDesc *channel; + +}; + +#endif /* AUDIOEDITOR_H */ diff --git a/kaffeine/src/input/dvb/audioeditorui.ui b/kaffeine/src/input/dvb/audioeditorui.ui new file mode 100644 index 0000000..20b07ef --- /dev/null +++ b/kaffeine/src/input/dvb/audioeditorui.ui @@ -0,0 +1,319 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>AudioEditorUI</class> +<widget class="QDialog"> + <property name="name"> + <cstring>AudioEditorUI</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>439</width> + <height>284</height> + </rect> + </property> + <property name="caption"> + <string>Audio PIDs editor</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLayoutWidget" row="0" column="0"> + <property name="name"> + <cstring>layout24</cstring> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout23</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QGroupBox"> + <property name="name"> + <cstring>groupBox10</cstring> + </property> + <property name="title"> + <string>Audio PIDs</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QListBox" row="0" column="0"> + <item> + <property name="text"> + <string>New Item</string> + </property> + </item> + <property name="name"> + <cstring>pidList</cstring> + </property> + </widget> + </grid> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout21</cstring> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout16</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout15</cstring> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QPushButton"> + <property name="name"> + <cstring>upBtn</cstring> + </property> + <property name="text"> + <string>Move Up</string> + </property> + </widget> + <widget class="QPushButton"> + <property name="name"> + <cstring>downBtn</cstring> + </property> + <property name="text"> + <string>Move Down</string> + </property> + </widget> + <widget class="QPushButton"> + <property name="name"> + <cstring>delBtn</cstring> + </property> + <property name="text"> + <string>Remove</string> + </property> + </widget> + </vbox> + </widget> + <spacer> + <property name="name"> + <cstring>spacer8</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </hbox> + </widget> + <spacer> + <property name="name"> + <cstring>spacer10</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout14</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout13</cstring> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QPushButton"> + <property name="name"> + <cstring>updateBtn</cstring> + </property> + <property name="text"> + <string><< Update Selected</string> + </property> + </widget> + <widget class="QPushButton"> + <property name="name"> + <cstring>newBtn</cstring> + </property> + <property name="text"> + <string><< New</string> + </property> + </widget> + </vbox> + </widget> + <widget class="QGroupBox"> + <property name="name"> + <cstring>groupBox9</cstring> + </property> + <property name="title"> + <string>Properties</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QSpinBox" row="0" column="1"> + <property name="name"> + <cstring>pidSpin</cstring> + </property> + <property name="maxValue"> + <number>8192</number> + </property> + </widget> + <widget class="QLabel" row="0" column="0"> + <property name="name"> + <cstring>textLabel3</cstring> + </property> + <property name="text"> + <string>Pid:</string> + </property> + </widget> + <widget class="QLabel" row="1" column="0"> + <property name="name"> + <cstring>textLabel4</cstring> + </property> + <property name="text"> + <string>Lang:</string> + </property> + </widget> + <widget class="QCheckBox" row="2" column="0"> + <property name="name"> + <cstring>ac3Cb</cstring> + </property> + <property name="text"> + <string>AC3</string> + </property> + </widget> + <widget class="QLineEdit" row="1" column="1"> + <property name="name"> + <cstring>langLe</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>2</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + </grid> + </widget> + </hbox> + </widget> + </vbox> + </widget> + </hbox> + </widget> + <widget class="Line"> + <property name="name"> + <cstring>line3</cstring> + </property> + <property name="frameShape"> + <enum>HLine</enum> + </property> + <property name="frameShadow"> + <enum>Sunken</enum> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout19</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <spacer> + <property name="name"> + <cstring>spacer9</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + <widget class="QPushButton"> + <property name="name"> + <cstring>okBtn</cstring> + </property> + <property name="text"> + <string>Close</string> + </property> + </widget> + </hbox> + </widget> + </vbox> + </widget> + </grid> +</widget> +<connections> + <connection> + <sender>okBtn</sender> + <signal>clicked()</signal> + <receiver>AudioEditorUI</receiver> + <slot>accept()</slot> + </connection> +</connections> +<tabstops> + <tabstop>okBtn</tabstop> + <tabstop>pidList</tabstop> + <tabstop>upBtn</tabstop> + <tabstop>downBtn</tabstop> + <tabstop>delBtn</tabstop> + <tabstop>updateBtn</tabstop> + <tabstop>newBtn</tabstop> + <tabstop>pidSpin</tabstop> + <tabstop>langLe</tabstop> + <tabstop>ac3Cb</tabstop> +</tabstops> +<layoutdefaults spacing="6" margin="11"/> +</UI> diff --git a/kaffeine/src/input/dvb/broadcasteditor.cpp b/kaffeine/src/input/dvb/broadcasteditor.cpp new file mode 100644 index 0000000..0e6c8a6 --- /dev/null +++ b/kaffeine/src/input/dvb/broadcasteditor.cpp @@ -0,0 +1,132 @@ +/* + * broadcasteditor.cpp + * + * Copyright (C) 2005 Christophe Thommeret <hftom@free.fr> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include <qdir.h> +#include <qvaluelist.h> + +#include <kpushbutton.h> +#include <kiconloader.h> +#include <klocale.h> + +#include "broadcasteditor.h" + +BroadcastEditor::BroadcastEditor( QWidget *parent, QPtrList<ChannelDesc> *ch, QPtrList<ChannelDesc> *ret ) : BroadcastEditorUI( parent ) +{ + KIconLoader *icon = new KIconLoader(); + + tvPix = icon->loadIcon( "kdvbtv", KIcon::Small ); + tvcPix = icon->loadIcon( "kdvbtvc", KIcon::Small ); + raPix = icon->loadIcon( "kdvbra", KIcon::Small ); + racPix = icon->loadIcon( "kdvbrac", KIcon::Small ); + addBtn->setGuiItem( KGuiItem(i18n("Add"), icon->loadIconSet("forward", KIcon::Small) ) ); + resetBtn->setGuiItem( KGuiItem(i18n("Reset"), icon->loadIconSet("reload", KIcon::Small) ) ); + cancelBtn->setGuiItem( KGuiItem(i18n("Cancel"), icon->loadIconSet("cancel", KIcon::Small) ) ); + okBtn->setGuiItem( KGuiItem(i18n("OK"), icon->loadIconSet("ok", KIcon::Small) ) ); + + connect( channelLb, SIGNAL(doubleClicked(QListBoxItem*)), this, SLOT(slotAddChannel(QListBoxItem*)) ); + + chan = ch; + list = ret; + + resetList(); + delete icon; +} + +BroadcastEditor::~BroadcastEditor() +{ +} + +ChannelDesc* BroadcastEditor::getChannel( const QString &name ) +{ + int i; + + for ( i=0; i<(int)chan->count(); i++ ) { + if ( chan->at(i)->name==name ) return chan->at(i); + } + return 0; +} + +void BroadcastEditor::slotAddChannel(QListBoxItem*) +{ + addToList(); +} + +void BroadcastEditor::addToList() +{ + int i; + QString curName; + QValueList<QListBoxItem*> qvl; + ChannelDesc *c=0, *d=0; + + for ( i=0; i<(int)channelLb->count(); i++ ) { + if ( channelLb->isSelected(i) ) { + curName = channelLb->text(i); + c = getChannel( curName ); + if ( !c ) continue; + broadcastLb->insertItem( *channelLb->pixmap(i), channelLb->text(i) ); + list->append( c ); + qvl.append(channelLb->item(i)); + } + } + if ( !c ) return; + for ( i=0; i<(int)qvl.count(); i++ ) channelLb->takeItem( qvl[i] ); + + qvl.clear(); + for ( i=0; i<(int)channelLb->count(); i++ ) { + d = getChannel( channelLb->text(i) ); + if ( !d ) continue; + if ( d->tp!=c->tp ) qvl.append(channelLb->item(i)); + } + for ( i=0; i<(int)qvl.count(); i++ ) channelLb->takeItem( qvl[i] ); + + channelLb->setSelectionMode( QListBox::Extended ); +} + +bool BroadcastEditor::getChannelList() +{ + int i; + ChannelDesc *c; + + for ( i=0; i<(int)chan->count(); i++ ) { + c = chan->at(i); + if ( c->fta ) { + if ( c->type==1 ) channelLb->insertItem( tvcPix, c->name ); + else channelLb->insertItem( racPix, c->name ); + } + else { + if ( c->type==1 ) channelLb->insertItem( tvPix, c->name ); + else channelLb->insertItem( raPix, c->name ); + } + } + return true; +} + +void BroadcastEditor::resetList() +{ + addBtn->setEnabled( true ); + channelLb->clear(); + broadcastLb->clear(); + list->clear(); + getChannelList(); + channelLb->sort(); + channelLb->setSelectionMode( QListBox::Single ); +} + +#include "broadcasteditor.moc" diff --git a/kaffeine/src/input/dvb/broadcasteditor.h b/kaffeine/src/input/dvb/broadcasteditor.h new file mode 100644 index 0000000..13c619f --- /dev/null +++ b/kaffeine/src/input/dvb/broadcasteditor.h @@ -0,0 +1,58 @@ +/* + * broadcasteditor.h + * + * Copyright (C) 2005 Christophe Thommeret <hftom@free.fr> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef BROADCASTEDITOR_H +#define BROADCASTEDITOR_H + +#include <qpixmap.h> +#include <qfile.h> +#include <qlistbox.h> + +#include "broadcasteditorui.h" +#include "channeldesc.h" + +class BroadcastEditor : public BroadcastEditorUI +{ + Q_OBJECT + +public: + + BroadcastEditor( QWidget *parent, QPtrList<ChannelDesc> *ch, QPtrList<ChannelDesc> *ret ); + ~BroadcastEditor(); + + QPtrList<ChannelDesc> *chan; + QPtrList<ChannelDesc> *list; + +public slots: + + virtual void addToList(); + virtual void resetList(); + void slotAddChannel(QListBoxItem*); + +private: + + bool getChannelList(); + ChannelDesc* getChannel( const QString &name ); + + QPixmap tvPix, raPix, tvcPix, racPix; + +}; + +#endif /* BROADCASTEDITOR_H */ diff --git a/kaffeine/src/input/dvb/broadcasteditorui.ui b/kaffeine/src/input/dvb/broadcasteditorui.ui new file mode 100644 index 0000000..034bd39 --- /dev/null +++ b/kaffeine/src/input/dvb/broadcasteditorui.ui @@ -0,0 +1,315 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>BroadcastEditorUI</class> +<widget class="QDialog"> + <property name="name"> + <cstring>BroadcastEditorUI</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>458</width> + <height>378</height> + </rect> + </property> + <property name="caption"> + <string>Broadcasting Editor</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>11</number> + </property> + <property name="spacing"> + <number>6</number> + </property> + <widget class="QLayoutWidget" row="0" column="0"> + <property name="name"> + <cstring>Layout6</cstring> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <property name="spacing"> + <number>6</number> + </property> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>Layout4</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <property name="spacing"> + <number>6</number> + </property> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>Layout2</cstring> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <property name="spacing"> + <number>6</number> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>TextLabel1</cstring> + </property> + <property name="text"> + <string>Available channels:</string> + </property> + <property name="scaledContents"> + <bool>false</bool> + </property> + </widget> + <widget class="QListBox"> + <item> + <property name="text"> + <string>New Item</string> + </property> + </item> + <property name="name"> + <cstring>channelLb</cstring> + </property> + <property name="columnMode"> + <enum>FixedNumber</enum> + </property> + </widget> + </vbox> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>Layout1</cstring> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <property name="spacing"> + <number>6</number> + </property> + <spacer> + <property name="name"> + <cstring>Spacer1</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>20</height> + </size> + </property> + </spacer> + <widget class="KPushButton"> + <property name="name"> + <cstring>addBtn</cstring> + </property> + <property name="text"> + <string></string> + </property> + </widget> + <widget class="KPushButton"> + <property name="name"> + <cstring>resetBtn</cstring> + </property> + <property name="text"> + <string></string> + </property> + </widget> + <spacer> + <property name="name"> + <cstring>Spacer2</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>20</height> + </size> + </property> + </spacer> + </vbox> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>Layout3</cstring> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <property name="spacing"> + <number>6</number> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>TextLabel2</cstring> + </property> + <property name="text"> + <string>Broadcasting list:</string> + </property> + </widget> + <widget class="QListBox"> + <item> + <property name="text"> + <string>New Item</string> + </property> + </item> + <property name="name"> + <cstring>broadcastLb</cstring> + </property> + <property name="columnMode"> + <enum>FixedNumber</enum> + </property> + </widget> + </vbox> + </widget> + </hbox> + </widget> + <widget class="Line"> + <property name="name"> + <cstring>Line1</cstring> + </property> + <property name="frameShape"> + <enum>HLine</enum> + </property> + <property name="frameShadow"> + <enum>Sunken</enum> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>Layout5</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <property name="spacing"> + <number>6</number> + </property> + <widget class="KPushButton"> + <property name="name"> + <cstring>cancelBtn</cstring> + </property> + <property name="text"> + <string></string> + </property> + </widget> + <spacer> + <property name="name"> + <cstring>Spacer3</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>20</height> + </size> + </property> + </spacer> + <widget class="KPushButton"> + <property name="name"> + <cstring>okBtn</cstring> + </property> + <property name="text"> + <string></string> + </property> + </widget> + </hbox> + </widget> + </vbox> + </widget> + </grid> +</widget> +<customwidgets> +</customwidgets> +<connections> + <connection> + <sender>addBtn</sender> + <signal>clicked()</signal> + <receiver>BroadcastEditorUI</receiver> + <slot>addToList()</slot> + </connection> + <connection> + <sender>resetBtn</sender> + <signal>clicked()</signal> + <receiver>BroadcastEditorUI</receiver> + <slot>resetList()</slot> + </connection> + <connection> + <sender>cancelBtn</sender> + <signal>clicked()</signal> + <receiver>BroadcastEditorUI</receiver> + <slot>reject()</slot> + </connection> + <connection> + <sender>okBtn</sender> + <signal>clicked()</signal> + <receiver>BroadcastEditorUI</receiver> + <slot>accept()</slot> + </connection> +</connections> +<tabstops> + <tabstop>channelLb</tabstop> + <tabstop>addBtn</tabstop> + <tabstop>resetBtn</tabstop> + <tabstop>broadcastLb</tabstop> + <tabstop>cancelBtn</tabstop> + <tabstop>okBtn</tabstop> +</tabstops> +<slots> + <slot>addToList()</slot> + <slot>resetList()</slot> +</slots> +<layoutdefaults spacing="6" margin="11"/> +<includehints> + <includehint>kpushbutton.h</includehint> + <includehint>kpushbutton.h</includehint> + <includehint>kpushbutton.h</includehint> + <includehint>kpushbutton.h</includehint> +</includehints> +</UI> diff --git a/kaffeine/src/input/dvb/channeldesc.cpp b/kaffeine/src/input/dvb/channeldesc.cpp new file mode 100644 index 0000000..5ab4acf --- /dev/null +++ b/kaffeine/src/input/dvb/channeldesc.cpp @@ -0,0 +1,184 @@ +/* + * channeldesc.cpp + * + * Copyright (C) 2003-2006 Christophe Thommeret <hftom@free.fr> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include <math.h> + +#include "channeldesc.h" + +AudioPid::AudioPid() +{ + pid=ac3=0; + lang=""; +} + +AudioPid::AudioPid( unsigned short apid ) +{ + pid = apid; + ac3=0; + lang=""; +} + +AudioPid::~AudioPid() +{ +} + +ChannelDesc::ChannelDesc() +{ + fta=sid=ttpid=vpid=pmtpid=type=0; + vType=0; + num=0; + name=provider=category=""; + completed = 0; + tp.freq=tp.sr=0; + tp.pol='v'; + maxapid=MAXAPID; + for ( int i=0; i<maxapid; i++ ) { + apid[i].pid=apid[i].ac3=0; + apid[i].lang=""; + } + napid=0; + maxsubpid=MAXSUBPID; + for ( int i=0; i<maxsubpid; i++ ) { + subpid[i].pid=subpid[i].page=subpid[i].id=0; + subpid[i].type=0; + subpid[i].lang="???"; + } + nsubpid=0; +} + +ChannelDesc::ChannelDesc( const ChannelDesc &chan ) +{ + num = chan.num; + fta = chan.fta; + sid = chan.sid; + vpid = chan.vpid; + vType = chan.vType; + pmtpid = chan.pmtpid; + type = chan.type; + ttpid = chan.ttpid; + name = chan.name; + provider = chan.provider; + category = chan.category; + completed = chan.completed; + tp = chan.tp; + maxapid = chan.maxapid; + for ( int i=0; i<maxapid; i++ ) { + apid[i] = chan.apid[i]; + apid[i].ac3 = chan.apid[i].ac3; + apid[i].lang = chan.apid[i].lang; + } + napid = chan.napid; + maxsubpid = chan.maxsubpid; + for ( int i=0; i<maxsubpid; i++ ) { + subpid[i] = chan.subpid[i]; + subpid[i].type = chan.subpid[i].type; + subpid[i].lang = chan.subpid[i].lang; + } + nsubpid = chan.nsubpid; +} + +ChannelDesc::~ChannelDesc() +{ +} + +Transponder::Transponder() +{ + source = ""; + type = FE_QPSK; + freq = 0; + sr = 0; + pol = 'v'; + nid=tsid = 0; + inversion=INVERSION_AUTO; + modulation=QAM_AUTO; + hierarchy=HIERARCHY_AUTO; + guard=GUARD_INTERVAL_AUTO; + transmission=TRANSMISSION_MODE_AUTO; + coderateL=FEC_AUTO; + coderateH=FEC_AUTO; + bandwidth=BANDWIDTH_AUTO; + snr = 0; +} + +Transponder::Transponder( const Transponder &trans ) +{ + source = trans.source; + type = trans.type; + freq = trans.freq; + sr = trans.sr; + pol = trans.pol; + tsid = trans.tsid; + nid = trans.nid; + inversion=trans.inversion; + modulation=trans.modulation; + hierarchy=trans.hierarchy; + guard=trans.guard; + transmission=trans.transmission; + coderateL=trans.coderateL; + coderateH=trans.coderateH; + bandwidth=trans.bandwidth; +} + +bool Transponder::sameAs( Transponder *trans ) +{ + int f1 = this->freq*1000; + int f2 = trans->freq*1000; + + if ( fabs(f1-f2) < 2000 ) return true; + return false; +} + +bool Transponder::operator==( const Transponder &t ) +{ + if ( this->bandwidth==t.bandwidth + && this->source==t.source + && this->coderateH==t.coderateH + && this->coderateL==t.coderateL + && this->freq==t.freq + && this->guard==t.guard + && this->hierarchy==t.hierarchy + && this->inversion==t.inversion + && this->modulation==t.modulation + && this->pol==t.pol + && this->sr==t.sr + && this->transmission==t.transmission ) return true; + return false; +} + +bool Transponder::operator!=( const Transponder &t ) +{ + if ( this->bandwidth!=t.bandwidth + || this->source!=t.source + || this->coderateH!=t.coderateH + || this->coderateL!=t.coderateL + || this->freq!=t.freq + || this->guard!=t.guard + || this->hierarchy!=t.hierarchy + || this->inversion!=t.inversion + || this->modulation!=t.modulation + || this->pol!=t.pol + || this->sr!=t.sr + || this->transmission!=t.transmission ) return true; + return false; +} + +Transponder::~Transponder() +{ +} diff --git a/kaffeine/src/input/dvb/channeldesc.h b/kaffeine/src/input/dvb/channeldesc.h new file mode 100644 index 0000000..f4bc1ab --- /dev/null +++ b/kaffeine/src/input/dvb/channeldesc.h @@ -0,0 +1,137 @@ +/* + * channeldesc.h + * + * Copyright (C) 2003-2006 Christophe Thommeret <hftom@free.fr> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef CHANNELDESC_H +#define CHANNELDESC_H + +#include <qstring.h> +#include <qptrlist.h> +#include <qdatetime.h> +#include <qvaluelist.h> +#include <qpixmap.h> + +#include <linux/dvb/frontend.h> + +#include "kaffeinedvbevents.h" + +#define MAXAPID 20 +#define MAXSUBPID 10 + +class RecTimer +{ + +public: + + QString name; + QString fullPath; + QString channel; + QDateTime begin; + QTime duration; + char running; + int mode; +}; + +class AudioPid +{ + +public: + + AudioPid(); + AudioPid( unsigned short apid ); + ~AudioPid(); + + unsigned short pid; + QString lang; + char ac3; +}; + +class SubPid +{ + +public: + + unsigned short pid, page, id; + unsigned char type; + QString lang; +}; + +class Transponder +{ + +public: + + Transponder(); + Transponder( const Transponder &trans ); //copy + ~Transponder(); + bool sameAs( Transponder *trans ); + bool operator==( const Transponder &t ); + bool operator!=( const Transponder &t ); + + QString source; + fe_type_t type; // S, C or T + unsigned long freq; + QValueList<unsigned long> freqlist; + char pol; + unsigned long sr; + unsigned short nid; + unsigned short tsid; + fe_spectral_inversion_t inversion; + fe_modulation_t modulation; + fe_hierarchy_t hierarchy; + fe_guard_interval_t guard; + fe_transmit_mode_t transmission; + fe_code_rate_t coderateL; + fe_code_rate_t coderateH; + fe_bandwidth_t bandwidth; + int snr; +}; + +class ChannelDesc +{ + +public: + + ChannelDesc(); + ChannelDesc( const ChannelDesc &chan ); //copy + ~ChannelDesc(); + + QString provider; + QString name; + QString category; + unsigned int num; + unsigned short sid; + unsigned short vpid; + unsigned char vType; // video stream type + AudioPid apid[MAXAPID]; + char napid; + char maxapid; + unsigned short ttpid; + SubPid subpid[MAXSUBPID]; + char nsubpid; + char maxsubpid; + unsigned short pmtpid; + unsigned char fta; // 0 for free + unsigned char type; // 1 for TV , 2 for RA + int completed; + Transponder tp; + QPixmap pix; +}; + +#endif /* CHANNELDESC_H */ diff --git a/kaffeine/src/input/dvb/channeleditor.cpp b/kaffeine/src/input/dvb/channeleditor.cpp new file mode 100644 index 0000000..6b04fe4 --- /dev/null +++ b/kaffeine/src/input/dvb/channeleditor.cpp @@ -0,0 +1,330 @@ +/* + * channeleditor.cpp + * + * Copyright (C) 2004-2005 Christophe Thommeret <hftom@free.fr> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include <qbuttongroup.h> +#include <qradiobutton.h> +#include <qspinbox.h> +#include <qcombobox.h> +#include <qcheckbox.h> +#include <qgroupbox.h> +#include <qlineedit.h> +#include <qpushbutton.h> + +#include <klocale.h> +#include <kmessagebox.h> + +#include "channeleditor.h" +#include "audioeditor.h" +#include "subeditor.h" + +ChannelEditor::ChannelEditor( QStringList src, bool m, ChannelDesc *chan, QPtrList<ChannelDesc> *cdesc, QWidget *parent ) : ChannelEditorUI( parent ) +{ + int i; + channel = chan; + mode = m; + chandesc = cdesc; + orgName = channel->name; + + sourceComb->insertStringList( src ); + for ( i=0; i<(int)sourceComb->count(); i++ ) { + if ( sourceComb->text(i)==channel->tp.source ) { + sourceComb->setCurrentItem(i); + break; + } + } + + if ( channel->tp.type==FE_QAM ) initC(); + else if ( channel->tp.type==FE_OFDM ) initT(); + else if ( channel->tp.type==FE_QPSK ) initS(); + else initA(); + + if ( mode ) { + ftaCb->setEnabled( false ); + pidsGroup->setEnabled( false ); + numSpin->setEnabled( false ); + setCaption( i18n("Initial Transponder Settings") ); + } + else { + numSpin->setMinValue( 1 ); + numSpin->setMaxValue( chandesc->count() ); + chanNum = channel->num; + numSpin->setValue( channel->num ); + sidSpin->setValue( channel->sid ); + vpidSpin->setValue( channel->vpid ); + ttpidSpin->setValue( channel->ttpid ); + tsidSpin->setValue( channel->tp.tsid ); + nidSpin->setValue( channel->tp.nid ); + ftaCb->setChecked( channel->fta ); + } + nameLe->setText( channel->name ); + + connect( apidBtn, SIGNAL(clicked()), this, SLOT(editAudio()) ); + connect( subpidBtn, SIGNAL(clicked()), this, SLOT(editSubtitle()) ); +} + +void ChannelEditor::editAudio() +{ + AudioEditor dlg( channel, this ); + + dlg.exec(); +} + +void ChannelEditor::editSubtitle() +{ + SubEditor dlg( channel, this ); + + dlg.exec(); +} + +void ChannelEditor::accept() +{ + int ret, i; + QString name; + + name = nameLe->text().stripWhiteSpace(); + if ( name.isEmpty() ) { + KMessageBox::sorry( this, i18n("You must give it a name!") ); + return; + } + + if ( !mode ) { + for ( ret=0; ret<(int)chandesc->count(); ret++ ) { + if ( (channel->name==chandesc->at(ret)->name) && (channel->name!=orgName) ) { + KMessageBox::sorry( this, i18n("This name is not unique.") ); + return; + } + } + if ( ftaCb->isChecked() ) channel->fta = 1; + else channel->fta = 0; + channel->vpid = vpidSpin->value(); + channel->sid = sidSpin->value(); + channel->ttpid = ttpidSpin->value(); + channel->tp.tsid = tsidSpin->value(); + channel->tp.nid = nidSpin->value(); + if ( !channel->napid ) { + KMessageBox::sorry( this, i18n("Missing audio pid(s)!") ); + return; + } + if ( numSpin->value()!=chanNum ) { + for ( i=0; i<(int)chandesc->count(); i++ ) { + if ( (int)chandesc->at(i)->num==numSpin->value() ) { + chandesc->at(i)->num = chanNum; + break; + } + } + } + channel->num = numSpin->value(); + if ( channel->vpid ) channel->type = 1; + else channel->type = 2; + } + channel->name = name; + channel->tp.source = sourceComb->currentText(); + if ( channel->tp.type==FE_QPSK ) { + channel->tp.freq = freqSpin->value(); + channel->tp.sr = srSpin->value(); + if ( verticalRadio->isChecked() ) channel->tp.pol = 'v'; + else channel->tp.pol = 'h'; + channel->tp.coderateH = (fe_code_rate_t)(FEC_NONE+coderateHComb->currentItem()); + channel->tp.inversion = (fe_spectral_inversion_t)(INVERSION_OFF+inversionComb->currentItem()); + } + else if ( channel->tp.type==FE_QAM ) { + channel->tp.freq = freqSpin->value(); + channel->tp.sr = srSpin->value(); + channel->tp.coderateH = (fe_code_rate_t)(FEC_NONE+coderateHComb->currentItem()); + channel->tp.inversion = (fe_spectral_inversion_t)(INVERSION_OFF+inversionComb->currentItem()); + channel->tp.modulation = (fe_modulation_t)(QPSK+modulationComb->currentItem()); + } + else if ( channel->tp.type==FE_OFDM ) { + channel->tp.freq = freqSpin->value(); + channel->tp.inversion = (fe_spectral_inversion_t)(INVERSION_OFF+inversionComb->currentItem()); + channel->tp.coderateH = (fe_code_rate_t)(FEC_NONE+coderateHComb->currentItem()); + channel->tp.coderateL = (fe_code_rate_t)(FEC_NONE+coderateLComb->currentItem()); + channel->tp.modulation = (fe_modulation_t)(QPSK+modulationComb->currentItem()); + channel->tp.transmission = (fe_transmit_mode_t)(TRANSMISSION_MODE_2K+transmissionComb->currentItem()); + channel->tp.bandwidth = (fe_bandwidth_t)(BANDWIDTH_8_MHZ+bandwidthComb->currentItem()); + channel->tp.hierarchy = (fe_hierarchy_t)(HIERARCHY_NONE+hierarchyComb->currentItem()); + channel->tp.guard = (fe_guard_interval_t)(GUARD_INTERVAL_1_32+guardComb->currentItem()); + } + else { + channel->tp.freq = freqSpin->value(); + channel->tp.inversion = (fe_spectral_inversion_t)(INVERSION_OFF+inversionComb->currentItem()); + switch (modulationComb->currentItem()) { + case 0: channel->tp.modulation = QAM_64; break; + case 1: channel->tp.modulation = QAM_256; break; + case 2: channel->tp.modulation = VSB_8; break; + case 3: channel->tp.modulation = VSB_16; break; + default: channel->tp.modulation = QAM_AUTO; break; + } + } + + done( Accepted ); +} + +void ChannelEditor::initS() +{ + freqSpin->setValue( channel->tp.freq ); + srSpin->setValue( channel->tp.sr ); + if ( channel->tp.pol=='v' ) polGroup->setButton( 0 ) ; + else polGroup->setButton( 1 ) ; + inversionComb->insertStringList( inversionList() ); + inversionComb->setCurrentItem( INVERSION_OFF+channel->tp.inversion ); + coderateHComb->insertStringList( coderateList() ); + coderateHComb->setCurrentItem( FEC_NONE+channel->tp.coderateH ); + transmissionComb->setEnabled( false ); + coderateLComb->setEnabled( false ); + bandwidthComb->setEnabled( false ); + modulationComb->setEnabled( false ); + hierarchyComb->setEnabled( false ); + guardComb->setEnabled( false ); +} + +void ChannelEditor::initC() +{ + freqSpin->setValue( channel->tp.freq ); + srSpin->setValue( channel->tp.sr ); + inversionComb->insertStringList( inversionList() ); + inversionComb->setCurrentItem( INVERSION_OFF+channel->tp.inversion ); + coderateHComb->insertStringList( coderateList() ); + coderateHComb->setCurrentItem( FEC_NONE+channel->tp.coderateH ); + modulationComb->insertStringList( modulationList() ); + modulationComb->setCurrentItem( QPSK+channel->tp.modulation ); + polGroup->setEnabled( false ); + transmissionComb->setEnabled( false ); + coderateLComb->setEnabled( false ); + bandwidthComb->setEnabled( false ); + hierarchyComb->setEnabled( false ); + guardComb->setEnabled( false ); +} + +void ChannelEditor::initT() +{ + freqSpin->setValue( channel->tp.freq ); + inversionComb->insertStringList( inversionList() ); + inversionComb->setCurrentItem( INVERSION_OFF+channel->tp.inversion ); + coderateHComb->insertStringList( coderateList() ); + coderateHComb->setCurrentItem( FEC_NONE+channel->tp.coderateH ); + coderateLComb->insertStringList( coderateList() ); + coderateLComb->setCurrentItem( FEC_NONE+channel->tp.coderateL ); + modulationComb->insertStringList( modulationList() ); + modulationComb->setCurrentItem( QPSK+channel->tp.modulation ); + transmissionComb->insertStringList( transmissionList() ); + transmissionComb->setCurrentItem( TRANSMISSION_MODE_2K+channel->tp.transmission ); + bandwidthComb->insertStringList( bandwidthList() ); + bandwidthComb->setCurrentItem( BANDWIDTH_8_MHZ+channel->tp.bandwidth ); + hierarchyComb->insertStringList( hierarchyList() ); + hierarchyComb->setCurrentItem( HIERARCHY_NONE+channel->tp.hierarchy ); + guardComb->insertStringList( guardList() ); + guardComb->setCurrentItem( GUARD_INTERVAL_1_32+channel->tp.guard ); + srSpin->setEnabled( false ); + polGroup->setEnabled( false ); +} + +void ChannelEditor::initA() +{ + freqSpin->setValue( channel->tp.freq ); + inversionComb->insertStringList( inversionList() ); + inversionComb->setCurrentItem( INVERSION_OFF+channel->tp.inversion ); + modulationComb->insertStringList( modulationListAtsc() ); + switch (channel->tp.modulation) { + case QAM_64: modulationComb->setCurrentItem(0); break; + case QAM_256: modulationComb->setCurrentItem(1); break; + case VSB_8: modulationComb->setCurrentItem(2); break; + case VSB_16: modulationComb->setCurrentItem(3); break; + default: modulationComb->setCurrentItem(4); break; + } + srSpin->setEnabled( false ); + polGroup->setEnabled( false ); + transmissionComb->setEnabled( false ); + coderateHComb->setEnabled( false ); + coderateLComb->setEnabled( false ); + bandwidthComb->setEnabled( false ); + hierarchyComb->setEnabled( false ); + guardComb->setEnabled( false ); +} + +QStringList ChannelEditor::inversionList() +{ + QStringList list; + + list<<"OFF"<<"ON"<<"AUTO"; + return list; +} + +QStringList ChannelEditor::coderateList() +{ + QStringList list; + + list<<"NONE"<<"1/2"<<"2/3"<<"3/4"<<"4/5"<<"5/6"<<"6/7"<<"7/8"<<"8/9"<<"AUTO"; + return list; +} + +QStringList ChannelEditor::modulationList() +{ + QStringList list; + + list<<"QPSK"<<"QAM 16"<<"QAM 32"<<"QAM 64"<<"QAM 128"<<"QAM 256"<<"AUTO"; + return list; +} + +QStringList ChannelEditor::modulationListAtsc() +{ + QStringList list; + + list<<"QAM 64"<<"QAM 256"<<"VSB 8"<<"VSB 16"<<"AUTO"; + return list; +} + +QStringList ChannelEditor::transmissionList() +{ + QStringList list; + + list<<"2K"<<"8K"<<"AUTO"; + return list; +} + +QStringList ChannelEditor::bandwidthList() +{ + QStringList list; + + list<<"8 MHz"<<"7 MHz"<<"6 MHz"<<"AUTO"; + return list; +} + +QStringList ChannelEditor::hierarchyList() +{ + QStringList list; + + list<<"NONE"<<"1"<<"2"<<"4"<<"AUTO"; + return list; +} + +QStringList ChannelEditor::guardList() +{ + QStringList list; + + list<<"1/32"<<"1/16"<<"1/8"<<"1/4"<<"AUTO"; + return list; +} + +ChannelEditor::~ChannelEditor() +{ +} + +#include "channeleditor.moc" diff --git a/kaffeine/src/input/dvb/channeleditor.h b/kaffeine/src/input/dvb/channeleditor.h new file mode 100644 index 0000000..6a3b3f8 --- /dev/null +++ b/kaffeine/src/input/dvb/channeleditor.h @@ -0,0 +1,70 @@ +/* + * channeleditor.h + * + * Copyright (C) 2004-2005 Christophe Thommeret <hftom@free.fr> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef CHANNELEDITOR_H +#define CHANNELEDITOR_H + +#include <qstringlist.h> + +#include "channeleditorui.h" +#include "channeldesc.h" + +class ChannelEditor : public ChannelEditorUI +{ + Q_OBJECT + +public: + + ChannelEditor( QStringList src, bool m, ChannelDesc *chan, QPtrList<ChannelDesc> *cdesc, QWidget *parent ); + ~ChannelEditor(); + +protected: + + virtual void accept(); + +private slots: + + void editAudio(); + void editSubtitle(); + +private: + + void initS(); + void initC(); + void initT(); + void initA(); + QStringList inversionList(); + QStringList coderateList(); + QStringList modulationList(); + QStringList modulationListAtsc(); + QStringList transmissionList(); + QStringList bandwidthList(); + QStringList hierarchyList(); + QStringList guardList(); + + ChannelDesc *channel; + QPtrList<ChannelDesc> *chandesc; + bool mode; + QString orgName; + int chanNum; + +}; + +#endif /* CHANNELEDITOR_H */ diff --git a/kaffeine/src/input/dvb/channeleditorui.ui b/kaffeine/src/input/dvb/channeleditorui.ui new file mode 100644 index 0000000..5b75f18 --- /dev/null +++ b/kaffeine/src/input/dvb/channeleditorui.ui @@ -0,0 +1,704 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>ChannelEditorUI</class> +<widget class="QDialog"> + <property name="name"> + <cstring>ChannelEditorUI</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>477</width> + <height>533</height> + </rect> + </property> + <property name="caption"> + <string>Channel Editor</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="Line" row="1" column="0"> + <property name="name"> + <cstring>line2</cstring> + </property> + <property name="frameShape"> + <enum>HLine</enum> + </property> + <property name="frameShadow"> + <enum>Sunken</enum> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + </widget> + <widget class="QLayoutWidget" row="0" column="0"> + <property name="name"> + <cstring>layout9</cstring> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout8</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>textLabel1_4</cstring> + </property> + <property name="text"> + <string>Source:</string> + </property> + </widget> + <widget class="QComboBox"> + <property name="name"> + <cstring>sourceComb</cstring> + </property> + </widget> + <spacer> + <property name="name"> + <cstring>spacer3</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </hbox> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout5</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>textLabel1</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>4</hsizetype> + <vsizetype>5</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Name:</string> + </property> + </widget> + <widget class="QLineEdit"> + <property name="name"> + <cstring>nameLe</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>3</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + <widget class="QLabel"> + <property name="name"> + <cstring>textLabel2_2</cstring> + </property> + <property name="text"> + <string>Nr:</string> + </property> + </widget> + <widget class="QSpinBox"> + <property name="name"> + <cstring>numSpin</cstring> + </property> + <property name="maxValue"> + <number>99999</number> + </property> + </widget> + </hbox> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout6</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QGroupBox"> + <property name="name"> + <cstring>freqGroup</cstring> + </property> + <property name="title"> + <string></string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QButtonGroup" row="2" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>polGroup</cstring> + </property> + <property name="title"> + <string>Polarity</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QRadioButton" row="0" column="0"> + <property name="name"> + <cstring>verticalRadio</cstring> + </property> + <property name="text"> + <string>Vertical</string> + </property> + </widget> + <widget class="QRadioButton" row="0" column="1"> + <property name="name"> + <cstring>horizontalRadio</cstring> + </property> + <property name="text"> + <string>Horizontal</string> + </property> + </widget> + </grid> + </widget> + <widget class="QLabel" row="0" column="0"> + <property name="name"> + <cstring>textLabel2</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>4</hsizetype> + <vsizetype>5</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Frequency:</string> + </property> + </widget> + <widget class="QLabel" row="1" column="0"> + <property name="name"> + <cstring>textLabel3</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>4</hsizetype> + <vsizetype>5</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Symbol rate:</string> + </property> + </widget> + <widget class="QSpinBox" row="1" column="1"> + <property name="name"> + <cstring>srSpin</cstring> + </property> + <property name="maxValue"> + <number>99999</number> + </property> + </widget> + <widget class="QSpinBox" row="0" column="1"> + <property name="name"> + <cstring>freqSpin</cstring> + </property> + <property name="maxValue"> + <number>999999</number> + </property> + <property name="minValue"> + <number>0</number> + </property> + <property name="value"> + <number>0</number> + </property> + </widget> + <widget class="QCheckBox" row="3" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>ftaCb</cstring> + </property> + <property name="text"> + <string>Scrambled</string> + </property> + </widget> + </grid> + </widget> + <widget class="QGroupBox"> + <property name="name"> + <cstring>pidsGroup</cstring> + </property> + <property name="title"> + <string></string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout7</cstring> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QSpinBox" row="1" column="1"> + <property name="name"> + <cstring>tsidSpin</cstring> + </property> + <property name="maxValue"> + <number>65535</number> + </property> + </widget> + <widget class="QSpinBox" row="4" column="1"> + <property name="name"> + <cstring>ttpidSpin</cstring> + </property> + <property name="maxValue"> + <number>8191</number> + </property> + <property name="minValue"> + <number>0</number> + </property> + <property name="value"> + <number>0</number> + </property> + </widget> + <widget class="QLabel" row="2" column="0"> + <property name="name"> + <cstring>textLabel12</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>4</hsizetype> + <vsizetype>5</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Service ID:</string> + </property> + </widget> + <widget class="QLabel" row="0" column="0"> + <property name="name"> + <cstring>textLabel2_3</cstring> + </property> + <property name="text"> + <string>Network ID:</string> + </property> + </widget> + <widget class="QLabel" row="4" column="0"> + <property name="name"> + <cstring>textLabel15</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>4</hsizetype> + <vsizetype>5</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Teletext PID:</string> + </property> + </widget> + <widget class="QSpinBox" row="3" column="1"> + <property name="name"> + <cstring>vpidSpin</cstring> + </property> + <property name="maxValue"> + <number>8191</number> + </property> + <property name="minValue"> + <number>0</number> + </property> + <property name="value"> + <number>0</number> + </property> + </widget> + <widget class="QSpinBox" row="2" column="1"> + <property name="name"> + <cstring>sidSpin</cstring> + </property> + <property name="maxValue"> + <number>65535</number> + </property> + </widget> + <widget class="QSpinBox" row="0" column="1"> + <property name="name"> + <cstring>nidSpin</cstring> + </property> + <property name="maxValue"> + <number>65535</number> + </property> + </widget> + <widget class="QLabel" row="3" column="0"> + <property name="name"> + <cstring>textLabel13</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>4</hsizetype> + <vsizetype>5</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Video PID:</string> + </property> + </widget> + <widget class="QLabel" row="1" column="0"> + <property name="name"> + <cstring>textLabel1_2</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>4</hsizetype> + <vsizetype>5</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Transport stream ID:</string> + </property> + </widget> + </grid> + </widget> + <widget class="QPushButton"> + <property name="name"> + <cstring>subpidBtn</cstring> + </property> + <property name="text"> + <string>Subtitle PIDs...</string> + </property> + </widget> + <widget class="QPushButton"> + <property name="name"> + <cstring>apidBtn</cstring> + </property> + <property name="focusPolicy"> + <enum>TabFocus</enum> + </property> + <property name="text"> + <string>Audio PIDs...</string> + </property> + </widget> + </vbox> + </widget> + </hbox> + </widget> + <widget class="QGroupBox"> + <property name="name"> + <cstring>extendedGroup</cstring> + </property> + <property name="title"> + <string></string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QComboBox" row="0" column="1"> + <property name="name"> + <cstring>transmissionComb</cstring> + </property> + </widget> + <widget class="QLabel" row="3" column="0"> + <property name="name"> + <cstring>textLabel11</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>4</hsizetype> + <vsizetype>5</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Bandwidth:</string> + </property> + </widget> + <widget class="QLabel" row="2" column="0"> + <property name="name"> + <cstring>textLabel10</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>4</hsizetype> + <vsizetype>5</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>FEC high:</string> + </property> + </widget> + <widget class="QLabel" row="0" column="0"> + <property name="name"> + <cstring>textLabel8</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>4</hsizetype> + <vsizetype>5</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Transmission:</string> + </property> + </widget> + <widget class="QComboBox" row="3" column="1"> + <property name="name"> + <cstring>bandwidthComb</cstring> + </property> + </widget> + <widget class="QComboBox" row="2" column="1"> + <property name="name"> + <cstring>coderateHComb</cstring> + </property> + </widget> + <widget class="QComboBox" row="1" column="1"> + <property name="name"> + <cstring>coderateLComb</cstring> + </property> + </widget> + <widget class="QLabel" row="1" column="0"> + <property name="name"> + <cstring>textLabel9</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>4</hsizetype> + <vsizetype>5</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>FEC low:</string> + </property> + </widget> + <widget class="QComboBox" row="3" column="3"> + <property name="name"> + <cstring>guardComb</cstring> + </property> + </widget> + <widget class="QLabel" row="3" column="2"> + <property name="name"> + <cstring>textLabel7</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>4</hsizetype> + <vsizetype>5</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Guard interval:</string> + </property> + </widget> + <widget class="QComboBox" row="2" column="3"> + <property name="name"> + <cstring>hierarchyComb</cstring> + </property> + </widget> + <widget class="QLabel" row="2" column="2"> + <property name="name"> + <cstring>textLabel6</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>4</hsizetype> + <vsizetype>5</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Hierarchy:</string> + </property> + </widget> + <widget class="QLabel" row="1" column="2"> + <property name="name"> + <cstring>textLabel5</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>4</hsizetype> + <vsizetype>5</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Modulation:</string> + </property> + </widget> + <widget class="QComboBox" row="1" column="3"> + <property name="name"> + <cstring>modulationComb</cstring> + </property> + </widget> + <widget class="QComboBox" row="0" column="3"> + <property name="name"> + <cstring>inversionComb</cstring> + </property> + </widget> + <widget class="QLabel" row="0" column="2"> + <property name="name"> + <cstring>textLabel4</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>4</hsizetype> + <vsizetype>5</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Inversion:</string> + </property> + </widget> + </grid> + </widget> + <spacer> + <property name="name"> + <cstring>spacer6</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>98</height> + </size> + </property> + </spacer> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout14</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QPushButton"> + <property name="name"> + <cstring>okBtn</cstring> + </property> + <property name="text"> + <string>&OK</string> + </property> + </widget> + <spacer> + <property name="name"> + <cstring>spacer4</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>150</width> + <height>20</height> + </size> + </property> + </spacer> + <widget class="QPushButton"> + <property name="name"> + <cstring>cancelBtn</cstring> + </property> + <property name="text"> + <string>&Cancel</string> + </property> + </widget> + </hbox> + </widget> + </vbox> + </widget> + </grid> +</widget> +<connections> + <connection> + <sender>okBtn</sender> + <signal>clicked()</signal> + <receiver>ChannelEditorUI</receiver> + <slot>accept()</slot> + </connection> + <connection> + <sender>cancelBtn</sender> + <signal>clicked()</signal> + <receiver>ChannelEditorUI</receiver> + <slot>reject()</slot> + </connection> +</connections> +<tabstops> + <tabstop>nameLe</tabstop> + <tabstop>numSpin</tabstop> + <tabstop>freqSpin</tabstop> + <tabstop>srSpin</tabstop> + <tabstop>verticalRadio</tabstop> + <tabstop>horizontalRadio</tabstop> + <tabstop>ftaCb</tabstop> + <tabstop>tsidSpin</tabstop> + <tabstop>sidSpin</tabstop> + <tabstop>vpidSpin</tabstop> + <tabstop>ttpidSpin</tabstop> + <tabstop>apidBtn</tabstop> + <tabstop>transmissionComb</tabstop> + <tabstop>coderateLComb</tabstop> + <tabstop>coderateHComb</tabstop> + <tabstop>bandwidthComb</tabstop> + <tabstop>inversionComb</tabstop> + <tabstop>modulationComb</tabstop> + <tabstop>hierarchyComb</tabstop> + <tabstop>guardComb</tabstop> + <tabstop>cancelBtn</tabstop> + <tabstop>okBtn</tabstop> + <tabstop>sourceComb</tabstop> +</tabstops> +<layoutdefaults spacing="6" margin="11"/> +</UI> diff --git a/kaffeine/src/input/dvb/cleaner.cpp b/kaffeine/src/input/dvb/cleaner.cpp new file mode 100644 index 0000000..8214bc9 --- /dev/null +++ b/kaffeine/src/input/dvb/cleaner.cpp @@ -0,0 +1,82 @@ +/* + * cleaner.cpp + * + * Copyright (C) 2005-2007 Christophe Thommeret <hftom@free.fr> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include <sys/statvfs.h> + +#include <qdir.h> +#include <qstringlist.h> +#include <qptrlist.h> +#include <qfileinfo.h> + +#include "cleaner.h" + +Cleaner::Cleaner( const QString &lpath, const QString &rpath ) +{ + setPaths( lpath, rpath ); + + connect( &timer, SIGNAL(timeout()), this, SLOT(doClean()) ); + timer.start( 60*1000 ); +} + +Cleaner::~Cleaner() +{ + wait(); +} + +void Cleaner::doClean() +{ + start(IdlePriority); +} + +void Cleaner::setPaths( const QString &lpath, const QString &rpath ) +{ + livePath = lpath; + recordPath = rpath; +} + +void Cleaner::run() +{ + QStringList list; + QDir d; + double freemb; + struct statvfs buf; + + d.setPath( livePath ); + list = d.entryList( "DVBLive-*", QDir::Files, QDir::Name ); + if ( list.count()>1 ) d.remove( list[0] ); + + + if ( statvfs( recordPath.local8Bit(), &buf ) ) { + fprintf(stderr,"Couldn't get file system statistics\n"); + return; + } + + freemb = (double)(((double)(buf.f_bavail)*(double)(buf.f_bsize))/(1024.0*1024.0)); + if ( freemb<1000 ) { + d.setPath( recordPath ); + const QFileInfoList *infos = d.entryInfoList( "*.m2t", QDir::Files|QDir::NoSymLinks|QDir::Writable, QDir::Time|QDir::Reversed ); + QFileInfoListIterator it( *infos ); + QFileInfo *i; + /*if ( ( i=it.current() )!=0 ) + d.remove( i->absFilePath() );*/ + } +} + +#include "cleaner.moc" diff --git a/kaffeine/src/input/dvb/cleaner.h b/kaffeine/src/input/dvb/cleaner.h new file mode 100644 index 0000000..215af32 --- /dev/null +++ b/kaffeine/src/input/dvb/cleaner.h @@ -0,0 +1,54 @@ +/* + * cleaner.h + * + * Copyright (C) 2005-2007 Christophe Thommeret <hftom@free.fr> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef CLEANER_H +#define CLEANER_H + +#include <qobject.h> +#include <qthread.h> +#include <qstring.h> +#include <qtimer.h> + +class Cleaner : public QObject, public QThread +{ + + Q_OBJECT + +public: + + Cleaner( const QString &lpath, const QString &rpath ); + ~Cleaner(); + void setPaths( const QString &lpath, const QString &rpath ); + +protected: + + virtual void run(); + +private slots: + + void doClean(); + +private: + + QTimer timer; + QString livePath, recordPath; +}; + +#endif /* CLEANER_H */ diff --git a/kaffeine/src/input/dvb/crontimer.cpp b/kaffeine/src/input/dvb/crontimer.cpp new file mode 100644 index 0000000..00078ea --- /dev/null +++ b/kaffeine/src/input/dvb/crontimer.cpp @@ -0,0 +1,109 @@ +/* + * crontimer.cpp + * + * Copyright (C) 2005 Christophe Thommeret <hftom@free.fr> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include <kmessagebox.h> +#include <klocale.h> +#include <kiconloader.h> +#include <kpushbutton.h> + +#include "crontimer.h" + +CronTimer::CronTimer( int m, QWidget *parent ) : CronTimerUI( parent ) +{ + connect( cronBtnGrp, SIGNAL(clicked(int)), this, SLOT(modeSelected(int)) ); + mode = m; + switch ( mode ) { + case Noone : cronBtnGrp->setButton( 0 ); break; + case Daily : cronBtnGrp->setButton( 1 ); break; + case Weekly : cronBtnGrp->setButton( 2 ); break; + case Monthly : cronBtnGrp->setButton( 3 ); break; + default : cronBtnGrp->setButton( 4 ); + } + if ( mode>Monthly ) { + daysGb->setEnabled( true ); + if ( mode&Monday ) monCb->setChecked( true ); + if ( mode&Tuesday ) tueCb->setChecked( true ); + if ( mode&Wednesday ) wedCb->setChecked( true ); + if ( mode&Thursday ) thuCb->setChecked( true ); + if ( mode&Friday ) friCb->setChecked( true ); + if ( mode&Saturday ) satCb->setChecked( true ); + if ( mode&Sunday ) sunCb->setChecked( true ); + } + else + daysGb->setEnabled( false ); + + KIconLoader *icon = new KIconLoader(); + cancelBtn->setGuiItem( KGuiItem(i18n("Cancel"), icon->loadIconSet("cancel", KIcon::Small) ) ); + okBtn->setGuiItem( KGuiItem(i18n("OK"), icon->loadIconSet("ok", KIcon::Small) ) ); + delete icon; +} + + + +CronTimer::~CronTimer() +{ +} + + + +int CronTimer::getMode() const +{ + return mode; +} + + + +void CronTimer::modeSelected( int id ) +{ + if ( id==4 ) + daysGb->setEnabled( true ); + else + daysGb->setEnabled( false ); +} + + + +void CronTimer::accept() +{ + switch ( cronBtnGrp->selectedId() ) { + case 0 : mode = Noone; break; + case 1 : mode = Daily; break; + case 2 : mode = Weekly; break; + case 3 : mode = Monthly; break; + case 4 : { + mode = Custom; + if ( monCb->isChecked() ) mode+=Monday; + if ( tueCb->isChecked() ) mode+=Tuesday; + if ( wedCb->isChecked() ) mode+=Wednesday; + if ( thuCb->isChecked() ) mode+=Thursday; + if ( friCb->isChecked() ) mode+=Friday; + if ( satCb->isChecked() ) mode+=Saturday; + if ( sunCb->isChecked() ) mode+=Sunday; + if ( mode<Monday ) { + KMessageBox::sorry( this, i18n("You have to choose some days.") ); + return; + } + } + } + + done( Accepted ); +} + +#include "crontimer.moc" diff --git a/kaffeine/src/input/dvb/crontimer.h b/kaffeine/src/input/dvb/crontimer.h new file mode 100644 index 0000000..bb079bd --- /dev/null +++ b/kaffeine/src/input/dvb/crontimer.h @@ -0,0 +1,58 @@ +/* + * crontimer.h + * + * Copyright (C) 2005 Christophe Thommeret <hftom@free.fr> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef CRONTIMER_H +#define CRONTIMER_H + +#include <qwidget.h> +#include <qbuttongroup.h> +#include <qcheckbox.h> +#include <qradiobutton.h> + +#include "crontimerui.h" + +class CronTimer : public CronTimerUI +{ + + Q_OBJECT + +public: + + CronTimer( int m, QWidget *parent ); + ~CronTimer(); + int getMode() const; + + enum Type { Noone=0, Daily=1, Weekly=2, Monthly=4, Custom=8, Monday=16, Tuesday=32, Wednesday=64, Thursday=128, Friday=256, Saturday=512, Sunday=1024 }; + +protected: + + virtual void accept(); + +private slots: + + void modeSelected( int id ); + +private: + + int mode; + +}; + +#endif /* CRONTIMER_H */ diff --git a/kaffeine/src/input/dvb/crontimerui.ui b/kaffeine/src/input/dvb/crontimerui.ui new file mode 100644 index 0000000..1a70361 --- /dev/null +++ b/kaffeine/src/input/dvb/crontimerui.ui @@ -0,0 +1,354 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>CronTimerUI</class> +<widget class="QDialog"> + <property name="name"> + <cstring>CronTimerUI</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>317</width> + <height>288</height> + </rect> + </property> + <property name="caption"> + <string>Repeated Timer</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLayoutWidget" row="0" column="0"> + <property name="name"> + <cstring>layout13</cstring> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout12</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <spacer> + <property name="name"> + <cstring>spacer5</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>32</width> + <height>20</height> + </size> + </property> + </spacer> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout11</cstring> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QButtonGroup"> + <property name="name"> + <cstring>cronBtnGrp</cstring> + </property> + <property name="title"> + <string></string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QRadioButton"> + <property name="name"> + <cstring>noneRad</cstring> + </property> + <property name="text"> + <string>None</string> + </property> + <property name="buttonGroupId"> + <number>0</number> + </property> + </widget> + <widget class="QRadioButton"> + <property name="name"> + <cstring>dailyRad</cstring> + </property> + <property name="text"> + <string>Daily</string> + </property> + <property name="buttonGroupId"> + <number>1</number> + </property> + </widget> + <widget class="QRadioButton"> + <property name="name"> + <cstring>weeklyRad</cstring> + </property> + <property name="text"> + <string>Weekly</string> + </property> + <property name="buttonGroupId"> + <number>2</number> + </property> + </widget> + <widget class="QRadioButton"> + <property name="name"> + <cstring>mnthlyRad</cstring> + </property> + <property name="text"> + <string>Monthly</string> + </property> + <property name="buttonGroupId"> + <number>3</number> + </property> + </widget> + <widget class="QRadioButton"> + <property name="name"> + <cstring>customRad</cstring> + </property> + <property name="text"> + <string>Custom</string> + </property> + <property name="buttonGroupId"> + <number>4</number> + </property> + </widget> + </vbox> + </widget> + <spacer> + <property name="name"> + <cstring>spacer2</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>67</height> + </size> + </property> + </spacer> + </vbox> + </widget> + <spacer> + <property name="name"> + <cstring>spacer3</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>39</width> + <height>20</height> + </size> + </property> + </spacer> + <widget class="QGroupBox"> + <property name="name"> + <cstring>daysGb</cstring> + </property> + <property name="title"> + <string></string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QCheckBox"> + <property name="name"> + <cstring>monCb</cstring> + </property> + <property name="text"> + <string>Monday</string> + </property> + </widget> + <widget class="QCheckBox"> + <property name="name"> + <cstring>tueCb</cstring> + </property> + <property name="text"> + <string>Tuesday</string> + </property> + </widget> + <widget class="QCheckBox"> + <property name="name"> + <cstring>wedCb</cstring> + </property> + <property name="text"> + <string>Wednesday</string> + </property> + </widget> + <widget class="QCheckBox"> + <property name="name"> + <cstring>thuCb</cstring> + </property> + <property name="text"> + <string>Thursday</string> + </property> + </widget> + <widget class="QCheckBox"> + <property name="name"> + <cstring>friCb</cstring> + </property> + <property name="text"> + <string>Friday</string> + </property> + </widget> + <widget class="QCheckBox"> + <property name="name"> + <cstring>satCb</cstring> + </property> + <property name="text"> + <string>Saturday</string> + </property> + </widget> + <widget class="QCheckBox"> + <property name="name"> + <cstring>sunCb</cstring> + </property> + <property name="text"> + <string>Sunday</string> + </property> + </widget> + </vbox> + </widget> + <spacer> + <property name="name"> + <cstring>spacer4</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>32</width> + <height>20</height> + </size> + </property> + </spacer> + </hbox> + </widget> + <spacer> + <property name="name"> + <cstring>spacer6</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>95</height> + </size> + </property> + </spacer> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout9</cstring> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="KPushButton" row="1" column="0"> + <property name="name"> + <cstring>cancelBtn</cstring> + </property> + <property name="text"> + <string></string> + </property> + </widget> + <spacer row="1" column="1"> + <property name="name"> + <cstring>spacer1</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>177</width> + <height>20</height> + </size> + </property> + </spacer> + <widget class="Line" row="0" column="0" rowspan="1" colspan="3"> + <property name="name"> + <cstring>line1</cstring> + </property> + <property name="frameShape"> + <enum>HLine</enum> + </property> + <property name="frameShadow"> + <enum>Sunken</enum> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + </widget> + <widget class="KPushButton" row="1" column="2"> + <property name="name"> + <cstring>okBtn</cstring> + </property> + <property name="text"> + <string></string> + </property> + </widget> + </grid> + </widget> + </vbox> + </widget> + </grid> +</widget> +<customwidgets> +</customwidgets> +<connections> + <connection> + <sender>cancelBtn</sender> + <signal>clicked()</signal> + <receiver>CronTimerUI</receiver> + <slot>reject()</slot> + </connection> + <connection> + <sender>okBtn</sender> + <signal>clicked()</signal> + <receiver>CronTimerUI</receiver> + <slot>accept()</slot> + </connection> +</connections> +<layoutdefaults spacing="6" margin="11"/> +<includehints> + <includehint>kpushbutton.h</includehint> + <includehint>kpushbutton.h</includehint> +</includehints> +</UI> diff --git a/kaffeine/src/input/dvb/dvbcam.cpp b/kaffeine/src/input/dvb/dvbcam.cpp new file mode 100644 index 0000000..1cb5b86 --- /dev/null +++ b/kaffeine/src/input/dvb/dvbcam.cpp @@ -0,0 +1,926 @@ +/* + * dvbcam.cpp + * + * Copyright (C) 2006 Christoph Pfister <christophpfister@gmail.com> + * + * code based on ca_zap (LGPL) + * Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com) + * Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include <unistd.h> +#include <stdio.h> +#include <fcntl.h> +#include <sys/ioctl.h> +#include <sys/poll.h> +#include <linux/dvb/ca.h> + +#include <libdvbapi/dvbca.h> +#include <libdvbapi/dvbdemux.h> +#include <libdvben50221/en50221_app_ai.h> +#include <libdvben50221/en50221_app_ca.h> +#include <libdvben50221/en50221_app_rm.h> +#include <libdvben50221/en50221_app_tags.h> +#include <libdvben50221/en50221_session.h> +#include <libucsi/mpeg/section.h> + +#include <qthread.h> +#include <qstring.h> + +#include "dvbcam.h" + +class DvbCamCamHandler +{ +public: + virtual ~DvbCamCamHandler(); + + bool init(); + + virtual void poll() = 0; + virtual bool registerCam(int ca_fd, uint8_t slot) = 0; + + bool sendPmt(char *pmt_buffer, int size); + +protected: + DvbCamCamHandler(); + + static int infoCallback(void *arg, uint8_t slot_id, uint16_t session_number, uint32_t ca_id_count, uint16_t *ca_ids); + + virtual bool sub_init() = 0; + + void *AiResource; + void *CaResource; + en50221_app_send_functions SendFuncs; + + volatile int SessionNumber; +}; + +class DvbCamCamThread : protected QThread +{ +public: + DvbCamCamThread(int adapter, int ca_device, int ci_type); + ~DvbCamCamThread(); + + void start(); + void stop(); + void wait(); + + bool processPmt(int demux_fd); + +private: + void run(); + + int Adapter; + int CaDevice; + int ciType; + + DvbCamCamHandler *CamHandler; + + char PmtBuffer[4096]; // we imply that processPmt is only once called + + volatile int PmtSize; // PmtSize <= 0 means PmtBuffer invalid + volatile bool Stopped; +}; + +class DvbCamPmtThread : protected QThread +{ +public: + DvbCamPmtThread(DvbCamCamThread *cam_thread, int adapter, int demux_device, int service_id); + ~DvbCamPmtThread(); + + void start(); + void stop(); + void wait(); + +private: + int createSectionFilter(uint16_t pid, uint8_t table_id); + int processPat(int demux_fd); + void run(); + + DvbCamCamThread *CamThread; + int Adapter; + int DemuxDevice; + int ServiceId; + + volatile bool Stopped; +}; + +class DvbCamCamHandlerLLCI : public DvbCamCamHandler +{ +public: + DvbCamCamHandlerLLCI(); + ~DvbCamCamHandlerLLCI(); + +private: + struct SlResource + { + en50221_app_public_resource_id resid; + uint32_t binary_resource_id; + en50221_sl_resource_callback callback; + void *arg; + }; + + static int llci_rm_enq_callback(void *arg, uint8_t slot_id, uint16_t session_number); + static int llci_rm_reply_callback(void *arg, uint8_t slot_id, uint16_t session_number, uint32_t resource_id_count, uint32_t *resource_ids); + static int llci_rm_changed_callback(void *arg, uint8_t slot_id, uint16_t session_number); + static int llci_lookup_callback(void *arg, uint8_t slot_id, uint32_t requested_resource_id, en50221_sl_resource_callback *callback_out, void **arg_out, uint32_t *connected_resource_id); + static int llci_session_callback(void *arg, int reason, uint8_t slot_id, uint16_t session_number, uint32_t resource_id); + + void poll(); + bool registerCam(int ca_fd, uint8_t slot); + bool sub_init(); + + void *RmResource; + void *SessionLayer; + void *TransportLayer; + + SlResource Resources[3]; +}; + +class DvbCamCamHandlerHLCI : public DvbCamCamHandler +{ +public: + DvbCamCamHandlerHLCI(); + ~DvbCamCamHandlerHLCI(); + +private: + static int hlci_send_data(void *arg, uint16_t session_number, uint8_t *data, uint16_t data_length); + static int hlci_send_datav(void *arg, uint16_t session_number, iovec *vector, int iov_count); + + void poll(); + bool registerCam(int ca_fd, uint8_t slot); + bool sub_init(); +}; + +// class DvbCam + +DvbCam::DvbCam(int adapter, int ca_device, int demux_device, int ci_type) +{ + Adapter = adapter; + CaDevice = ca_device; + DemuxDevice = demux_device; + ciType = ci_type; + + isRunning = false; + + CamThread = NULL; + PmtThread = NULL; + + // at that time, we do reset in cam_thread + /*if ( ciType!=CA_CI ) { //do not reset HLCI + int ca_fd = dvbca_open( Adapter, CaDevice ); + if(ca_fd < 0) // should not happen + fprintf(stderr, "CamThread: [error] opening ca device failed\n"); + else { + if(dvbca_reset(ca_fd, 0)) + fprintf(stderr, "CamThread: [error] resetting cam slot failed\n"); + close(ca_fd); + } + }*/ +} + +DvbCam::~DvbCam() +{ + stop(); +} + +int DvbCam::probe( int adapter, int ca_device ) +{ + int fdCa; + ca_caps_t cap; + ca_slot_info_t info; + QString s = QString("/dev/dvb/adapter%1/ca%2").arg( adapter ).arg( ca_device ); + + if ( (fdCa = open( s.ascii(), O_RDWR )) < 0) { + fprintf(stderr, "DvbCam::probe(): %s:", s.ascii()); + perror(" "); + return -1; + } + + if ( ioctl(fdCa, CA_GET_CAP, &cap) == 0) { + if ( cap.slot_num>0 ) { + info.num = 0; + if ( ioctl(fdCa, CA_GET_SLOT_INFO, &info) == 0) { + if ( (info.type & CA_CI_LINK)!=0) { + fprintf(stderr, "DvbCam::probe(): LLCI slot found on %s\n", s.ascii()); + if ( (info.flags & CA_CI_MODULE_PRESENT)!=0 ) { + fprintf(stderr, "DvbCam::probe(): CA module present on %s\n", s.ascii()); + close (fdCa); + return CA_CI_LINK; + } + else + fprintf(stderr, "DvbCam::probe(): no CA module present on %s\n", s.ascii()); + } + else if ( (info.type & CA_CI)!=0 ) { + fprintf(stderr, "DvbCam::probe(): HLCI slot found on %s\n", s.ascii()); + if ( (info.flags & CA_CI_MODULE_PRESENT)!=0 ) { + fprintf(stderr, "DvbCam::probe(): CA module present on %s\n", s.ascii()); + close (fdCa); + return CA_CI; + } + else + fprintf(stderr, "DvbCam::probe(): no CA module present on %s\n", s.ascii()); + } + else + fprintf(stderr, "DvbCam::probe(): unsupported CI interface on %s\n", s.ascii()); + } + else + fprintf(stderr, "DvbCam::Probe(): ioctl failed on %s\n", s.ascii()); + } + else + fprintf(stderr, "DvbCam::Probe(): no CI slot found on %s\n", s.ascii()); + } + else + fprintf(stderr, "DvbCam::Probe(): ioctl failed on %s\n", s.ascii()); + + close (fdCa); + return -1; +} + +void DvbCam::restart(int service_id) +{ + stop(); + + isRunning = true; + sid = service_id; + + CamThread = new DvbCamCamThread(Adapter, CaDevice, ciType); + CamThread->start(); + + PmtThread = new DvbCamPmtThread(CamThread, Adapter, DemuxDevice, service_id); + PmtThread->start(); +} + +void DvbCam::stop() +{ + if(PmtThread != NULL) { + PmtThread->stop(); + } + if(CamThread != NULL) { + CamThread->stop(); + } + if(PmtThread != NULL) { + PmtThread->wait(); + delete PmtThread; + PmtThread = NULL; + } + if(CamThread != NULL) { + CamThread->wait(); + delete CamThread; // be careful about deletion: PmtThread uses CamThread internally + CamThread = NULL; + } + isRunning = false; +} + +// class DvbCamCamThread + +DvbCamCamThread::DvbCamCamThread(int adapter, int ca_device, int ci_type) +{ + Adapter = adapter; + CaDevice = ca_device; + ciType = ci_type; + + CamHandler = NULL; +} + +DvbCamCamThread::~DvbCamCamThread() +{ + wait(); // should never be necessary +} + +void DvbCamCamThread::start() +{ + PmtSize = 0; + Stopped = false; + QThread::start(); +} + +void DvbCamCamThread::stop() +{ + Stopped = true; +} + +void DvbCamCamThread::wait() +{ + QThread::wait(); +} + +bool DvbCamCamThread::processPmt(int demux_fd) +{ + // read section + char si_buf[4096]; + int size = read(demux_fd, si_buf, sizeof(si_buf)); + if(size <= 0) { + return false; + } + + // parse section + section *parsed_section = section_codec(reinterpret_cast<unsigned char *> (si_buf), size); + if(parsed_section == NULL) { + return false; + } + + // parse section_ext + section_ext *parsed_section_ext = section_ext_decode(parsed_section, 1); // crc check on + if(parsed_section_ext == NULL) { + return false; + } + + // parse pmt + mpeg_pmt_section *parsed_pmt = mpeg_pmt_section_codec(parsed_section_ext); + if(parsed_pmt == NULL) { + return false; + } + + // translate it into a cam pmt + PmtSize = en50221_ca_format_pmt(parsed_pmt, reinterpret_cast<unsigned char *> (PmtBuffer), sizeof(PmtBuffer), 0, CA_LIST_MANAGEMENT_ONLY, CA_PMT_CMD_ID_OK_DESCRAMBLING); + if(PmtSize <= 0) { + return false; + } + + // the DvbCamCamThread will send it to the cam + return true; +} + +void DvbCamCamThread::run() +{ + fprintf(stderr, "CamThread: started\n"); + + int ca_fd = dvbca_open(Adapter, CaDevice); + if(ca_fd < 0) { + fprintf(stderr, "CamThread: [error] opening ca device failed\n"); + return; + } + + fprintf(stderr, "CamThread: just using the first cam slot\n"); + + if ( ciType!=CA_CI ) { // do not reset HLCI + if(dvbca_reset(ca_fd, 0)) { + fprintf(stderr, "CamThread: [error] resetting cam slot failed\n"); + close(ca_fd); + return; + } + } + + while(!Stopped) { + bool cam_ready = false; + switch(dvbca_get_cam_state(ca_fd, 0)) { + case DVBCA_CAMSTATE_MISSING: { + /*fprintf(stderr, "CamThread: [error] no cam detected\n"); + close(ca_fd); + return; */ // FIXME: find a more reliable solution + break; + } + case DVBCA_CAMSTATE_READY: { + fprintf(stderr, "CamThread: cam 0 is ready\n"); + cam_ready = true; + break; + } + case DVBCA_CAMSTATE_INITIALISING: { + if ( ciType==CA_CI ) { // workaround needed for hlci + fprintf(stderr, "CamThread: cam 0 is ready [hlci workaround]\n"); + cam_ready = true; + } + break; + } + default: { + fprintf(stderr, "CamThread: [error] querying the cam state failed\n"); + close(ca_fd); + return; + } + } + if(cam_ready) { + break; + } + usleep(100000); // 100 ms + } + + if(!Stopped) { + switch(dvbca_get_interface_type(ca_fd, 0)) { + case DVBCA_INTERFACE_LINK: { + fprintf(stderr, "CamThread: LLCI cam slot detected\n"); + CamHandler = new DvbCamCamHandlerLLCI(); + break; + } + case DVBCA_INTERFACE_HLCI: { + fprintf(stderr, "CamThread: HLCI cam slot detected\n"); + CamHandler = new DvbCamCamHandlerHLCI(); + break; + } + default: { + fprintf(stderr, "CamThread: [error] unknown cam slot type\n"); + close(ca_fd); + return; + } + } + } + + if(!Stopped) { + if(!CamHandler->init()) { + fprintf(stderr, "CamThread: [error] cam slot initialization failed\n"); + delete CamHandler; + CamHandler = NULL; + close(ca_fd); + return; + } + } + + if(!Stopped) { + if(!CamHandler->registerCam(ca_fd, 0)) { + fprintf(stderr, "CamThread: [error] registering cam 0 failed\n"); + delete CamHandler; + CamHandler = NULL; + close(ca_fd); + return; + } + } + + while(!Stopped) { + CamHandler->poll(); + if(PmtSize > 0) { + if(CamHandler->sendPmt(PmtBuffer, PmtSize)) { + fprintf(stderr, "CamThread: pmt sent to cam\n"); + PmtSize = 0; + } + } + } + + fprintf(stderr, "CamThread: stopping requested\n"); + + delete CamHandler; + CamHandler = NULL; + close(ca_fd); + + fprintf(stderr, "CamThread: stopped\n"); + return; +} + +// class DvbCamPmtThread + +DvbCamPmtThread::DvbCamPmtThread(DvbCamCamThread *cam_thread, int adapter, int demux_device, int service_id) +{ + CamThread = cam_thread; + Adapter = adapter; + DemuxDevice = demux_device; + ServiceId = service_id; +} + +DvbCamPmtThread::~DvbCamPmtThread() +{ + wait(); // should never be necessary +} + +void DvbCamPmtThread::start() +{ + Stopped = false; + QThread::start(); +} + +void DvbCamPmtThread::stop() +{ + Stopped = true; +} + +void DvbCamPmtThread::wait() +{ + QThread::wait(); +} + +int DvbCamPmtThread::createSectionFilter(uint16_t pid, uint8_t table_id) +{ + // open the demuxer + int demux_fd = dvbdemux_open_demux(Adapter, DemuxDevice, 0); + if(demux_fd < 0) { + return -1; + } + + // create a section filter + uint8_t filter[18] = {table_id}; + uint8_t mask[18] = {0xff}; + if(dvbdemux_set_section_filter(demux_fd, pid, filter, mask, 1, 1)) { // crc check on + close(demux_fd); + return -1; + } + + return demux_fd; +} + +int DvbCamPmtThread::processPat(int demux_fd) +{ + // read section + char si_buf[4096]; + int size = read(demux_fd, si_buf, sizeof(si_buf)); + if(size < 0) { + return -1; + } + + // parse section + section *parsed_section = section_codec(reinterpret_cast<unsigned char *> (si_buf), size); + if(parsed_section == NULL) { + return -1; + } + + // parse section_ext + section_ext *parsed_section_ext = section_ext_decode(parsed_section, 1); // crc check on + if(parsed_section_ext == NULL) { + return -1; + } + + // parse pat + mpeg_pat_section *parsed_pat = mpeg_pat_section_codec(parsed_section_ext); + if(parsed_pat == NULL) { + return -1; + } + + // try and find the requested program + mpeg_pat_program *cur_program; + mpeg_pat_section_programs_for_each(parsed_pat, cur_program) { + if(cur_program->program_number == ServiceId) { + return cur_program->pid; + } + } + + fprintf(stderr, "PmtThread: [warning] the requested service id couldn't be found\n"); + + return -1; +} + +void DvbCamPmtThread::run() +{ + fprintf(stderr, "PmtThread: started\n"); + + int demux_fd = createSectionFilter(TRANSPORT_PAT_PID, stag_mpeg_program_association); + if(demux_fd < 0) { + fprintf(stderr, "PmtThread: [error] opening demux device failed\n"); + return; + } + + pollfd poll_desc; + poll_desc.fd = demux_fd; + poll_desc.events = POLLIN | POLLPRI; + while(!Stopped) { + int ret = poll(&poll_desc, 1, 100); // 100 ms + if(ret < 0) { + fprintf(stderr, "PmtThread: [error] polling demux device failed\n"); + close(demux_fd); + return; + } + if((ret > 0) && (poll_desc.revents != 0) && ((poll_desc.revents & ~(POLLIN | POLLPRI)) == 0)) { + int processed_pat = processPat(demux_fd); + if(processed_pat >= 0) { + close(demux_fd); + demux_fd = createSectionFilter(processed_pat, stag_mpeg_program_map); + if(demux_fd < 0) { + fprintf(stderr, "PmtThread: [error] opening demux device failed\n"); + return; + } + poll_desc.fd = demux_fd; + break; + } + } + } + + while(!Stopped) { + int ret = poll(&poll_desc, 1, 100); // 100 ms + if(ret < 0) { + fprintf(stderr, "PmtThread: [error] polling demux device failed\n"); + close(demux_fd); + return; + } + if((ret > 0) && (poll_desc.revents != 0) && ((poll_desc.revents & ~(POLLIN | POLLPRI)) == 0)) { + if(CamThread->processPmt(demux_fd)) { + fprintf(stderr, "PmtThread: new pmt received\n"); + close(demux_fd); + fprintf(stderr, "PmtThread: stopped\n"); + return; + } + } + } + + fprintf(stderr, "PmtThread: stopping requested\n"); + + close(demux_fd); + + fprintf(stderr, "PmtThread: stopped\n"); + return; +} + +// class DvbCamCamHandler + +DvbCamCamHandler::DvbCamCamHandler() +{ + AiResource = NULL; + CaResource = NULL; + + SessionNumber = -1; +} + +DvbCamCamHandler::~DvbCamCamHandler() +{ + if(CaResource != NULL) { + en50221_app_ca_destroy(CaResource); + CaResource = NULL; + } + if(AiResource != NULL) { + en50221_app_ai_destroy(AiResource); + AiResource = NULL; + } +} + +bool DvbCamCamHandler::init() +{ + AiResource = en50221_app_ai_create(&SendFuncs); + CaResource = en50221_app_ca_create(&SendFuncs); + + if(CaResource != NULL) { + en50221_app_ca_register_info_callback(CaResource, infoCallback, this); + } + + return sub_init(); +} + +bool DvbCamCamHandler::sendPmt(char *pmt_buffer, int size) +{ + if((CaResource != NULL) && (SessionNumber >= 0)) { + if(!en50221_app_ca_pmt(CaResource, SessionNumber, reinterpret_cast<unsigned char *> (pmt_buffer), size)) { + return true; + } + } + + return false; +} + +int DvbCamCamHandler::infoCallback(void *arg, uint8_t /*slot_id*/, uint16_t session_number, uint32_t /*ca_id_count*/, uint16_t */*ca_ids*/) +{ + (static_cast<DvbCamCamHandler *> (arg))->SessionNumber = session_number; + return 0; +} + +// class DvbCamCamHandlerLLCI + +#define MAX_CARDS 1 +#define MAX_TC 16 +#define MAX_SESSIONS 16 + +DvbCamCamHandlerLLCI::DvbCamCamHandlerLLCI() +{ + RmResource = NULL; + SessionLayer = NULL; + TransportLayer = NULL; +} + +DvbCamCamHandlerLLCI::~DvbCamCamHandlerLLCI() +{ + if(SessionLayer != NULL) { + en50221_sl_destroy(SessionLayer); + SessionLayer = NULL; + } + if(TransportLayer != NULL) { + en50221_tl_destroy(TransportLayer); + TransportLayer = NULL; + } + if(RmResource != NULL) { + en50221_app_rm_destroy(RmResource); + RmResource = NULL; + } +} + +int DvbCamCamHandlerLLCI::llci_rm_enq_callback(void *arg, uint8_t /*slot_id*/, uint16_t session_number) +{ + uint32_t resource_ids[] = {EN50221_APP_RM_RESOURCEID, EN50221_APP_AI_RESOURCEID, EN50221_APP_CA_RESOURCEID}; + en50221_app_rm_reply(arg, session_number, sizeof(resource_ids) / 4, resource_ids); + return 0; +} + +int DvbCamCamHandlerLLCI::llci_rm_reply_callback(void *arg, uint8_t /*slot_id*/, uint16_t session_number, uint32_t /*resource_id_count*/, uint32_t */*resource_ids*/) +{ + en50221_app_rm_changed(arg, session_number); + return 0; +} + +int DvbCamCamHandlerLLCI::llci_rm_changed_callback(void *arg, uint8_t /*slot_id*/, uint16_t session_number) +{ + en50221_app_rm_enq(arg, session_number); + return 0; +} + +int DvbCamCamHandlerLLCI::llci_lookup_callback(void *arg, uint8_t /*slot_id*/, uint32_t requested_resource_id, en50221_sl_resource_callback *callback_out, void **arg_out, uint32_t *connected_resource_id) +{ + // decode the resource id + en50221_app_public_resource_id resid; + if(!en50221_app_decode_public_resource_id(&resid, requested_resource_id)) { + return -1; + } + + // try and find an instance of the resource + const SlResource *Resources = (static_cast<DvbCamCamHandlerLLCI *> (arg))->Resources; + int i; + for(i = 0; i < 3; ++i) { + if((resid.resource_class == Resources[i].resid.resource_class) && (resid.resource_type == Resources[i].resid.resource_type)) { + *callback_out = Resources[i].callback; + *arg_out = Resources[i].arg; + *connected_resource_id = Resources[i].binary_resource_id; + return 0; + } + } + return -1; +} + +int DvbCamCamHandlerLLCI::llci_session_callback(void *arg, int reason, uint8_t /*slot_id*/, uint16_t session_number, uint32_t resource_id) +{ + if(reason == S_SCALLBACK_REASON_CAMCONNECTED) { + if(resource_id == EN50221_APP_RM_RESOURCEID) { + void *RmResource = (static_cast<DvbCamCamHandlerLLCI *> (arg))->Resources[0].arg; + en50221_app_rm_enq(RmResource, session_number); + } + else if(resource_id == EN50221_APP_AI_RESOURCEID) { + void *AiResource = (static_cast<DvbCamCamHandlerLLCI *> (arg))->Resources[1].arg; + en50221_app_ai_enquiry(AiResource, session_number); + } + else if(resource_id == EN50221_APP_CA_RESOURCEID) { + void *CaResource = (static_cast<DvbCamCamHandlerLLCI *> (arg))->Resources[2].arg; + en50221_app_ca_info_enq(CaResource, session_number); + } + } + return 0; +} + +void DvbCamCamHandlerLLCI::poll() +{ + if(en50221_tl_poll(TransportLayer)) { + fprintf(stderr, "CamThread: [warning] polling the stack failed\n"); + usleep(10000); // wait 10 ms to not block + } +} + +bool DvbCamCamHandlerLLCI::registerCam(int ca_fd, uint8_t slot) +{ + // register the slot + int slot_id = en50221_tl_register_slot(TransportLayer, ca_fd, slot, 1000, 100); + if(slot_id < 0) { + return false; + } + + // create a new connection on the slot + if(en50221_tl_new_tc(TransportLayer, slot_id) < 0) { + return false; + } + + return true; +} + +bool DvbCamCamHandlerLLCI::sub_init() +{ + // create transport layer + TransportLayer = en50221_tl_create(MAX_CARDS, MAX_TC); + if(TransportLayer == NULL) { + return false; + } + + // create session layer + SessionLayer = en50221_sl_create(TransportLayer, MAX_SESSIONS); + if(SessionLayer == NULL) { + en50221_tl_destroy(TransportLayer); + TransportLayer = NULL; + return false; + } + + // create sendfuncs + SendFuncs.arg = SessionLayer; + SendFuncs.send_data = en50221_sl_send_data; + SendFuncs.send_datav = en50221_sl_send_datav; + + // create the resource manager resource + RmResource = en50221_app_rm_create(&SendFuncs); + en50221_app_decode_public_resource_id(&Resources[0].resid, EN50221_APP_RM_RESOURCEID); + Resources[0].binary_resource_id = EN50221_APP_RM_RESOURCEID; + Resources[0].callback = en50221_app_rm_message; + Resources[0].arg = RmResource; + en50221_app_rm_register_enq_callback(RmResource, llci_rm_enq_callback, RmResource); + en50221_app_rm_register_reply_callback(RmResource, llci_rm_reply_callback, RmResource); + en50221_app_rm_register_changed_callback(RmResource, llci_rm_changed_callback, RmResource); + + // integrate the application information resource + en50221_app_decode_public_resource_id(&Resources[1].resid, EN50221_APP_AI_RESOURCEID); + Resources[1].binary_resource_id = EN50221_APP_AI_RESOURCEID; + Resources[1].callback = en50221_app_ai_message; + Resources[1].arg = AiResource; + + // integrate the ca resource + en50221_app_decode_public_resource_id(&Resources[2].resid, EN50221_APP_CA_RESOURCEID); + Resources[2].binary_resource_id = EN50221_APP_CA_RESOURCEID; + Resources[2].callback = en50221_app_ca_message; + Resources[2].arg = CaResource; + + // register session layer callbacks + en50221_sl_register_lookup_callback(SessionLayer, llci_lookup_callback, this); + en50221_sl_register_session_callback(SessionLayer, llci_session_callback, this); + + return true; +} + +// class DvbCamCamHandlerHLCI + +DvbCamCamHandlerHLCI::DvbCamCamHandlerHLCI() +{ +} + +DvbCamCamHandlerHLCI::~DvbCamCamHandlerHLCI() +{ +} + +int DvbCamCamHandlerHLCI::hlci_send_data(void *arg, uint16_t /*session_number*/, uint8_t *data, uint16_t data_length) +{ + return dvbca_hlci_write(static_cast<int> (reinterpret_cast<intptr_t> (arg)), data, data_length); +} + +int DvbCamCamHandlerHLCI::hlci_send_datav(void *arg, uint16_t /*session_number*/, iovec *vector, int iov_count) +{ + // calculate the total length of the data to send + uint32_t data_size = 0; + for(int i = 0; i < iov_count; ++i) { + data_size += vector[i].iov_len; + } + + // allocate memory for it + uint8_t *buf = new uint8_t[data_size]; + + // merge the iovecs + uint8_t *pos = buf; + for(int i = 0; i < iov_count; ++i) { + memcpy(pos, vector[i].iov_base, vector[i].iov_len); + pos += vector[i].iov_len; + } + + // send it + int status = dvbca_hlci_write(static_cast<int> (reinterpret_cast<intptr_t> (arg)), buf, data_size); + delete buf; + return status; +} + +void DvbCamCamHandlerHLCI::poll() +{ + // we do nothing here for the moment + usleep(100000); // 100 ms +} + +bool DvbCamCamHandlerHLCI::registerCam(int ca_fd, uint8_t /*slot*/) +{ + SendFuncs.arg = reinterpret_cast<void *> (ca_fd); + + // get application information + if(en50221_app_ai_enquiry(AiResource, 0)) { + fprintf(stderr, "CamThread: [DEBUG #1]\n"); + return false; + } + + uint8_t buf[256]; + int size = dvbca_hlci_read(ca_fd, TAG_APP_INFO, buf, sizeof(buf)); + if(size <= 0) { + fprintf(stderr, "CamThread: [DEBUG #2]\n"); + return false; + } + + if(en50221_app_ai_message(AiResource, 0, 0, EN50221_APP_AI_RESOURCEID, buf, size)) { + fprintf(stderr, "CamThread: [DEBUG #3]\n"); + return false; + } + + // FIXME: try to change this soon + buf[0] = TAG_CA_INFO >> 16; + buf[1] = TAG_CA_INFO >> 8; + buf[2] = TAG_CA_INFO; + buf[3] = 0; + if(en50221_app_ca_message(CaResource, 0, 0, EN50221_APP_CA_RESOURCEID, buf, 4)) { + fprintf(stderr, "CamThread: [DEBUG #4]\n"); + return false; + } + + fprintf(stderr, "CamThread: [DEBUG #5]\n"); + + return true; +} + +bool DvbCamCamHandlerHLCI::sub_init() +{ + // create sendfuncs + SendFuncs.arg = NULL; + SendFuncs.send_data = hlci_send_data; + SendFuncs.send_datav = hlci_send_datav; + + return true; +} diff --git a/kaffeine/src/input/dvb/dvbcam.h b/kaffeine/src/input/dvb/dvbcam.h new file mode 100644 index 0000000..47a4012 --- /dev/null +++ b/kaffeine/src/input/dvb/dvbcam.h @@ -0,0 +1,52 @@ +/* + * dvbcam.h + * + * Copyright (C) 2006 Christoph Pfister <christophpfister@gmail.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef DVBCAM_H +#define DVBCAM_H + +class DvbCamCamThread; +class DvbCamPmtThread; + +class DvbCam +{ +public: + DvbCam(int adapter, int ca_device, int demux_device, int ci_type); + ~DvbCam(); + + void restart(int service_id); + void stop(); + bool running() { return isRunning; } + int serviceId() { return sid; } + + static int probe( int adapter, int ca_device ); + +private: + int Adapter; + int CaDevice; + int DemuxDevice; + bool isRunning; + int sid; + int ciType; + + DvbCamCamThread *CamThread; + DvbCamPmtThread *PmtThread; +}; + +#endif /* DVBCAM_H */ diff --git a/kaffeine/src/input/dvb/dvbconfig.cpp b/kaffeine/src/input/dvb/dvbconfig.cpp new file mode 100644 index 0000000..746d745 --- /dev/null +++ b/kaffeine/src/input/dvb/dvbconfig.cpp @@ -0,0 +1,1478 @@ +/* + * dvbconfig.cpp + * + * Copyright (C) 2004-2007 Christophe Thommeret <hftom@free.fr> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include <fcntl.h> +#include <sys/ioctl.h> +#include <unistd.h> +#include <errno.h> + +#include <qdir.h> +#include <qlayout.h> +#include <qgroupbox.h> +#include <qregexp.h> +#include <qradiobutton.h> + +#include <klocale.h> +#include <kiconloader.h> +#include <kmessagebox.h> +#include <kfiledialog.h> +#include <ktar.h> +#include <kstandarddirs.h> + +#include "dvbconfig.h" +#include "kaffeinedvbplugin.h" + + + +MSpinBox::MSpinBox( QWidget *parent, int devNum ) : QSpinBox( 1, 4, 1, parent ) +{ + deviceNumber = devNum; + connect( this, SIGNAL(valueChanged(int)), this, SLOT(slotValueChanged(int)) ); +} + + + +void MSpinBox::slotValueChanged( int value ) +{ + emit signalValueChanged( value, deviceNumber ); +} + + + +MPushButton::MPushButton( QWidget *parent, int devNum, int lnbNum ) : KPushButton( parent ) +{ + deviceNumber = devNum; + lnbNumber = lnbNum; + connect( this, SIGNAL(clicked()), this, SLOT(isClicked()) ); +} + + + +void MPushButton::isClicked() +{ + emit clicked( deviceNumber, lnbNumber ); +} + + + +MComboBox::MComboBox( QWidget *parent, int devNum, int lnbNum ) : QComboBox( parent ) +{ + deviceNumber = devNum; + lnbNumber = lnbNum; + connect( this, SIGNAL(activated(int)), this, SLOT(isActivated(int)) ); +} + + + +void MComboBox::isActivated( int index ) +{ + emit activated( index, deviceNumber, lnbNumber ); +} + + + +LNB::LNB() +{ + switchFreq = 11700; + loFreq = 9750; + hiFreq = 10600; + rotorType = 0; + speed13v = 2.5; + speed18v = 1.5; +} + + + +Device::Device( int anum, int tnum, fe_type_t t, const QString &n, bool as ) +{ + adapter = anum; + tuner = tnum; + type = t; + name = n; + source = ""; + canAutoscan= as; + tuningTimeout = 1500; +} + + + +Category::Category( const QString &tname, const QString &ticon ) +{ + name = tname; + icon = ticon; +} + + + +DVBconfig::DVBconfig( const QString &dvbConf ) +{ + dvbConfigDir = dvbConf; + dvbConfigIconsDir = dvbConf+"icons/"; + QDir dir; + dir.setPath( dvbConfigIconsDir ); + if ( !dir.exists() ) + dir.mkdir( dvbConfigIconsDir ); + config = new KConfig( dvbConfigDir+"dvbrc" ); + downProgress = 0; + sizeFile = 0; + categories.setAutoDelete( true ); + devList.setAutoDelete( true ); + startup(); + readConfig(); +} + + + +DVBconfig::~DVBconfig() +{ + saveConfig(); + delete config; + categories.clear(); + devList.clear(); +} + + + +bool DVBconfig::haveDvbDevice() +{ + int i, j, res, fdFrontend=0; + struct dvb_frontend_info info; + + QStringList list, flist; + QDir d; + d.setPath( "/dev/dvb/" ); + list = d.entryList( "adapter*", QDir::Dirs, QDir::Name ); + + for ( i=0; i<(int)list.count(); i++ ) { + d.setPath( "/dev/dvb/"+list[i]+"/" ); + flist = d.entryList( "frontend*", QDir::System, QDir::Name ); + for ( j=0; j<(int)flist.count(); j++ ) { + fdFrontend = open( QString("/dev/dvb/%1/%2").arg( list[i] ).arg( flist[j] ).ascii(), O_RDWR); + if ( fdFrontend>0 ) { + if ( (res = ioctl( fdFrontend, FE_GET_INFO, &info ) < 0) ) + perror( QString("/dev/dvb/%1/%2 FE_GET_INFO: ").arg( list[i] ).arg( flist[j] ).ascii() ); + else { + close( fdFrontend ); + return true; + } + close( fdFrontend ); + } + } + } + + return false; +} + + + +void DVBconfig::startup() +{ + int i=0, j=0, res, fdFrontend=0; + struct dvb_frontend_info info; + bool as; + + QStringList list, flist; + QString s, t; + QDir d; + d.setPath( "/dev/dvb/" ); + list = d.entryList( "adapter*", QDir::Dirs, QDir::Name ); + + for ( i=0; i<(int)list.count(); i++ ) { + d.setPath( "/dev/dvb/"+list[i]+"/" ); + flist = d.entryList( "frontend*", QDir::System, QDir::Name ); + for ( j=0; j<(int)flist.count(); j++ ) { + s = list[i]; + t = flist[j]; + fdFrontend = open( QString("/dev/dvb/%1/%2").arg( s ).arg( t ).ascii(), O_RDWR); + if ( fdFrontend>0 ) { + if ( !(res = ioctl( fdFrontend, FE_GET_INFO, &info ) < 0) ) { + if ( (info.type==FE_OFDM) + && (info.caps & FE_CAN_QAM_AUTO) + && (info.caps & FE_CAN_TRANSMISSION_MODE_AUTO) + && (info.caps & FE_CAN_GUARD_INTERVAL_AUTO) + && (info.caps & FE_CAN_HIERARCHY_AUTO) + && (info.caps & FE_CAN_FEC_AUTO) ) + as = true; + else + as = false; + fprintf(stderr,"/dev/dvb/%s/%s : opened ( %s )\n", s.ascii(), t.ascii(), info.name ); + devList.append( new Device( s.replace("adapter","").toInt(), t.replace("frontend","").toInt(), info.type, info.name, as ) ); + } + close( fdFrontend ); + } + else + perror( QString("/dev/dvb/%1/%2").arg( s ).arg( t ).ascii() ); + } + } + + //devList.append( new Device( 3, 0, FE_QPSK, "Dummy S", false ) ); +} + + + +void DVBconfig::setDownloadResult( Job *job ) +{ + if ( downProgress && job ) { + delete downProgress; + downProgress = 0; + } +} + + + +void DVBconfig::setDownloadPercent( Job *job, unsigned long percent ) +{ + if ( downProgress && job ) + downProgress->progressBar()->setProgress( percent ); +} + + + +bool DVBconfig::loadDvbData( QWidget *parent ) +{ + QString s=""; + FileCopyJob *job; + QFile f( dvbConfigDir+"dvbdata.tar.gz" ); + + //if ( f.exists() ) f.remove(); + downProgress = new KProgressDialog( parent, "progress", i18n("Downloading... "), i18n("Copying data files..."), true ); + downProgress->progressBar()->setTotalSteps( 100 ); + //job = file_copy( KURL( "http://hftom.free.fr/kaxtv/dvbdata.tar.gz" ), KURL( dvbConfigDir+"dvbdata.tar.gz" ), -1, true, false, false ); + job = file_copy( KURL( "http://hftom.free.fr/kaxtv/dvbdata.tar.gz" ), KURL( dvbConfigDir+"dvbdata.tar.gz" ), -1, true, false, false ); + connect( job, SIGNAL(result(KIO::Job*)), this, SLOT(setDownloadResult(KIO::Job*)) ); + connect( job, SIGNAL(percent(KIO::Job*,unsigned long)), this, SLOT(setDownloadPercent(KIO::Job*,unsigned long)) ); + downProgress->exec(); + disconnect( job, SIGNAL(result(KIO::Job*)), this, SLOT(setDownloadResult(KIO::Job*)) ); + disconnect( job, SIGNAL(percent(KIO::Job*,unsigned long)), this, SLOT(setDownloadPercent(KIO::Job*,unsigned long)) ); + if ( downProgress ) { + delete downProgress; + downProgress = 0; + } + KTar tar( dvbConfigDir+"dvbdata.tar.gz"); + if ( tar.open( IO_ReadOnly ) ) { + tar.directory()->copyTo( dvbConfigDir ); + return true; + } + else + return false; +} + + + +bool DVBconfig::localData() +{ + QString s = locate("data","kaffeine/dvbdata.tar.gz"); + KTar tar( s ); + if ( tar.open( IO_ReadOnly ) ) { + tar.directory()->copyTo( dvbConfigDir ); + return true; + } + else + return false; +} + + + +bool DVBconfig::haveData() +{ + if ( !QDir( dvbConfigDir+"dvb-s" ).exists() || !QDir( dvbConfigDir+"dvb-c" ).exists() || !QDir( dvbConfigDir+"dvb-t" ).exists() ) { + loadDvbData(0); + if ( !QDir( dvbConfigDir+"dvb-s" ).exists() || !QDir( dvbConfigDir+"dvb-c" ).exists() || !QDir( dvbConfigDir+"dvb-t" ).exists() ) { + if ( !localData() ) + return false; + } + } + return true; +} + + + +QStringList DVBconfig::getSourcesList( fe_type_t type ) +{ + QString s; + QStringList list; + + switch ( type ) { + case FE_QPSK : s = "dvb-s"; break; + case FE_QAM : s = "dvb-c"; break; + case FE_OFDM : s = "dvb-t"; break; + default : return list; + } + list = QDir( dvbConfigDir+s ).entryList( QDir::Files, QDir::Name ); + return list; +} + + + +void DVBconfig::addCategory( const QString &name, const QString &icon ) +{ + categories.append( new Category( name, icon ) ); +} + + + +void DVBconfig::removeCategory( const QString &name ) +{ + int i; + + for ( i=0; i<(int)categories.count(); i++ ) { + if ( categories.at(i)->name==name ) { + categories.remove( i ); + break; + } + } +} + + + +void DVBconfig::changeIconCategory( const QString &name, const QString &icon ) +{ + int i; + + if ( name==i18n("All") ) + allIcon = icon; + else if ( name==i18n("TV") ) + tvIcon = icon; + else if ( name==i18n("Radio") ) + radioIcon = icon; + else { + for ( i=0; i<(int)categories.count(); i++ ) { + if ( categories.at(i)->name==name ) { + categories.at(i)->icon = icon; + break; + } + } + } +} + + + +int DVBconfig::readDvbChanOrder() +{ + config->setGroup( "DVB Options" ); + int sort = config->readNumEntry("ChannelsSorting", 0); + return sort; +} + + + +void DVBconfig::saveDvbChanOrder( int s, int col ) +{ + int sort = (s<<1) | col; + config->setGroup( "DVB Options" ); + config->writeEntry("ChannelsSorting", sort); + config->sync(); +} + + + +void DVBconfig::readConfig() +{ + QSize size; + QString s; + int i, j; + + config->setGroup( "DVB Options" ); + broadcastAddress = config->readEntry( "BroadcastAddress", "192.168.0.255" ); + broadcastPort = config->readNumEntry( "BroadcastPort", 1234 ); + senderPort = config->readNumEntry( "SenderPort", 1235 ); + size = QSize(600, 350); + epgSize = config->readSizeEntry( "EPG Geometry", &size ); + size = QSize(600, 300); + timerSize = config->readSizeEntry( "Timers Geometry", &size ); + size = QSize(300, 300); + scanSize = config->readSizeEntry( "Scan Geometry", &size ); + beginMargin = config->readNumEntry( "BeginMargin", 5 ); + endMargin = config->readNumEntry( "EndMargin", 10 ); + instantDuration = config->readNumEntry( "InstantDuration", 120 ); + recordDir = config->readEntry( "RecordDir", QDir::homeDirPath() ); + if ( !recordDir.endsWith("/") ) + recordDir+= "/"; + sizeFile = config->readNumEntry("SizeFile",0); + shiftDir = config->readEntry( "ShiftDir", QDir::homeDirPath() ); + if ( !shiftDir.endsWith("/") ) + shiftDir+= "/"; + filenameFormat = config->readEntry( "filenameFormat", "%name" ); + for ( i=0; i<(int)devList.count(); i++ ) { + devList.at(i)->source = config->readEntry( QString("DVB%1").arg(i), "" ); + devList.at(i)->tuningTimeout = config->readNumEntry( QString("DVB%1_TIMEOUT").arg(i), 1500 ); + if ( devList.at(i)->type!=FE_QPSK ) + continue; + devList.at(i)->numLnb = config->readNumEntry( QString("DVB%1_NLNB").arg(i), 1 ); + for ( j=0; j<devList.at(i)->numLnb; j++ ) { + devList.at(i)->lnb[j].switchFreq = config->readNumEntry( QString("DVB%1_LNB%2_switch").arg(i).arg(j), 11700 ); + devList.at(i)->lnb[j].loFreq = config->readNumEntry( QString("DVB%1_LNB%2_lo").arg(i).arg(j), 9750 ); + devList.at(i)->lnb[j].hiFreq = config->readNumEntry( QString("DVB%1_LNB%2_hi").arg(i).arg(j), 10600 ); + devList.at(i)->lnb[j].rotorType = config->readNumEntry( QString("DVB%1_LNB%2_rotor").arg(i).arg(j), 0 ); + devList.at(i)->lnb[j].source = config->readListEntry( QString("DVB%1_LNB%2_source").arg(i).arg(j) ); + devList.at(i)->lnb[j].position = config->readIntListEntry( QString("DVB%1_LNB%2_position").arg(i).arg(j) ); + devList.at(i)->lnb[j].speed13v = config->readDoubleNumEntry( QString("DVB%1_LNB%2_speed13v").arg(i).arg(j), 2.5 ); + devList.at(i)->lnb[j].speed18v = config->readDoubleNumEntry( QString("DVB%1_LNB%2_speed18v").arg(i).arg(j), 1.5 ); + } + } + j = config->readNumEntry( "NumCategories", 0 ); + for ( i=0; i<j; i++ ) + categories.append( new Category( config->readEntry( QString("CategoryName%1").arg(i), "" ), config->readEntry( QString("CategoryIcon%1").arg(i), "kaffeine" ) ) ); + allIcon = config->readEntry( "AllIcon", "kaffeine" ); + tvIcon = config->readEntry( "TvIcon", "kdvbtv" ); + radioIcon = config->readEntry( "RadioIcon", "kdvbra" ); + lastChannel = config->readNumEntry( "LastChannel", 1 ); + splitSizes = config->readIntListEntry("SplitSizes"); + defaultCharset = config->readEntry( "DefaultCharset", "ISO8859-1" ); + usalsLatitude = config->readDoubleNumEntry( "UsalsLatitude", 0.0 ); + usalsLongitude = config->readDoubleNumEntry( "UsalsLongitude", 0.0 ); + for ( i=0; i<(int)devList.count(); i++ ) { + devList.at(i)->usalsLatitude = usalsLatitude; + devList.at(i)->usalsLongitude = usalsLongitude; + } +} + + + +void DVBconfig::saveConfig() +{ + int i, j; + + config->setGroup( "DVB Options" ); + config->writeEntry( "EPG Geometry", epgSize ); + config->writeEntry( "Timers Geometry", timerSize ); + config->writeEntry( "Scan Geometry", scanSize ); + config->writeEntry( "BeginMargin", beginMargin ); + config->writeEntry( "EndMargin", endMargin ); + config->writeEntry( "InstantDuration", instantDuration ); + config->writeEntry( "RecordDir", recordDir ); + config->writeEntry( "ShiftDir", shiftDir ); + config->writeEntry( "filenameFormat", filenameFormat ); + config->writeEntry( "BroadcastAddress", broadcastAddress ); + config->writeEntry( "BroadcastPort", broadcastPort ); + config->writeEntry( "SenderPort", senderPort ); + for ( i=0; i<(int)devList.count(); i++ ) { + config->writeEntry( QString("DVB%1").arg(i), devList.at(i)->source ); + config->writeEntry( QString("DVB%1_TIMEOUT").arg(i), devList.at(i)->tuningTimeout ); + if ( devList.at(i)->type!=FE_QPSK ) + continue; + config->writeEntry( QString("DVB%1_NLNB").arg(i), devList.at(i)->numLnb ); + for ( j=0; j<devList.at(i)->numLnb; j++ ) { + config->writeEntry( QString("DVB%1_LNB%2_switch").arg(i).arg(j), devList.at(i)->lnb[j].switchFreq ); + config->writeEntry( QString("DVB%1_LNB%2_lo").arg(i).arg(j), devList.at(i)->lnb[j].loFreq ); + config->writeEntry( QString("DVB%1_LNB%2_hi").arg(i).arg(j), devList.at(i)->lnb[j].hiFreq ); + config->writeEntry( QString("DVB%1_LNB%2_rotor").arg(i).arg(j), devList.at(i)->lnb[j].rotorType ); + config->writeEntry( QString("DVB%1_LNB%2_source").arg(i).arg(j), devList.at(i)->lnb[j].source ); + config->writeEntry( QString("DVB%1_LNB%2_position").arg(i).arg(j), devList.at(i)->lnb[j].position ); + config->writeEntry( QString("DVB%1_LNB%2_speed13v").arg(i).arg(j), devList.at(i)->lnb[j].speed13v ); + config->writeEntry( QString("DVB%1_LNB%2_speed18v").arg(i).arg(j), devList.at(i)->lnb[j].speed18v ); + } + } + config->writeEntry( "NumCategories", categories.count() ); + for ( i=0; i<(int)categories.count(); i++ ) { + config->writeEntry( QString("CategoryName%1").arg(i), categories.at(i)->name ); + config->writeEntry( QString("CategoryIcon%1").arg(i), categories.at(i)->icon ); + } + config->writeEntry( "AllIcon", allIcon ); + config->writeEntry( "TvIcon", tvIcon ); + config->writeEntry( "RadioIcon", radioIcon ); + config->writeEntry( "LastChannel", lastChannel ); + config->writeEntry( "SplitSizes", splitSizes ); + config->writeEntry( "DefaultCharset", defaultCharset ); + config->writeEntry( "UsalsLatitude", usalsLatitude ); + config->writeEntry( "UsalsLongitude", usalsLongitude ); + config->writeEntry( "SizeFile", sizeFile ); + config->sync(); +} + + + +bool DVBconfig::firstRun() +{ + config->setGroup( "DVB Options" ); + if ( config->readNumEntry( "FirstRun", 0 )<3 ) { + config->writeEntry( "FirstRun", 3 ); + return true; + } + return false; +} + + + +DvbConfigDialog::DvbConfigDialog( DVBconfig *dc, QWidget *parent, KaffeineDvbPlugin *p ) : + KDialogBase ( IconList, i18n("DVB Settings"), Ok|Cancel, Ok, parent, "dvbConfigDialog", true, true ) +{ + QLabel *lab; + KIconLoader *icon = new KIconLoader(); + QHBoxLayout *h1; + QString s; + int i; + QVBoxLayout *vb; + QGroupBox *gb; + QGridLayout *grid, *sgrid; + QLabel *ident; + QLabel *dvbType; + int gridLine; + QFrame *page; + QSpinBox *spin; + KPushButton *usals; + QWidget *swidg; + QStringList rotorList; rotorList<<i18n("No rotor")<<i18n("USALS rotor")<<i18n("Positions rotor"); + + dvbConfig = dc; + timeoutSpin.setAutoDelete( true ); + + for ( i=0; i<(int)dvbConfig->devList.count(); i++ ) { + page = addPage( i18n("DVB Device")+" "+QString("%1:%2").arg(dvbConfig->devList.at(i)->adapter).arg(dvbConfig->devList.at(i)->tuner), i18n("Device Settings"), + KGlobal::instance()->iconLoader()->loadIcon( "hwinfo", KIcon::NoGroup, KIcon::SizeMedium ) ); + vb = new QVBoxLayout( page, 6, 6 ); + gb = new QGroupBox( "", page ); + grid = new QGridLayout( gb, 1, 1, 20, 6 ); + gridLine = 0; + + lab = new QLabel( i18n("<qt><b>Name:</b></qt>"), gb ); + grid->addWidget( lab, gridLine, 0 ); + ident = new QLabel( dvbConfig->devList.at(i)->name, gb ); + grid->addMultiCellWidget( ident, gridLine, gridLine, 1, 3 ); + ++gridLine; + + lab = new QLabel( i18n("<qt><b>Type:</b></qt>"), gb ); + grid->addWidget( lab, gridLine, 0 ); + dvbType = new QLabel( gb ); + switch ( dvbConfig->devList.at(i)->type ) { + case FE_QAM : dvbType->setText( i18n("Cable") ); break; + case FE_OFDM : dvbType->setText( i18n("Terrestrial") ); break; + case FE_QPSK : dvbType->setText( i18n("Satellite") ); break; + case FE_ATSC : dvbType->setText( i18n("Atsc") ); break; + default : dvbType->setText( i18n("Unknown") ); + } + grid->addMultiCellWidget( dvbType, gridLine, gridLine, 1, 3 ); + ++gridLine; + + lab = new QLabel( i18n("Tuner timeout :"), gb ); + grid->addWidget( lab, gridLine, 0 ); + spin = new QSpinBox( 500, 5000, 100, gb ); + spin->setValue( dvbConfig->devList.at(i)->tuningTimeout ); + timeoutSpin.append( spin ); + grid->addWidget( spin, gridLine, 1 ); + lab = new QLabel( i18n("(ms)"), gb ); + grid->addWidget( lab, gridLine, 2 ); + ++gridLine; + + if ( dvbConfig->devList.at(i)->type==FE_QPSK ) { + lab = new QLabel( i18n("Number of LNBs:"), gb ); + grid->addWidget( lab, gridLine, 0 ); + satNumber[i] = new MSpinBox( gb, i ); + connect( satNumber[i], SIGNAL(signalValueChanged(int,int)), this, SLOT(satNumberChanged(int,int))); + grid->addWidget( satNumber[i], gridLine, 1 ); + usals = new KPushButton( gb ); + usals->setGuiItem( KGuiItem(i18n("Set rotor coordinates..."), icon->loadIconSet("move", KIcon::Small) ) ); + connect( usals, SIGNAL(clicked()), this, SLOT(setUsals())); + grid->addWidget( usals, gridLine, 2 ); + + ++gridLine; + + lnb0[i] = new MPushButton( gb, i, 0 ); + lnb0[i]->setGuiItem( KGuiItem(i18n("LNB 1 settings..."), icon->loadIconSet("hwinfo", KIcon::Small) ) ); + lnb0[i]->setEnabled(true); + grid->addWidget( lnb0[i], gridLine, 0 ); + connect( lnb0[i], SIGNAL(clicked(int,int)), this, SLOT(setLnb(int,int))); + rotor0[i] = new MComboBox( gb, i, 0 ); + rotor0[i]->insertStringList( rotorList ); + rotor0[i]->setCurrentItem( dvbConfig->devList.at(i)->lnb[0].rotorType ); + grid->addWidget( rotor0[i], gridLine, 1 ); + connect( rotor0[i], SIGNAL(activated(int,int,int)), this, SLOT(setRotor(int,int,int))); + swidg = new QWidget( gb ); + sgrid = new QGridLayout( swidg, 1, 1, 0, 0 ); + sat0[i] = new QComboBox( swidg ); + sat0[i]->insertStringList( dvbConfig->getSourcesList(dvbConfig->devList.at(i)->type) ); + sgrid->addWidget( sat0[i], 0, 0 ); + src0[i] = new MPushButton( swidg, i, 0 ); + src0[i]->setGuiItem( KGuiItem(i18n("Sources list...") ) ); + connect( src0[i], SIGNAL(clicked(int,int)), this, SLOT(setRotorSources(int,int)) ); + sgrid->addWidget( src0[i], 1, 0 ); + if ( dvbConfig->devList.at(i)->lnb[0].rotorType==0 ) { + setSource( sat0[i], dvbConfig->devList.at(i)->lnb[0].source[0] ); + src0[i]->hide(); + } + else { + sat0[i]->hide(); + } + grid->addWidget( swidg, gridLine, 2 ); + ++gridLine; + + lnb1[i] = new MPushButton( gb, i, 1 ); + lnb1[i]->setGuiItem( KGuiItem(i18n("LNB 2 settings..."), icon->loadIconSet("hwinfo", KIcon::Small) ) ); + lnb1[i]->setEnabled(false); + grid->addWidget( lnb1[i], gridLine, 0 ); + connect( lnb1[i], SIGNAL(clicked(int,int)), this, SLOT(setLnb(int,int))); + rotor1[i] = new MComboBox( gb, i, 1 ); + rotor1[i]->setEnabled( false ); + rotor1[i]->insertStringList( rotorList ); + rotor1[i]->setCurrentItem( dvbConfig->devList.at(i)->lnb[1].rotorType ); + grid->addWidget( rotor1[i], gridLine, 1 ); + connect( rotor1[i], SIGNAL(activated(int,int,int)), this, SLOT(setRotor(int,int,int))); + swidg = new QWidget( gb ); + sgrid = new QGridLayout( swidg, 1, 1, 0, 0 ); + sat1[i] = new QComboBox( swidg ); + sat1[i]->setEnabled(false); + sat1[i]->insertStringList( dvbConfig->getSourcesList(dvbConfig->devList.at(i)->type) ); + sgrid->addWidget( sat1[i], 0, 0 ); + src1[i] = new MPushButton( swidg, i, 1 ); + src1[i]->setEnabled(false); + src1[i]->setGuiItem( KGuiItem(i18n("Sources list...") ) ); + connect( src1[i], SIGNAL(clicked(int,int)), this, SLOT(setRotorSources(int,int)) ); + sgrid->addWidget( src1[i], 1, 0 ); + if ( dvbConfig->devList.at(i)->lnb[1].rotorType==0 ) { + setSource( sat1[i], dvbConfig->devList.at(i)->lnb[1].source[0] ); + src1[i]->hide(); + } + else { + sat1[i]->hide(); + } + grid->addWidget( swidg, gridLine, 2 ); + ++gridLine; + + lnb2[i] = new MPushButton( gb, i, 2 ); + lnb2[i]->setGuiItem( KGuiItem(i18n("LNB 3 settings..."), icon->loadIconSet("hwinfo", KIcon::Small) ) ); + lnb2[i]->setEnabled(false); + grid->addWidget( lnb2[i], gridLine, 0 ); + connect( lnb2[i], SIGNAL(clicked(int,int)), this, SLOT(setLnb(int,int))); + rotor2[i] = new MComboBox( gb, i, 2 ); + rotor2[i]->setEnabled(false); + rotor2[i]->insertStringList( rotorList ); + rotor2[i]->setCurrentItem( dvbConfig->devList.at(i)->lnb[2].rotorType ); + grid->addWidget( rotor2[i], gridLine, 1 ); + connect( rotor2[i], SIGNAL(activated(int,int,int)), this, SLOT(setRotor(int,int,int))); + swidg = new QWidget( gb ); + sgrid = new QGridLayout( swidg, 1, 1, 0, 0 ); + sat2[i] = new QComboBox( swidg ); + sat2[i]->setEnabled(false); + sat2[i]->insertStringList( dvbConfig->getSourcesList(dvbConfig->devList.at(i)->type) ); + sgrid->addWidget( sat2[i], 0, 0 ); + src2[i] = new MPushButton( swidg, i, 2 ); + src2[i]->setEnabled(false); + src2[i]->setGuiItem( KGuiItem(i18n("Sources list...") ) ); + connect( src2[i], SIGNAL(clicked(int,int)), this, SLOT(setRotorSources(int,int)) ); + sgrid->addWidget( src2[i], 1, 0 ); + if ( dvbConfig->devList.at(i)->lnb[2].rotorType==0 ) { + setSource( sat2[i], dvbConfig->devList.at(i)->lnb[2].source[0] ); + src2[i]->hide(); + } + else { + sat2[i]->hide(); + } + grid->addWidget( swidg, gridLine, 2 ); + ++gridLine; + + lnb3[i] = new MPushButton( gb, i, 3 ); + lnb3[i]->setGuiItem( KGuiItem(i18n("LNB 4 settings..."), icon->loadIconSet("hwinfo", KIcon::Small) ) ); + lnb3[i]->setEnabled(false); + grid->addWidget( lnb3[i], gridLine, 0 ); + connect( lnb3[i], SIGNAL(clicked(int,int)), this, SLOT(setLnb(int,int))); + rotor3[i] = new MComboBox( gb, i, 3 ); + rotor3[i]->setEnabled(false); + rotor3[i]->insertStringList( rotorList ); + rotor3[i]->setCurrentItem( dvbConfig->devList.at(i)->lnb[3].rotorType ); + grid->addWidget( rotor3[i], gridLine, 1 ); + connect( rotor3[i], SIGNAL(activated(int,int,int)), this, SLOT(setRotor(int,int,int))); + swidg = new QWidget( gb ); + sgrid = new QGridLayout( swidg, 1, 1, 0, 0 ); + sat3[i] = new QComboBox( swidg ); + sat3[i]->setEnabled(false); + sat3[i]->insertStringList( dvbConfig->getSourcesList(dvbConfig->devList.at(i)->type) ); + sgrid->addWidget( sat3[i], 0, 0 ); + src3[i] = new MPushButton( swidg, i, 3 ); + src3[i]->setEnabled(false); + src3[i]->setGuiItem( KGuiItem(i18n("Sources list...") ) ); + connect( src3[i], SIGNAL(clicked(int,int)), this, SLOT(setRotorSources(int,int)) ); + sgrid->addWidget( src3[i], 1, 0 ); + if ( dvbConfig->devList.at(i)->lnb[3].rotorType==0 ) { + setSource( sat3[i], dvbConfig->devList.at(i)->lnb[3].source[0] ); + src3[i]->hide(); + } + else { + sat3[i]->hide(); + } + grid->addWidget( swidg, gridLine, 2 ); + ++gridLine; + + satNumber[i]->setValue( dvbConfig->devList.at(i)->numLnb ); + } + else { + lab = new QLabel( i18n("Source:"), gb ); + grid->addWidget( lab, gridLine, 0 ); + sat0[i] = new QComboBox( gb ); + if ( dvbConfig->devList.at(i)->canAutoscan ) + sat0[i]->insertItem( "AUTO" ); + sat0[i]->insertStringList( dvbConfig->getSourcesList(dvbConfig->devList.at(i)->type) ); + setSource( sat0[i], dvbConfig->devList.at(i)->source ); + grid->addWidget( sat0[i], gridLine, 1 ); + ++gridLine; + + if ( dvbConfig->devList.at(i)->canAutoscan ) { + lab = new QLabel( i18n("<qt>This device seems to support the <b><i>autoscan</i></b> feature. " + "You can choose <b>AUTO</b> in Source list to let Kaffeine " + "search for a range of frequencies.<br>" + "If <b><i>autoscan</i></b> fails to find your channels, choose a real Source in list.</qt>"), gb ); + grid->addMultiCellWidget( lab, gridLine, gridLine, 0, 3 ); + ++gridLine; + } + } + lab = new QLabel( i18n("<qt><i>If you can't find your network/location in the list, you'll have to create one. " + "Look in $HOME/.kde/share/apps/kaffeine/dvb-x/ and take an existing file as start point. " + "Fill in with the values for your network/location and give it a sensible name " + "(follow the naming convention). If you think your new file could be usefull for others, send it to " + "kaffeine-user(AT)lists.sf.net.</i></qt>"), gb ); + grid->addMultiCellWidget( lab, gridLine, gridLine, 0, 3 ); + + vb->addWidget( gb ); + vb->addItem( new QSpacerItem( 20, 20, QSizePolicy::Ignored, QSizePolicy::Ignored ) ); + } + + page = addPage(i18n("Recording"),i18n("DVB Recording Options"), + KGlobal::instance()->iconLoader()->loadIcon( "hdd_unmount", KIcon::NoGroup, KIcon::SizeMedium ) ); + vb = new QVBoxLayout( page, 6, 6 ); + gb = new QGroupBox( "", page ); + grid = new QGridLayout( gb, 1, 1, 20, 6 ); + + lab = new QLabel( i18n("Records directory:"), gb ); + grid->addWidget( lab, 0, 0 ); + recordDirLe = new QLineEdit( gb ); + recordDirLe->setReadOnly( true ); + grid->addWidget( recordDirLe, 0, 1 ); + recordDirBtn = new QToolButton( gb ); + recordDirBtn->setIconSet( icon->loadIconSet("fileopen", KIcon::Small) ); + grid->addWidget( recordDirBtn, 0, 2 ); + + lab = new QLabel( i18n("Time shifting directory:"), gb ); + grid->addWidget( lab, 1, 0 ); + shiftDirLe = new QLineEdit( gb ); + shiftDirLe->setReadOnly( true ); + grid->addWidget( shiftDirLe, 1, 1 ); + shiftDirBtn = new QToolButton( gb ); + shiftDirBtn->setIconSet( icon->loadIconSet("fileopen", KIcon::Small) ); + grid->addWidget( shiftDirBtn, 1, 2 ); + + lab = new QLabel( i18n("Begin margin:"), gb ); + grid->addWidget( lab, 2, 0 ); + beginSpin = new QSpinBox( gb ); + h1 = new QHBoxLayout(); + h1->addWidget( beginSpin ); + lab = new QLabel( i18n("(minutes)"), gb ); + h1->addWidget( lab ); + grid->addLayout( h1, 2, 1 ); + + lab = new QLabel( i18n("End margin:"), gb ); + grid->addWidget( lab, 3, 0 ); + endSpin = new QSpinBox( gb ); + h1 = new QHBoxLayout(); + h1->addWidget( endSpin ); + lab = new QLabel( i18n("(minutes)"), gb ); + h1->addWidget( lab ); + grid->addLayout( h1, 3, 1 ); + + lab = new QLabel( i18n("Instant record duration:"), gb ); + grid->addWidget( lab, 4, 0 ); + instantDurationSpin = new QSpinBox( 1, 1440, 1, gb ); + h1 = new QHBoxLayout(); + h1->addWidget( instantDurationSpin ); + lab = new QLabel( i18n("(minutes)"), gb ); + h1->addWidget( lab ); + grid->addLayout( h1, 4, 1 ); + + lab = new QLabel( i18n("Max file size (0=Unlimited):"), gb ); + grid->addWidget( lab, 5, 0 ); + sizeFileSpin = new QSpinBox( 1, 9999, 1, gb ); + sizeFileSpin->setMinValue(0); + h1 = new QHBoxLayout(); + h1->addWidget( sizeFileSpin ); + lab = new QLabel( i18n("(MB)"), gb ); + h1->addWidget( lab ); + grid->addLayout( h1, 5, 1 ); + + lab = new QLabel( i18n("Filename Format:"), gb ); + grid->addWidget( lab, 7, 0 ); + filenameFormatLe = new QLineEdit( gb ); + grid->addWidget( filenameFormatLe, 7, 1 ); + helpNameBtn = new QToolButton( gb ); + helpNameBtn->setIconSet( icon->loadIconSet("help", KIcon::Small) ); + grid->addWidget( helpNameBtn, 7, 2 ); + + vb->addWidget( gb ); + vb->addItem( new QSpacerItem( 20, 20, QSizePolicy::Ignored, QSizePolicy::Ignored ) ); + + recordDirLe->setText( dvbConfig->recordDir ); + shiftDirLe->setText( dvbConfig->shiftDir ); + beginSpin->setValue( dvbConfig->beginMargin ); + endSpin->setValue( dvbConfig->endMargin ); + instantDurationSpin->setValue( dvbConfig->instantDuration ); + sizeFileSpin->setValue( dvbConfig->sizeFile ); + filenameFormatLe->setText( dvbConfig->filenameFormat ); + + page = addPage(i18n("Broadcasting"),i18n("DVB Broadcasting"), + KGlobal::instance()->iconLoader()->loadIcon( "network_local", KIcon::NoGroup, KIcon::SizeMedium ) ); + vb = new QVBoxLayout( page, 6, 6 ); + gb = new QGroupBox( "", page ); + grid = new QGridLayout( gb, 1, 1, 20, 6 ); + + lab = new QLabel( i18n("Broadcast address:"), gb ); + grid->addWidget( lab, 0, 0 ); + broadcastLe = new QLineEdit( gb ); + grid->addWidget( broadcastLe, 0, 1 ); + lab = new QLabel( i18n("Broadcast port:"), gb ); + grid->addWidget( lab, 1, 0 ); + bportSpin = new QSpinBox( 1, 65535, 1, gb ); + grid->addWidget( bportSpin, 1, 1 ); + lab = new QLabel( i18n("Info port:"), gb ); + grid->addWidget( lab, 2, 0 ); + sportSpin = new QSpinBox( 1, 65535, 1, gb ); + grid->addWidget( sportSpin, 2, 1 ); + + vb->addWidget( gb ); + vb->addItem( new QSpacerItem( 20, 20, QSizePolicy::Ignored, QSizePolicy::Ignored ) ); + + broadcastLe->setText( dvbConfig->broadcastAddress ); + bportSpin->setValue( dvbConfig->broadcastPort ); + sportSpin->setValue( dvbConfig->senderPort ); + + page = addPage(i18n("Misc"),i18n("Misc"), + KGlobal::instance()->iconLoader()->loadIcon( "misc", KIcon::NoGroup, KIcon::SizeMedium ) ); + vb = new QVBoxLayout( page, 6, 6 ); + gb = new QGroupBox( "", page ); + grid = new QGridLayout( gb, 1, 1, 20, 6 ); + + lab = new QLabel( i18n("Default charset (restart needed):"), gb ); + grid->addWidget( lab, 0, 0 ); + charsetComb = new QComboBox( gb ); + charsetComb->insertItem( "ISO8859-1" ); + charsetComb->insertItem( "ISO6937" ); + if ( dvbConfig->defaultCharset=="ISO8859-1" ) + charsetComb->setCurrentItem( 0 ); + else if ( dvbConfig->defaultCharset=="ISO6937" ) + charsetComb->setCurrentItem( 1 ); + grid->addWidget( charsetComb, 0, 1 ); + + lab = new QLabel( i18n("Update scan data:"), gb ); + grid->addWidget( lab, 1, 0 ); + updateBtn = new KPushButton( gb ); + updateBtn->setGuiItem( KGuiItem(i18n("Download"), icon->loadIconSet("khtml_kget", KIcon::Small) ) ); + grid->addWidget( updateBtn, 1, 1 ); + + lab = new QLabel( i18n("Dump epg's events to \n~/kaffeine_dvb_events.tx:"), gb ); + grid->addWidget( lab, 2, 0 ); + dumpBtn = new KPushButton( gb ); + dumpBtn->setGuiItem( KGuiItem(i18n("Dump"), icon->loadIconSet("filesave", KIcon::Small) ) ); + grid->addWidget( dumpBtn, 2, 1 ); + + vb->addWidget( gb ); + vb->addItem( new QSpacerItem( 20, 20, QSizePolicy::Ignored, QSizePolicy::Ignored ) ); + + if ( p ) { + page = addPage(i18n("DVB plugins"),i18n("DVB plugins"), + KGlobal::instance()->iconLoader()->loadIcon( "misc", KIcon::NoGroup, KIcon::SizeMedium ) ); + vb = new QVBoxLayout( page, 6, 6 ); + gb = new QGroupBox( "", page ); + grid = new QGridLayout( gb, 1, 1, 20, 6 ); + + KPushButton *btn = new KPushButton( p->pluginName(), gb ); + grid->addWidget( btn, 0, 0 ); + connect( btn, SIGNAL(clicked()), p, SLOT(configDialog()) ); + vb->addWidget( gb ); + vb->addItem( new QSpacerItem( 20, 20, QSizePolicy::Ignored, QSizePolicy::Ignored ) ); + } + + connect( recordDirBtn, SIGNAL(clicked()), this, SLOT(setRecordDir()) ); + connect( shiftDirBtn, SIGNAL(clicked()), this, SLOT(setShiftDir()) ); + connect( updateBtn, SIGNAL(clicked()), this, SLOT(downloadData()) ); + connect( helpNameBtn, SIGNAL(clicked()), this, SLOT(fileTemplateHelp()) ); + delete icon; +} + + + +void DvbConfigDialog::setUsals() +{ + KDialogBase *dlg = new KDialogBase( this, "usalsConfigDialog", true, i18n("Rotors settings"), Ok|Cancel, Ok, true ); + QGridLayout *grid; + QWidget *page = new QWidget( dlg ); + dlg->setMainWidget( page ); + + QVBoxLayout *vb = new QVBoxLayout( page, 6, 6 ); + QLabel *lab = new QLabel( i18n("Set your position coordinates for rotors:"), page ); + vb->addWidget( lab ); + lab = new QLabel( "(Sydney: -33.8916, 151.2417 - New York: 40.7139, -74.0063)", page ); + vb->addWidget( lab ); + grid = new QGridLayout( 0, 1, 1 ); + lab = new QLabel( i18n("Latitude:"), page ); + grid->addWidget( lab, 0, 0 ); + QLineEdit *latitude = new QLineEdit( page ); + latitude->setText( QString().setNum( dvbConfig->usalsLatitude ) ); + grid->addWidget( latitude, 0, 1 ); + lab = new QLabel( i18n("Longitude:"), page ); + grid->addWidget( lab, 1, 0 ); + QLineEdit *longitude = new QLineEdit( page ); + longitude->setText( QString().setNum( dvbConfig->usalsLongitude ) ); + grid->addWidget( longitude, 1, 1 ); + vb->addLayout( grid ); + vb->addItem( new QSpacerItem( 20, 20, QSizePolicy::Ignored, QSizePolicy::Ignored ) ); + + if ( dlg->exec()==QDialog::Accepted ) { + dvbConfig->usalsLatitude = latitude->text().toDouble(); + dvbConfig->usalsLongitude = longitude->text().toDouble(); + for ( int i=0; i<(int)dvbConfig->devList.count(); i++ ) { + dvbConfig->devList.at(i)->usalsLatitude = dvbConfig->usalsLatitude; + dvbConfig->devList.at(i)->usalsLongitude = dvbConfig->usalsLongitude; + } + } +} + + + +void DvbConfigDialog::setRotorSources( int devNum, int lnbNum ) +{ + RotorConfig rotor( dvbConfig->devList.at(devNum), dvbConfig, lnbNum, this ); + rotor.exec(); +} + + + +void DvbConfigDialog::setRotor( int index, int devNum, int lnbNum ) +{ + QComboBox *comb; + QPushButton *btn; + + switch ( lnbNum ) { + case 0 : comb=sat0[devNum]; btn=src0[devNum]; break; + case 1 : comb=sat1[devNum]; btn=src1[devNum]; break; + case 2 : comb=sat2[devNum]; btn=src2[devNum]; break; + case 3 : comb=sat3[devNum]; btn=src3[devNum]; break; + default : return; + } + + dvbConfig->devList.at(devNum)->lnb[lnbNum].rotorType=index; + + if ( index==0 ) { + btn->hide(); + comb->show(); + } + else { + comb->hide(); + btn->show(); + } +} + + + +void DvbConfigDialog::setLnb( int devNum, int lnbNum ) +{ + LnbConfig lnb( &dvbConfig->devList.at(devNum)->lnb[lnbNum], this ); + lnb.exec(); +} + + + +void DvbConfigDialog::downloadData() +{ + int ret; + +loop: + if ( !dvbConfig->loadDvbData(0) ) { + ret = KMessageBox::questionYesNo( this, i18n("<qt>Can't get DVB data from http://hftom.free.fr/kaxtv/dvbdata.tar.gz!<br>\ + Check your internet connection, and say Yes to try again.<br>\ + Or say No to cancel.<br> Should I try again?</qt>") ); + if ( ret==KMessageBox::Yes ) + goto loop; + return; + } +} + + + +void DvbConfigDialog::setSource( QComboBox *box, QString s ) +{ + int pos, i; + + pos = s.find("|"); + if ( pos>=0 ) + s = s.right( s.length()-pos-1 ); + for ( i=0; i<(int)box->count(); i++ ) { + if ( box->text(i)==s ) { + box->setCurrentItem(i); + break; + } + } +} + + + +void DvbConfigDialog::satNumberChanged( int value, int devNum ) +{ + sat0[devNum]->setEnabled( value > 0 ); + sat1[devNum]->setEnabled( value > 1 ); + sat2[devNum]->setEnabled( value > 2 ); + sat3[devNum]->setEnabled( value > 3 ); + + src0[devNum]->setEnabled( value > 0 ); + src1[devNum]->setEnabled( value > 1 ); + src2[devNum]->setEnabled( value > 2 ); + src3[devNum]->setEnabled( value > 3 ); + + lnb0[devNum]->setEnabled( value > 0 ); + lnb1[devNum]->setEnabled( value > 1 ); + lnb2[devNum]->setEnabled( value > 2 ); + lnb3[devNum]->setEnabled( value > 3 ); + + rotor0[devNum]->setEnabled( value > 0 ); + rotor1[devNum]->setEnabled( value > 1 ); + rotor2[devNum]->setEnabled( value > 2 ); + rotor3[devNum]->setEnabled( value > 3 ); +} + + + +void DvbConfigDialog::fileTemplateHelp() +{ + KMessageBox::information( this, i18n("Special strings are:\n- %chan (channel's name)\n- %date (the starting date, YYMMdd-hhmmss)\n- %name (the name given in timer editor or the program name from EPG)\nSo, if you set template to '%chan-%date-%name', the resulting filename will be, for example, BBC-20070919-210000-News.m2t") ); +} + + + +void DvbConfigDialog::setRecordDir() +{ + QString s = KFileDialog::getExistingDirectory( recordDirLe->text().stripWhiteSpace() ); + if ( !s.isEmpty() ) + recordDirLe->setText( s ); +} + + + +void DvbConfigDialog::setShiftDir() +{ + QString s = KFileDialog::getExistingDirectory( shiftDirLe->text().stripWhiteSpace() ); + if ( !s.isEmpty() ) + shiftDirLe->setText( s ); +} + + + +void DvbConfigDialog::accept() +{ + QString s; + int i; + + if ( recordDirLe->text().stripWhiteSpace().isEmpty() ) { + KMessageBox::sorry( this, i18n("Invalid records directory.") ); + recordDirLe->setFocus(); + return; + } + if ( shiftDirLe->text().stripWhiteSpace().isEmpty() ) { + KMessageBox::sorry( this, i18n("Invalid time shifting directory.") ); + shiftDirLe->setFocus(); + return; + } + if ( bportSpin->value()==sportSpin->value() ) { + KMessageBox::sorry( this, i18n("Broadcast and Info ports must be different.") ); + sportSpin->setFocus(); + return; + } + if ( !QRegExp("(\\d{1,3}\\.){3}\\d{1,3}").exactMatch( broadcastLe->text().stripWhiteSpace() ) ) { + KMessageBox::sorry( this, i18n("Invalid broadcast address.") ); + broadcastLe->setFocus(); + return; + } + if ( !filenameFormatLe->text().contains("%chan") && !filenameFormatLe->text().contains("%date") && !filenameFormatLe->text().contains("%name") ) { + KMessageBox::sorry( this, i18n("Invalid filename format.") ); + filenameFormatLe->setFocus(); + return; + } + + for ( i=0; i<(int)dvbConfig->devList.count(); i++ ) { + switch (dvbConfig->devList.at(i)->type) { + case FE_QPSK: { + dvbConfig->devList.at(i)->numLnb = satNumber[i]->value(); + if ( dvbConfig->devList.at(i)->lnb[3].rotorType==0 ) { + dvbConfig->devList.at(i)->lnb[3].source.clear(); + dvbConfig->devList.at(i)->lnb[3].source.append(sat3[i]->currentText()); + } + if ( dvbConfig->devList.at(i)->lnb[2].rotorType==0 ) { + dvbConfig->devList.at(i)->lnb[2].source.clear(); + dvbConfig->devList.at(i)->lnb[2].source.append(sat2[i]->currentText()); + } + if ( dvbConfig->devList.at(i)->lnb[1].rotorType==0 ) { + dvbConfig->devList.at(i)->lnb[1].source.clear(); + dvbConfig->devList.at(i)->lnb[1].source.append(sat1[i]->currentText()); + } + if ( dvbConfig->devList.at(i)->lnb[0].rotorType==0 ) { + dvbConfig->devList.at(i)->lnb[0].source.clear(); + dvbConfig->devList.at(i)->lnb[0].source.append(sat0[i]->currentText()); + } + s = "S"; + break; + } + case FE_QAM: { + s = "C"; + s+="|"+sat0[i]->currentText(); + break; + } + case FE_OFDM: { + s = "T"; + s+="|"+sat0[i]->currentText(); + break; + } + case FE_ATSC: { + s = "A"; + s+="|"+sat0[i]->currentText(); + break; + } + } + dvbConfig->devList.at(i)->source = s; + dvbConfig->devList.at(i)->tuningTimeout = timeoutSpin.at(i)->value(); + } + + dvbConfig->recordDir = recordDirLe->text(); + if ( !dvbConfig->recordDir.endsWith("/") ) + dvbConfig->recordDir+= "/"; + dvbConfig->shiftDir = shiftDirLe->text(); + if ( !dvbConfig->shiftDir.endsWith("/") ) + dvbConfig->shiftDir+= "/"; + dvbConfig->beginMargin = beginSpin->value(); + dvbConfig->endMargin = endSpin->value(); + dvbConfig->instantDuration = instantDurationSpin->value(); + dvbConfig->sizeFile = sizeFileSpin->value(); + dvbConfig->filenameFormat = filenameFormatLe->text(); + dvbConfig->defaultCharset = charsetComb->currentText(); + dvbConfig->broadcastAddress = broadcastLe->text().stripWhiteSpace(); + dvbConfig->broadcastPort = bportSpin->value(); + dvbConfig->senderPort = sportSpin->value(); + dvbConfig->saveConfig(); + done( Accepted ); +} + + + +DvbConfigDialog::~DvbConfigDialog() +{ +} + + + +LnbConfig::LnbConfig( LNB *b, QWidget *parent ) : + KDialogBase ( parent, "lnbConfigDialog", true, i18n("LNB Settings"), Ok|Cancel, Ok, true ) +{ + QGridLayout *grid; + + QWidget *page = new QWidget( this ); + setMainWidget( page ); + + lnb = b; + + QVBoxLayout *vb = new QVBoxLayout( page, 6, 6 ); + univ = new QPushButton( i18n("Universal LNB"), page ); + connect( univ, SIGNAL(clicked()), this, SLOT(setUniversal()) ); + vb->addWidget( univ ); + cmono = new QPushButton( i18n("C-Band LNB"), page ); + connect( cmono, SIGNAL(clicked()), this, SLOT(setCBandMono()) ); + vb->addWidget( cmono ); + cmulti = new QPushButton( i18n("C-Band Multipoint LNB"), page ); + connect( cmulti, SIGNAL(clicked()), this, SLOT(setCBandMulti()) ); + vb->addWidget( cmulti ); + + grid = new QGridLayout( 0, 1, 1 ); + nLO = new QButtonGroup( 3, Qt::Horizontal, page ); + connect( nLO, SIGNAL(clicked(int)), this, SLOT(setDual(int)) ); + new QRadioButton( i18n("Dual LO"), nLO ); + new QRadioButton( i18n("Single LO"), nLO ); + new QRadioButton( i18n("H/V LO"), nLO ); + grid->addMultiCellWidget( nLO, 0, 0, 0, 1 ); + slofLab = new QLabel( i18n("Dual LO switch frequency:")+i18n(" (MHz)"), page ); + grid->addWidget( slofLab, 1, 0 ); + slof = new QSpinBox( 0, 13000, 1, page ); + grid->addWidget( slof, 1, 1 ); + loLab = new QLabel( i18n("Lo-band frequency:")+i18n(" (MHz)"), page ); + grid->addWidget( loLab, 2, 0 ); + lo = new QSpinBox( 0, 13000, 1, page ); + grid->addWidget( lo, 2, 1 ); + hiLab = new QLabel( i18n("Hi-band frequency:")+i18n(" (MHz)"), page ); + grid->addWidget( hiLab, 3, 0 ); + hi = new QSpinBox( 0, 13000, 1, page ); + grid->addWidget( hi, 3, 1 ); + singleLab = new QLabel( i18n("Single LO frequency:")+i18n(" (MHz)"), page ); + grid->addWidget( singleLab, 4, 0 ); + single = new QSpinBox( 0, 13000, 1, page ); + grid->addWidget( single, 4, 1 ); + verticalLab = new QLabel( i18n("Vertical pol. LO frequency:")+i18n(" (MHz)"), page ); + grid->addWidget( verticalLab, 5, 0 ); + vertical = new QSpinBox( 0, 13000, 1, page ); + grid->addWidget( vertical, 5, 1 ); + horizontalLab = new QLabel( i18n("Horizontal pol. LO frequency:")+i18n(" (MHz)"), page ); + grid->addWidget( horizontalLab, 6, 0 ); + horizontal = new QSpinBox( 0, 13000, 1, page ); + grid->addWidget( horizontal, 6, 1 ); + + vb->addLayout( grid ); + vb->addItem( new QSpacerItem( 20, 20, QSizePolicy::Ignored, QSizePolicy::Ignored ) ); + + + slof->setValue( lnb->switchFreq ); + lo->setValue( lnb->loFreq ); + hi->setValue( lnb->hiFreq ); + single->setValue( lnb->loFreq ); + vertical->setValue( lnb->loFreq ); + horizontal->setValue( lnb->hiFreq ); + + if ( lnb->switchFreq ) { + nLO->setButton( 0 ); + setDual( 0 ); + } + else { + if ( lnb->hiFreq ) { + nLO->setButton( 2 ); + setDual( 2 ); + } + else { + nLO->setButton( 1 ); + setDual( 1 ); + } + } +} + + + +void LnbConfig::setDual( int id ) +{ + switch ( id ) { + case 0: { + singleLab->hide(); + single->hide(); + verticalLab->hide(); + vertical->hide(); + horizontalLab->hide(); + horizontal->hide(); + slofLab->show(); + slof->show(); + loLab->show(); + lo->show(); + hiLab->show(); + hi->show(); + break; + } + case 1: { + slofLab->hide(); + slof->hide(); + loLab->hide(); + lo->hide(); + hiLab->hide(); + hi->hide(); + verticalLab->hide(); + vertical->hide(); + horizontalLab->hide(); + horizontal->hide(); + singleLab->show(); + single->show(); + break; + } + case 2: { + slofLab->hide(); + slof->hide(); + loLab->hide(); + lo->hide(); + hiLab->hide(); + hi->hide(); + singleLab->hide(); + single->hide(); + verticalLab->show(); + vertical->show(); + horizontalLab->show(); + horizontal->show(); + break; + } + } +} + + + +void LnbConfig::setUniversal() +{ + nLO->setButton( 0 ); + setDual( 0 ); + slof->setValue( 11700 ); + lo->setValue( 9750 ); + hi->setValue( 10600 ); +} + + + +void LnbConfig::setCBandMono() +{ + nLO->setButton( 1 ); + setDual( 1 ); + single->setValue( 5150 ); +} + + + +void LnbConfig::setCBandMulti() +{ + nLO->setButton( 2 ); + setDual( 2 ); + vertical->setValue( 5150 ); + horizontal->setValue( 5750 ); +} + + + +void LnbConfig::accept() +{ + switch ( nLO->selectedId() ) { + case 0: { + lnb->switchFreq = slof->value(); + lnb->loFreq = lo->value(); + lnb->hiFreq = hi->value(); + break; + } + case 1: { + lnb->switchFreq = 0; + lnb->hiFreq = 0; + lnb->loFreq = single->value(); + break; + } + case 2: { + lnb->switchFreq = 0; + lnb->loFreq = vertical->value(); + lnb->hiFreq = horizontal->value(); + break; + } + } + done( Accepted ); +} + + + +RotorConfig::RotorConfig( Device *d, DVBconfig *c, int lnb, QWidget *parent ) : + KDialogBase ( parent, "rotorConfigDialog", true, i18n("Rotor Settings"), Ok|Cancel, Ok, true ) +{ + int i; + + QWidget *page = new QWidget( this ); + setMainWidget( page ); + + dev = d; + config = c; + lnbNum = lnb; + + QVBoxLayout *vb = new QVBoxLayout( page, 6, 6 ); + QGridLayout *grid = new QGridLayout( 0, 1, 1 ); + QLabel *lab = new QLabel( i18n("Sattelite:"), page ); + grid->addWidget( lab, 0, 0 ); + if ( dev->lnb[lnbNum].rotorType==2 ) { + lab = new QLabel( i18n("Position:"), page ); + grid->addWidget( lab, 0, 1 ); + } + srcComb = new QComboBox( page ); + srcComb->insertStringList( config->getSourcesList( dev->type ) ); + grid->addWidget( srcComb, 1, 0 ); + position = new QSpinBox( 0, 500, 1, page ); + grid->addWidget( position, 1, 1 ); + vb->addLayout( grid ); + vb->addItem( new QSpacerItem( 20, 10, QSizePolicy::Fixed, QSizePolicy::Fixed ) ); + + addBtn = new QPushButton( i18n("Add to list"), page ); + connect( addBtn, SIGNAL(clicked()), this, SLOT(add()) ); + vb->addWidget( addBtn ); + vb->addItem( new QSpacerItem( 20, 10, QSizePolicy::Fixed, QSizePolicy::Fixed ) ); + + listView = new QListView( page ); + listView->addColumn( i18n("Sattelite:") ); + vb->addWidget( listView ); + + resetBtn = new QPushButton( i18n("Clear list"), page ); + connect( resetBtn, SIGNAL(clicked()), this, SLOT(reset()) ); + vb->addWidget( resetBtn ); + vb->addItem( new QSpacerItem( 20, 20, QSizePolicy::Fixed, QSizePolicy::Fixed ) ); + + grid = new QGridLayout( 0, 1, 1 ); + lab = new QLabel( i18n("13V rotor speed:"), page ); + grid->addWidget( lab, 0, 0 ); + speed13 = new QLineEdit( page ); + speed13->setText( QString().setNum( dev->lnb[lnbNum].speed13v ) ); + grid->addWidget( speed13, 0, 1 ); + lab = new QLabel( i18n("sec./ °"), page ); + grid->addWidget( lab, 0, 2 ); + lab = new QLabel( i18n("18V rotor speed:"), page ); + grid->addWidget( lab, 1, 0 ); + speed18 = new QLineEdit( page ); + speed18->setText( QString().setNum( dev->lnb[lnbNum].speed18v ) ); + grid->addWidget( speed18, 1, 1 ); + lab = new QLabel( i18n("sec./ °"), page ); + grid->addWidget( lab, 1, 2 ); + vb->addLayout( grid ); + + vb->addItem( new QSpacerItem( 20, 20, QSizePolicy::Ignored, QSizePolicy::Ignored ) ); + + if ( dev->lnb[lnbNum].rotorType==2 ) { + listView->addColumn( i18n("Position:") ); + for ( i=0; i<(int)dev->lnb[lnbNum].source.count(); i++ ) + new QListViewItem( listView, dev->lnb[lnbNum].source[i], QString().setNum(dev->lnb[lnbNum].position[i]) ); + } + else { + position->hide(); + for ( i=0; i<(int)dev->lnb[lnbNum].source.count(); i++ ) + new QListViewItem( listView, dev->lnb[lnbNum].source[i] ); + } + +} + + + +void RotorConfig::reset() +{ + listView->clear(); + position->setValue( 1 ); +} + + + +void RotorConfig::add() +{ + if ( position->isHidden() ) { + new QListViewItem( listView, srcComb->currentText() ); + } + else { + new QListViewItem( listView, srcComb->currentText(), QString().setNum(position->value()) ); + } + +} + + + +void RotorConfig::accept() +{ + QListViewItem *it; + + dev->lnb[lnbNum].speed18v = speed18->text().toDouble(); + dev->lnb[lnbNum].speed13v = speed13->text().toDouble(); + dev->lnb[lnbNum].source.clear(); + dev->lnb[lnbNum].position.clear(); + for ( it=listView->firstChild(); it; it=it->nextSibling() ) { + dev->lnb[lnbNum].source.append( it->text(0) ); + if ( dev->lnb[lnbNum].rotorType==2 ) + dev->lnb[lnbNum].position.append( it->text(1).toInt() ); + } + done( Accepted ); +} + + +#include "dvbconfig.moc" diff --git a/kaffeine/src/input/dvb/dvbconfig.h b/kaffeine/src/input/dvb/dvbconfig.h new file mode 100644 index 0000000..f52b9cc --- /dev/null +++ b/kaffeine/src/input/dvb/dvbconfig.h @@ -0,0 +1,301 @@ +/* + * dvbconfig.h + * + * Copyright (C) 2004-2007 Christophe Thommeret <hftom@free.fr> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef DVBCONFIG_H +#define DVBCONFIG_H + +#include <qspinbox.h> +#include <qlabel.h> +#include <qlineedit.h> +#include <qcombobox.h> +#include <qtoolbutton.h> +#include <qbuttongroup.h> +#include <qlistview.h> + +#include <kdialogbase.h> +#include <kpushbutton.h> +#include <kconfig.h> +#include <kio/job.h> +#include <kprogress.h> + +#include <linux/dvb/frontend.h> + +using namespace KIO; + +class MSpinBox : public QSpinBox +{ + Q_OBJECT +public: + MSpinBox( QWidget *parent, int devNum ); +public slots: + void slotValueChanged( int value ); +signals: + void signalValueChanged( int value, int devNum ); +private: + int deviceNumber; +}; + + + +class MPushButton : public KPushButton +{ + Q_OBJECT +public: + MPushButton( QWidget *parent, int devNum, int lnbNum ); +private slots: + void isClicked(); +signals: + void clicked( int devnum, int lnbnum ); +private: + int deviceNumber; + int lnbNumber; +}; + + + +class MComboBox : public QComboBox +{ + Q_OBJECT +public: + MComboBox( QWidget *parent, int devNum, int lnbNum ); +private slots: + void isActivated( int index ); +signals: + void activated( int index, int devnum, int lnbnum ); +private: + int deviceNumber; + int lnbNumber; +}; + + + +class LNB +{ +public: + LNB(); + + unsigned int switchFreq; + unsigned int loFreq; + unsigned int hiFreq; + int rotorType; + double speed13v, speed18v; + QStringList source; + QValueList<int> position; + QString currentSource; +}; + + + +class Device +{ +public: + Device( int anum, int tnum, fe_type_t t, const QString &n, bool as ); + int adapter, tuner; + fe_type_t type; + QString name; + QString source; + int numLnb; + LNB lnb[4]; + bool canAutoscan; + int tuningTimeout; + double usalsLatitude, usalsLongitude; +}; + + + +class Category +{ +public: + Category( const QString &tname, const QString &ticon ); + QString name; + QString icon; +}; + + + +class DVBconfig : public QObject +{ + Q_OBJECT + +public: + + DVBconfig( const QString &dvbConf ); + ~DVBconfig(); + void readConfig(); + void saveConfig(); + int readDvbChanOrder(); + void saveDvbChanOrder( int s, int col ); + void startup(); + static bool haveDvbDevice(); + bool loadDvbData( QWidget *parent ); + bool localData(); + QStringList getSourcesList( fe_type_t type ); + bool haveData(); + bool firstRun(); + void addCategory( const QString &name, const QString &icon ); + void removeCategory( const QString &name ); + void changeIconCategory( const QString &name, const QString &icon ); + + KConfig *config; + QString recordDir, shiftDir, filenameFormat; + int beginMargin, endMargin, instantDuration, sizeFile; + QSize epgSize, scanSize, timerSize; + QPtrList<Device> devList; + QPtrList<Category> categories; + QString allIcon, tvIcon, radioIcon; + QString dvbConfigDir; + QString dvbConfigIconsDir; + QString broadcastAddress; + int broadcastPort, senderPort; + int lastChannel; + QValueList<int> splitSizes; + QString defaultCharset; + double usalsLatitude, usalsLongitude; + +private: + + KProgressDialog *downProgress; + bool downloadFinished; + +private slots: + + void setDownloadResult( KIO::Job *job ); + void setDownloadPercent( KIO::Job *job, unsigned long percent ); +}; + + + +class KaffeineDvbPlugin; + +class DvbConfigDialog : public KDialogBase +{ + Q_OBJECT + +public: + + DvbConfigDialog( DVBconfig *dc, QWidget *parent, KaffeineDvbPlugin *p ); + ~DvbConfigDialog(); + void setSource( QComboBox *box, QString s ); + + QLineEdit *recordDirLe, *shiftDirLe, *broadcastLe, *filenameFormatLe; + QSpinBox *beginSpin, *endSpin, *instantDurationSpin, *bportSpin, *sportSpin, *sizeFileSpin; + MSpinBox *satNumber[8]; + QComboBox *sat0[8]; + QComboBox *sat1[8]; + QComboBox *sat2[8]; + QComboBox *sat3[8]; + MPushButton *src0[8]; + MPushButton *src1[8]; + MPushButton *src2[8]; + MPushButton *src3[8]; + MComboBox *rotor0[8]; + MComboBox *rotor1[8]; + MComboBox *rotor2[8]; + MComboBox *rotor3[8]; + MPushButton *lnb0[8]; + MPushButton *lnb1[8]; + MPushButton *lnb2[8]; + MPushButton *lnb3[8]; + KPushButton *updateBtn, *dumpBtn; + QToolButton *recordDirBtn, *shiftDirBtn, *helpNameBtn; + DVBconfig *dvbConfig; + QComboBox *charsetComb; + QPtrList<QSpinBox> timeoutSpin; + +private slots: + + void fileTemplateHelp(); + void setRecordDir(); + void setShiftDir(); + void satNumberChanged( int value, int devNum ); + void downloadData(); + void setLnb( int devNum, int lnbNum ); + void setRotor( int index, int devNum, int lnbNum ); + void setRotorSources( int devNum, int lnbNum ); + void setUsals(); + +protected slots: + + virtual void accept(); +}; + + + +class LnbConfig : public KDialogBase +{ + Q_OBJECT + +public: + + LnbConfig( LNB *b, QWidget *parent ); + +protected slots: + + virtual void accept(); + void setDual( int id ); + void setUniversal(); + void setCBandMono(); + void setCBandMulti(); + +private: + + QSpinBox *slof; + QSpinBox *lo, *hi, *single, *vertical, *horizontal; + QLabel *slofLab, *loLab, *hiLab, *singleLab, *verticalLab, *horizontalLab; + QButtonGroup *nLO; + QPushButton *univ, *cmono, *cmulti; + + LNB *lnb; +}; + + + +class RotorConfig : public KDialogBase +{ + Q_OBJECT + +public: + + RotorConfig( Device *d, DVBconfig *c, int lnb, QWidget *parent ); + +protected slots: + + virtual void accept(); + +private slots: + + void reset(); + void add(); + +private: + + QSpinBox *position; + QComboBox *srcComb; + QListView *listView; + QPushButton *addBtn, *resetBtn; + QLineEdit *speed13, *speed18; + + Device *dev; + int lnbNum; + DVBconfig *config; +}; + + +#endif /* DVBCONFIG_H */ diff --git a/kaffeine/src/input/dvb/dvbevents.cpp b/kaffeine/src/input/dvb/dvbevents.cpp new file mode 100644 index 0000000..13e1265 --- /dev/null +++ b/kaffeine/src/input/dvb/dvbevents.cpp @@ -0,0 +1,424 @@ +/* + * dvbevents.cpp + * + * Copyright (C) 2003-2007 Christophe Thommeret <hftom@free.fr> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include <stdio.h> +#include <unistd.h> +#include <sys/time.h> +#include <sys/resource.h> + +#include <qdatetime.h> +#include <qfile.h> + +#include <klocale.h> +#include <kstandarddirs.h> +#include <ktrader.h> +#include <kparts/componentfactory.h> + +#include "dvbevents.h" + + + +DVBevents::DVBevents( QString devType, int anum, int tnum, const QString &charset, EventTable *table ) + : KaffeineDVBsection( anum, tnum, charset ) +{ + events = table; + KaffeineEpgPlugin *plug; + QString plugName; + int error; + + KTrader::OfferList offers = KTrader::self()->query("KaffeineEpgPlugin"); + KTrader::OfferList::Iterator end( offers.end() ); + for ( KTrader::OfferList::Iterator it=offers.begin(); it!=end; ++it ) { + error = 0; + KService::Ptr ptr = (*it); + if ( !ptr->name().contains(devType) ) + continue; + plug = KParts::ComponentFactory::createPartInstanceFromService<KaffeineEpgPlugin>(ptr, 0, ptr->name().ascii(), 0, 0, 0, &error ); + plugName = ptr->desktopEntryName(); + if (error > 0) { + fprintf( stderr, "Loading of EPG plugin %s failed: %s\n", plugName.ascii(), KLibLoader::self()->lastErrorMessage().ascii() ); + plug = NULL; + } + else { + plugs.append( plug ); + plug->setTable( table ); + plug->initSection( anum, tnum, charset ); + plugNames.append( plugName ); + } + } + fprintf( stderr, "%d EPG plugins loaded for device %d:%d.\n", plugs.count(), anum, tnum ); +} + + + +DVBevents::~DVBevents() +{ + int i; + + isRunning = false; + if ( !wait(2000) ) { + terminate(); + wait(); + } + for ( i=0; i<(int)plugs.count(); ++i ) { + plugs.at(i)->stop(); + KService::Ptr service = KService::serviceByDesktopName( plugNames[i] ); + KLibLoader::self()->unloadLibrary( service->library().ascii() ); + } +} + + + +bool DVBevents::shortEventDesc( unsigned char *buf, EventDesc *desc ) +{ + QString name, text; + int len, len2; + ShortEvent *ev; + + if ( !safeLen( buf+6 ) ) + return false; + len = getBits(buf,40,8); + if ( !safeLen( buf+6+len ) ) + return false; + name = getText( buf+6, len ); + if ( !safeLen( buf+6+len+1 ) ) + return false; + len2 = getBits(buf+6+len,0,8); + if ( !safeLen( buf+7+len+len2 ) ) + return false; + text = getText( buf+7+len, len2); + if ( desc->title.isEmpty() ) { + desc->title=name; + desc->subtitle=text; + return true; + } + desc->shortEvents.append( new ShortEvent() ); + ev = desc->shortEvents.getLast(); + ev->name = name; + ev->text = text; + return true; +} + + + +bool DVBevents::extEventDesc( unsigned char *buf, EventDesc *desc ) +{ + int loop, len1, len2; + unsigned char *b = buf; + QString s; + + if ( !safeLen( b+7 ) ) + return false; + loop = getBits(b+6,0,8); + b +=7; + + while ( loop>0 ) { + if ( !safeLen( b+1 ) ) + return false; + len1 = getBits(b,0,8); + if ( !safeLen( b+1+len1 ) ) + return false; + s = getText(b+1,len1); + if ( !safeLen( b+1+len1+1 ) ) + return false; + len2 = getBits(b+1+len1,0,8); + if ( !safeLen( buf+2+len1+len2 ) ) + return false; + if ( !s.isEmpty() ) + s = s+" : "; + s = s+getText(b+2+len1,len2); + desc->extEvents.append( new QString( s ) ); + b +=(2+len1+len2); + loop -=(2+len1+len2); + } + if ( !safeLen( b+1 ) ) + return false; + len1 = getBits(b,0,8); + if ( !safeLen( b+1+len1 ) ) + return false; + s = getText(b+1,len1); + desc->extEvents.append( new QString( s ) ); + return true; +} + + + +bool DVBevents::tableEIT( unsigned char* buffer ) +{ + unsigned char* buf = buffer; + unsigned int length, loop, sid, tid, eid, tsid, sn, lsn, nid; + int i, sec; + EventDesc *desc=0, *itdesc=0; + EventSid *slist; + QPtrList<EventDesc> *currentEvents; + bool nodesc, parse; + QDateTime start, cur, dt; + unsigned int cdt = QDateTime::currentDateTime().toTime_t(); + + tid = getBits(buf,0,8); + length = getBits(buf,12,12); + sid = getBits(buf,24,16); + sn = getBits(buf,48,8); + lsn = getBits(buf,56,8); + tsid = getBits(buf,64,16); + nid = getBits(buf,80,16); + length -=11; + buf +=14; + + slist = currentSrc->getEventSid( nid, tsid, sid ); + if ( !slist ) + return false; + slist->lock(); + currentEvents = slist->getEvents(); + QPtrListIterator<EventDesc> it( *currentEvents ); + + while ( length>4 ) { + nodesc=parse=false; + if ( !safeLen( buf+2 ) ) + goto stop; + eid = getBits(buf,0,16); + if ( !safeLen( buf+2+5 ) ) + goto stop; + start = getDateTime( buf+2 ); + nodesc=parse=true; + + it.toFirst(); + while ( (desc=it.current())!=0 ) { + if ( desc->sid==sid ) { + if ( desc->startDateTime==start || desc->eid==eid ) { + if ( desc->tid==0x4e && tid!=0x4e ) { + parse = false; + nodesc = false; + break; + } + else { + nodesc = false; + if ( (cdt-desc->loop)<300 ) { // only reparse events every 300 seconds + parse = false; + } + else { + desc->extEvents.clear(); + desc->shortEvents.clear(); + desc->title=desc->subtitle=""; + } + break; + } + } + } + ++it; + } + + if ( nodesc ) + desc = new EventDesc(); + if ( parse ) { + if ( !safeLen( buf+10 ) ) + goto stop; + desc->duration = getTime( buf+7 ); + if ( !safeLen( buf+11 ) ) + goto stop; + desc->running = getBits(buf,80,3); + desc->sid = sid; + desc->tid = tid; + desc->tsid = tsid; + desc->nid = nid; + desc->lsn = lsn; + desc->sn = sn; + desc->eid = eid; + desc->loop = cdt; + } + + if ( desc->sn != sn ) { + slist->unlock(); + return false; + } + if ( !safeLen( buf+12 ) ) + goto stop; + loop = getBits(buf,84,12); + buf +=12; + length -=(12+loop); + while ( loop>0 ) { + if ( parse ) { + if ( !safeLen( buf+1 ) ) + goto stop; + switch ( getBits(buf,0,8) ) { + case 0x4D : + if ( !shortEventDesc( buf, desc ) ) + goto stop; + break; + case 0x4E : + if ( !extEventDesc( buf, desc ) ) + goto stop; + break; + default : + break; + } + } + if ( !safeLen( buf+2 ) ) + goto stop; + loop -=( getBits(buf,8,8)+2 ); + buf +=( getBits(buf,8,8)+2 ); + } +//out: + if ( parse ) { + if ( !nodesc ) { + if ( start==desc->startDateTime ) + goto ifend; + currentEvents->take( currentEvents->find( desc ) ); + } + desc->startDateTime = start; + for ( i=0; i<(int)currentEvents->count(); i++ ) { + itdesc = currentEvents->at(i); + if ( desc->startDateTime<itdesc->startDateTime ) { + currentEvents->insert( i, desc ); + break; + } + itdesc = 0; + } + if ( !itdesc ) + currentEvents->append( desc ); + } +ifend: + if ( parse ) + ++(desc->sn); + if ( nodesc ) { + cur = QDateTime::currentDateTime(); + dt = desc->startDateTime; + sec = desc->duration.hour()*3600+desc->duration.minute()*60+desc->duration.second(); + if ( dt.addSecs( sec )<cur || desc->title.length()<3 ) { + currentEvents->remove( desc ); + } + else + desc->source = currentSrc->getSource(); + } + + } + slist->unlock(); + return true; +stop: + slist->unlock(); + fprintf( stderr, "Stop parsing EIT (%d:%d)\n", adapter, tuner ); + if ( nodesc ) + delete desc; + return false; +} + + + + +bool DVBevents::safeLen( unsigned char* buf ) +{ + if ( buf<(secbuf+readSize) ) + return true; + fprintf( stderr, "EIT (%d:%d) : buffer overflow! Rejected\n", adapter, tuner ); + return false; +} + + + +bool DVBevents::go( QString src, int freqKHz, bool all ) +{ + int tid, i; + + if ( isRunning ) + return true; + + if ( all ) + tid = 0; + else + tid = 0x4e; + + currentSrc = events->getEventSource( src ); + + if ( !setFilter( 0x12, tid, 1000 ) ) + return false; + isRunning = true; + start(); + fprintf(stderr,"dvbEvents %d:%d started\n", adapter, tuner); + + for ( i=0; i<(int)plugs.count(); ++i ) { + plugs.at(i)->go( src, freqKHz ); + } + + return true; +} + + + +void DVBevents::stop() +{ + int i; + + if ( !isRunning ) + return; + + isRunning = false; + if ( !wait(2000) ) { + terminate(); + wait(); + fprintf(stderr,"dvbEvents %d:%d terminated\n", adapter, tuner); + } + else + fprintf(stderr,"dvbEvents %d:%d ended\n", adapter, tuner); + stopFilter(); + + for ( i=0; i<(int)plugs.count(); ++i ) { + plugs.at(i)->stop(); + } +} + + + +void DVBevents::run() +{ + int n=0, tid; + int skip=0; + + setpriority(PRIO_PROCESS, 0, 19); // eit parsing is cpu eater on some astra multiplex. + while ( isRunning ) { + if ( !isRunning ) + break; + + if ( poll(pf,1,1000)>0 ){ + if ( pf[0].revents & POLLIN ){ + n = read( fdDemux, secbuf, 4096 ); + skip = 0; + } + else + skip++; + } + else + skip++; + + if (skip) + continue; + if ( n<16 ) + continue; + else + readSize = n; + + if ( !isRunning ) + break; + + tid = getBits(secbuf,0,8); + if ( tid>0x4D && tid<0x70 ) { + tableEIT( secbuf ); + } + } +} diff --git a/kaffeine/src/input/dvb/dvbevents.h b/kaffeine/src/input/dvb/dvbevents.h new file mode 100644 index 0000000..e5d693d --- /dev/null +++ b/kaffeine/src/input/dvb/dvbevents.h @@ -0,0 +1,59 @@ +/* + * dvbevents.h + * + * Copyright (C) 2003-2007 Christophe Thommeret <hftom@free.fr> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef DVBEVENTS_H +#define DVBEVENTS_H + +#include <qptrlist.h> + +#include "kaffeinedvbsection.h" +#include "kaffeinedvbevents.h" + + + +class DVBevents : public KaffeineDVBsection +{ + +public: + + DVBevents( QString devType, int anum, int tnum, const QString &charset, EventTable *table ); + ~DVBevents(); + bool go( QString src, int freqKHz, bool all=false ); + void stop(); + +private: + + virtual void run(); + bool tableEIT( unsigned char* buffer ); + bool shortEventDesc( unsigned char *buf, EventDesc *desc ); + bool extEventDesc( unsigned char *buf, EventDesc *desc ); + bool safeLen( unsigned char* buf ); + + unsigned char secbuf[4096]; + int readSize; + + EventTable *events; + EventSource *currentSrc; + + QPtrList<KaffeineEpgPlugin> plugs; + QStringList plugNames; +}; + +#endif /* DVBEVENTS_H */ diff --git a/kaffeine/src/input/dvb/dvbout.cpp b/kaffeine/src/input/dvb/dvbout.cpp new file mode 100644 index 0000000..0ede057 --- /dev/null +++ b/kaffeine/src/input/dvb/dvbout.cpp @@ -0,0 +1,568 @@ +/* + * dvbout.cpp + * + * Copyright (C) 2004-2007 Christophe Thommeret <hftom@free.fr> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include <fcntl.h> + +#include <kstandarddirs.h> + +#include "dvbout.h" +#include "kaffeinedvbplugin.h" + +#define NTS 64 + +DVBout::DVBout( ChannelDesc chan, int anum, int tnum, KaffeineDvbPlugin *p ) +{ + bool bok; + bok = true; + unsigned int i, j=0, k; + + for( i = 0 ; i < 256 ; i++ ) { + k = 0; + for (j = (i << 24) | 0x800000 ; j != 0x80000000 ; j <<= 1) { + k = (k << 1) ^ (((k ^ j) & 0x80000000) ? 0x04c11db7 : 0); + } + CRC32[i] = k; + } + + plug = 0; + if ( p ) { + plug = p; + plugHandle = plug->init( chan.sid, anum, tnum, chan.fta ); + } + + fdPipe=0; + channel = chan; + thWrite = 0; + rtp = 0; + if ( channel.vpid ) + pids.append( channel.vpid ); + for ( i=0; i<channel.napid && i<MAX_AUDIO; i++ ) + pids.append( channel.apid[i].pid ); + for ( i=0; i<channel.nsubpid && i<MAX_DVBSUB; i++ ) + pids.append( channel.subpid[i].pid ); + wBuf = NULL; + timeShifting = beginLive = false; + haveRec = haveLive = instantRec = haveBroadcast = false; + patpmt = wpatpmt = false; + connect( &stopRecTimer, SIGNAL(timeout()), this, SLOT(stopRec()) ); + connect( &timerPatPmt, SIGNAL(timeout()), this, SLOT(setPatPmt()) ); + if ( !pids.contains(8192) ) + timerPatPmt.start(500); +} + + + +void DVBout::calculateCRC( unsigned char *p_begin, unsigned char *p_end ) +{ + unsigned int i_crc = 0xffffffff; + + // Calculate the CRC + while( p_begin < p_end ) { + i_crc = (i_crc<<8) ^ CRC32[ (i_crc>>24) ^ ((unsigned int)*p_begin) ]; + p_begin++; + } + + // Store it after the data + p_end[0] = (i_crc >> 24) & 0xff; + p_end[1] = (i_crc >> 16) & 0xff; + p_end[2] = (i_crc >> 8) & 0xff; + p_end[3] = (i_crc >> 0) & 0xff; +} + + + +void DVBout::writePat() +{ + int i; + + tspat[0x00] = 0x47; // sync_byte + tspat[0x01] = 0x40; + tspat[0x02] = 0x00; // PID = 0x0000 + tspat[0x03] = 0x10; // | (ps->pat_counter & 0x0f); + tspat[0x04] = 0x00; // pointer_field. CRC calculation begins here + tspat[0x05] = 0x00; // 0x00: Program association section + tspat[0x06] = 0xb0; + tspat[0x07] = 0x11; // section_length = 0x011 + tspat[0x08] = 0x00; + tspat[0x09] = 0xbb; // TS id = 0x00b0 (what the vlc calls "Stream ID") + tspat[0x0a] = 0xc1; + // section # and last section # + tspat[0x0b] = tspat[0x0c] = 0x00; + // Network PID (useless) + tspat[0x0d] = tspat[0x0e] = 0x00; tspat[0x0f] = 0xe0; tspat[0x10] = 0x10; + // Program Map PID + pmtpid = 0xff; + while ( pids.contains( pmtpid ) ) pmtpid--; + tspat[0x11] = 0x03; tspat[0x12] = 0xe8; tspat[0x13] = 0xe0; tspat[0x14] = pmtpid; + // Put CRC in ts[0x15...0x18] + calculateCRC( tspat + 0x05, tspat + 0x15 ); + // needed stuffing bytes + for (i=0x19 ; i < 188 ; i++) tspat[i]=0xff; +} + + + +void DVBout::writePmt() +{ + int i, off=0; + + tspmt[0x00] = 0x47; //sync_byte + tspmt[0x01] = 0x40; + tspmt[0x02] = pmtpid; + tspmt[0x03] = 0x10; + tspmt[0x04] = 0x00; // pointer_field. CRC calculation begins here + tspmt[0x05] = 0x02; // 0x02: Program map section + tspmt[0x06] = 0xb0; + tspmt[0x07] = 0x20; // section_length + tspmt[0x08] = 0x03; + tspmt[0x09] = 0xe8; // prog number + tspmt[0x0a] = 0xc1; + // section # and last section # + tspmt[0x0b] = tspmt[0x0c] = 0x00; + // PCR PID + tspmt[0x0d] = channel.vpid>>8; tspmt[0x0e] = channel.vpid&0xff; + // program_info_length == 0 + tspmt[0x0f] = 0xf0; tspmt[0x10] = 0x00; + // Program Map / Video PID + tspmt[0x11] = channel.vType; // video stream type + tspmt[0x12] = channel.vpid>>8; tspmt[0x13] = channel.vpid&0xff; + tspmt[0x14] = 0xf0; tspmt[0x15] = 0x09; // es info length + // useless info + tspmt[0x16] = 0x07; tspmt[0x17] = 0x04; tspmt[0x18] = 0x08; tspmt[0x19] = 0x80; + tspmt[0x1a] = 0x24; tspmt[0x1b] = 0x02; tspmt[0x1c] = 0x11; tspmt[0x1d] = 0x01; + tspmt[0x1e] = 0xfe; + off = 0x1e; + // audio pids + i = 0; + for ( i=0; i<channel.napid && i<MAX_AUDIO; i++ ) { + if ( channel.apid[i].ac3 ) { + tspmt[++off] = 0x81; // stream type = xine see this as ac3 + tspmt[++off] = channel.apid[i].pid>>8; tspmt[++off] = channel.apid[i].pid&0xff; + tspmt[++off] = 0x00; tspmt[++off] = 0x0c; // es info length + tspmt[++off] = 0x05; tspmt[++off] = 0x04; tspmt[++off] = 0x41; + tspmt[++off] = 0x43; tspmt[++off] = 0x2d; tspmt[++off] = 0x33; + } + else { + tspmt[++off] = 0x04; // stream type = audio + tspmt[++off] = channel.apid[i].pid>>8; tspmt[++off] = channel.apid[i].pid&0xff; + tspmt[++off] = 0xf0; tspmt[++off] = 0x06; // es info length + } + tspmt[++off] = 0x0a; // iso639 descriptor tag + tspmt[++off] = 0x04; // descriptor length + if ( !channel.apid[i].lang.isEmpty() ) { + tspmt[++off] = channel.apid[i].lang.constref(0); + tspmt[++off] = channel.apid[i].lang.constref(1); + if ( channel.apid[i].ac3 ) + tspmt[++off] = '_'; + else + tspmt[++off] = channel.apid[i].lang.constref(2); + } + else if ( channel.apid[i].ac3 ) { + tspmt[++off] = 'd'; + tspmt[++off] = 'd'; + tspmt[++off] = 49+i; + } + else { + tspmt[++off] = 'c'; + tspmt[++off] = 'h'; + tspmt[++off] = 49+i; + } + tspmt[++off] = 0x00; // audio type + } + // Subtitles + for ( i=0; i<channel.nsubpid && i<MAX_DVBSUB; i++ ) { + tspmt[++off] = 0x06; // stream type = ISO_13818_PES_PRIVATE + tspmt[++off] = channel.subpid[i].pid>>8; tspmt[++off] = channel.subpid[i].pid&0xff; + tspmt[++off] = 0xf0; tspmt[++off] = 0x0a; // es info length + tspmt[++off] = 0x59; //DVB sub tag + tspmt[++off] = 0x08; // descriptor length + if ( !channel.subpid[i].lang.isEmpty() ) { + tspmt[++off] = channel.subpid[i].lang.constref(0); + tspmt[++off] = channel.subpid[i].lang.constref(1); + tspmt[++off] = channel.subpid[i].lang.constref(2); + } + else { + tspmt[++off] = 'c'; + tspmt[++off] = 'h'; + tspmt[++off] = 49+i; + } + tspmt[++off] = channel.subpid[i].type; //sub type + tspmt[++off] = channel.subpid[i].page>>8; tspmt[++off] = channel.subpid[i].page&0xff; // comp_page_id + tspmt[++off] = channel.subpid[i].id>>8; tspmt[++off] = channel.subpid[i].id&0xff; // anc_page_id + } + tspmt[0x07] = off-3; // update section_length + // Put CRC in ts[0x29...0x2c] + calculateCRC( tspmt+0x05, tspmt+off+1 ); + // needed stuffing bytes + for (i=off+5 ; i < 188 ; i++) tspmt[i]=0xff; +} + + + +bool DVBout::hasInstantRec() const +{ + return instantRec; +} + + + +bool DVBout::hasRec() const +{ + return haveRec; +} + + + +bool DVBout::hasLive() const +{ + if ( haveLive || fdPipe || timeShifting ) + return true; + return false; +} + + + +bool DVBout::hasBroadcast() const +{ + return haveBroadcast; +} + + + +bool DVBout::doPause( const QString &name ) // called from dvbstream::run() +{ + if ( !haveLive ) + return false; + + if ( !timeShifting ) { + liveFile.setName( name ); + liveFile.open( IO_WriteOnly|IO_Truncate ); + liveFile.writeBlock( (char*)tspat, TS_SIZE ); + liveFile.writeBlock( (char*)tspmt, TS_SIZE ); + mutex.lock(); + haveLive = false; + mutex.unlock(); + if ( !wait(100) ) { + terminate(); + wait(); + } + mutex.lock(); + haveLive = true; + if ( close( fdPipe )<0 ) + perror("close out pipe: "); + else + fprintf(stderr,"out pipe closed\n"); + fdPipe = 0; + mutex.unlock(); + timeShifting = true; + //emit shifting( timeShifting ); + } + return true; +} + + + +void DVBout::setPatPmt() +{ + patpmt = true; +} + + + +bool DVBout::goLive( const QString &name ) +{ + if ( fdPipe ) return false; + + haveLive = true; + pipeName = name; + beginLive = true; + //activeApid = napid; + + writePat(); + writePmt(); + if ( !pids.contains(8192) ) + patpmt = wpatpmt = true; + wBuf = new unsigned char[TS_SIZE*NTS*100]; + if ( !wBuf ) fprintf( stderr, "\nNO WBUF !!!\n\n" ); + wRead = wWrite = wDist = 0; + start(); + return true; +} + + + +void DVBout::preStopLive() +{ + mutex.lock(); + haveLive = false; + mutex.unlock(); +} + + + +void DVBout::stopLive() +{ + mutex.lock(); + if ( timeShifting ) { + liveFile.close(); + timeShifting = false; + emit shifting( timeShifting ); + } + mutex.unlock(); + if ( !wait(500) ) { + terminate(); + wait(); + } + if ( fdPipe ) { + close( fdPipe ); + fprintf( stderr, "pipe closed\n" ); + fdPipe = 0; + } + delete [] wBuf; + wBuf = NULL; +} + + + +bool DVBout::goBroadcast( Ts2Rtp *r ) +{ + if ( haveBroadcast ) return false; + fprintf(stderr,"Start Broadcast: %s\n", channel.name.ascii() ); + rtp = r; + haveBroadcast = true; + return true; +} + + + +void DVBout::stopBroadcast() +{ + if ( !haveBroadcast ) return; + fprintf(stderr,"Stop Broadcast: %s\n", channel.name.ascii() ); + mutex.lock(); + rtp->removeChannels(); + haveBroadcast = false; + mutex.unlock(); +} + + + +bool DVBout::goRec( const QString &name, int maxsize, RecTimer *t ) +{ + QString fname=name; + + if ( haveRec ) + return false; + + recTimer = t; + fileName=name; + fileNumber=0; + + if (maxsize>0) { + fileMaxSize = (long long int)1048576*(long long int)maxsize; + fname=fileName+"_"+QString().setNum(fileNumber); + } + else { + fileMaxSize = 0; + fname=fileName; + } + if ( QFile(fname+".m2t").exists() ) + renameFile( fname, ".m2t" ); + writePat(); + writePmt(); + if ( channel.apid[0].pid!=8192 ) + patpmt = true; + outFile.setName( fname+".m2t" ); + if ( !outFile.open( IO_WriteOnly | IO_Truncate ) ) + return false; + outFile.writeBlock( (char*)tspat, TS_SIZE ); + outFile.writeBlock( (char*)tspmt, TS_SIZE ); + recTimer->fullPath = fname+".m2t"; + + haveRec = true; + if ( recTimer ) { + QTime t = recTimer->duration.addSecs( QDateTime::currentDateTime().secsTo(recTimer->begin) ); + stopRecTimer.start( QTime().msecsTo( t ), true ); + } + else + instantRec = true; + fprintf( stderr, "Recording started: %s\n", channel.name.latin1() ); + return true; +} + + + +void DVBout::renameFile( QString &name, const QString &ext ) +{ + int index=1; + + while ( QFile(name+"-"+QString().setNum(index)+ext).exists() ) + index++; + + name = name+"-"+QString().setNum(index); +} + + + +void DVBout::changeTimer( int ms ) +{ + if ( stopRecTimer.isActive() ) + stopRecTimer.changeInterval( ms ); +} + + + +void DVBout::stopRec() +{ + if ( !haveRec ) + return; + + if ( stopRecTimer.isActive() ) + stopRecTimer.stop(); + mutex.lock(); + outFile.close(); + mutex.unlock(); + haveRec = instantRec = false; + fprintf( stderr, "Recording stopped: %s\n", channel.name.latin1() ); + if ( !haveLive && !haveBroadcast ) + emit endRecord( this, recTimer, true ); + else + emit endRecord( this, recTimer, false ); +} + + + +void DVBout::process( unsigned char *buf, int size ) +{ + int i, pid; + unsigned char *buffer=buf; + QString fname; + + for ( i=0; i<size; i+=TS_SIZE ) { + pid = (((buffer[1] & 0x1f) << 8) | buffer[2]); + if ( pids.contains( pid ) || pids.contains( 8192) ) { + memcpy( thBuf+thWrite, buffer, TS_SIZE ); + thWrite+=TS_SIZE; + if ( thWrite==(TS_SIZE*NTS ) ) { + if ( plug && plugHandle ) + plug->process( plugHandle, thBuf, TS_SIZE*NTS ); + mutex.lock(); + if ( haveLive && fdPipe ) { + if ( beginLive ) { + beginLive = !beginLive; + start(); + } + if ( wDist<95 ) { + memcpy( wBuf+(wWrite*TS_SIZE*NTS), thBuf, TS_SIZE*NTS ); + wpatpmt = patpmt; + ++wDist; + ++wWrite; + if ( wWrite>99 ) + wWrite = 0; + //fprintf(stderr,"WDIST = %d\n",wDist); + } + } + else if ( timeShifting ) { + if ( patpmt ) { + liveFile.writeBlock( (char*)tspat, TS_SIZE ); + liveFile.writeBlock( (char*)tspmt, TS_SIZE ); + } + liveFile.writeBlock( (char*)thBuf, TS_SIZE*NTS ); + } + if ( haveRec && fileNumber>=0 ) { + if ((fileMaxSize>0)&&(outFile.size()>=fileMaxSize)) { + outFile.close(); + fileNumber++; + fname=fileName+"_"+QString().setNum(fileNumber); + if (QFile(fname+"_"+QString().setNum(fileNumber)+".m2t").exists() ) + renameFile( fname, ".m2t" ); + + outFile.setName( fname+".m2t" ); + if ( !outFile.open( IO_WriteOnly | IO_Truncate ) ) + fileNumber=-1; + else + { + outFile.writeBlock( (char*)tspat, TS_SIZE ); + outFile.writeBlock( (char*)tspmt, TS_SIZE ); + recTimer->fullPath = fname+".m2t"; + } + } + if (fileNumber>=0) + { + if ( patpmt ) { + outFile.writeBlock( (char*)tspat, TS_SIZE ); + outFile.writeBlock( (char*)tspmt, TS_SIZE ); + } + outFile.writeBlock( (char*)thBuf, TS_SIZE*NTS ); + } + + } + if ( haveBroadcast ) + rtp->process( thBuf, TS_SIZE*NTS ); + patpmt = false; + mutex.unlock(); + thWrite = 0; + } + } + buffer+=TS_SIZE; + } +} + + + +void DVBout::run() +{ + if ( haveLive && fdPipe ) { + while ( haveLive && fdPipe ) { + if ( wDist>0 ) { + if ( wpatpmt ) { + write( fdPipe, tspat, TS_SIZE ); + write( fdPipe, tspmt, TS_SIZE ); + wpatpmt = false; + } + write( fdPipe, wBuf+(wRead*TS_SIZE*NTS), TS_SIZE*NTS ); + --wDist; + ++wRead; + if ( wRead>99 ) + wRead = 0; + } + else + usleep( 100 ); + } + return; + } + + if ( (fdPipe=open( pipeName.ascii(), O_WRONLY))<0 ) { + perror("PIPE FILE: "); + return; + } + fprintf(stderr,"pipe opened\n"); + emit playDvb(); +} + + + +DVBout::~DVBout() +{ + if ( plug ) + plug->close( plugHandle ); +} + +#include "dvbout.moc" diff --git a/kaffeine/src/input/dvb/dvbout.h b/kaffeine/src/input/dvb/dvbout.h new file mode 100644 index 0000000..bc97b47 --- /dev/null +++ b/kaffeine/src/input/dvb/dvbout.h @@ -0,0 +1,118 @@ +/* + * dvbout.h + * + * Copyright (C) 2004-2007 Christophe Thommeret <hftom@free.fr> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef DVBOUT_H +#define DVBOUT_H + +#include <qobject.h> +#include <qthread.h> +#include <qmutex.h> +#include <qstring.h> +#include <qfile.h> +#include <qtimer.h> +#include <qvaluelist.h> + +#include "channeldesc.h" +#include "ts2rtp.h" +#include "gdvb.h" + +class KaffeineDvbPlugin; + +class DVBout : public QObject, public QThread +{ + Q_OBJECT + +public: + + DVBout( ChannelDesc chan, int anum, int tnum, KaffeineDvbPlugin *p ); + ~DVBout(); + void process( unsigned char *buf, int size ); + bool goLive( const QString &name ); + void preStopLive(); + void stopLive(); + bool goBroadcast( Ts2Rtp *r ); + void stopBroadcast(); + bool goRec( const QString &name, int maxsize, RecTimer *t ); + bool hasRec() const; + bool hasLive() const; + bool hasBroadcast() const; + bool hasInstantRec() const; + bool timeShiftMode() const; + bool doPause( const QString &name ); + void changeTimer( int ms ); + QValueList<int> pidsList() { return pids; } + + ChannelDesc channel; + QValueList<int> dmx, pids; + RecTimer *recTimer; + +public slots: + + void stopRec(); + +private slots: + + void setPatPmt(); + +private: + + void writePmt(); + void writePat(); + void calculateCRC( unsigned char *p_begin, unsigned char *p_end ); + void renameFile( QString &name, const QString &ext ); + + int pmtpid; + bool patpmt, wpatpmt; + bool timeShifting; + QString pipeName; + QFile outFile, liveFile; + int fdPipe; + Ts2Rtp *rtp; + unsigned char thBuf[188*100]; + unsigned char *wBuf; + int wRead, wWrite, wDist; + unsigned char tspat[188]; + unsigned char tspmt[188]; + unsigned int CRC32[256]; + int thWrite; + bool beginLive; + bool haveRec, haveLive, instantRec, haveBroadcast; + QTimer stopRecTimer, timerPatPmt; + QMutex mutex; + KaffeineDvbPlugin *plug; + void *plugHandle; + + int fileNumber; + QString fileName; + long long int fileMaxSize; + +signals: + + void playDvb(); + void endRecord(DVBout*, RecTimer*, bool); + void shifting(bool); + +protected: + + virtual void run(); + +}; + +#endif /* DVBOUT_H */ diff --git a/kaffeine/src/input/dvb/dvbpanel.cpp b/kaffeine/src/input/dvb/dvbpanel.cpp new file mode 100644 index 0000000..4d70760 --- /dev/null +++ b/kaffeine/src/input/dvb/dvbpanel.cpp @@ -0,0 +1,2673 @@ +/* + * dvbpanel.cpp + * + * Copyright (C) 2004-2007 Christophe Thommeret <hftom@free.fr> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include <sys/statvfs.h> + +#include <qlayout.h> +#include <qfile.h> +#include <qdir.h> +#include <qstringlist.h> +#include <qlabel.h> +#include <qpixmap.h> +#include <qtooltip.h> +#include <qwhatsthis.h> +#include <qapplication.h> +#include <qpopupmenu.h> +#include <qmap.h> + +#include <kiconloader.h> +#include <klocale.h> +#include <kmessagebox.h> +#include <kstandarddirs.h> +#include <kinputdialog.h> +#include <kicondialog.h> +#include <kaction.h> +#include <kprocess.h> +#include <kfiledialog.h> +#include <ktrader.h> +#include <kxmlguifactory.h> +#include <kparts/componentfactory.h> + +#include "kaffeineinput.h" +#include "kaffeinedvbplugin.h" +#include "dvbpanel.h" +#include "channeldesc.h" +#include "dvbstream.h" +#include "kevents.h" +#include "broadcasteditor.h" +#include "channeleditor.h" + +#define CHANICONSIZE 28 + + + +DIconViewItem::DIconViewItem( DvbPanel *pan, QIconView *parent, const QString &text, const QPixmap &icon ) + : KIconViewItem( parent, text, icon ) +{ + panel = pan; +} + + + +void DIconViewItem::dropped( QDropEvent *e, const QValueList<QIconDragItem> & ) +{ + QString s; + + if ( !dropEnabled() ) + return; + if ( QTextDrag::decode( e, s ) ) + panel->moveChannel( text(), s ); +} + + + +DListView::DListView( QWidget *parent ) : KListView( parent ) +{ + visibleItems = 0; +} + + + +QDragObject* DListView::dragObject() +{ + if ( currentItem() ) + return new QTextDrag( currentItem()->text(1), this ); + else + return 0; +} + + + +DvbPanel::DvbPanel( QWidget *parent, QObject *objParent, const char *name ) : KaffeineInput(objParent,name) +{ + browseDvbStream = -1; + plug = NULL; + + isTuning = false; + timeShiftFileName = ""; + timersDialog = 0; + currentCategory = "All"; + channels.setAutoDelete( true ); + timers.setAutoDelete( true ); + dvb.setAutoDelete( true ); + + mainWidget = new QVBox( parent ); + mainWidget->setSizePolicy( QSizePolicy (QSizePolicy::Preferred, QSizePolicy::Preferred) ); + split = new QSplitter( mainWidget ); + split->setOpaqueResize( true ); + pbox = new QVBox( split ); + iconView = new KIconView( pbox ); + iconView->setVScrollBarMode( QScrollView::AlwaysOff ); + iconView->setHScrollBarMode( QScrollView::AlwaysOff ); + iconView->horizontalScrollBar()->setFixedHeight( 0 ); + connect( iconView, SIGNAL(rightButtonPressed(QIconViewItem*,const QPoint&)), this, SLOT(catContextMenu(QIconViewItem*,const QPoint&)) ); + connect( iconView, SIGNAL(clicked(QIconViewItem*)), this, SLOT(catSelected(QIconViewItem*)) ); + iconView->setArrangement(QIconView::TopToBottom); + iconView->setMargin(0); + iconView->setSpacing(0); + iconView->setItemsMovable(false); + iconView->setResizeMode(QIconView::Adjust); + iconView->setSizePolicy( QSizePolicy( QSizePolicy::Preferred, QSizePolicy::Minimum ) ); + playerBox = new QVBox( pbox ); + playerBox->setMinimumWidth( 200 ); + panel = new QFrame( split ); + panel->setLineWidth(1); + panel->setFrameStyle(QFrame::Panel|QFrame::Sunken); + split->moveToFirst( panel ); + split->setResizeMode( panel, QSplitter::KeepSize ); + + QVBoxLayout *vb = new QVBoxLayout( panel, 3, 3 ); + channelsBtn = new QToolButton( panel ); + channelsBtn->setAutoRaise( true ); + QToolTip::add( channelsBtn, i18n("Channels")); + dateBtn = new QToolButton( panel ); + dateBtn->setAutoRaise( true ); + QToolTip::add( dateBtn, i18n("Timers")); + infoBtn = new QToolButton( panel ); + infoBtn->setAutoRaise( true ); + QToolTip::add( infoBtn, i18n("Electronic Program Guide")); + osdBtn = new QToolButton( panel ); + osdBtn->setAutoRaise( true ); + QToolTip::add( osdBtn, i18n("OSD")); + configBtn = new QToolButton( panel ); + configBtn->setAutoRaise( true ); + QToolTip::add( configBtn, i18n("DVB settings")); + recallBtn = new QToolButton( panel ); + recallBtn->setAutoRaise( true ); + QToolTip::add( recallBtn, i18n("Recall")); + QHBoxLayout *h1 = new QHBoxLayout(); + h1->addItem( new QSpacerItem( 1, 1, QSizePolicy::Preferred, QSizePolicy::Minimum ) ); + h1->addWidget( channelsBtn ); + h1->addWidget( dateBtn ); + h1->addWidget( infoBtn ); + h1->addWidget( osdBtn ); + h1->addWidget( configBtn ); + h1->addWidget( recallBtn ); + h1->addItem( new QSpacerItem( 1, 1, QSizePolicy::Preferred, QSizePolicy::Minimum ) ); + vb->addLayout( h1 ); + + h1 = new QHBoxLayout(); + searchBtn = new QToolButton( panel ); + searchBtn->setAutoRaise( true ); + QToolTip::add( searchBtn, i18n("Search channel(s)")); + QLabel* filterLabel = new QLabel( i18n("Filter") + ":", panel ); + searchLE = new KLineEdit( panel ); + searchLE->setFocusPolicy( QWidget::ClickFocus ); + h1->addWidget( searchBtn ); + h1->addWidget( filterLabel ); + h1->addWidget( searchLE ); + vb->addLayout( h1 ); + + channelsCb = new DListView( panel ); + channelsCb->setHScrollBarMode( QListView::AlwaysOff ); + //channelsCb->setPaletteBackgroundColor( QColor(255,255,200) ); + connect( channelsCb, SIGNAL(itemRenamed(QListViewItem*)), this, SLOT(channelNumberChanged(QListViewItem*)) ); + connect( channelsCb, SIGNAL(doubleClicked(QListViewItem*)), this, SLOT(channelSelected(QListViewItem*)) ); + connect( channelsCb, SIGNAL(clicked(QListViewItem*)), this, SLOT(channelClicked(QListViewItem*)) ); + connect( channelsCb, SIGNAL(contextMenuRequested(QListViewItem*,const QPoint&,int)), this, SLOT(channelPopup(QListViewItem*,const QPoint&,int)) ); + channelsCb->setItemsRenameable( true ); + channelsCb->addColumn( i18n("Number") ); + channelsCb->addColumn( i18n("Name") ); + channelsCb->addColumn( i18n("Source") ); + channelsCb->setAllColumnsShowFocus( true ); + channelsCb->setSizePolicy( QSizePolicy (QSizePolicy::Preferred, QSizePolicy::MinimumExpanding) ); + //channelsCb->setEnabled( false ); + vb->addWidget( channelsCb ); + + h1 = new QHBoxLayout(); + recordBtn = new QToolButton( panel ); + QToolTip::add( recordBtn, i18n("Instant Record") ); + recordBtn->setToggleButton( true ); + h1->addWidget( recordBtn ); + broadcastBtn = new QToolButton( panel ); + QToolTip::add( broadcastBtn, i18n("Broadcast") ); + h1->addWidget( broadcastBtn ); + vb->addLayout( h1 ); + + h1 = new QHBoxLayout(); + h1->addItem( new QSpacerItem( 1, 1, QSizePolicy::Preferred, QSizePolicy::Minimum ) ); + shiftLed = new KLed( panel ); + shiftLed->setSizePolicy( QSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed ) ); + shiftLed->setDarkFactor( 500 ); + shiftLed->off(); + QToolTip::add( shiftLed, i18n("Time shifting") ); + h1->addWidget( shiftLed ); + h1->addItem( new QSpacerItem( 1, 1, QSizePolicy::Preferred, QSizePolicy::Minimum ) ); + recordLed = new KLed( panel ); + recordLed->setSizePolicy( QSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed ) ); + recordLed->setColor( QColor( 255,0,0 ) ); + recordLed->setDarkFactor( 500 ); + recordLed->off(); + QToolTip::add( recordLed, i18n("Recording") ); + h1->addWidget( recordLed ); + h1->addItem( new QSpacerItem( 1, 1, QSizePolicy::Preferred, QSizePolicy::Minimum ) ); + broadcastLed = new KLed( panel ); + broadcastLed->setSizePolicy( QSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed ) ); + broadcastLed->setColor( QColor( 255,128,0 ) ); + broadcastLed->setDarkFactor( 500 ); + broadcastLed->off(); + QToolTip::add( broadcastLed, i18n("Broadcasting") ); + h1->addWidget( broadcastLed ); + h1->addItem( new QSpacerItem( 1, 1, QSizePolicy::Preferred, QSizePolicy::Minimum ) ); + vb->addLayout( h1 ); + + KIconLoader *icon = new KIconLoader(); + tvPix = icon->loadIcon( "kdvbtv", KIcon::Small ); + tvcPix = icon->loadIcon( "kdvbtvc", KIcon::Small ); + raPix = icon->loadIcon( "kdvbra", KIcon::Small ); + racPix = icon->loadIcon( "kdvbrac", KIcon::Small ); + QIconSet iconset; + iconset.setPixmap( icon->loadIcon( "filesave", KIcon::Small ), QIconSet::Small ); + iconset.setPixmap( icon->loadIcon( "player_record", KIcon::Small), QIconSet::Small, QIconSet::Normal, QIconSet::On ); + recordBtn->setIconSet( iconset ); + broadcastBtn->setIconSet( icon->loadIconSet("network_local", KIcon::Small) ); + dateBtn->setIconSet( icon->loadIconSet("date", KIcon::Small) ); + infoBtn->setIconSet( icon->loadIconSet("view_text", KIcon::Small) ); + osdBtn->setIconSet( icon->loadIconSet("info", KIcon::Small) ); + channelsBtn->setIconSet( icon->loadIconSet("kdvbtv", KIcon::Small) ); + configBtn->setIconSet( icon->loadIconSet("configure", KIcon::Small) ); + recallBtn->setIconSet( icon->loadIconSet("reload", KIcon::Small) ); + searchBtn->setIconSet( icon->loadIconSet("locationbar_erase", KIcon::Small) ); + + setXMLFile("kaffeinedvb.rc"); + setupActions(); + + connect( this, SIGNAL(zap(ChannelDesc*)), SLOT(dvbZap(ChannelDesc*)) ); + connect( configBtn, SIGNAL(clicked()), this, SLOT(showConfigDialog())); + connect( recallBtn, SIGNAL(clicked()), this, SLOT(recallZap())); + + connect( recordBtn, SIGNAL(clicked()), this, SLOT(setRecord()) ); + connect( broadcastBtn, SIGNAL(clicked()), this, SLOT(setBroadcast()) ); + connect( infoBtn, SIGNAL(clicked()), this, SLOT(showEvents()) ); + connect( channelsBtn, SIGNAL(clicked()), this, SLOT(scanner()) ); + connect( dateBtn, SIGNAL(clicked()), this, SLOT(showTimers()) ); + connect( osdBtn, SIGNAL(clicked()), this, SLOT(dvbOSD())); + connect( searchBtn, SIGNAL(clicked()), this, SLOT(resetSearch()) ); + connect(searchLE, SIGNAL(textChanged(const QString&)), this, SLOT(searchChannel(const QString&))); + + connect( &timersTimer, SIGNAL(timeout()), this, SLOT(checkTimers()) ); + connect( &osdTimer, SIGNAL(timeout()), this, SLOT(resetOSD()) ); + connect( &showOsdTimer, SIGNAL(timeout()), this, SLOT(dvbOSD()) ); + connect( &tuningTimer, SIGNAL(timeout()), this, SLOT(setTuning()) ); + connect( &stopTuningTimer, SIGNAL(timeout()), this, SLOT(setTuning()) ); + connect( &diskTimer, SIGNAL(timeout()), this, SLOT(diskStatus()) ); + + setConfig(); + + updown = 1; + autocount = 0; + delete icon; + + events.loadEpg(); +} + + + +void DvbPanel::togglePanel() +{ + if ( panel->isHidden() ) + panel->show(); + else + panel->hide(); +} + + + +void DvbPanel::diskStatus() +{ + double freemb; + struct statvfs buf; + + if ( statvfs( dvbConfig->shiftDir.local8Bit(), &buf ) ) { + fprintf(stderr,"Couldn't get file system statistics\n"); + return; + } + + freemb = (double)(((double)(buf.f_bavail)*(double)(buf.f_bsize))/(1024.0*1024.0)); + if ( freemb<300 ) + emit showOSD( i18n("Warning: low disc space")+QString(" (%1").arg((int)freemb)+i18n("MB")+")", 5000, 3 ); +} + + + +void DvbPanel::channelPopup( QListViewItem *it, const QPoint &pos, int col ) +{ + QPoint p=pos; + + if ( !it ) + return; + + int i=col, j; + QImage img; + QPixmap pix; + QString name = it->text(1); + QString s; + + QPopupMenu *pop = new QPopupMenu(); + pop->insertItem( i18n("Select icon..."), 1 ); + pop->insertItem( i18n("Edit..."), 2 ); + i = 0; + i = pop->exec( QCursor::pos() ); + switch ( i ) { + case 0 : + break; + case 1 : + s = KFileDialog::getOpenFileName( QString::null, "image/png image/jpeg image/gif image/x-bmp image/x-xpm", 0, i18n("Choose channel icon")); + if ( s.isEmpty() ) + break; + img = QImage( s ); + if ( img.isNull() ) + break; + if ( img.width()>img.height() ) + img = img.smoothScale( CHANICONSIZE, img.height()*CHANICONSIZE/img.width() ); + else + img = img.smoothScale( img.width()*CHANICONSIZE/img.height(), CHANICONSIZE ); + pix.convertFromImage( img ); + for ( j=0; j<(int)channels.count(); j++ ) { + if ( channels.at(j)->name==name ) { + channels.at(j)->pix = pix; + break; + } + } + pix.save( dvbConfig->dvbConfigIconsDir+name, "PNG" ); + fillChannelList(); + break; + case 2: + editChannel( name ); + break; + + } + delete pop; +} + +bool DvbPanel::editChannel( QString &name ) +{ + int j; + ChannelDesc *chan=0; + QStringList list; + QPixmap pix; + + for ( j=0; j<(int)channels.count(); j++ ) { + chan = channels.at(j); + if ( chan->name==name ) { + j = -1; + list.append( chan->tp.source ); + break; + } + } + if ( j==-1 ) { + ChannelEditor dlg( list, false, chan, &channels, mainWidget ); + int ret = dlg.exec(); + if ( ret==ChannelEditor::Accepted ) { + pix.load( dvbConfig->dvbConfigIconsDir+chan->name ); + if ( !pix.isNull() ) + chan->pix = pix; + else { + if ( chan->type==1 ) { + if ( chan->fta ) + pix = tvcPix; + else + pix = tvPix; + } + else { + if ( chan->fta ) + pix = racPix; + else + pix = raPix; + } + } + fillChannelList( chan ); + return true; + } + } + return false; +} + + + + +void DvbPanel::getTargets( QStringList &uiNames, QStringList &iconNames, QStringList &targetNames ) +{ + uiNames.append( i18n("Digital TV") ); + iconNames.append( "tv" ); + targetNames.append( "DVB" ); +} + + + +bool DvbPanel::execTarget( const QString &target ) +{ + if ( target=="DVB" ) { + if ( !channelsCb->isEnabled() ) { + KMessageBox::information( mainWidget, i18n("Live digital TV only works with the xine engine.") ); + return true; + } + emit showMe( this ); + QTimer::singleShot( 100, this, SLOT(playLastChannel()) ); + return true; + } + return false; +} + + + +void DvbPanel::setupActions() +{ + new KAction(i18n("OSD Next Channel"), "next", CTRL+SHIFT+Key_W, this, SLOT(dvbOSDNext()), actionCollection(), "dvb_browse_next"); + new KAction(i18n("OSD Previous Channel"), "previous", CTRL+SHIFT+Key_Q, this, SLOT(dvbOSDPrev()), actionCollection(),"dvb_browse_prev"); + new KAction(i18n("OSD Zap"), "ok", CTRL+SHIFT+Key_E, this, SLOT(dvbOSDZap()), actionCollection(), "dvb_browse_zap"); + new KAction(i18n("OSD Next Event"), "down", CTRL+SHIFT+Key_S, this, SLOT(dvbOSDAdvance()), actionCollection(), "dvb_browse_advance"); + new KAction(i18n("OSD Previous Event"), "up", CTRL+SHIFT+Key_A, this, SLOT(dvbOSDRetreat()), actionCollection(), "dvb_browse_retreat"); + new KAction(i18n("Instant Record"), "filesave", 0, this, SLOT(setRecord()), actionCollection(), "dvb_instant_record"); + new KAction(i18n("Recall"), "reload", CTRL+SHIFT+Key_Z, this, SLOT(recallZap()), actionCollection(), "dvb_recall"); + new KAction(i18n("Show OSD"), "info", Key_O, this, SLOT(dvbOSD()), actionCollection(), "dvb_show_osd"); + new KAction(i18n("EPG..."), "view_text", Key_G, this, SLOT(showEvents()), actionCollection(), "dvb_show_epg"); + new KAction(i18n("Timers..."), "date", Key_T, this, SLOT(showTimers()), actionCollection(), "dvb_show_timers"); + new KAction(i18n("Broadcasting..."), "network_local", Key_B, this, SLOT(setBroadcast()), actionCollection(), "dvb_show_broadcast"); + new KAction(i18n("Channels..."), "kdvbtv", Key_C, this, SLOT(scanner()), actionCollection(), "dvb_channels"); + new KAction(i18n("Configure DVB..."), "configure", CTRL|Key_C, this, SLOT(showConfigDialog()), actionCollection(), "dvb_config"); +} + + + +QWidget *DvbPanel::wantPlayerWindow() +{ + return playerBox; +} + + + +QWidget *DvbPanel::inputMainWidget() +{ + return mainWidget; +} + + + +void DvbPanel::searchChannel( const QString &text ) +{ + int i, c=-1; + QListViewItemIterator it( channelsCb ); + if ( !it.current() ) + return; + for ( i=0; i<channelsCb->columns(); i++ ) { + if ( channelsCb->columnText(i)==i18n("Name") ) { + c = i; + break; + } + } + if ( c==-1 ) + return; + + channelsCb->visibleItems = 0; + + while ( it.current() ) { + if ( text.isEmpty() || it.current()->text( c ).contains( text, false ) ) { + it.current()->setVisible(true); + ++channelsCb->visibleItems; + } + else { + it.current()->setVisible(false); + } + ++it; + } +} + + + +void DvbPanel::resetSearch() +{ + searchLE->clear(); + searchChannel( "" ); +} + + + +void DvbPanel::channelNumberChanged( QListViewItem *it ) +{ + int i, j; + bool ok; + unsigned int oldNum=0; + unsigned int num = it->text(0).toUInt( &ok, 10 ); + + for ( i=0; i<(int)channels.count(); i++ ) { + if ( channels.at(i)->name==it->text(1) ) { + oldNum = channels.at(i)->num; + break; + } + } + + if ( num && oldNum ) { + for ( j=0; j<(int)channels.count(); j++ ) { + if ( channels.at(j)->num==num ) { + channels.at(j)->num = oldNum; + channels.at(i)->num = num; + break; + } + } + } + + if ((int)num > maxChannelNumber) + maxChannelNumber = num; + if ((int)num < minChannelNumber) + minChannelNumber = num; + + fillChannelList(); +} + + + +void DvbPanel::catSelected( QIconViewItem *it ) +{ + if ( !it ) return; + + if ( it->text()==i18n("All") ) + currentCategory = "All"; + else if ( it->text()==i18n("TV") ) + currentCategory = "TV"; + else if ( it->text()==i18n("Radio") ) + currentCategory = "Radio"; + else + currentCategory = it->text(); + fillChannelList(); +} + + + +void DvbPanel::catContextMenu( QIconViewItem *it, const QPoint &p ) +{ + bool ok; + QString name, icon; + int i=0, ret; + + QPopupMenu *pop = new QPopupMenu(); + if ( !it ) { + pop->insertItem( i18n("New Category..."), 0 ); + } + else { + pop->insertItem( i18n("Change Icon..."), 1 ); + if ( it->text()!=i18n("All") && it->text()!=i18n("Radio") && it->text()!=i18n("TV") ) + pop->insertItem( i18n("Delete Category..."), 2 ); + } + i = pop->exec( p ); + switch ( i ) { + case 0 : + name = KInputDialog::getText( i18n("New Category"), i18n("Enter a name for this category:"), QString::null, &ok); + for ( QIconViewItem *qitem = iconView->firstItem(); qitem; qitem = qitem->nextItem() ) { + if ( qitem->text()==name ) + ok = false; + } + if ( ok ) { + KIconViewItem* item = new DIconViewItem(this, iconView, name, KGlobal::iconLoader()->loadIcon("kaffeine", KIcon::NoGroup, KIcon::SizeSmallMedium)); + item->setDropEnabled( true ); + dvbConfig->addCategory( name, "kaffeine" ); + } + break; + case 1 : + icon = KIconDialog::getIcon(); + if ( !icon.isEmpty() ) { + it->setPixmap( KGlobal::iconLoader()->loadIcon(icon, KIcon::NoGroup, KIcon::SizeSmallMedium) ); + dvbConfig->changeIconCategory( it->text(), icon ); + } + break; + case 2 : + ret = KMessageBox::questionYesNo( mainWidget, i18n("Do you really want to delete this category?") ); + if ( ret==KMessageBox::Yes ) { + dvbConfig->removeCategory( it->text() ); + delete it; + currentCategory = "All"; + fillChannelList(); + } + break; + } + delete pop; +} + + + +void DvbPanel::moveChannel( const QString &cat, const QString &name ) +{ + int i; + ChannelDesc *chan; + QListViewItem *it; + + for ( i=0; i<(int)channels.count(); i++ ) { + chan = channels.at(i); + if ( chan->name==name ) { + if ( cat==i18n("All") ) + chan->category = ""; + else + chan->category = cat; + it = channelsCb->currentItem(); + if ( it && currentCategory!="All" && currentCategory!="TV" && currentCategory!="Radio" ) + delete it; + break; + } + } +} + + + +void DvbPanel::dumpEvents() +{ + EventSource *esrc; + EventTsid *et; + EventSid *es; + QPtrList<EventDesc> *esEvents; + EventDesc *desc; + int i, k, j, m, n; + QString s; + + QFile f( QDir::homeDirPath()+"/kaffeine_dvb_events.txt" ); + if ( f.open(IO_WriteOnly|IO_Truncate) ) { + fprintf( stderr, "Creating events file.\n"); + QTextStream tt( &f ); + tt << "Saved: "+QDateTime::currentDateTime().toString( "dd-MM-yyyy hh:mm:ss" )+"\n"; + k= 0; + for( i=0; i<events.getNSource(); i++ ) { + if ( !(esrc=events.getNEventSource( i )) ) + continue; + tt << esrc->getSource()+QString(" : %1 TS with events.\n").arg( esrc->getNTsid() ); + for ( m=0; m<esrc->getNTsid(); m++ ) { + if ( !(et=esrc->getNEventTsid( m )) ) + continue; + tt << QString("TSID %1 : %2 services with events\n").arg( et->getTsid() ).arg( et->getNSid() ); + for ( n=0; n<et->getNSid(); n++ ) { + if ( !(es=et->getNEventSid( n )) ) + continue; + tt << QString(" SID %1 : %2 events\n").arg( es->getSid() ).arg( es->getNDesc() ); + k+= es->getNDesc(); + } + } + } + tt << "Number of events : "+s.setNum( k )+"\n"; + fprintf( stderr, "Number of events : %d\n", k ); + tt << "-------------------------\n"; + tt << "\n"; + for( i=0; i<events.getNSource(); i++ ) { + if ( !(esrc=events.getNEventSource( i )) ) + continue; + for ( m=0; m<esrc->getNTsid(); m++ ) { + if ( !(et=esrc->getNEventTsid( m )) ) + continue; + for ( n=0; n<et->getNSid(); n++ ) { + if ( !(es=et->getNEventSid( n )) ) + continue; + esEvents = es->getEvents(); + es->lock(); + for ( j=0; j<(int)esEvents->count(); j++ ) { + if ( !(desc=esEvents->at( j )) ) + continue; + tt << "Source: "+desc->source+"\n"; + tt << QString("Network ID: %1\n").arg(desc->nid); + tt << QString("Transport Stream ID: %1\n").arg(desc->tsid); + tt << QString("Service ID: %1\n").arg(desc->sid); + tt << QString("Event ID: %1\n").arg(desc->eid); + tt << "Title: "+desc->title+"\n"; + tt << "Subtitle: "+desc->subtitle+"\n"; + tt << desc->startDateTime.toString( "dd-MM-yyyy hh:mm:ss" )+"\n"; + tt << desc->duration.toString( "hh:mm:ss" )+"\n"; + s = ""; + for ( k=0; k<(int)desc->shortEvents.count(); k++ ) { + s = s + desc->shortEvents.at(k)->name; + if (!desc->shortEvents.at(k)->name.isEmpty() && !desc->shortEvents.at(k)->text.isEmpty()) { + s = s + " : "; + s = s + desc->shortEvents.at(k)->text; + s = s+". "; + } + } + for ( k=0; k<(int)desc->extEvents.count(); k++ ) + s = s+ *desc->extEvents.at(k); + tt << s+"\n"; + tt << "\n"; + } + es->unlock(); + } + } + } + f.close(); + } + else fprintf( stderr, "Can't create events file!\n"); +} + + + +void DvbPanel::channelClicked( QListViewItem *it ) +{ + QPtrListIterator<ChannelDesc> iter( channels ); + ChannelDesc *itdesc, *desc=0; + DvbStream *d = 0; + + if ( !it ) + return; + + iter.toFirst(); + while ( (itdesc=iter.current())!=0 ) { + if ( itdesc->name==it->text(1) ) { + desc = itdesc; + break; + } + ++iter; + } + + if ( !desc ) + return; + + for (int j = 0; j < (int)dvb.count(); j ++) { + if (dvb.at(j)->canSource(desc)) { + d = dvb.at(j); + break; + } + } + + osdMode = 0; + dvbOSD( *desc, d ); +} + + + +void DvbPanel::resetOSD() +{ + osdMode = 0; +} + + + +void DvbPanel::dvbOSD() +{ + DvbStream *d = 0; + + if (browseDvbStream != -1 && osdMode != 0) { + dvbOSDSkip(0); + return; + } + + for (int i=0; i<(int)dvb.count(); i++ ) { + if ( dvb.at(i)->hasLive() ) { + d = dvb.at(i); + break; + } + } + + if ( d ) + dvbOSD( d->getLiveChannel(), d ); +} + + + +void DvbPanel::dvbOSDZap() +{ + ChannelDesc *chan = 0; + + if (browseDvbStream == -1) + return; + + osdMode = 0; + + for (int i=0; i<(int)channels.count(); i++) { + if ((int) channels.at(i)->num == browseDvbStream) { + chan = channels.at(i); + break; + } + } + + if (!chan) + return; + + dvbZap(chan); +} + + + +void DvbPanel::dvbOSDNext() +{ + browseDvbTimeShift = -1; + osdMode = 0; + + dvbOSDSkip(1); +} + + + +void DvbPanel::dvbOSDSkip(int skip, int timeShift /* = 0 */) +{ + DvbStream *d = 0; + ChannelDesc *chan = 0; + + int mychan = -1; + + if (browseDvbStream == -1) + mychan = dvbConfig->lastChannel; + else + mychan = browseDvbStream + skip; + + if (mychan < minChannelNumber) + mychan = maxChannelNumber; + else if (mychan > maxChannelNumber) + mychan = minChannelNumber; + + for (int i = 0; i < (int)channels.count(); i ++) { + if ((int) channels.at(i)->num == mychan) { + chan = channels.at(i); + break; + } + } + + if (!chan) + return; + + for (int j = 0; j < (int)dvb.count(); j ++) { + if (dvb.at(j)->canSource(chan)) { + d = dvb.at(j); + break; + } + } + + if (!d) + return; + + browseDvbStream = chan->num; + + dvbOSD(*chan, d, timeShift); +} + + + +void DvbPanel::dvbOSDPrev() +{ + browseDvbTimeShift = -1; + osdMode = 0; + + dvbOSDSkip(-1); +} + + + +void DvbPanel::dvbOSDHide() +{ + browseDvbStream = -1; + browseDvbTimeShift = -1; +} + + + +void DvbPanel::dvbOSDAdvance() +{ + osdMode = 0; + + dvbOSDSkip(0, 1); +} + + + +void DvbPanel::dvbOSDRetreat() +{ + osdMode = 0; + + dvbOSDSkip(0, -1); +} + + + +void DvbPanel::dvbOSD(ChannelDesc liveChannel, DvbStream *d, int timeShift /* = 0 */) +{ + QStringList list; + EventSource *esrc; + EventSid *es; + QPtrList<EventDesc> *esEvents; + EventDesc *desc; + QString s; + int i, j, k; + int first=0; + + if ( !d || liveChannel.name.isEmpty() ) + return; + + if ( osdMode==2 ) { + osdTimer.stop(); + osdMode = 0; + list.append( "STOP" ); + emit showDvbOSD( s.setNum( liveChannel.num )+" - "+liveChannel.name, list ); + return; + } + + if ( osdMode==1 ) + osdTimer.stop(); + + if ( osdMode==0 ) { + if ( d->liveIsRecording() ) + list.append( "R" ); + if ( d->timeShiftMode() ) + list.append( "T" ); + } + else + list.append( "E" ); + + int myshift = 0; + + if (browseDvbTimeShift == -1) + myshift = 0; + else + myshift = browseDvbTimeShift + timeShift; + + if (myshift < 0) + myshift = 0; + + browseDvbTimeShift = myshift; + + k = 0; + + esrc = events.getEventSource( liveChannel.tp.source ); + es = esrc->getEventSid( liveChannel.tp.nid, liveChannel.tp.tsid, liveChannel.sid ); + if ( !es ) + goto end; + es->lock(); + esEvents = es->getEvents(); + + for ( j=myshift; j<(myshift+2); j++ ) { + desc = esEvents->at( j ); + if ( !desc ) + continue; + + if ( !desc->title.isEmpty() ) { + s = desc->startDateTime.toString( "hh:mm" ); + s = s+" - "; + s = s+desc->title; + if ( !osdMode && !first && !myshift ) { + QDateTime dt = QDateTime::currentDateTime(); + int secs = desc->startDateTime.secsTo( dt ); + i = QTime().secsTo( desc->duration ); + if ( i!=0 ) + i = secs*100/i; + if ( i>100 ) + i = 100; + list.append( QString("BAR")+QString().setNum( i ) ); + ++first; + } + list.append( s ); + k++; + } + else if ( osdMode ) + list.append( "" ); + if ( osdMode==0 ) { + if ( k>1 ) + break; + else + continue; + } + list.append( desc->subtitle ); + s = ""; + for ( i=0; i<(int)desc->shortEvents.count(); i++ ) { + s = s + desc->shortEvents.at(i)->name; + if (!desc->shortEvents.at(i)->name.isEmpty() && !desc->shortEvents.at(i)->text.isEmpty()) { + s+= " : "; + s+= desc->shortEvents.at(i)->text; + s+= ". "; + } + } + for ( i=0; i<(int)desc->extEvents.count(); i++ ) + s+= *desc->extEvents.at(i); + list.append( s ); + break; + } + es->unlock(); + +end: + if ( osdMode==0 ) + osdTimer.start( 5000, true ); + osdMode++; + emit showDvbOSD( s.setNum( liveChannel.num )+" - "+liveChannel.name, list ); +} + + + +void DvbPanel::enableLiveDvb( bool on ) +{ + channelsCb->setEnabled( on ); +} + + + +void DvbPanel::checkFirstRun() +{ + if ( dvbConfig->firstRun() ) + showConfigDialog(); +} + + + +void DvbPanel::setConfig() +{ + int i; + int error = 0; + KIconViewItem* item = NULL; + DvbStream *d; + + QString s = locateLocal("appdata", ""); + dvbConfig = new DVBconfig( s ); + item = new DIconViewItem(this, iconView, i18n("All"), KGlobal::iconLoader()->loadIcon(dvbConfig->allIcon, KIcon::NoGroup, KIcon::SizeSmallMedium)); + iconView->setFixedHeight( item->height()+iconView->horizontalScrollBar()->height() ); + item->setDropEnabled( true ); + item = new DIconViewItem(this, iconView, i18n("Radio"), KGlobal::iconLoader()->loadIcon(dvbConfig->radioIcon, KIcon::NoGroup, KIcon::SizeSmallMedium)); + item->setDropEnabled( false ); + item = new DIconViewItem(this, iconView, i18n("TV"), KGlobal::iconLoader()->loadIcon(dvbConfig->tvIcon, KIcon::NoGroup, KIcon::SizeSmallMedium)); + item->setDropEnabled( false ); + + KTrader::OfferList offers = KTrader::self()->query("KaffeineDvbPlugin"); + KTrader::OfferList::Iterator it = offers.begin(); + if ( it!=offers.end() ) { + KService::Ptr ptr = (*it); + plugName = ptr->desktopEntryName(); + plug = KParts::ComponentFactory::createPartInstanceFromService<KaffeineDvbPlugin>(ptr, 0, ptr->name().ascii(), 0, 0, 0, &error); + if (error > 0) { + fprintf( stderr, "Loading of DVB plugin failed: %s\n", KLibLoader::self()->lastErrorMessage().ascii() ); + plug = NULL; + } + else { + fprintf( stderr, "DVB plugin loaded\n."); + } + } + + for ( i=0; i<(int)dvbConfig->categories.count(); i++ ) { + item = new DIconViewItem(this, iconView, dvbConfig->categories.at(i)->name, KGlobal::iconLoader()->loadIcon(dvbConfig->categories.at(i)->icon, KIcon::NoGroup, KIcon::SizeSmallMedium)); + item->setDropEnabled( true ); + } + + for ( i=0; i<(int)dvbConfig->devList.count(); i++ ) { + d = new DvbStream( dvbConfig->devList.at(i), dvbConfig->defaultCharset, &events ); + d->setPlug( plug ); + dvb.append( d ); + connect( d, SIGNAL(shifting(bool)), this, SLOT(setShiftLed(bool)) ); + connect( d, SIGNAL(isBroadcasting(bool)), this, SLOT(setBroadcastLed(bool)) ); + connect( d, SIGNAL(timerEnded(RecTimer*)), this, SLOT(killTimer(RecTimer*)) ); + connect( d, SIGNAL(isRecording(bool)), this, SLOT(setRecordLed(bool)) ); + connect( d, SIGNAL(playDvb()), this, SLOT(pipeOpened()) ); + } + fifoName = QDir::homeDirPath()+"/.kaxtv.ts"; + QFile f( fifoName ); + if ( f.exists() ) + f.remove(); + if ( (mkfifo( fifoName.ascii(), 0644 ))<0 ) { + perror( fifoName.latin1() ); + fifoName = ""; + } + fifoName1 = QDir::homeDirPath()+"/.kaxtv1.ts"; + QFile f1( fifoName1 ); + if ( f1.exists() ) + f1.remove(); + if ( (mkfifo( fifoName1.ascii(), 0644 ))<0 ) { + perror( fifoName1.latin1() ); + fifoName1 = ""; + } + currentFifo = fifoName; + getTimerList(); + timersTimer.start( 5000 ); + getChannelList(); + rtp = new Ts2Rtp(); + rtp->setSocket( dvbConfig->broadcastAddress, dvbConfig->broadcastPort, dvbConfig->senderPort ); + cleaner = new Cleaner( dvbConfig->shiftDir, dvbConfig->recordDir ); + split->setSizes( dvbConfig->splitSizes ); + recallChannel = dvbConfig->lastChannel; +} + + + +void DvbPanel::showConfigDialog() +{ + int ret; + +loop: + if ( !dvbConfig->haveData() ) { + ret = KMessageBox::questionYesNo( mainWidget, i18n("<qt>Can't get DVB data from http://hftom.free.fr/kaxtv/dvbdata.tar.gz!<br>\ + Check your internet connection, and say Yes to try again.<br>\ + Or say No to cancel.<br>\ + If you already have this archive, copy it to ~/.kde/share/apps/kaffeine/dvbdata.tar.gz and say Yes.<br><br>Should I try again?</qt>") ); + if ( ret==KMessageBox::Yes ) + goto loop; + return; + } + + DvbConfigDialog dlg( dvbConfig, mainWidget, plug ); + connect( dlg.dumpBtn, SIGNAL(clicked()), this, SLOT(dumpEvents()) ); + ret = dlg.exec(); + disconnect( dlg.dumpBtn, SIGNAL(clicked()), this, SLOT(dumpEvents()) ); + if ( ret==DvbConfigDialog::Rejected ) + return; + rtp->setSocket( dvbConfig->broadcastAddress, dvbConfig->broadcastPort, dvbConfig->senderPort ); + cleaner->setPaths( dvbConfig->shiftDir, dvbConfig->recordDir ); +} + + + +QPtrList<Transponder> DvbPanel::getSourcesStatus() +{ + int i, j; + QStringList list; + QPtrList<Transponder> ss; + Transponder t; + + for ( i=0; i<(int)dvb.count(); i++ ) { + list = dvb.at(i)->getSources(); + for ( j=0; j<(int)list.count(); j++ ) { + if ( dvb.at(i)->hasRec() || dvb.at(i)->hasBroadcast() ) + t = dvb.at(i)->getCurrentTransponder(); + else { + t = Transponder(); + t.source = list[j]; + } + ss.append( new Transponder( t ) ); + } + } + return ss; +} + + + +void DvbPanel::fillChannelList( ChannelDesc *ch ) +{ + int i, j; + ChannelDesc *chan; + KListViewItem *it, *visible=0; + bool cont=false; + QPtrList<Transponder> trans = getSourcesStatus(); + trans.setAutoDelete( true ); + + searchLE->clear(); + channelsCb->clear(); + for ( i=0; i<(int)channels.count(); i++ ) { + chan = channels.at(i); + for ( j=0; j<(int)trans.count(); j++ ) { + cont = false; + if ( trans.at(j)->source==chan->tp.source ) { + if ( trans.at(j)->freq ) { + if ( chan->tp==*trans.at(j) ) break; + } + else + break; + } + cont = true; + } + if ( cont ) + continue; + if ( currentCategory=="TV" ) { + if ( chan->type!=1 ) + continue; + } + else if ( currentCategory=="Radio" ) { + if ( chan->type!=2 ) + continue; + } + else if ( currentCategory!="All" && chan->category!=currentCategory ) + continue; + it = new KListViewItem( channelsCb, QString().sprintf("%04d", chan->num), chan->name, chan->tp.source ); + if ( ch && ch==chan ) + visible = it; + it->setDragEnabled( true ); + chan->pix.load( dvbConfig->dvbConfigIconsDir+chan->name ); + if ( !chan->pix.isNull() ) + it->setPixmap( 1, chan->pix ); + else { + if ( chan->type==1 ) { + if ( chan->fta ) + it->setPixmap( 1, tvcPix ); + else + it->setPixmap( 1, tvPix ); + } + else { + if ( chan->fta ) + it->setPixmap( 1, racPix ); + else + it->setPixmap( 1, raPix ); + } + } + } + channelsCb->visibleItems = channelsCb->childCount(); + trans.clear(); + if ( visible ) { + channelsCb->ensureItemVisible( visible ); + channelsCb->setSelected( visible, true ); + } +} + + + +DvbStream* DvbPanel::getWorkingDvb( int mode, ChannelDesc *chan ) +{ + int i, ret; + QValueList<int> working; // notTuned=0, hasLive=1, hasBroadcast=2, hasRec=3, can'tDoChannel=4 + + for ( i=0; i<(int)dvb.count(); i++ ) + working.append( 0 ); + + // fill in working status + for ( i=0; i<(int)dvb.count(); i++ ) { + if ( !dvb.at(i)->canSource( chan ) ) { + working[i] = 4; + continue; + } + if ( dvb.at(i)->isTuned() ) { + if ( dvb.at(i)->getCurrentTransponder()==chan->tp ) { + return dvb.at(i); // use that one since it's already tuned on the good mplex + } + else if ( dvb.at(i)->hasRec() ) + working[i] = 3; + else if ( dvb.at(i)->hasBroadcast() ) + working[i] = 2; + else + working[i] = 1; + } + else + working[i] = 0; + } + ret = 0; + // search for least working card + for ( i=1; i<(int)working.count(); i++ ) { + if ( working[i]<working[0] ) { + working[0] = working[i]; + ret = i; + } + } + if ( working[0]<mode ) + return dvb.at(ret); + else + return 0; +} + + + +void DvbPanel::setBroadcast() +{ + int ret, i; + QPtrList<ChannelDesc> list; + bool live=false; + DvbStream *d; + + BroadcastEditor dlg( mainWidget, &channels, &list ); + ret = dlg.exec(); + if ( ret==BroadcastEditor::Rejected ) + return; + + for ( i=0; i<(int)dvb.count(); i++ ) { + if ( dvb.at(i)->hasBroadcast() ) + dvb.at(i)->stopBroadcast(); + } + if ( ! list.count() ) { + return; + } + + d = getWorkingDvb( 2, list.at(0) ); + + if ( d ) + ret = d->canStartBroadcast( live, list.at(0) ); + else + ret = -1; + if ( ret==0 ) { + if ( live ) { + stopLive(); + emit dvbStop(); + } + if ( !d->startBroadcast( &list, rtp ) ) { + KMessageBox::information( mainWidget, i18n("Broadcasting failed.") ); + } + } + else + KMessageBox::information( mainWidget, i18n("Can't start broadcasting.") ); +} + + + +void DvbPanel::checkTimers() +{ + int i, j, ret; + bool live=false; + RecTimer *t; + ChannelDesc *chan; + QDateTime cur=QDateTime::currentDateTime(); + DvbStream *d; + + for ( i=0; i<(int)timers.count(); i++ ) { + t = timers.at(i); + if ( t->running ) + continue; + if ( t->begin<=cur && cur<t->begin.addSecs(QTime().secsTo(t->duration)) ) { + chan = 0; + for ( j=0; j<(int)channels.count(); j++ ) { + if ( channels.at(j)->name==t->channel ) { + chan = channels.at(j); + break; + } + } + if ( !chan ) + continue; + d = getWorkingDvb( 3, chan ); + live = false; + if ( d ) + ret = d->canStartTimer( live, chan ); + else + ret = -1; + if ( ret==0 ) { + if ( live ) { + stopLive(); + emit dvbStop(); + } + if ( d->startTimer( chan, dvbConfig->recordDir, dvbConfig->sizeFile, t, dvbConfig->filenameFormat ) ) { + KProcess proc; + proc << QDir::homeDirPath()+"/bin/kaffeine_recording"; + proc << "On"; + proc.start( KProcess::DontCare ); + t->running = 1; + if ( timersDialog ) + emit timersChanged(); + saveTimerList(); + i--; + } + else + fprintf( stderr, "start timer failed!!!\n" ); + } + else + fprintf( stderr, "Cant start timer !!!\n" ); + } + else if ( t->mode ) { + if (t->begin.addSecs(t->duration.hour()*3600+t->duration.minute()*60+60)<cur) { + updateModeTimer( t ); + if ( timersDialog ) + emit timersChanged(); + } + } + } +} + + + +void DvbPanel::setRecord() +{ + ChannelDesc curchan; + QString s=""; + int ret, i, r=0; + bool live=false; + RecTimer *t, *rt; + EventDesc *desc; + DvbStream *d=0; + + for ( i=0; i<(int)dvb.count(); i++ ) { + if ( dvb.at(i)->hasLive() ) { + d = dvb.at(i); + curchan = d->getLiveChannel(); + break; + } + } + if ( !d ) { + recordBtn->setOn( false ); + showTimers(); + return; + } + + desc = events.getEventDesc( curchan.tp.source, curchan.tp.nid, curchan.tp.tsid, curchan.sid, 0 ); + + if ( desc ) + s = desc->title; + + if ( s.isEmpty() ) { + if ( !dvbConfig->filenameFormat.contains("%chan") ) + s = curchan.name; + if ( !dvbConfig->filenameFormat.contains("%date") ) + s+="_"+QDateTime::currentDateTime().toString( "yyyyMMdd-hhmmss" ); + } + + rt = new RecTimer(); + rt->name = s; + rt->channel = curchan.name; + rt->begin = QDateTime::currentDateTime(); + rt->duration = QTime( 0,0,0).addSecs( dvbConfig->instantDuration*60 ) ; + rt->running = 1; + rt->mode = 0; + + ret = d->canStartTimer( live, &curchan ); + if ( ret==0 ) { + if ( d->startTimer( &curchan, dvbConfig->recordDir, dvbConfig->sizeFile, rt, dvbConfig->filenameFormat ) ) { + KProcess proc; + proc << QDir::homeDirPath()+"/bin/kaffeine_recording"; + proc << "On"; + proc.start( KProcess::DontCare ); + + for ( i=0; i<(int)timers.count(); i++ ) { + t = timers.at(i); + if ( rt->begin>t->begin ) + r=i+1; + } + timers.insert( r, rt ); + if ( timersDialog ) + emit timersChanged(); + saveTimerList(); + emit showOSD( i18n("Instant Record successfully started"), 5000, 3 ); + } + else { + KMessageBox::information( mainWidget, i18n("Instant Recording failed to start.") ); + fprintf( stderr, "DvbPanel::setRecord:start timer failed!\n" ); + delete rt; + } + } + else { + delete rt; + for ( i=0; i<(int)timers.count(); i++ ) { + t = timers.at(i); + if ( d->liveIsRecording() && t->running && curchan.name == t->channel ) { + d->updateTimer( t, 0 ); + emit showOSD( i18n("Recording successfully stopped"), 5000, 3 ); + return; + } + } + showTimers(); + } +} + + + +void DvbPanel::setRecordLed( bool on ) +{ + int i; + bool rec=false; + + if ( on ) { + recordLed->on(); + fillChannelList(); + } + else { + for ( i=0; i<(int)dvb.count(); i++ ) { + if ( dvb.at(i)->hasRec() ) { + rec = true; + break; + } + } + if ( !rec ) + recordLed->off(); + else + recordLed->on(); + fillChannelList(); + } + + for ( i=0; i<(int)dvb.count(); i++ ) { + if ( dvb.at(i)->liveIsRecording() ) { + recordBtn->setOn( true ); + return; + } + } + recordBtn->setOn( false ); +} + + +void DvbPanel::setBroadcastLed( bool on ) +{ + int i; + bool broad=false; + + if ( on ) { + broadcastLed->on(); + fillChannelList(); + } + else { + for ( i=0; i<(int)dvb.count(); i++ ) { + if ( dvb.at(i)->hasBroadcast() ) { + broad = true; + break; + } + } + if ( !broad ) + broadcastLed->off(); + else + broadcastLed->on(); + fillChannelList(); + } +} + + + +void DvbPanel::killTimer( RecTimer *t ) +{ + int i; + + for ( i=0; i<(int)timers.count(); i++ ) { + if ( timers.at(i)==t ) { + KProcess proc; + proc << QDir::homeDirPath()+"/bin/kaffeine_recording"; + if ( recordLed->state()==KLed::On ) + proc << "On"; + else + proc << "Off"; + proc << KProcess::quote( t->fullPath ); + proc.start( KProcess::DontCare ); + + if ( t->mode ) + updateModeTimer( t ); + else + timers.remove( t ); + if ( timersDialog ) + emit timersChanged(); + return; + } + } +} + + + +void DvbPanel::updateModeTimer( RecTimer *t ) +{ + int stop=0, r=0, i; + + if ( t->mode==CronTimer::Daily ) + t->begin = t->begin.addDays(1); + else if ( t->mode==CronTimer::Weekly ) + t->begin = t->begin.addDays(7); + else if ( t->mode==CronTimer::Monthly ) + t->begin = t->begin.addMonths(1); + else while ( !stop ) { + t->begin = t->begin.addDays(1); + if ( (t->begin.date().dayOfWeek()==1) && (t->mode&CronTimer::Monday) ) stop++; + else if ( (t->begin.date().dayOfWeek()==2) && (t->mode&CronTimer::Tuesday) ) stop++; + else if ( (t->begin.date().dayOfWeek()==3) && (t->mode&CronTimer::Wednesday) ) stop++; + else if ( (t->begin.date().dayOfWeek()==4) && (t->mode&CronTimer::Thursday) ) stop++; + else if ( (t->begin.date().dayOfWeek()==5) && (t->mode&CronTimer::Friday) ) stop++; + else if ( (t->begin.date().dayOfWeek()==6) && (t->mode&CronTimer::Saturday) ) stop++; + else if ( (t->begin.date().dayOfWeek()==7) && (t->mode&CronTimer::Sunday) ) stop++; + } + + RecTimer *nt = new RecTimer(); + nt->name = t->name; + nt->channel = t->channel; + nt->begin = t->begin; + nt->duration = t->duration; + nt->running = 0; + nt->mode = t->mode; + timers.remove( t ); + for ( i=0; i<(int)timers.count(); i++ ) { + t = timers.at(i); + if ( nt->begin>t->begin ) + r=i+1; + } + timers.insert( r, nt ); +} + + + +void DvbPanel::showTimers() +{ + int i; + QStringList list; + QMap<QString,QString> map; + + if ( channels.count()==0 ) { + KMessageBox::sorry( 0, i18n("You may want to define some channel first!") ); + return; + } + for ( QPtrListIterator<ChannelDesc> it(channels); it.current(); ++it ) + map[it.current()->name] = it.current()->name; + QMap<QString,QString>::Iterator it; + QMap<QString,QString>::Iterator end(map.end()); + for ( it = map.begin(); it != end; ++it ) + list.append( it.data() ); + + timersDialog = new KRecord( list, &timers, mainWidget, dvbConfig->timerSize ); + for ( i=0; i<(int)dvb.count(); i++ ) { + connect( timersDialog, SIGNAL(updateTimer(RecTimer*,int)), dvb.at(i), SLOT(updateTimer(RecTimer*,int)) ); + } + connect( this, SIGNAL(timersChanged()), timersDialog, SLOT(refresh()) ); + timersDialog->exec(); + for ( i=0; i<(int)dvb.count(); i++ ) { + disconnect( timersDialog, SIGNAL(updateTimer(RecTimer*,int)), dvb.at(i), SLOT(updateTimer(RecTimer*,int)) ); + } + disconnect( this, SIGNAL(timersChanged()), timersDialog, SLOT(refresh()) ); + dvbConfig->timerSize = timersDialog->size(); + delete timersDialog; + timersDialog = 0; + saveTimerList(); +} + + + +int DvbPanel::getSNR( int device ) +{ + if ( device<0 || device>=(int)dvb.count() ) + return -1; + return dvb.at(device)->getSNR(); +} + + +void DvbPanel::dvbNewTimer( QString name, QString channel, QString datetime, QString duration ) +{ + newTimer( channel, name, QDateTime::fromString( datetime, Qt::ISODate ), QTime::fromString( duration ), false ); +} + + + +void DvbPanel::newTimer( QString channel, QString name, QDateTime begin, QTime duration, bool warn ) +{ + int i, r=0; + RecTimer *t; + RecTimer *rt = new RecTimer(); + + rt->name = name.replace("/","_").replace(">","_").replace("<","_").replace(":","_").replace('"',"_").replace("\\","_").replace("|","_"); + rt->channel = channel; + rt->begin = begin.addSecs( -(dvbConfig->beginMargin*60) ); + rt->duration = duration.addSecs( (dvbConfig->beginMargin+dvbConfig->endMargin)*60 ) ; + rt->running = 0; + rt->mode = 0; + + for ( i=0; i<(int)timers.count(); i++ ) { + t = timers.at(i); + if ( rt->begin>t->begin ) + r=i+1; + } + timers.insert( r, rt ); + if ( warn ) + KMessageBox::information( 0, i18n("Timer successfully created.") ); +} + + + +void DvbPanel::scanner() +{ + int ret; + +loop: + if ( !dvbConfig->haveData() ) { + ret = KMessageBox::questionYesNo( mainWidget, i18n("<qt>Can't get DVB data from http://hftom.free.fr/kaxtv/dvbdata.tar.gz!<br>\ + Check your internet connection, and say Yes to try again.<br>\ + Or say No to cancel.<br>\ + If you already have this archive, copy it to ~/.kde/share/apps/kaffeine/dvbdata.tar.gz and say Yes.<br><br>Should I try again?</qt>") ); + if ( ret==KMessageBox::Yes ) + goto loop; + return; + } + + if ( !dvbConfig->haveData() ) + return; + ScanDialog dlg( &dvb, &channels, dvbConfig->scanSize, dvbConfig->dvbConfigDir, dvbConfig->defaultCharset ); + dlg.exec(); + dvbConfig->scanSize = dlg.size(); + fillChannelList(); + saveChannelList(); +} + + + +void DvbPanel::showEvents() +{ + events.doClean( false ); + KEvents dlg( &channels, &dvb, &events, mainWidget, dvbConfig->epgSize ); + connect( &dlg, SIGNAL(addTimer(QString,QString,QDateTime,QTime)), this, SLOT(newTimer(QString,QString,QDateTime,QTime)) ); + connect( &dlg, SIGNAL(zapTo(const QString &)), this, SLOT(channelSelected(const QString &)) ); + dlg.exec(); + dvbConfig->epgSize = dlg.size(); + disconnect( &dlg, SIGNAL(addTimer(QString,QString,QDateTime,QTime)), this, SLOT(newTimer(QString,QString,QDateTime,QTime)) ); + disconnect( &dlg, SIGNAL(zapTo(const QString &)), this, SLOT(channelSelected(const QString &)) ); + events.doClean( true ); +} + + + +void DvbPanel::setShiftLed( bool on ) +{ + if ( on ) { + shiftLed->on(); + diskTimer.start( 300000 ); + } + else { + shiftLed->off(); + diskTimer.stop(); + } +} + + + +void DvbPanel::channelSelected( const QString &name ) +{ + QPtrListIterator<ChannelDesc> iter( channels ); + ChannelDesc *itdesc; + + iter.toFirst(); + while ( (itdesc=iter.current())!=0 ) { + if ( itdesc->name==name ) { + dvbZap( itdesc ); + break; + } + ++iter; + } +} + + + +void DvbPanel::channelSelected( QListViewItem *it ) +{ + QPtrListIterator<ChannelDesc> iter( channels ); + ChannelDesc *itdesc; + + if ( !it ) + return; + + iter.toFirst(); + while ( (itdesc=iter.current())!=0 ) { + if ( itdesc->name==it->text(1) ) { + dvbZap( itdesc ); + break; + } + ++iter; + } +} + + + +bool DvbPanel::nextTrack( MRL& ) +{ + next(); + return false; +} + + + +bool DvbPanel::previousTrack( MRL& ) +{ + previous(); + return false; +} + + + +bool DvbPanel::currentTrack( MRL& ) +{ + playLastChannel(); + return false; +} + + + +bool DvbPanel::trackNumber( int num, MRL& ) +{ + playNumChannel( num ); + return false; +} + + + +void DvbPanel::recallZap() +{ + emit showMe( this ); + playNumChannel( recallChannel ); +} + + + +void DvbPanel::playNumChannel( int num ) +{ + int j; + bool ok=false; + + if ( !channelsCb->isEnabled() ) + return; + + for ( j=0; j<(int)channels.count(); j++ ) { + if ( (int)channels.at(j)->num==num ) { + ok = true; + break; + } + } + + if ( ok ) + dvbZap( channels.at( j ) ); +} + + + +bool DvbPanel::playbackFinished( MRL& ) +{ + return false; +} + + + +void DvbPanel::playLastChannel() +{ + /*int ret, i, j; + QPtrList<ChannelDesc> list; + bool live=false, ok=false; + DvbStream *d; + + for ( i=0; i<(int)dvb.count(); i++ ) { + if ( dvb.at(i)->hasBroadcast() ) + dvb.at(i)->stopBroadcast(); + } + ++dvbConfig->lastChannel; + if ( dvbConfig->lastChannel>channels.count() ) + dvbConfig->lastChannel = 1; + for ( j=0; j<(int)channels.count(); j++ ) { + if ( (int)channels.at(j)->num==dvbConfig->lastChannel ) { + ok = true; + list.append( channels.at(j) ); + break; + } + } + if ( ! list.count() ) { + QTimer::singleShot( 2000, this, SLOT(playLastChannel()) ); + return; + } + d = getWorkingDvb( 2, list.at(0) ); + if ( d ) + ret = d->canStartBroadcast( live, list.at(0) ); + else + ret = -1; + if ( ret==0 ) { + if ( live ) { + stopLive(); + emit dvbStop(); + } + if ( !d->startBroadcast( &list, rtp ) ) { + fprintf( stderr, "Broadcasting failed.\n" ); + } + else { + fprintf( stderr, "Tuning to: %s / autocount: %lu\n", channels.at(j)->name.ascii(), autocount ); + ++autocount; + } + } + else + fprintf( stderr, "Can't start broadcasting.\n"); + + QTimer::singleShot( 2000, this, SLOT(playLastChannel()) ); + return;*/ + + + + + int j; + bool ok=false; + + if ( !channelsCb->isEnabled() ) + return; + + for ( j=0; j<(int)channels.count(); j++ ) { + if ( (int)channels.at(j)->num==dvbConfig->lastChannel ) { + ok = true; + break; + } + } + if ( !ok ) + return; + + dvbZap( channels.at(j) ); +} + + + +void DvbPanel::next() +{ + if ( !channelsCb->isEnabled() ) + return; + + QListViewItem* nextItem; + + QListViewItem* playingItem = channelsCb->findItem( QString().sprintf("%04d", dvbConfig->lastChannel), 0 ); + + if ( !playingItem == 0 ) // yes, it's in the current category + { + if ( playingItem == channelsCb->lastItem() ) + nextItem = channelsCb->firstChild(); // wrap around + else + nextItem = playingItem->itemBelow(); + } + else // not in current category, user has switched category, use first in current cat + nextItem = channelsCb->firstChild(); + + channelsCb->setSelected( nextItem, true ); + channelSelected( nextItem ); + +} + + + +void DvbPanel::previous() +{ + if ( !channelsCb->isEnabled() ) + return; + + QListViewItem* prevItem; + + QListViewItem* playingItem = channelsCb->findItem( QString().sprintf("%04d", dvbConfig->lastChannel), 0 ); + + if ( !playingItem == 0 ) // yes, it's in the current category + { + if ( playingItem == channelsCb->firstChild() ) + prevItem = channelsCb->lastItem(); // wrap around + else + prevItem = playingItem->itemAbove(); + } + else // not in current category, user has switched category, use first in current cat + prevItem = channelsCb->firstChild(); + + channelsCb->setSelected( prevItem, true ); + channelSelected( prevItem ); +} + + + +void DvbPanel::dvbZap( ChannelDesc *chan ) +{ + int i; + DvbStream *d=0; + + if ( currentFifo.isEmpty() || isTuning ) + return; + + isTuning = true; + emit setTimeShiftFilename( "" ); + for ( i=0; i<(int)dvb.count(); i++ ) { + if ( dvb.at(i)->getCurrentTransponder()==chan->tp ) { + d = dvb.at(i); + break; + } + } + for ( i=0; i<(int)dvb.count(); i++ ) { + if ( dvb.at(i)->hasLive() ) { + dvb.at(i)->preStopLive(); + emit dvbPause( false ); + dvb.at(i)->stopLive( chan ); + break; + } + } + finalZap( d, chan ); +} + + + +void DvbPanel::pipeOpened() +{ + tuningTimer.start( 1000, true ); +} + + + +void DvbPanel::setTuning() +{ + tuningTimer.stop(); + stopTuningTimer.stop(); + isTuning = false; +} + + + +void DvbPanel::finalZap( DvbStream *d, ChannelDesc *chan ) +{ + QString s, t; + int i; + DvbStream *d1=d, *d2=0; + + emit setCurrentPlugin( this ); + + fprintf( stderr, "Tuning to: %s / autocount: %lu\n", chan->name.latin1(), autocount ); + QTime tm; + tm.start(); + if ( !d1 ) { + for ( i=0; i<(int)dvb.count(); i++ ) { + if ( !dvb.at(i)->canSource( chan ) ) + continue; + if ( dvb.at(i)->isTuned() ) { + if ( dvb.at(i)->getCurrentTransponder()==chan->tp ) { + d1 = dvb.at(i); + break; + } + else d2 = dvb.at(i); + } + else { + d1 = dvb.at(i); + break; + } + } + if ( !d1 && d2 ) + d1 = d2; + } + + if ( !d1 ) { + emit dvbStop(); + isTuning = false; + return; + } + + int ret = d1->goLive( chan, currentFifo ); + + switch ( ret ) { + case DvbStream::ErrIsRecording : + emit showOSD( i18n("Still recording."), 5000, 3 ); + break; + case DvbStream::ErrIsBroadcasting : + emit showOSD( i18n("Still broadcasting."), 5000, 3 ); + break; + case DvbStream::ErrCantTune : + emit showOSD( i18n("Can't tune dvb!"), 5000, 3 ); + break; + case DvbStream::ErrCantSetPids : + emit showOSD( i18n("Can't set pid(s)"), 5000, 3 ); + break; + case DvbStream::ErrCamUsed : + emit showOSD( i18n("No CAM free"), 5000, 3 ); + break; + } + + fprintf( stderr, "Tuning delay: %d ms\n", tm.elapsed() ); + osdMode = 0; + if ( ret<1 ) { + emit dvbOpen( currentFifo, s.setNum( chan->num)+" - "+chan->name, chan->vpid ); + showOsdTimer.start( 2000, true ); + ++autocount; + stopTuningTimer.start( 5000, true ); + if ( currentFifo==fifoName ) { + if ( !fifoName1.isEmpty() ) + currentFifo = fifoName1; + } + else { + if ( !fifoName.isEmpty() ) + currentFifo = fifoName; + } + if ( channelsCb->visibleItems<5 ) { + resetSearch(); + } + + if ( d1->liveIsRecording() ) + recordBtn->setOn( true ); + else + recordBtn->setOn( false ); + } + else { + recordBtn->setOn( false ); + isTuning = false; + emit dvbStop(); + } + if ( dvbConfig->lastChannel!=(int)chan->num ) { + recallChannel = dvbConfig->lastChannel; + dvbConfig->lastChannel = chan->num; + } + //QTimer::singleShot( 3000, this, SLOT(playLastChannel()) ); +} + + + +void DvbPanel::pauseLiveTV() +{ + int i; + DvbStream *d=0; + + for ( i=0; i<(int)dvb.count(); i++ ) { + if ( dvb.at(i)->hasLive() ) { + d = dvb.at(i); + break; + } + } + if ( !d ) + return; + + timeShiftFileName = dvbConfig->shiftDir+"DVBLive-"+QDateTime::currentDateTime().toString("yyyyMMddThhmmss")+".m2t"; + if ( d->doPause( timeShiftFileName ) ) + emit setTimeShiftFilename( timeShiftFileName ); +} + + + +bool DvbPanel::timeShiftMode() +{ + int i; + + for ( i=0; i<(int)dvb.count(); i++ ) { + if ( dvb.at(i)->hasLive() ) { + return dvb.at(i)->timeShiftMode(); + break; + } + } + return false; +} + + + +void DvbPanel::stopLive() +{ + int i; + ChannelDesc chan; + + for ( i=0; i<(int)dvb.count(); i++ ) { + if ( dvb.at(i)->hasLive() ) { + recallChannel = dvb.at(i)->getLiveChannel().num; + dvb.at(i)->preStopLive(); + dvb.at(i)->stopLive( &chan ); + break; + } + } + recordBtn->setOn( false ); + emit setTimeShiftFilename( "" ); +} + + +// TV | vpid(stream_type) | apid1(lang)(ac3),apid2, | ttpid | sid | tsid | type(S,C,T)source | freq | sr | pol | fecH | inv | mod | fecL | bw | trans | guard | hier | number / subpid1(type)(pageid)(ancid)(lang),subpid2..., | category | nid | +bool DvbPanel::getChannelList() +{ + bool ret=false; + QString s, c, t, u, type; + int pos, tpos; + ChannelDesc *chan; + QString src=""; + int ns; + KListViewItem *it; + QPixmap pix; + + maxChannelNumber = 0; + minChannelNumber = -1; + + int sort = dvbConfig->readDvbChanOrder(); + if ( sort ) { + int column = sort&1; + int order = sort>>1; + switch (order){ + case 1: + channelsCb->setSorting ( column, FALSE ); + break; + case 0: + channelsCb->setSorting ( column, TRUE ); + break; + } + } + + QFile f( locateLocal("appdata", "channels.dvb" ) ); + if ( f.open(IO_ReadOnly) ) { + QTextStream tt( &f ); + while ( !tt.eof() ) { + s = tt.readLine(); + if ( s.startsWith("#") ) { + if ( s.contains("KaxTV") ) + break; + continue; + } + chan = new ChannelDesc(); + pos = s.find("|"); + c = s.left( pos ); + if ( c=="TV" || c=="TVC" ) + chan->type=1; + else + chan->type=2; + if ( c=="TVC" || c=="RAC" ) + chan->fta=1; + s = s.right( s.length()-pos-1 ); + pos = s.find("|"); + chan->name = s.left( pos ); + s = s.right( s.length()-pos-1 ); + pos = s.find("|"); + c = s.left( pos ); + s = s.right( s.length()-pos-1 ); + tpos = c.find("("); + if ( tpos>0 ) + chan->vpid = c.left(tpos).toUShort(); + else + chan->vpid = c.toUShort(); + if( tpos>0 ) { + t = c.right( c.length()-tpos-1); + t.remove(")"); + chan->vType = t.toUShort(); + } + else + chan->vType = 2; + if ( !chan->vpid ) + chan->vType = 0; + pos = s.find("|"); + c = s.left( pos ); + s = s.right( s.length()-pos-1 ); + while ( (pos=c.find(","))!=-1 ) { + t = c.left(pos); + chan->napid++; + if ( t.contains("(ac3)") ) { + chan->apid[chan->napid-1].ac3=1; + t.remove("(ac3)"); + } + if( (tpos=t.find("("))!=-1 ) { + t.remove(")"); + chan->apid[chan->napid-1].lang=t.right( t.length()-tpos-1 ); + t = t.left( tpos ); + } + chan->apid[chan->napid-1].pid=t.toUShort(); + c = c.right( c.length()-pos-1 ); + } + pos = s.find("|"); + chan->ttpid = s.left(pos).toUShort(); + s = s.right( s.length()-pos-1 ); + pos = s.find("|"); + chan->sid = s.left(pos).toUShort(); + s = s.right( s.length()-pos-1 ); + pos = s.find("|"); + chan->tp.tsid = s.left(pos).toUShort(); + s = s.right( s.length()-pos-1 ); + pos = s.find("|"); + c = s.left(pos); + if ( c.startsWith("T") ) { + chan->tp.type=FE_OFDM; + chan->tp.source = "Terrestrial"; + } + else if ( c.startsWith("C") ) { + chan->tp.type=FE_QAM; + chan->tp.source = "Cable"; + } + else if ( c.startsWith("S") ) { + chan->tp.type=FE_QPSK; + c.remove( 0, 1 ); + chan->tp.source = c; + } + else { + chan->tp.type=FE_ATSC; + chan->tp.source = "Atsc"; + } + s = s.right( s.length()-pos-1 ); + pos = s.find("|"); + chan->tp.freq = s.left(pos).toULong(); + s = s.right( s.length()-pos-1 ); + pos = s.find("|"); + chan->tp.sr = s.left(pos).toULong(); + s = s.right( s.length()-pos-1 ); + pos = s.find("|"); + c = s.left( pos ); + chan->tp.pol = c[0].latin1(); + s = s.right( s.length()-pos-1 ); + pos = s.find("|"); + switch ( s.left(pos).toInt() ) { + case 0 : chan->tp.coderateH = FEC_NONE; break; + case 12 : chan->tp.coderateH = FEC_1_2; break; + case 23 : chan->tp.coderateH = FEC_2_3; break; + case 34 : chan->tp.coderateH = FEC_3_4; break; + case 45 : chan->tp.coderateH = FEC_4_5; break; + case 56 : chan->tp.coderateH = FEC_5_6; break; + case 67 : chan->tp.coderateH = FEC_6_7; break; + case 78 : chan->tp.coderateH = FEC_7_8; break; + case 89 : chan->tp.coderateH = FEC_8_9; break; + case -1 : chan->tp.coderateH = FEC_AUTO; + } + s = s.right( s.length()-pos-1 ); + pos = s.find("|"); + switch ( s.left(pos).toInt() ) { + case 0 : chan->tp.inversion = INVERSION_OFF; break; + case 1 : chan->tp.inversion = INVERSION_ON; break; + case -1 : chan->tp.inversion = INVERSION_AUTO; + } + s = s.right( s.length()-pos-1 ); + pos = s.find("|"); + switch ( s.left(pos).toInt() ) { + case 8 : chan->tp.modulation = QPSK; break; + case 16 : chan->tp.modulation = QAM_16; break; + case 32 : chan->tp.modulation = QAM_32; break; + case 64 : chan->tp.modulation = QAM_64; break; + case 128 : chan->tp.modulation = QAM_128; break; + case 256 : chan->tp.modulation = QAM_256; break; + case 108 : chan->tp.modulation = VSB_8; break; + case 116 : chan->tp.modulation = VSB_16; break; + case -1 : chan->tp.modulation = QAM_AUTO; + } + s = s.right( s.length()-pos-1 ); + pos = s.find("|"); + switch ( s.left(pos).toInt() ) { + case 0 : chan->tp.coderateL = FEC_NONE; break; + case 12 : chan->tp.coderateL = FEC_1_2; break; + case 23 : chan->tp.coderateL = FEC_2_3; break; + case 34 : chan->tp.coderateL = FEC_3_4; break; + case 45 : chan->tp.coderateL = FEC_4_5; break; + case 56 : chan->tp.coderateL = FEC_5_6; break; + case 67 : chan->tp.coderateL = FEC_6_7; break; + case 78 : chan->tp.coderateL = FEC_7_8; break; + case 89 : chan->tp.coderateL = FEC_8_9; break; + case -1 : chan->tp.coderateL = FEC_AUTO; + } + s = s.right( s.length()-pos-1 ); + pos = s.find("|"); + switch ( s.left(pos).toInt() ) { + case 8 : chan->tp.bandwidth = BANDWIDTH_8_MHZ; break; + case 7 : chan->tp.bandwidth = BANDWIDTH_7_MHZ; break; + case 6 : chan->tp.bandwidth = BANDWIDTH_6_MHZ; break; + case -1 : chan->tp.bandwidth = BANDWIDTH_AUTO; + } + s = s.right( s.length()-pos-1 ); + pos = s.find("|"); + switch ( s.left(pos).toInt() ) { + case 2 : chan->tp.transmission = TRANSMISSION_MODE_2K; break; + case 8 : chan->tp.transmission = TRANSMISSION_MODE_8K; break; + case -1 : chan->tp.transmission = TRANSMISSION_MODE_AUTO; + } + s = s.right( s.length()-pos-1 ); + pos = s.find("|"); + switch ( s.left(pos).toInt() ) { + case 32 : chan->tp.guard = GUARD_INTERVAL_1_32; break; + case 16 : chan->tp.guard = GUARD_INTERVAL_1_16; break; + case 8 : chan->tp.guard = GUARD_INTERVAL_1_8; break; + case 4 : chan->tp.guard = GUARD_INTERVAL_1_4; break; + case -1 : chan->tp.guard = GUARD_INTERVAL_AUTO; + } + s = s.right( s.length()-pos-1 ); + pos = s.find("|"); + switch ( s.left(pos).toInt() ) { + case 0 : chan->tp.hierarchy = HIERARCHY_NONE; break; + case 1 : chan->tp.hierarchy = HIERARCHY_1; break; + case 2 : chan->tp.hierarchy = HIERARCHY_2; break; + case 4 : chan->tp.hierarchy = HIERARCHY_4; break; + case -1 : chan->tp.hierarchy = HIERARCHY_AUTO; + } + s = s.right( s.length()-pos-1 ); + pos = s.find("|"); + chan->num = s.left(pos).toUInt(); + s = s.right( s.length()-pos-1 ); + pos = s.find("|"); + c = s.left( pos ); + s = s.right( s.length()-pos-1 ); + while ( (pos=c.find(","))!=-1 ) { + t = c.left(pos); + tpos=t.find("("); + ns = (int)chan->nsubpid; + chan->subpid[ns].pid = t.left(tpos).toUShort(); + t = t.right( t.length()-tpos-1 ); + tpos=t.find(")"); + chan->subpid[ns].type = t.left(tpos).toUShort(); + t = t.right( t.length()-tpos-2 ); + tpos=t.find(")"); + chan->subpid[ns].page = t.left(tpos).toUShort(); + t = t.right( t.length()-tpos-2 ); + tpos=t.find(")"); + chan->subpid[ns].id = t.left(tpos).toUShort(); + t = t.right( t.length()-tpos-2 ); + tpos=t.find(")"); + chan->subpid[ns].lang = t.left(tpos); + c = c.right( c.length()-pos-1 ); + chan->nsubpid++; + } + pos = s.find("|"); + chan->category = s.left( pos ); + s = s.right( s.length()-pos-1 ); + pos = s.find("|"); + chan->tp.nid = s.left(pos).toUShort(); + + if ( chan->tp.source.isEmpty() ) { + delete chan; + continue; + } + + chan->pix.load( dvbConfig->dvbConfigIconsDir+chan->name ); + it = new KListViewItem( channelsCb, QString().sprintf("%04d", chan->num), chan->name, chan->tp.source ); + it->setDragEnabled( true ); + if ( !chan->pix.isNull() ) + it->setPixmap( 1, chan->pix ); + else { + if ( chan->type==1 ) { + if ( chan->fta ) + it->setPixmap( 1, tvcPix ); + else + it->setPixmap( 1, tvPix ); + } + else { + if ( chan->fta ) + it->setPixmap( 1, racPix ); + else + it->setPixmap( 1, raPix ); + } + } + channels.append( chan ); + if ( chan->num<=0 ) + chan->num = channels.count(); + + if ( (int)chan->num > maxChannelNumber ) + maxChannelNumber = chan->num; + if ( minChannelNumber == -1 || (int)chan->num < minChannelNumber ) + minChannelNumber = chan->num; + + } + ret = true; + f.close(); + } + return ret; +} + + + +bool DvbPanel::saveChannelList() +{ + bool ret=false; + int i, k; + QString s; + ChannelDesc *chan=0; + + QFile f( locateLocal("appdata", "channels.dvb" ) ); + if ( f.open(IO_WriteOnly|IO_Truncate) ) { + QTextStream tt( &f ); + tt<<"#Generated by Kaffeine 0.5\n"; + for( i=0; i<(int)channels.count(); i++ ) { + chan = channels.at(i); + if ( chan->type==1 ) { + if ( chan->fta ) + tt<<"TVC|"; + else + tt<<"TV|"; + } + else { + if ( chan->fta ) + tt<<"RAC|"; + else + tt<<"RA|"; + } + tt<< chan->name+"|"; + tt<< s.setNum(chan->vpid); + if ( chan->vType ) { + tt<< "("; + tt<< s.setNum(chan->vType); + tt<< ")"; + } + tt<< "|"; + for ( k=0; k<chan->napid; k++ ) { + tt<< s.setNum(chan->apid[k].pid); + if ( !chan->apid[k].lang.isEmpty() ) + tt<< "("+chan->apid[k].lang+")"; + if ( chan->apid[k].ac3 ) + tt<< "(ac3)"; + tt<< ","; + } + tt<< "|"; + tt<< s.setNum(chan->ttpid)+"|"; + tt<< s.setNum(chan->sid)+"|"; + tt<< s.setNum(chan->tp.tsid)+"|"; + switch ( chan->tp.type ) { + case FE_QPSK : tt<< "S"; tt<< chan->tp.source; break; + case FE_QAM : tt<< "Cable"; break; + case FE_OFDM : tt<< "Terrestrial"; break; + case FE_ATSC : tt<< "Atsc"; break; + } + tt<< "|"; + tt<< s.setNum(chan->tp.freq)+"|"; + tt<< s.setNum(chan->tp.sr)+"|"; + if ( chan->tp.pol=='h' ) + tt<< "h|"; + else + tt<< "v|"; + switch ( chan->tp.coderateH ) { + case FEC_NONE : tt<< "0|"; break; + case FEC_1_2 : tt<< "12|"; break; + case FEC_2_3 : tt<< "23|"; break; + case FEC_3_4 : tt<< "34|"; break; + case FEC_4_5 : tt<< "45|"; break; + case FEC_5_6 : tt<< "56|"; break; + case FEC_6_7 : tt<< "67|"; break; + case FEC_7_8 : tt<< "78|"; break; + case FEC_8_9 : tt<< "89|"; break; + case FEC_AUTO : tt<< "-1|"; + } + switch ( chan->tp.inversion ) { + case INVERSION_OFF : tt<< "0|"; break; + case INVERSION_ON : tt<< "1|"; break; + case INVERSION_AUTO : tt<< "-1|"; + } + switch ( chan->tp.modulation ) { + case QPSK : tt<< "8|"; break; + case QAM_16 : tt<< "16|"; break; + case QAM_32 : tt<< "32|"; break; + case QAM_64 : tt<< "64|"; break; + case QAM_128 : tt<< "128|"; break; + case QAM_256 : tt<< "256|"; break; + case VSB_8 : tt<< "108|"; break; + case VSB_16 : tt<< "116|"; break; + case QAM_AUTO : tt<< "-1|"; + } + switch ( chan->tp.coderateL ) { + case FEC_NONE : tt<< "0|"; break; + case FEC_1_2 : tt<< "12|"; break; + case FEC_2_3 : tt<< "23|"; break; + case FEC_3_4 : tt<< "34|"; break; + case FEC_4_5 : tt<< "45|"; break; + case FEC_5_6 : tt<< "56|"; break; + case FEC_6_7 : tt<< "67|"; break; + case FEC_7_8 : tt<< "78|"; break; + case FEC_8_9 : tt<< "89|"; break; + case FEC_AUTO : tt<< "-1|"; + } + switch ( chan->tp.bandwidth ) { + case BANDWIDTH_8_MHZ : tt<< "8|"; break; + case BANDWIDTH_7_MHZ : tt<< "7|"; break; + case BANDWIDTH_6_MHZ : tt<< "6|"; break; + case BANDWIDTH_AUTO : tt<< "-1|"; + } + switch ( chan->tp.transmission ) { + case TRANSMISSION_MODE_8K : tt<< "8|"; break; + case TRANSMISSION_MODE_2K : tt<< "2|"; break; + case TRANSMISSION_MODE_AUTO : tt<< "-1|"; + } + switch ( chan->tp.guard ) { + case GUARD_INTERVAL_1_32 : tt<< "32|"; break; + case GUARD_INTERVAL_1_16 : tt<< "16|"; break; + case GUARD_INTERVAL_1_8 : tt<< "8|"; break; + case GUARD_INTERVAL_1_4 : tt<< "4|"; break; + case GUARD_INTERVAL_AUTO : tt<< "-1|"; + } + switch ( chan->tp.hierarchy ) { + case HIERARCHY_NONE : tt<< "0|"; break; + case HIERARCHY_1 : tt<< "1|"; break; + case HIERARCHY_2 : tt<< "2|"; break; + case HIERARCHY_4 : tt<< "4|"; break; + case HIERARCHY_AUTO : tt<< "-1|"; + } + tt<< s.setNum(chan->num)+"|"; + for ( k=0; k<chan->nsubpid; k++ ) { + tt<< s.setNum(chan->subpid[k].pid); + tt<< "("+s.setNum(chan->subpid[k].type)+")"; + tt<< "("+s.setNum(chan->subpid[k].page)+")"; + tt<< "("+s.setNum(chan->subpid[k].id)+")"; + tt<< "("+chan->subpid[k].lang+")"; + tt<< ","; + } + tt<< "|"; + tt<< chan->category+"|"; + tt<< s.setNum(chan->tp.nid)+"|\n"; + } + ret = true; + f.close(); + } + return ret; +} + + + +bool DvbPanel::getTimerList() +{ + bool ret=false; + QString s; + int pos; + RecTimer *t; + + QFile f( locateLocal("appdata", "timers.dvb" ) ); + if ( f.open(IO_ReadOnly) ) { + QTextStream tt( &f ); + while ( !tt.eof() ) { + s = tt.readLine(); + if ( s.startsWith("#") ) + continue; + t = new RecTimer(); + pos = s.find("|"); + t->name = s.left( pos ); + s = s.right( s.length()-pos-1 ); + pos = s.find("|"); + t->channel = s.left( pos ); + s = s.right( s.length()-pos-1 ); + pos = s.find("|"); + t->begin = QDateTime::fromString( s.left( pos ), Qt::ISODate ); + s = s.right( s.length()-pos-1 ); + pos = s.find("|"); + t->duration = QTime::fromString( s.left( pos ) ); + s = s.right( s.length()-pos-1 ); + pos = s.find("|"); + //t->filetype = s.left( pos ).toInt(); + t->mode = 0; + s = s.right( s.length()-pos-1 ); + pos = s.find("|"); + t->mode = s.left( pos ).toInt(); + t->running = 0; + timers.append( t ); + } + ret = true; + f.close(); + } + return ret; +} + + + +bool DvbPanel::saveTimerList() +{ + bool ret=false; + int i; + QString s; + RecTimer *t; + + QFile f( locateLocal("appdata", "timers.dvb" ) ); + if ( f.open(IO_WriteOnly|IO_Truncate) ) { + QTextStream tt( &f ); + tt<<"#Generated by Kaffeine 0.5\n"; + for( i=0; i<(int)timers.count(); i++ ) { + t = timers.at(i); + if ( t->running && !t->mode ) + continue; + tt<< t->name+"|"; + tt<< t->channel+"|"; + tt<< t->begin.toString("yyyy-MM-ddThh:mm:ss")+"|"; + tt<< t->duration.toString()+"|"; + tt<< s.setNum(0/*t->filetype*/)+"|"; + tt<< s.setNum(t->mode)+"|"; + tt<< "\n"; + } + ret = true; + f.close(); + } + return ret; +} + + + +bool DvbPanel::close() +{ + int ret=0, i; + bool rec = false; + + for ( i=0; i<(int)dvb.count(); i++ ) { + if ( dvb.at(i)->hasRec() ) { + rec = true; + break; + } + } + + if ( rec ) { + ret = KMessageBox::questionYesNo( 0, i18n("Kaffeine is still recording. Do you really want to quit?") ); + if ( ret!=KMessageBox::Yes ) + return false; + } + else if ( timers.count() ) { + ret = KMessageBox::questionYesNo( 0, i18n("Kaffeine has queued timers. Do you really want to quit?") ); + if ( ret!=KMessageBox::Yes ) + return false; + } + emit dvbStop(); + stopLive(); + return true; +} + + + +void DvbPanel::saveConfig() +{ + saveTimerList(); + saveChannelList(); + dvbConfig->splitSizes = split->sizes(); + dvbConfig->saveDvbChanOrder( channelsCb->sortOrder(), channelsCb->sortColumn() ); + dvbConfig->saveConfig(); + //delete dvbConfig; +} + + +DvbPanel::~DvbPanel() +{ + dvb.clear(); + delete rtp; + delete cleaner; + if ( plug ) { + KService::Ptr service = KService::serviceByDesktopName( plugName ); + KLibLoader::self()->unloadLibrary( service->library().ascii() ); + } + events.saveEpg(); +} + +#include "dvbpanel.moc" diff --git a/kaffeine/src/input/dvb/dvbpanel.h b/kaffeine/src/input/dvb/dvbpanel.h new file mode 100644 index 0000000..5545040 --- /dev/null +++ b/kaffeine/src/input/dvb/dvbpanel.h @@ -0,0 +1,242 @@ +/* + * dvbpanel.h + * + * Copyright (C) 2004-2007 Christophe Thommeret <hftom@free.fr> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef DVBPANEL_H +#define DVBPANEL_H + +#include <qframe.h> +#include <qcombobox.h> +#include <qtoolbutton.h> +#include <qptrlist.h> +#include <qtimer.h> +#include <qsplitter.h> +#include <qvbox.h> + +#include <kapp.h> +#include <kpushbutton.h> +#include <kled.h> +#include <klistview.h> +#include <kiconview.h> +#include <klineedit.h> + +#include "scandialog.h" +#include "dvbconfig.h" +#include "krecord.h" +#include "ts2rtp.h" +#include "cleaner.h" +#include "dvbevents.h" + + + +class ChannelDesc; +class DvbStream; +class DvbPanel; +class KaffeineInput; +class KaffeineDvbPlugin; + + + +class DListView : public KListView +{ + Q_OBJECT +public: + DListView( QWidget *parent ); + + int visibleItems; + +protected: + virtual QDragObject* dragObject(); +}; + + + +class DIconViewItem : public KIconViewItem +{ +public: + DIconViewItem( DvbPanel *pan, QIconView *parent, const QString &text, const QPixmap &icon ); +protected: + void dropped( QDropEvent *e, const QValueList<QIconDragItem> & ); +private: + DvbPanel *panel; +}; + + + +class DvbPanel : public KaffeineInput +{ + Q_OBJECT + +public: + + DvbPanel( QWidget *parent, QObject *objParent, const char *name=0); + ~DvbPanel(); + bool getChannelList(); + bool saveChannelList(); + bool timeShiftMode(); + void setConfig(); + void enableLiveDvb( bool on ); + void checkFirstRun(); + void moveChannel( const QString &cat, const QString &name ); + + // Reimplemented from KaffeineInput + QWidget *wantPlayerWindow(); + QWidget *inputMainWidget(); + void toggleLayout( bool ); + bool close(); + bool nextTrack( MRL& ); + bool previousTrack( MRL& ); + bool currentTrack( MRL& ); + bool trackNumber( int, MRL& ); + bool playbackFinished( MRL& ); + void getTargets( QStringList &uiNames, QStringList &iconNames, QStringList &targetNames ); + void togglePanel(); + bool execTarget( const QString& ); + void saveConfig(); + //*************************************** + + QPtrList<ChannelDesc> channels; + QPtrList<RecTimer> timers; + QPtrList<DvbStream> dvb; + QString fifoName, fifoName1, currentFifo; + QString timeShiftFileName; + Ts2Rtp *rtp; + QVBox *mainWidget; + QVBox *playerBox, *pbox; + +public slots: + + void playLastChannel(); + void playNumChannel( int num ); + void stopLive(); + void setShiftLed( bool on ); + void setRecordLed( bool on ); + void setBroadcastLed( bool on ); + void setRecord(); + void setBroadcast(); + void pauseLiveTV(); + void killTimer( RecTimer *t ); + void showEvents(); + void showTimers(); + void scanner(); + void showConfigDialog(); + void next(); + void previous(); + void recallZap(); + void dvbOSD(); + + void dvbOSDNext(); + void dvbOSDPrev(); + void dvbOSDSkip(int skip, int timeShift = 0); + void dvbOSDZap(); + void dvbOSDHide(); + + void dvbOSDAdvance(); + void dvbOSDRetreat(); + + void dvbNewTimer( QString name, QString channel, QString datetime, QString duration ); + int getSNR( int device ); + void diskStatus(); + +private: + + void setupActions(); + bool getTimerList(); + bool saveTimerList(); + void fillChannelList( ChannelDesc *ch=0 ); + QPtrList<Transponder> getSourcesStatus(); + void updateModeTimer( RecTimer *t ); + DvbStream* getWorkingDvb( int mode, ChannelDesc *chan ); + + void dvbOSD(ChannelDesc liveChannel, DvbStream *d, int timeShift = 0); + DvbStream* getLiveDVBStream(); + + QPixmap tvPix, raPix, tvcPix, racPix; + QSplitter *split; + QFrame *panel; + KIconView *iconView; + DListView *channelsCb; + QToolButton *broadcastBtn, *recordBtn; + QToolButton *dateBtn, *infoBtn, *channelsBtn, *configBtn, *osdBtn, *recallBtn; + KLed *shiftLed, *recordLed, *broadcastLed; + QTimer timersTimer; + DVBconfig *dvbConfig; + KRecord *timersDialog; + int updown; + unsigned long autocount; + int currentChannelNumber; + Cleaner *cleaner; + int osdMode; + QTimer osdTimer; + QTimer showOsdTimer; + QString currentCategory; + bool isTuning; + QTimer tuningTimer, stopTuningTimer; + QTimer diskTimer; + KLineEdit *searchLE; + QToolButton *searchBtn; + int recallChannel; + + int browseDvbStream; + int maxChannelNumber, minChannelNumber; + int browseDvbTimeShift; + + KaffeineDvbPlugin *plug; + QString plugName; + + EventTable events; + +private slots: + + void searchChannel( const QString &text ); + void resetSearch(); + void checkTimers(); + bool editChannel( QString &name ); + void channelSelected( QListViewItem *it ); + void channelClicked( QListViewItem *it ); + void channelSelected( const QString &name ); + void channelPopup( QListViewItem *it, const QPoint &pos, int col ); + void dvbZap( ChannelDesc *chan ); + void finalZap( DvbStream *d, ChannelDesc *chan ); + void newTimer( QString channel, QString name, QDateTime begin, QTime duration, bool warn=true ); + void dumpEvents(); + void resetOSD(); + void catContextMenu( QIconViewItem*, const QPoint& ); + void catSelected( QIconViewItem* ); + void channelNumberChanged( QListViewItem* ); + void pipeOpened(); + void setTuning(); + +signals: + + void zap( ChannelDesc* ); + void playDvb(); + void timersChanged(); + void dvbOpen( const QString &filename, const QString &chanName, int haveVideo ); + void dvbStop(); + void dvbPause( bool pauseLive ); + void setTimeShiftFilename( const QString& ); + void showOSD( const QString &text, int duration, int priority ); + void showDvbOSD( const QStringList& ); + void showDvbOSD( const QString&, const QStringList& ); + + void updateTimer(RecTimer*, int); +}; + +#endif /* DVBPANEL_H */ diff --git a/kaffeine/src/input/dvb/dvbsection.h b/kaffeine/src/input/dvb/dvbsection.h new file mode 100644 index 0000000..e86e834 --- /dev/null +++ b/kaffeine/src/input/dvb/dvbsection.h @@ -0,0 +1,26 @@ +/* + * dvbsection.h + * + * Copyright (C) 2003-2007 Christophe Thommeret <hftom@free.fr> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef DVBSECTION_H +#define DVBSECTION_H + +#include "kaffeinedvbsection.h" + +#endif /* DVBSECTION_H */ diff --git a/kaffeine/src/input/dvb/dvbsi.cpp b/kaffeine/src/input/dvb/dvbsi.cpp new file mode 100644 index 0000000..395d796 --- /dev/null +++ b/kaffeine/src/input/dvb/dvbsi.cpp @@ -0,0 +1,866 @@ +/* + * dvbsi.cpp + * + * Copyright (C) 2003-2007 Christophe Thommeret <hftom@free.fr> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include <stdio.h> +#include <unistd.h> +#include <sys/poll.h> + +#include <qdir.h> + +#include <kapplication.h> + +#include "dvbsi.h" + +#define TIMER_EVENT_SCAN_END 100 + + + +NitSection::NitSection( QPtrList<Transponder> *tp, bool *end, bool *ok, int anum, int tnum ) : KaffeineDVBsection( anum, tnum ) +{ + ended = end; + transponders = tp; + start(); +} + + + +NitSection::~NitSection() +{ + stop(); +} + + + +void NitSection::stop() +{ + if ( !wait(10000) ) { + terminate(); + wait(); + } +} + + + +void NitSection::run() +{ + getSection( 0x10, 0x40, 60000 ); + *ended = true; +} + + + +bool NitSection::getSection( int pid, int tid, int timeout ) +{ + unsigned char buf[4096]; + int i, n=0; + int skip=0; + int last=1, current=0, loop=0; + QValueList<int> list; + + if ( !setFilter( pid, tid, timeout ) ) + return false; + + do { + if ( poll(pf,1,timeout)>0 ){ + if ( pf[0].revents & POLLIN ){ + n = read( fdDemux, buf, 4096 ); + skip = 0; + } + else + skip++; + } + else + skip++; + + if ( skip || n<4 ) { + fprintf(stderr,"\nInvalid section length or timeout: pid=%d\n\n", pid); + stopFilter(); + return false; + } + + last = getBits(buf,56,8); + current = getBits(buf,48,8); + for ( i=0; i<(int)list.count(); i++ ) { + if ( current==list[i] ) { + i = -1; + break; + } + } + if ( i>-1 ) + list.append( current ); + else { + loop++; // missing section ? + continue; + } + switch ( getBits(buf,0,8) ) { + case 0x40 : + fprintf(stderr,"Reading NIT: pid=%d\n", pid); + tableNIT( buf ); + break; + default: + break; + } + loop = 0; + } while ( (int)list.count()<=last && loop<=last ); + + stopFilter(); + return true; +} + + + +bool NitSection::tableNIT( unsigned char* buf ) +{ + int length, loop, i, j; + Transponder *trans, *curtrans; + + loop = getBits(buf,68,12); + buf +=10+loop; + length = getBits(buf,4,12); + buf +=2; + + while ( length>0 ) { + trans = new Transponder(); + trans->source = transponders->at(0)->source; + trans->tsid = getBits(buf,0,16); + loop = getBits(buf,36,12); + buf +=6; + length -=(6+loop); + while ( loop>0 ) { + switch ( getBits(buf,0,8) ) { + case 0x43 : + satelliteDesc( buf, trans ); + break; + case 0x44 : + cableDesc( buf, trans ); + break; + case 0x5a : + terrestrialDesc( buf, trans ); + break; + case 0x62 : + fprintf(stderr," Found frequency list.\n"); + freqListDesc( buf, trans ); + break; + default : + break; + } + loop -=( getBits(buf,8,8)+2 ); + buf +=( getBits(buf,8,8)+2 ); + } + if ( trans->freq==0 ) { + delete trans; + continue; + } + curtrans = 0; + for ( i=0; i<(int)transponders->count(); i++ ) { + if ( trans->tsid==transponders->at(i)->tsid || trans->sameAs( transponders->at(i) ) ) { + curtrans = transponders->at(i); + break; + } + } + if ( !curtrans ) + transponders->append( trans ); + else { + for ( i=0; i<(int)trans->freqlist.count(); i++ ) { + for ( j=0; j<(int)curtrans->freqlist.count(); j++ ) { + if ( curtrans->freqlist[j]==trans->freqlist[i] ) { + j = -1; + break; + } + } + if ( j!=-1 ) { + fprintf(stderr," Appending freq %lu to %lu\n", trans->freqlist[i], curtrans->freq ); + curtrans->freqlist.append( trans->freqlist[i] ); + } + } + delete trans; + } + } + + return true; +} + + + +void NitSection::satelliteDesc( unsigned char* buf, Transponder *trans ) +{ + QString s, t; + + trans->type = FE_QPSK; + s = t.setNum( getBits(buf,16,32), 16 ); + trans->freq = s.toInt(); + trans->freq /=100; + if ( getBits(buf,65,2) ) + trans->pol = 'v'; + else + trans->pol = 'h'; + s = t.setNum( getBits(buf,72,28), 16 ); + trans->sr = s.toInt(); + trans->sr /=10; + switch ( getBits(buf,100,4) ) { + case 1 : trans->coderateH = FEC_1_2; break; + case 2 : trans->coderateH = FEC_2_3; break; + case 3 : trans->coderateH = FEC_3_4; break; + case 4 : trans->coderateH = FEC_5_6; break; + case 5 : trans->coderateH = FEC_7_8; break; + case 6 : trans->coderateH = FEC_8_9; break; + case 7 : trans->coderateH = FEC_NONE; break; + } +} + + + +void NitSection::cableDesc( unsigned char* buf, Transponder *trans ) +{ + QString s, t; + + trans->type = FE_QAM; + s = t.setNum( getBits(buf,16,32), 16 ); + trans->freq = s.toInt(); + trans->freq /=10; + switch ( getBits(buf,64,8) ) { + case 1 : trans->modulation = QAM_16; break; + case 2 : trans->modulation = QAM_32; break; + case 3 : trans->modulation = QAM_64; break; + case 4 : trans->modulation = QAM_128; break; + case 5 : trans->modulation = QAM_256; break; + } + s = t.setNum( getBits(buf,72,28), 16 ); + trans->sr = s.toInt(); + trans->sr /=10; + switch ( getBits(buf,100,4) ) { + case 1 : trans->coderateH = FEC_1_2; break; + case 2 : trans->coderateH = FEC_2_3; break; + case 3 : trans->coderateH = FEC_3_4; break; + case 4 : trans->coderateH = FEC_5_6; break; + case 5 : trans->coderateH = FEC_7_8; break; + case 6 : trans->coderateH = FEC_8_9; break; + case 7 : trans->coderateH = FEC_NONE; break; + } +} + + + +void NitSection::terrestrialDesc( unsigned char* buf, Transponder *trans ) +{ + trans->type = FE_OFDM; + trans->freq = getBits(buf,16,32)/100; + trans->bandwidth = (fe_bandwidth_t)(BANDWIDTH_8_MHZ + getBits(buf,48,3)); + switch ( getBits(buf,56,2) ) { + case 0 : trans->modulation = QPSK; break; + case 1 : trans->modulation = QAM_16; break; + case 2 : trans->modulation = QAM_64; break; + } + trans->hierarchy = (fe_hierarchy_t)(HIERARCHY_NONE + getBits(buf,58,3)); + switch ( getBits(buf,61,3) ) { + case 0 : trans->coderateH = FEC_1_2; break; + case 1 : trans->coderateH = FEC_2_3; break; + case 2 : trans->coderateH = FEC_3_4; break; + case 3 : trans->coderateH = FEC_5_6; break; + case 4 : trans->coderateH = FEC_7_8; break; + } + switch ( getBits(buf,64,3) ) { + case 0 : trans->coderateL = FEC_1_2; break; + case 1 : trans->coderateL = FEC_2_3; break; + case 2 : trans->coderateL = FEC_3_4; break; + case 3 : trans->coderateL = FEC_5_6; break; + case 4 : trans->coderateL = FEC_7_8; break; + } + trans->guard = (fe_guard_interval_t)(GUARD_INTERVAL_1_32 + getBits(buf,67,2)); + switch ( getBits(buf,69,2) ) { + case 0 : trans->transmission = TRANSMISSION_MODE_2K; break; + case 1 : trans->transmission = TRANSMISSION_MODE_8K; break; + } +} + + + +void NitSection::freqListDesc( unsigned char* buf, Transponder *trans ) +{ + unsigned char len, type; + unsigned char *b=buf; + QString s, t; + unsigned long freq; + + len = getBits(b,8,8); + type = getBits(b,22,2); + len-= 1; + b+= 3; + while ( len>0 ) { + switch ( type ) { + case 1: // satellite + s = t.setNum( getBits(b,0,32), 16 ); + freq = s.toInt(); + freq /=100; + fprintf( stderr, " %lu\n", freq ); + trans->freqlist.append( freq ); + break; + case 2: // cable + s = t.setNum( getBits(b,0,32), 16 ); + freq = s.toInt(); + freq /=10; + fprintf( stderr, " %lu\n", freq ); + trans->freqlist.append( freq ); + break; + case 3: // terrestrial + freq = getBits(b,0,32)/100; + fprintf( stderr, " %lu\n", freq ); + trans->freqlist.append( freq ); + break; + } + len-= 4; + b+= 4; + } +} + + + +DVBsi::DVBsi( bool *ok, int anum, int tnum, DvbStream *d, const QString &charset ) : KaffeineDVBsection( anum, tnum, charset ) +{ + channels.setAutoDelete( true ); + transponders.setAutoDelete( true ); + isRunning = false; + dvb = d; + adapter = anum; + tuner = tnum; + ns = 0; +} + + + +DVBsi::~DVBsi() +{ + isRunning = false; + wait(); + channels.clear(); + transponders.clear(); +} + + + +void DVBsi::serviceDesc( unsigned char* buf, ChannelDesc *desc ) +{ + unsigned int i, j; + + desc->type = getBits(buf,16,8); + i = getBits(buf,24,8); + desc->provider = getText( buf+4, i ).stripWhiteSpace(); + j = getBits(buf+i,32,8); + desc->name = getText( buf+5+i, j ).stripWhiteSpace(); + if ( desc->name.isEmpty() ) + desc->name = "Unknown"; + fprintf(stderr,"%s: sid=%d\n", desc->name.latin1(), desc->sid ); +} + + + +bool DVBsi::tableSDT( unsigned char* buf ) +{ + int length, loop; + ChannelDesc *desc; + QString s; + unsigned short tsid; + unsigned short nid; + + tsid = getBits(buf+3,0,16); + nid = getBits(buf+8,0,16); + length = getBits(buf,12,12); + length -=8; + buf +=11; + + while ( length>4 ) { + desc = new ChannelDesc(); + channels.append( desc ); + desc->tp.tsid = tsid; + desc->tp.nid = nid; + desc->sid = getBits(buf,0,16); + //desc->fta = getBits(buf,27,1 ); + loop = getBits(buf,28,12); + buf +=5; + length -=(5+loop); + while ( loop>0 ) { + switch ( getBits(buf,0,8) ) { + case 0x48 : + serviceDesc( buf, desc ); + break; + default : + break; + } + loop -=( getBits(buf,8,8)+2 ); + buf +=( getBits(buf,8,8)+2 ); + } + } + return true; +} + + + +bool DVBsi::tablePMT( unsigned char* buf ) +{ + int length, loop; + int type; + int sid; + int i; + int pid=0; + ChannelDesc *desc=0; + QString lang; + int ns; + unsigned char st; + bool audio, ac3; + + + sid = getBits(buf+3,0,16); + for ( i=indexChannels; i<(int)channels.count(); i++ ) { + if ( channels.at( i )->sid==sid ) { + desc = channels.at( i ); + break; + } + } + + if ( !desc ) + return false; + + length = getBits(buf,12,12); + loop = getBits(buf+10,4,12); + length -=(9+loop); + buf +=12; + + while ( loop>0 ) { + switch ( getBits(buf,0,8) ) { + case 0x09 : + desc->fta = 1; + break; + default : + break; + } + loop -=( getBits(buf,8,8)+2 ); + buf +=( getBits(buf,8,8)+2 ); + } + + while ( length>4 ) { + audio=ac3=false; + type = getBits(buf,0,8); + pid = getBits(buf,11,13); + if ( type==1/*mpeg1*/ || type==2/*mpeg2*/ || type==16/*mpeg4*/ || type==27/*h264*/ ) { + desc->type=1; + desc->vpid = pid; + desc->vType = type; + } + if ( type==3 || type==4 ) { + audio = true; + } + loop = getBits(buf,28,12); + buf +=5; + length -=(5+loop); + while ( loop>0 ) { + switch ( getBits(buf,0,8) ) { + case 0x09 : + desc->fta = 1; + break; + case 0x0A : + lang = langDesc( buf ); + break; + case 0x56 : + if ( type==6 ) + desc->ttpid = pid; + break; + case 0x59 : // DVB subtitle descriptor + ns = (int)desc->nsubpid; + if ( type==6 && ns<desc->maxsubpid ) { + st = getBits(buf+5,0,8); + if ( st>=0x10 && st<=0x23 ) { + desc->subpid[ns].type = st; + desc->subpid[ns].pid = pid; + desc->subpid[ns].page = getBits(buf+6,0,16); + desc->subpid[ns].id = getBits(buf+8,0,16); + desc->subpid[ns].lang = langDesc(buf); + fprintf( stderr, "\nDVB SUB on %s page_id: %d anc_id: %d lang: %s\n\n", + desc->name.latin1(), desc->subpid[ns].page, desc->subpid[ns].id, + desc->subpid[ns].lang.latin1() ); + desc->nsubpid++; + } + } + break; + case 0x6a : + audio = true; + ac3 = true; + break; + default : + break; + } + loop -=( getBits(buf,8,8)+2 ); + buf +=( getBits(buf,8,8)+2 ); + } + if ( audio && desc->napid<desc->maxapid ) { + if ( !desc->vpid ) + desc->type=2; + desc->apid[(int)desc->napid].pid = pid; + if ( ac3 ) + desc->apid[(int)desc->napid].ac3 = 1; + if ( !lang.isEmpty() ) + desc->apid[(int)desc->napid].lang = lang; + desc->napid++; + } + } + + return true; +} + + + +bool DVBsi::tablePAT( unsigned char *buf ) +{ + int length, i, sid, tsid, pmt; + bool got; + ChannelDesc *desc; + + tsid = getBits(buf+3,0,16); + length = getBits(buf,12,12); + length -=5; + buf +=8; + + while ( length>4 ) { + sid = getBits(buf,0,16); + pmt = getBits(buf,19,13); + buf +=4; + length -=4; + got = false; + for ( i=indexChannels; i<(int)channels.count(); i++ ) { + if ( channels.at( i )->sid==sid ) { + channels.at( i )->pmtpid = pmt; + got = true; + break; + } + } + if ( !got && sid!=0 ) { + desc = new ChannelDesc(); + channels.append( desc ); + desc->tp.tsid = tsid; + desc->sid = sid; + desc->pmtpid = pmt; + desc->name = QString("TSID:%1-SID:%2").arg(tsid).arg(sid); + } + } + + return true; +} + + + +bool DVBsi::getSection( int pid, int tid, int timeout, int sid ) +{ + unsigned char buf[4096]; + int i, n=0; + int skip=0; + int last=1, current=0, loop=0; + QValueList<int> list, sidList; + int cursid; + + if ( !setFilter( pid, tid, timeout ) ) + return false; + + do { + if ( poll(pf,1,timeout)>0 ){ + if ( pf[0].revents & POLLIN ){ + n = read( fdDemux, buf, 4096 ); + skip = 0; + } + else + skip++; + } + else + skip++; + + if ( skip || n<4 ) { + fprintf(stderr,"\nInvalid section length or timeout: pid=%d\n\n", pid); + stopFilter(); + return false; + } + + cursid = getBits(buf+3,0,16); + if ( sid && cursid!=sid && !sidList.contains(cursid) ) { + sidList.append( cursid ); + continue; + } + + last = getBits(buf,56,8); + current = getBits(buf,48,8); + for ( i=0; i<(int)list.count(); i++ ) { + if ( current==list[i] ) { + i = -1; + break; + } + } + if ( i>-1 ) + list.append( current ); + else { + loop++; // missing section ? + continue; + } + switch ( getBits(buf,0,8) ) { + case 0x42 : + fprintf(stderr,"Reading SDT: pid=%d\n", pid); + tableSDT( buf ); + break; + case 0x00 : + fprintf(stderr,"Reading PAT: pid=%d\n", pid); + tablePAT( buf ); + break; + case 0x02 : + fprintf(stderr,"Reading PMT: pid=%d\n", pid); + tablePMT( buf ); + break; + default: + break; + } + loop = 0; + } while ( (int)list.count()<=last && loop<=last ); + + stopFilter(); + return true; +} + + + +void DVBsi::stop() +{ + if ( !isRunning ) + return; + + isRunning = false; + if ( !wait(10000) ) { + if ( ns ) { + ns->stop(); + delete ns; + ns = 0; + } + terminate(); + wait(); + if ( scanMode<2 ) + dvb->stopScan(); + } +} + + + +void DVBsi::out( bool stopscan ) +{ + if ( ns ) { + ns->stop(); + delete ns; + ns = 0; + } + if ( stopscan ) + dvb->stopScan(); + KApplication::kApplication()->postEvent( this, new QTimerEvent( TIMER_EVENT_SCAN_END ) ); +} + + + +void DVBsi::go( QPtrList<Transponder> trans, int mode ) +{ + int i; + + if ( isRunning ) + return; + + scanMode = mode; + transponders.clear(); + for ( i=0; i<(int)trans.count(); i++ ) + transponders.append( new Transponder( *trans.at(i) ) ); + channels.clear(); + isRunning = true; + start(); +} + + + +void DVBsi::timerEvent( QTimerEvent *e ) +{ + switch ( e->timerId() ) { + case TIMER_EVENT_SCAN_END : + emit end( true ); + break; + } +} + + + +void DVBsi::run() +{ + int i, j=0, k=0; + ChannelDesc chan; + Transponder trans; + unsigned short tsid, nid; + bool nitEnded=true, ok; + + progressTransponder = 0; + + if ( scanMode<2 ) { + dvb->stopScan(); + for ( i=0; i<(int)transponders.count(); i++ ) { + if ( !isRunning ) { + out(); + return; + } + chan.tp = *transponders.at(i); + usleep( 100000 ); + if ( !dvb->tuneDvb( &chan, false ) ) { + for ( k=0; k<(int)chan.tp.freqlist.count(); k++ ) { + chan.tp.freq = chan.tp.freqlist[k]; + fprintf(stderr,"Trying alternate frequency\n"); + if ( dvb->tuneDvb( &chan, false ) ) { + k = -1; + transponders.at(i)->freq = chan.tp.freq; + break; + } + else + usleep( 400000 ); + } + if ( k>-1 ) { + fprintf(stderr,"dvbsi: Cant tune DVB\n"); + progressTransponder++; + usleep( 400000 ); + continue; + } + } + + indexChannels = j; + fprintf(stderr,"Transponders: %d/%d\n", i+1, transponders.count() ); + if ( scanMode ) { + nitEnded = false; + ns = new NitSection( &transponders, &nitEnded, &ok, adapter, tuner ); //NIT + } + if ( !getSection( 0x11, 0x42 ) ) //SDT + continue; + if ( !isRunning ) { + out(); + return; + } + getSection( 0x00, 0x00 ); //PAT + for ( ; j<(int)channels.count(); j++ ) { + if ( channels.at( j )->pmtpid==0 ) { + channels.at(j)->completed = 1; + continue; + } + if ( !isRunning ) { + out(); + return; + } + getSection( channels.at( j )->pmtpid, 0x02, 5000, channels.at( j )->sid ); //PMTs + tsid = channels.at(j)->tp.tsid; + nid = channels.at(j)->tp.nid; + channels.at(j)->tp = *transponders.at(i); + if ( channels.at(j)->tp.tsid==0 ) + channels.at(j)->tp.tsid = tsid; + channels.at(j)->tp.nid = nid; + channels.at(j)->tp.snr = dvb->getSNR(); + channels.at(j)->completed = 1; + } + while( !nitEnded ) { + if ( !ok ) { + ns->stop(); + break; + } + else + msleep( 50 ); + } + if ( scanMode ) { + delete ns; + ns = 0; + } + dvb->stopScan(); + progressTransponder++; + } + fprintf(stderr,"Transponders: %d\n", transponders.count()); + } + else if ( scanMode==2 ) { + indexChannels = 0; + trans = dvb->getCurrentTransponder(); + getSection( 0x11, 0x42 ); //SDT + getSection( 0x00, 0x00 ); //PAT + for ( j=0; j<(int)channels.count(); j++ ) { + if ( channels.at( j )->pmtpid==0 ) { + channels.at(j)->completed = 1; + continue; + } + if ( !isRunning ) { + out(false); + return; + } + getSection( channels.at( j )->pmtpid, 0x02, 5000, channels.at( j )->sid ); //PMTs + tsid = channels.at(j)->tp.tsid; + nid = channels.at(j)->tp.nid; + channels.at(j)->tp = trans; + channels.at(j)->tp.tsid = tsid; + channels.at(j)->tp.nid = nid; + channels.at(j)->tp.snr = dvb->getSNR(); + channels.at(j)->completed = 1; + } + } + fprintf(stderr,"dvbsi: The end :)\n"); + isRunning = false; + listChannels(); + KApplication::kApplication()->postEvent( this, new QTimerEvent( TIMER_EVENT_SCAN_END ) ); +} + + + +bool DVBsi::listChannels() +{ + QString s,t; + int i, valid=0; + bool ac3; + + for ( i=0; i<(int)channels.count(); i++ ) { + ac3 = false; + if ( channels.at( i )->vType<16 ) + continue; + /*if ( channels.at( i )->nsubpid==0 ) + continue; + if ( channels.at( i )->pmtpid==0 ) + continue; + if ( channels.at(i)->name.isEmpty() ) + continue; + if ( channels.at( i )->type<1 ) + continue; + if ( channels.at( i )->type>2 ) + continue; + if ( channels.at( i )->type==1 && channels.at(i)->vpid==0 ) + continue; + if ( channels.at( i )->type==1 && channels.at(i)->napid==0 ) + continue; + if ( channels.at( i )->type==2 && channels.at(i)->napid==0 ) + continue; + if ( channels.at( i )->type==2 && channels.at(i)->vpid!=0 ) + continue;*/ + + s = "|"+channels.at(i)->name; + s = s+"|"+t.setNum(channels.at(i)->tp.freq); + s = s+"|"+channels.at(i)->tp.pol; + s = s+"|"+t.setNum(channels.at(i)->tp.sr); + fprintf(stderr, "%s\n", s.latin1() ); + valid++; + } + fprintf(stderr, "Channels found: %d\n", valid ); + return true; +} + +#include "dvbsi.moc" diff --git a/kaffeine/src/input/dvb/dvbsi.h b/kaffeine/src/input/dvb/dvbsi.h new file mode 100644 index 0000000..df1f6e7 --- /dev/null +++ b/kaffeine/src/input/dvb/dvbsi.h @@ -0,0 +1,98 @@ +/* + * dvbsi.h + * + * Copyright (C) 2003-2007 Christophe Thommeret <hftom@free.fr> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef DVBSI_H +#define DVBSI_H + +#include "dvbsection.h" +#include "dvbstream.h" + + + +class NitSection : public KaffeineDVBsection +{ + +public: + + NitSection( QPtrList<Transponder> *tp, bool *end, bool *ok, int anum, int tnum ); + ~NitSection(); + bool getSection( int pid, int tid, int timeout=5000 ); + bool tableNIT( unsigned char* buf ); + void satelliteDesc( unsigned char* buf, Transponder *trans ); + void cableDesc( unsigned char* buf, Transponder *trans ); + void terrestrialDesc( unsigned char* buf, Transponder *trans ); + void freqListDesc( unsigned char* buf, Transponder *trans ); + void stop(); + + bool *ended; + QPtrList<Transponder> *transponders; + +protected: + + virtual void run(); +}; + + + +class DVBsi : public QObject, public KaffeineDVBsection +{ + Q_OBJECT + +public: + + DVBsi( bool *ok, int anum, int tnum, DvbStream *d, const QString &charset ); + ~DVBsi(); + bool getSection( int pid, int tid, int timeout=5000, int sid=0 ); + bool listChannels(); + bool tableSDT( unsigned char* buf ); + bool tablePAT( unsigned char *buf ); + bool tablePMT( unsigned char* buf ); + void serviceDesc( unsigned char* buf, ChannelDesc *desc ); + + QPtrList<ChannelDesc> channels; + QPtrList<Transponder> transponders; + DvbStream *dvb; + int indexChannels; + int progressTransponder; + int adapter, tuner; + +public slots: + + void go( QPtrList<Transponder> trans, int mode=1 ); + void stop(); + +protected: + + virtual void run(); + virtual void timerEvent( QTimerEvent *e ); + +private: + + void out( bool stopscan=true ); + + int scanMode; + NitSection *ns; + +signals: + + void end( bool ); +}; + +#endif /* DVBSI_H */ diff --git a/kaffeine/src/input/dvb/dvbstream.cpp b/kaffeine/src/input/dvb/dvbstream.cpp new file mode 100644 index 0000000..302c0d0 --- /dev/null +++ b/kaffeine/src/input/dvb/dvbstream.cpp @@ -0,0 +1,1390 @@ +/* + * dvbstream.cpp + * + * Copyright (C) 2003-2007 Christophe Thommeret <hftom@free.fr> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include <stdio.h> +#include <stdlib.h> +#include <ctype.h> +#include <sys/ioctl.h> +#include <sys/time.h> +#include <sys/stat.h> +#include <resolv.h> +#include <fcntl.h> +#include <unistd.h> +#include <signal.h> +#include <values.h> +#include <string.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <netdb.h> +#include <errno.h> +#include <math.h> + +#include <linux/dvb/dmx.h> + +#include <qdir.h> +#include <qprogressdialog.h> + +#include <klocale.h> +#include <kapplication.h> + +#include "dvbstream.h" +#include "dvbevents.h" +#include "gdvb.h" +#include "dvbcam.h" +#include "kaffeinedvbplugin.h" + +#define MAXTUNETRY 1 + + + +DvbStream::DvbStream( Device *d, const QString &charset, EventTable *et ) +{ + dvbDevice = d; + isRunning = false; + timeShifting = false; + waitPause = 0; + delOut = 0; + fdFrontend = fdDvr = 0; + ndmx = 0; + currentTransponder = Transponder(); + frontendName = QString("/dev/dvb/adapter%1/frontend%2").arg( dvbDevice->adapter ).arg( dvbDevice->tuner ); + dvrName = QString("/dev/dvb/adapter%1/dvr%2").arg( dvbDevice->adapter ).arg( dvbDevice->tuner ); + demuxName = QString("/dev/dvb/adapter%1/demux%2").arg( dvbDevice->adapter ).arg( dvbDevice->tuner ); + + out.setAutoDelete( true ); + + QString deviceType="NONE"; + switch ( dvbDevice->type ) { + case FE_QPSK: deviceType = "DVBS"; break; + case FE_OFDM: deviceType = "DVBT"; break; + case FE_QAM: deviceType = "DVBC"; break; + case FE_ATSC: deviceType = "DVBA"; break; + } + dvbEvents = new DVBevents( deviceType, dvbDevice->adapter, dvbDevice->tuner, charset, et ); + + camProbed = false; + cam = NULL; + plug = NULL; + + connect( &statusTimer, SIGNAL(timeout()), this, SLOT(checkStatus()) ); +} + + + +void DvbStream::setPlug( KaffeineDvbPlugin *p ) +{ + plug = p; +} + + + +void DvbStream::probeCam() +{ + int ci_type=0; + if ( camProbed ) + return; + if ( (ci_type=DvbCam::probe( dvbDevice->adapter, 0 ))>0 ) + cam = new DvbCam( dvbDevice->adapter, 0, dvbDevice->tuner, ci_type ); + camProbed = true; +} + + + +QStringList DvbStream::getSources( bool all ) +{ + if ( !all ) { + if ( dvbDevice->type==FE_OFDM ) + return QStringList( "Terrestrial" ); + if ( dvbDevice->type==FE_QAM ) + return QStringList( "Cable" ); + if ( dvbDevice->type==FE_ATSC ) + return QStringList( "Atsc" ); + } + QStringList source; + int i; + if ( dvbDevice->type==FE_QPSK ) { + for ( i=0; i<dvbDevice->numLnb; i++ ) + source+= dvbDevice->lnb[i].source; + } + else { + QString s = dvbDevice->source; + source+= s.remove(0,2); + } + return source; +} + + + +bool DvbStream::canSource( ChannelDesc *chan ) +{ + if ( chan->tp.type!=dvbDevice->type ) { + return false; + } + if ( dvbDevice->type!=FE_QPSK ) { + if ( chan->tp.type==dvbDevice->type ) + return true; + else + return false; + } + int i; + for ( i=0; i<dvbDevice->numLnb; i++ ) { + if ( dvbDevice->lnb[i].source.contains(chan->tp.source) ) + return true; + } + return false; +} + + + +int DvbStream::getSatPos( const QString &src ) +{ + int i; + + if ( dvbDevice->type!=FE_QPSK ) + return -1; + + for ( i=0; i<dvbDevice->numLnb; i++ ) + if ( dvbDevice->lnb[i].source.contains(src) ) + return i; + return -1; +} + + + +bool DvbStream::openFe() +{ + if ( fdFrontend ) { + fprintf(stderr,"openFe: fdFrontend != 0\n"); + return false; + } + fdFrontend = open( frontendName.ascii(), O_RDWR ); + if ( fdFrontend<0 ) { + perror("openFe:"); + fdFrontend = 0; + return false; + } + return true; +} + + + +bool DvbStream::closeFe() +{ + if ( !fdFrontend ) + return true; + if ( close( fdFrontend )<0 ) { + perror("closeFe: "); + return false; + } + fprintf(stderr,"Frontend closed\n"); + fdFrontend = 0; + currentTransponder = Transponder(); + return true; +} + + + +void DvbStream::connectStatus( bool con ) +{ + if ( con ) + statusTimer.start( 1000 ); + else + statusTimer.stop(); +} + + + +ChannelDesc DvbStream::getLiveChannel() +{ + int i; + + for ( i=0; i<(int)out.count(); i++ ) { + if ( out.at(i)->hasLive() ) + return out.at(i)->channel; + } + return ChannelDesc(); +} + + + +bool DvbStream::hasLive() +{ + int i; + + for ( i=0; i<(int)out.count(); i++ ) { + if ( out.at(i)->hasLive() ) + return true; + } + return false; +} + + + +bool DvbStream::hasRec() +{ + int i; + + for ( i=0; i<(int)out.count(); i++ ) { + if ( out.at(i)->hasRec() ) + return true; + } + return false; +} + + + +bool DvbStream::hasBroadcast() +{ + int i; + + for ( i=0; i<(int)out.count(); i++ ) { + if ( out.at(i)->hasBroadcast() ) + return true; + } + return false; +} + + + +bool DvbStream::liveIsRecording() +{ + int i; + + for ( i=0; i<(int)out.count(); i++ ) { + if ( out.at(i)->hasLive() ) { + if ( out.at(i)->hasRec() ) + return true; + else + return false; + } + } + return false; +} + + + +Transponder DvbStream::getCurrentTransponder() +{ + return currentTransponder; +} + + + +unsigned long DvbStream::getCurrentFreq() +{ + return currentTransponder.freq; +} + + + +bool DvbStream::isTuned() +{ + if ( fdFrontend ) + return true; + else + return false; +} + + + +bool DvbStream::tuneDvb( ChannelDesc *chan, bool dvr ) +{ + unsigned long lof=0; + int res, hiband=0; + struct dvb_frontend_parameters feparams; + struct dvb_frontend_info fe_info; + fe_status_t status; + unsigned long freq=chan->tp.freq; + unsigned long srate=chan->tp.sr; + int lnbPos = getSatPos( chan->tp.source ); + int rotorMove = 0; + int loop=0, i; + + closeFe(); + if ( !openFe() ) + return false; + + if ( (res = ioctl( fdFrontend, FE_GET_INFO, &fe_info ) < 0) ) { + perror("FE_GET_INFO: "); + return false; + } + + probeCam(); + + fprintf(stderr, "Using DVB device %d:%d \"%s\"\n", dvbDevice->adapter, dvbDevice->tuner, fe_info.name); + + freq*=1000; + srate*=1000; + + switch( fe_info.type ) { + case FE_OFDM : { + if (freq < 1000000) + freq*=1000UL; + feparams.frequency=freq; + feparams.u.ofdm.bandwidth=chan->tp.bandwidth; + feparams.u.ofdm.code_rate_HP=chan->tp.coderateH; + feparams.u.ofdm.code_rate_LP=chan->tp.coderateL; + feparams.u.ofdm.constellation=chan->tp.modulation; + feparams.u.ofdm.transmission_mode=chan->tp.transmission; + feparams.u.ofdm.guard_interval=chan->tp.guard; + feparams.u.ofdm.hierarchy_information=chan->tp.hierarchy; + fprintf(stderr,"tuning DVB-T to %lu Hz\n", freq); + fprintf(stderr,"inv:%d bw:%d fecH:%d fecL:%d mod:%d tm:%d gi:%d hier:%d\n", chan->tp.inversion, + chan->tp.bandwidth, chan->tp.coderateH, chan->tp.coderateL, chan->tp.modulation, + chan->tp.transmission, chan->tp.guard, chan->tp.hierarchy ); + break; + } + case FE_QAM : { + fprintf(stderr,"tuning DVB-C to %lu\n", freq); + feparams.frequency=freq; + feparams.u.qam.symbol_rate = srate; + feparams.u.qam.fec_inner = chan->tp.coderateH; + feparams.u.qam.modulation = chan->tp.modulation; + fprintf(stderr,"inv:%d sr:%lu fecH:%d mod:%d\n", chan->tp.inversion, + srate, chan->tp.coderateH, chan->tp.modulation ); + break; + } + case FE_QPSK : { + fprintf(stderr,"tuning DVB-S to %lu %c %lu\n", freq, chan->tp.pol, srate); + if (freq > 2200000) { + if ( dvbDevice->lnb[lnbPos].switchFreq ) { // Dual LO + if ( freq<(dvbDevice->lnb[lnbPos].switchFreq*1000) ) { + lof = dvbDevice->lnb[lnbPos].loFreq*1000; + } + else { + lof = dvbDevice->lnb[lnbPos].hiFreq*1000; + hiband = 1; + } + } + else { + if ( dvbDevice->lnb[lnbPos].hiFreq ) { // C Band Multipoint + if ( (chan->tp.pol=='h') || (chan->tp.pol=='H') ) + lof = (dvbDevice->lnb[lnbPos].hiFreq*1000); + else + lof = (dvbDevice->lnb[lnbPos].loFreq*1000); + } + else // Single LO + lof = (dvbDevice->lnb[lnbPos].loFreq*1000); + } + if ( freq<lof ) + feparams.frequency = ( lof-freq ); + else + feparams.frequency = ( freq-lof ); + } + else + feparams.frequency=freq; + + feparams.u.qpsk.symbol_rate=srate; + feparams.u.qpsk.fec_inner=chan->tp.coderateH; + fprintf(stderr,"inv:%d fecH:%d\n", chan->tp.inversion, chan->tp.coderateH ); + if ( setDiseqc( lnbPos, chan, hiband, rotorMove, dvr )!=0 ) { + closeFe(); + return false; + } + break; + } + case FE_ATSC : { + fprintf(stderr,"tuning ATSC to %lu\n", freq); + feparams.frequency=freq; + feparams.u.vsb.modulation = chan->tp.modulation; + fprintf(stderr,"inv:%d mod:%d\n", chan->tp.inversion, chan->tp.modulation ); + break; + } + } + if ( chan->tp.inversion==INVERSION_AUTO ) { + if ( fe_info.caps & FE_CAN_INVERSION_AUTO ) + feparams.inversion=chan->tp.inversion; + else { + fprintf(stderr,"Can NOT inversion_auto\n"); + feparams.inversion=INVERSION_OFF; + } + } + else + feparams.inversion=chan->tp.inversion; + + if ( rotorMove ) + loop = 2; + + while ( loop>-1 ) { + if (ioctl(fdFrontend,FE_SET_FRONTEND,&feparams) < 0) { + perror("ERROR tuning \n"); + closeFe(); + return false; + } + for ( i=0; i<(dvbDevice->tuningTimeout/100); i++ ) { + usleep( 100000 ); + fprintf( stderr, "." ); + if ( ioctl( fdFrontend, FE_READ_STATUS, &status )==-1 ) { + perror( "FE_READ_STATUS" ); + break; + } + if ( status & FE_HAS_LOCK ) { + fprintf(stderr," LOCKED."); + loop = 0; + break; + } + } + fprintf(stderr,"\n"); + --loop; + } + + if ( !( status & FE_HAS_LOCK ) ) { + fprintf( stderr, "\nNot able to lock to the signal on the given frequency\n" ); + closeFe(); + return false; + } + + if ( rotorMove ) + dvbDevice->lnb[lnbPos].currentSource = chan->tp.source; + + if ( !dvr ) + return true; + + if ( ( fdDvr = open( dvrName.ascii(), O_RDONLY|O_NONBLOCK)) < 0 ) { + perror("DVR DEVICE: "); + closeFe(); + fdDvr = 0; + return false; + } + pfd.fd=fdDvr; + pfd.events=POLLIN|POLLPRI; + + currentTransponder = chan->tp; + return true; +} + + + +int DvbStream::setDiseqc( int switchPos, ChannelDesc *chan, int hiband, int &rotor, bool dvr ) +{ + struct dvb_diseqc_master_cmd switchCmd[] = { + { { 0xe0, 0x10, 0x38, 0xf0, 0x00, 0x00 }, 4 }, + { { 0xe0, 0x10, 0x38, 0xf2, 0x00, 0x00 }, 4 }, + { { 0xe0, 0x10, 0x38, 0xf1, 0x00, 0x00 }, 4 }, + { { 0xe0, 0x10, 0x38, 0xf3, 0x00, 0x00 }, 4 }, + { { 0xe0, 0x10, 0x38, 0xf4, 0x00, 0x00 }, 4 }, + { { 0xe0, 0x10, 0x38, 0xf6, 0x00, 0x00 }, 4 }, + { { 0xe0, 0x10, 0x38, 0xf5, 0x00, 0x00 }, 4 }, + { { 0xe0, 0x10, 0x38, 0xf7, 0x00, 0x00 }, 4 }, + { { 0xe0, 0x10, 0x38, 0xf8, 0x00, 0x00 }, 4 }, + { { 0xe0, 0x10, 0x38, 0xfa, 0x00, 0x00 }, 4 }, + { { 0xe0, 0x10, 0x38, 0xf9, 0x00, 0x00 }, 4 }, + { { 0xe0, 0x10, 0x38, 0xfb, 0x00, 0x00 }, 4 }, + { { 0xe0, 0x10, 0x38, 0xfc, 0x00, 0x00 }, 4 }, + { { 0xe0, 0x10, 0x38, 0xfe, 0x00, 0x00 }, 4 }, + { { 0xe0, 0x10, 0x38, 0xfd, 0x00, 0x00 }, 4 }, + { { 0xe0, 0x10, 0x38, 0xff, 0x00, 0x00 }, 4 }, + }; + + int i; + int voltage18 = ( (chan->tp.pol=='H')||(chan->tp.pol=='h') ); + int ci = 4 * switchPos + 2 * hiband + (voltage18 ? 1 : 0); + + fprintf( stderr, "DiSEqC: switch pos %i, %sV, %sband (index %d)\n", switchPos, voltage18 ? "18" : "13", hiband ? "hi" : "lo", ci ); + if ( ci < 0 || ci >= (int)(sizeof(switchCmd)/sizeof(struct dvb_diseqc_master_cmd)) ) + return -EINVAL; + + if ( ioctl(fdFrontend, FE_SET_TONE, SEC_TONE_OFF) ) + perror("FE_SET_TONE failed"); + usleep(15*1000); + if ( ioctl(fdFrontend, FE_SET_VOLTAGE, ci%2 ? SEC_VOLTAGE_18 : SEC_VOLTAGE_13) ) + perror("FE_SET_VOLTAGE failed"); + + fprintf( stderr, "DiSEqC: %02x %02x %02x %02x %02x %02x\n", switchCmd[ci].msg[0], switchCmd[ci].msg[1], switchCmd[ci].msg[2], switchCmd[ci].msg[3], switchCmd[ci].msg[4], switchCmd[ci].msg[5] ); + for ( i=0; i<2; ++i ) { + usleep(15*1000); + if ( ioctl(fdFrontend, FE_DISEQC_SEND_MASTER_CMD, &switchCmd[ci]) ) + perror("FE_DISEQC_SEND_MASTER_CMD failed"); + } + + QString msg; + if ( dvbDevice->lnb[switchPos].rotorType!=0 && chan->tp.source!=dvbDevice->lnb[switchPos].currentSource ) { + int i, index=-1; + double angle=0.0, oldAngle=0.0; + fprintf( stderr, "Driving rotor to %s\n", chan->tp.source.ascii() ); + for ( i=0; i<(int)dvbDevice->lnb[switchPos].source.count(); i++ ) { + if ( dvbDevice->lnb[switchPos].source[i]==chan->tp.source ) { + index = i; + break; + } + } + angle = getSourceAngle( chan->tp.source ); + if ( dvbDevice->lnb[switchPos].rotorType==1 ) { + fprintf( stderr, "Rotor: gotoX=%f\n", angle ); + gotoX( angle ); + } + else { + int pos = dvbDevice->lnb[switchPos].position[index]; + fprintf( stderr, "Rotor: gotoN=%d\n", pos ); + rotorCommand( 9, pos ); + } + if ( dvbDevice->lnb[switchPos].currentSource.isEmpty() ) { + rotor = 10; + msg = i18n("Moving rotor from unknown position..."); + } + else { + oldAngle = getSourceAngle( dvbDevice->lnb[switchPos].currentSource ); + fprintf( stderr, "old rotor pos: %f °\n", oldAngle ); + fprintf( stderr, "new rotor pos: %f °\n", angle ); + angle = fabs(angle-oldAngle); + fprintf( stderr, "Rotation angle: %f °\n", angle ); + if ( voltage18 ) + rotor = (int)(angle*dvbDevice->lnb[switchPos].speed18v)+1; + else + rotor = (int)(angle*dvbDevice->lnb[switchPos].speed13v)+1; + msg = i18n("Moving rotor..."); + } + fprintf( stderr, "Rotation time: %d sec.\n", rotor ); + } + + if ( rotor ) { + int j; + if ( !dvr ) { + for ( j=0; j<(rotor*2); j++ ) { + usleep( 500000 ); + } + } + else { + QProgressDialog progress( msg, i18n("Cancel"), rotor*2, 0, "progress", true ); + for ( j=0; j<(rotor*2); j++ ) { + progress.setProgress( j ); + qApp->processEvents(); + if ( progress.wasCanceled() ) + break; + usleep( 500000 ); + } + progress.setProgress( rotor*2 ); + qApp->processEvents(); + } + } + + for ( i=0; i<2; ++i ) { + usleep(15*1000); + if ( ioctl(fdFrontend, FE_DISEQC_SEND_BURST, (ci/4)%2 ? SEC_MINI_B : SEC_MINI_A) ) + perror("FE_DISEQC_SEND_BURST failed"); + } + + usleep(15*1000); + if ( ioctl(fdFrontend, FE_SET_TONE, (ci/2)%2 ? SEC_TONE_ON : SEC_TONE_OFF) ) + perror("FE_SET_TONE failed"); + + return 0; +} + + + +double DvbStream::getSourceAngle( QString source ) +{ + double angle=1.0; + int pos = source.findRev("-"); + source.remove(0,pos+1); + source = source.upper(); + if ( source.endsWith("W") ) + angle = -1.0; + source.truncate( source.length()-1 ); + angle*= source.toDouble(); + return getAzimuth( angle ); +} + + + +#define TO_RADS (M_PI / 180.0) +#define TO_DEC (180.0 / M_PI) + +double DvbStream::getAzimuth( double angle ) +{ + double latitude = dvbDevice->usalsLatitude; + double longitude = dvbDevice->usalsLongitude; + double P, Ue, Us, az, x, el, Azimuth; + + P = latitude*TO_RADS; // Earth Station Latitude + Ue = longitude*TO_RADS; // Earth Station Longitude + Us = angle*TO_RADS; // Satellite Longitude + + az = M_PI+atan( tan( Us-Ue )/sin( P ) ); + x = acos( cos(Us-Ue)*cos(P) ); + el = atan( ( cos( x )-0.1513 )/sin( x ) ); + Azimuth = atan( ( -cos(el)*sin(az) )/( sin(el)*cos(P)-cos(el)*sin(P)*cos(az)) )* TO_DEC; + + return Azimuth; +} + + + +void DvbStream::gotoX( double azimuth ) +{ + double USALS=0.0; + int CMD1=0x00, CMD2=0x00; + int DecimalLookup[10] = { 0x00, 0x02, 0x03, 0x05, 0x06, 0x08, 0x0A, 0x0B, 0x0D, 0x0E }; + + if ( azimuth>0.0 ) + CMD1 = 0xE0; // East + else + CMD1 = 0xD0; // West + + USALS = fabs( azimuth ); + + while (USALS > 16) { + CMD1++; + USALS-= 16; + } + while (USALS >= 1.0) { + CMD2+=0x10; + USALS--; + } + USALS*= 10.0; + int rd = (int)USALS; + USALS-= rd; + if ( USALS>0.5 ) + ++rd; + CMD2+= DecimalLookup[rd]; + + rotorCommand( 12, CMD1, CMD2 ); +} + + + +void DvbStream::rotorCommand( int cmd, int n1, int n2, int n3 ) +{ + struct dvb_diseqc_master_cmd cmds[] = { + { { 0xe0, 0x31, 0x60, 0x00, 0x00, 0x00 }, 3 }, //0 Stop Positioner movement + { { 0xe0, 0x31, 0x63, 0x00, 0x00, 0x00 }, 3 }, //1 Disable Limits + { { 0xe0, 0x31, 0x66, 0x00, 0x00, 0x00 }, 3 }, //2 Set East Limit + { { 0xe0, 0x31, 0x67, 0x00, 0x00, 0x00 }, 3 }, //3 Set West Limit + { { 0xe0, 0x31, 0x68, 0x00, 0x00, 0x00 }, 4 }, //4 Drive Motor East continously + { { 0xe0, 0x31, 0x68,256-n1,0x00, 0x00 }, 4 }, //5 Drive Motor East nn steps + { { 0xe0, 0x31, 0x69,256-n1,0x00, 0x00 }, 4 }, //6 Drive Motor West nn steps + { { 0xe0, 0x31, 0x69, 0x00, 0x00, 0x00 }, 4 }, //7 Drive Motor West continously + { { 0xe0, 0x31, 0x6a, n1, 0x00, 0x00 }, 4 }, //8 Store nn + { { 0xe0, 0x31, 0x6b, n1, 0x00, 0x00 }, 4 }, //9 Goto nn + { { 0xe0, 0x31, 0x6f, n1, n2, n3 }, 4}, //10 Recalculate Position + { { 0xe0, 0x31, 0x6a, 0x00, 0x00, 0x00 }, 4 }, //11 Enable Limits + { { 0xe0, 0x31, 0x6e, n1, n2, 0x00 }, 5 }, //12 Gotoxx + { { 0xe0, 0x10, 0x38, 0xF4, 0x00, 0x00 }, 4 } //13 User + }; + + int i; + for ( i=0; i<2; ++i ) { + usleep(15*1000); + if ( ioctl( fdFrontend, FE_DISEQC_SEND_MASTER_CMD, &cmds[cmd] ) ) + perror("Rotor : FE_DISEQC_SEND_MASTER_CMD failed"); + } +} + + + +bool DvbStream::setPids( DVBout *o ) +{ + int i, dmx; + struct dmx_pes_filter_params pesFilterParams; + dmx_pes_type_t pestype = DMX_PES_OTHER; + QValueList<int> pidList; + + pidList = o->pidsList(); + + for ( i=0; i<(int)pidList.count(); i++ ) { + if ( ( dmx = open( demuxName.ascii(), O_RDWR)) < 0 ) { + fprintf(stderr,"FD %i: ",i); + perror("DEMUX DEVICE: "); + return false; + } + else + o->dmx.append(dmx); + } + + for ( i=0; i<(int)pidList.count(); i++ ) { + pesFilterParams.pid = pidList[i]; + pesFilterParams.input = DMX_IN_FRONTEND; + pesFilterParams.output = DMX_OUT_TS_TAP; + pesFilterParams.pes_type = pestype; + pesFilterParams.flags = DMX_IMMEDIATE_START; + if ( ioctl( o->dmx[i], DMX_SET_PES_FILTER, &pesFilterParams) < 0) { + fprintf( stderr, "FILTER %i: ", pidList[i] ); + perror("DMX SET PES FILTER"); + } + } + + ndmx +=pidList.count(); + + return true; +} + + + +void DvbStream::removePids( DVBout *o ) +{ + int i; + + for ( i=0; i<(int)o->dmx.count(); i++ ) + close( o->dmx[i] ); + ndmx -=o->dmx.count(); +} + + + +void DvbStream::removeOut( DVBout *o ) +{ + disconnect( o, SIGNAL(endRecord(DVBout*,RecTimer*,bool)), this, SLOT(recordEnded(DVBout*,RecTimer*,bool)) ); + disconnect( o, SIGNAL(playDvb()), this, SLOT(receivePlayDvb()) ); + disconnect( o, SIGNAL(shifting(bool)), this, SLOT(receiveShifting(bool)) ); + delOut = o; + while ( delOut ) + usleep(100); +} + + + +bool DvbStream::checkStatus() +{ + int32_t strength; + fe_status_t festatus; + bool ret=true; + + strength=0; + ioctl(fdFrontend,FE_READ_SIGNAL_STRENGTH,&strength); + emit signalStatus(strength*100/65535); + + strength=0; + ioctl(fdFrontend,FE_READ_SNR,&strength); + emit snrStatus(strength*100/65535); + + memset( &festatus, 0, sizeof(festatus) ); + ioctl(fdFrontend,FE_READ_STATUS,&festatus); + + if (festatus & FE_HAS_LOCK) + emit lockStatus( true ); + else { + emit lockStatus( false ); + ret = false; + } + + return ret; +} + + + +int DvbStream::getSNR() +{ + int32_t snr=0; + if ( fdFrontend ) { + ioctl( fdFrontend, FE_READ_SNR, &snr ); + snr = snr*100/65535; + } + return snr; +} + + + +bool DvbStream::hasVideo() +{ + if ( getLiveChannel().vpid ) + return true; + return false; +} + + + +void DvbStream::run() +{ + unsigned char buf[188]; + int n, i, thWrite=0; + int WSIZE=188*8; + DVBout *o=0; + + signal( SIGPIPE, SIG_IGN ); + + while ( isRunning ) { + if ( poll( &pfd, 1, 100 ) ) { + n = read( fdDvr, buf, 188 ); + if ( n==188 ) { + memcpy( thBuf+thWrite, buf, n ); + thWrite+=n; + if ( thWrite==WSIZE ) { + for ( i=0; i<(int)out.count(); i++ ) + out.at(i)->process( thBuf, WSIZE ); + thWrite = 0; + } + } + } + else + usleep(1000); + + if ( waitPause>0 ) { + o = 0; + for ( i=0; i<(int)out.count(); i++ ) + if ( out.at(i)->hasLive() ) + o = out.at(i); + if ( o ) { + if ( o->doPause( timeShiftFileName ) ) + waitPause = 0; + else + waitPause = -1; + } + else + waitPause = -1; + } + + if ( delOut ) { + out.remove( delOut ); + delOut = 0; + } + } + + fprintf(stderr,"dvbstream::run() end\n"); +} + + + +bool DvbStream::doPause( const QString &name ) +{ + //if ( !hasVideo() ) return false; + + if ( !timeShifting ) { + timeShiftFileName = name; + waitPause = 1; + while ( waitPause>0 ) + usleep(100); + if ( waitPause<0 ) + return false; + else + receiveShifting( true ); + return true; + } + return false; +} + + + +bool DvbStream::timeShiftMode() +{ + return timeShifting; +} + + + +void DvbStream::receiveShifting( bool b ) +{ + timeShifting = b; + emit shifting( b ); +} + + + +bool DvbStream::running() const +{ + return isRunning; +} + + + +void DvbStream::receivePlayDvb() +{ + KApplication::kApplication()->postEvent( this, new QTimerEvent( 500 ) ); +} + + + +void DvbStream::timerEvent( QTimerEvent* ev ) +{ + switch ( ev->timerId() ) { + case 500: + emit playDvb(); + } +} + + + +void DvbStream::recordEnded( DVBout *o, RecTimer* t, bool kill ) +{ + int i; + + if ( kill ) { + removePids( o ); + removeOut( o ); + if ( out.count()==0 ) + stop(); + else if ( cam ) { + for ( i=0; i<(int)out.count(); i++ ) { + if ( out.at(i)->channel.fta ) { + i=-1; + break; + } + } + if ( i!=-1 ) + cam->stop(); + } + } + recordingState(); + if ( t ) + emit timerEnded( t ); +} + + + +void DvbStream::recordingState() +{ + int i; + + for ( i=0; i<(int)out.count(); i++ ) { + if ( out.at(i)->hasRec() ) { + emit isRecording( true ); + return; + } + } + emit isRecording( false ); +} + + + +void DvbStream::updateTimer( RecTimer *t, int ms ) +{ + int i; + + for ( i=0; i<(int)out.count(); i++ ) { + if ( out.at(i)->recTimer==t ) { + if ( ms ) + out.at(i)->changeTimer( ms ); + else + out.at(i)->stopRec(); + return; + } + } + if ( !ms ) + emit timerEnded( t ); // not running +} + + + +void DvbStream::stopBroadcast() +{ + int i; + DVBout *o=0; + QPtrList<DVBout> p; + + for ( i=0; i<(int)out.count(); i++ ) { + o = out.at(i); + o->stopBroadcast(); + if ( !o->hasLive() && !o->hasRec() ) + p.append( o ); + } + for ( i=0; i<(int)p.count(); i++ ) { + removePids( p.at(i) ); + removeOut( p.at(i) ); + } + if ( out.count()==0 ) + stop(); + emit isBroadcasting( false ); +} + + + +int DvbStream::canStartBroadcast( bool &live, ChannelDesc *chan ) +{ + int i, ret=0; + + for ( i=0; i<(int)out.count(); i++ ) { + if ( (chan->tp!=out.at(i)->channel.tp) && out.at(i)->hasRec() ) + return ErrIsRecording; + if ( cam && out.at(i)->hasRec() && out.at(i)->channel.fta && chan->fta && out.at(i)->channel.sid!=chan->sid ) + return ErrCamUsed; + if ( out.at(i)->hasLive() && chan->tp!=out.at(i)->channel.tp ) + live = true; + } + return ret; +} + + + +bool DvbStream::startBroadcast( QPtrList<ChannelDesc> *list, Ts2Rtp *rtp ) +{ + int i, j; + bool stop=false, newout; + DVBout *o=0; + int no=0; + ChannelDesc *chan=list->at(0); + QPtrList<ChannelDesc> broadcastList; + broadcastList.setAutoDelete( true ); + + if ( !isTuned() ) { + for ( i=0; i<MAXTUNETRY; i++ ) { + if ( tuneDvb( chan ) ) { + i = -1; + break; + } + else + usleep(100000); + } + if ( i<0 ) + stop = true; + else + return false; + } + + for ( i=0; i<(int)list->count(); i++ ) { + newout = false; + o = 0; + for ( j=0; j<(int)out.count(); j++ ) { + if ( out.at(j)->channel.name==list->at(i)->name ) + o = out.at(j); + } + + if ( !o ) { + o = new DVBout( *list->at(i), dvbDevice->adapter, dvbDevice->tuner, plug ); + connect( o, SIGNAL(endRecord(DVBout*,RecTimer*,bool)), this, SLOT(recordEnded(DVBout*,RecTimer*,bool)) ); + connect( o, SIGNAL(playDvb()), this, SLOT(receivePlayDvb()) ); + connect( o, SIGNAL(shifting(bool)), this, SLOT(receiveShifting(bool)) ); + out.append( o ); + if ( !setPids( o ) ) { + removePids( o ); + removeOut( o ); + o = 0; + } + else + newout = true; + } + + if ( o ) { + if ( !o->goBroadcast( rtp ) ) { + if ( newout ) { + removePids( o ); + removeOut( o ); + } + } + else { + broadcastList.append( new ChannelDesc( *list->at(i) ) ); + no++; + } + } + } + + if ( !no && stop ) + stopFrontend(); + else + rtp->addChannels( &broadcastList ); + + fprintf(stderr,"NOUT: %d\n", out.count() ); + + if ( !no ) + return false; + else + startReading(); + emit isBroadcasting( true ); + return true; +} + + + +int DvbStream::canStartTimer( bool &live, ChannelDesc *chan ) +{ + int i, ret=0; + DVBout *o; + + for ( i=0; i<(int)out.count(); i++ ) { + o = out.at(i); + if ( (chan->tp!=o->channel.tp) && o->hasRec() ) + return ErrIsRecording; + if ( (o->channel.name==chan->name) && o->hasRec() ) + return ErrIsRecording; + if ( (chan->tp==o->channel.tp) && o->hasRec() ) { + if ( chan->fta && cam && o->channel.fta ) + return ErrCamUsed; + } + if ( o->hasLive() ) { + if ( chan->tp!=o->channel.tp ) + live = true; + else if ( cam && chan->fta && o->channel.fta ) + live = true; + } + } + return ret; +} + + + +bool DvbStream::startTimer( ChannelDesc *chan, QString path, int maxsize, RecTimer *t, QString name ) +{ + int i; + bool stop=false, newout=false; + DVBout *o=0; + QPtrList<DVBout> p; + + for ( i=0; i<(int)out.count(); i++ ) { + if ( out.at(i)->channel.name==chan->name ) + o = out.at(i); + else { + if ( out.at(i)->hasBroadcast() && out.at(i)->channel.tp!=chan->tp ) { + p.append( out.at(i) ); + } + } + } + + for ( i=0; i<(int)p.count(); i++ ) { + p.at(i)->stopBroadcast(); + removePids( p.at(i) ); + removeOut( p.at(i) ); + } + + if ( p.count() ) { + emit isBroadcasting( false ); + this->stop(); + } + + if ( !isTuned() ) { + for ( i=0; i<MAXTUNETRY; i++ ) { + if ( tuneDvb( chan ) ) { + i = -1; + break; + } + else + usleep(100000); + } + if ( i<0 ) + stop = true; + else + return false; + } + + if ( !o ) { + o = new DVBout( *chan, dvbDevice->adapter, dvbDevice->tuner, plug ); + connect( o, SIGNAL(endRecord(DVBout*,RecTimer*,bool)), this, SLOT(recordEnded(DVBout*,RecTimer*,bool)) ); + connect( o, SIGNAL(playDvb()), this, SLOT(receivePlayDvb()) ); + connect( o, SIGNAL(shifting(bool)), this, SLOT(receiveShifting(bool)) ); + out.append( o ); + if ( !setPids( o ) ) { + if ( stop ) + stopFrontend(); + removePids( o ); + removeOut( o ); + return false; + } + newout = true; + } + + if ( t->mode && !name.contains("%date") ) + name+= "-%date"; + name = name.replace( "%chan", chan->name ).replace("%date", t->begin.toString( "yyyyMMdd-hhmmss" ) ).replace("%name", t->name ); + name = name.replace( "/", "_" ).replace( ">", "_" ).replace("<","_").replace(":","_").replace('"',"_").replace("\\","_").replace("|","_"); + name = path+name; + + if ( !o->goRec( name, maxsize, t ) ) { + if ( stop ) + stopFrontend(); + if ( newout ) { + removePids( o ); + removeOut( o ); + } + return false; + } + + fprintf(stderr,"NOUT: %d\n", out.count() ); + if ( chan->fta && cam && ( ((cam->running() && chan->sid!=cam->serviceId()) || !cam->running()) ) ) + cam->restart( chan->sid ); + + startReading(); + + recordingState(); + return true; +} + + + +int DvbStream::goLive( ChannelDesc *chan, const QString &pipeName ) +{ + int i; + bool stop=false; + DVBout *o=0; + + for ( i=0; i<(int)out.count(); i++ ) { + if ( (chan->tp!=out.at(i)->channel.tp) && out.at(i)->hasRec() ) + return ErrIsRecording; + if ( (chan->tp!=out.at(i)->channel.tp) && out.at(i)->hasBroadcast() ) + return ErrIsBroadcasting; + if ( (chan->tp==out.at(i)->channel.tp) && (out.at(i)->hasBroadcast() || out.at(i)->hasRec())) { + if ( chan->fta && cam && cam->running() && (cam->serviceId()!=chan->sid) ) + return ErrCamUsed; + } + if ( out.at(i)->channel.name==chan->name ) + o = out.at(i); + } + + if ( !isTuned() ) { + for ( i=0; i<MAXTUNETRY; i++ ) { + if ( tuneDvb( chan ) ) { + i = -1; + break; + } + else + usleep(100000); + } + if ( i<0 ) + stop = true; + else + return ErrCantTune; + } + + if ( !o ) { + o = new DVBout( *chan, dvbDevice->adapter, dvbDevice->tuner, plug ); + connect( o, SIGNAL(endRecord(DVBout*,RecTimer*,bool)), this, SLOT(recordEnded(DVBout*,RecTimer*,bool)) ); + connect( o, SIGNAL(playDvb()), this, SLOT(receivePlayDvb()) ); + connect( o, SIGNAL(shifting(bool)), this, SLOT(receiveShifting(bool)) ); + out.append( o ); + if ( !setPids( o ) ) { + if ( stop ) + stopFrontend(); + removePids( o ); + removeOut( o ); + return ErrCantSetPids; + } + } + + if ( o->hasRec() ) + i = ErrDontSwitchAudio; + else + i = 0; + + o->goLive( pipeName ); + fprintf(stderr,"NOUT: %d\n", out.count() ); + + if ( chan->fta && cam && !cam->running() ) + cam->restart( chan->sid ); + startReading(); + + return i; +} + + + +void DvbStream::preStopLive() +{ + int i; + DVBout *o; + + for ( i=0; i<(int)out.count(); i++ ) { + o = out.at(i); + if ( o->hasLive() ) { + o->preStopLive(); + break; + } + } +} + + + +void DvbStream::stopLive( ChannelDesc *chan ) +{ + int i; + DVBout *o; + QPtrList<DVBout> p; + bool camUsed = false; + + fprintf(stderr,"Asked to stop\n"); + for ( i=0; i<(int)out.count(); i++ ) { + o = out.at(i); + if ( o->hasLive() ) { + o->stopLive(); + if ( !o->hasRec() && !o->hasBroadcast() ) { + p.append( o ); + } + break; + } + } + for ( i=0; i<(int)p.count(); i++ ) { + removePids( p.at(i) ); + removeOut( p.at(i) ); + } + fprintf(stderr,"Live stopped\n"); + if ( cam ) { + for ( i=0; i<(int)out.count(); i++ ) { + if ( out.at(i)->channel.fta ) + camUsed = true; + } + } + if ( cam && !camUsed ) + cam->stop(); + if ( out.count()==0 && chan->tp!=currentTransponder ) + stop(); +} + + + +void DvbStream::startReading() +{ + if ( !isRunning ) { + isRunning = true; + start(); + dvbEvents->go( currentTransponder.source, currentTransponder.freq, true ); + } +} + + + +void DvbStream::stop() +{ + isRunning = false; + if ( !wait(10000) ) { + terminate(); + wait(); + fprintf(stderr,"dvbstream::run() terminated\n"); + } + if ( cam ) + cam->stop(); + dvbEvents->stop(); + stopFrontend(); +} + + + +void DvbStream::stopFrontend() +{ + if ( fdDvr ) { + close( fdDvr ); + fprintf(stderr,"fdDvr closed\n"); + fdDvr = 0; + } + closeFe(); +} + + + +void DvbStream::setScanning( bool b ) +{ + connectStatus( b ); +} + + + +void DvbStream::stopScan() +{ + closeFe(); +} + + + +DvbStream::~DvbStream() +{ + stop(); + if ( cam ) { + cam->stop(); + delete cam; + } + delete dvbEvents; +} + +#include "dvbstream.moc" diff --git a/kaffeine/src/input/dvb/dvbstream.h b/kaffeine/src/input/dvb/dvbstream.h new file mode 100644 index 0000000..a5deb52 --- /dev/null +++ b/kaffeine/src/input/dvb/dvbstream.h @@ -0,0 +1,163 @@ +/* + * dvbstream.h + * + * Copyright (C) 2003-2007 Christophe Thommeret <hftom@free.fr> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef DVBSTREAM_H +#define DVBSTREAM_H + +#include <sys/poll.h> +#include <sys/stat.h> + +#include <qthread.h> +#include <qptrlist.h> +#include <qfile.h> +#include <qobject.h> +#include <qtimer.h> +#include <qstringlist.h> + +#include "channeldesc.h" +#include "dvbout.h" +#include "ts2rtp.h" +#include "dvbconfig.h" + +#define MAX_CHANNELS 8 + +class DVBevents; +class DvbCam; +class KaffeineDvbPlugin; +class EventTable; + + + +class DvbStream : public QObject, public QThread +{ + Q_OBJECT + +public : + + enum { ErrDontSwitchAudio=-1, ErrCantTune=1, ErrCantSetPids=2, ErrIsRecording=3, ErrNoLive=4, + ErrCantOpenFile=5, ErrIsBroadcasting=6, ErrCamUsed=7 }; + + DvbStream( Device *d, const QString &charset, EventTable *et ); + ~DvbStream(); + int getAdapter() { return dvbDevice->adapter; } + int getTuner() { return dvbDevice->tuner; } + fe_type_t getType() {return dvbDevice->type; } + void setPlug( KaffeineDvbPlugin *p ); + QStringList getSources( bool all=false ); + bool canSource( ChannelDesc *chan ); + bool tuneDvb( ChannelDesc *chan, bool dvr=true ); + void stopFrontend(); + virtual void run(); + int goLive( ChannelDesc *chan, const QString &pipeName ); + void preStopLive(); + void stopLive( ChannelDesc *chan ); + void stop(); + void stopScan(); + void setScanning( bool b ); + bool hasVideo(); + bool doPause( const QString &name ); + bool timeShiftMode(); + bool running() const; + ChannelDesc getLiveChannel(); + Transponder getCurrentTransponder(); + unsigned long getCurrentFreq(); + bool isTuned(); + bool startTimer( ChannelDesc *chan, QString path, int maxsize, RecTimer *t, QString filename ); + int canStartTimer( bool &live, ChannelDesc *chan ); + int canStartBroadcast( bool &live, ChannelDesc *chan ); + bool startBroadcast( QPtrList<ChannelDesc> *list, Ts2Rtp *rtp ); + void stopBroadcast(); + bool hasRec(); + bool hasBroadcast(); + bool hasLive(); + bool liveIsRecording(); + int getSNR(); + + unsigned char thBuf[188*10]; + struct pollfd pfd; + DVBevents *dvbEvents; + +public slots: + + bool checkStatus(); + void receivePlayDvb(); + void recordEnded( DVBout *o, RecTimer *t, bool kill ); + void receiveShifting( bool b ); + void updateTimer( RecTimer *t, int ms ); + +protected: + + void timerEvent( QTimerEvent* ev ); + +private : + + int setDiseqc( int switchPos, ChannelDesc *chan, int hiband, int &rotor, bool dvr ); + void rotorCommand( int cmd, int n1=0, int n2=0, int n3=0 ); + void gotoX( double azimuth ); + double getAzimuth( double angle ); + double getSourceAngle( QString source ); + int getSatPos( const QString &src ); + bool setPids( DVBout *o ); + void removePids( DVBout *o ); + void removeOut( DVBout *o ); + void recordingState(); + void startReading(); + void probeCam(); + bool openFe(); + bool closeFe(); + void connectStatus( bool con ); + + QFile liveFile; + bool timeShifting; + QPtrList<DVBout> out; + Device *dvbDevice; + int waitPause; + DVBout *delOut; + Transponder currentTransponder; + + QString frontendName; + QString dvrName; + QString demuxName; + int fdFrontend; + int ndmx; + int fdDvr, fdPipe; + bool isRunning; + QTimer statusTimer; + QString timeShiftFileName; + DvbCam *cam; + bool camProbed; + KaffeineDvbPlugin *plug; + +signals: + + void playDvb(); + void isRecording(bool); + void isBroadcasting(bool); + void timerEnded(RecTimer*); + + void errorMsg( QString ); + void snrStatus( int ); + void signalStatus( int ); + void lockStatus( bool ); + void shifting( bool ); + +}; + +#endif /* DVBSTREAM_H */ diff --git a/kaffeine/src/input/dvb/gdvb.h b/kaffeine/src/input/dvb/gdvb.h new file mode 100644 index 0000000..7f1951c --- /dev/null +++ b/kaffeine/src/input/dvb/gdvb.h @@ -0,0 +1,30 @@ +/* + * gdvb.h + * + * Copyright (C) 2004-2005 Christophe Thommeret <hftom@free.fr> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef GDVB_H +#define GDVB_H + +#define TS_SIZE 188 +#define MAX_AUDIO 6 +#define MAX_DVBSUB 3 + +enum { OutLive=2, OutRec=4, OutRtp=8, OutTS=16 }; + +#endif /* GDVB_H */ diff --git a/kaffeine/src/input/dvb/kaffeinedvb.rc b/kaffeine/src/input/dvb/kaffeinedvb.rc new file mode 100644 index 0000000..0104b78 --- /dev/null +++ b/kaffeine/src/input/dvb/kaffeinedvb.rc @@ -0,0 +1,24 @@ +<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd"> +<kpartgui name="kaffeinedvb" version="5"> +<MenuBar> + <Menu name="dvb"><text>&DVB</text> + <Action name="dvb_show_osd"/> + <Action name="dvb_browse_next" /> + <Action name="dvb_browse_prev" /> + <Action name="dvb_browse_zap" /> + <Action name="dvb_browse_advance" /> + <Action name="dvb_browse_retreat" /> + <Separator/> + <Action name="dvb_instant_record"/> + <Separator/> + <Action name="dvb_recall"/> + <Separator/> + <Action name="dvb_show_epg"/> + <Action name="dvb_show_timers"/> + <Action name="dvb_show_broadcast"/> + <Separator/> + <Action name="dvb_channels"/> + <Action name="dvb_config"/> + </Menu> +</MenuBar> +</kpartgui> diff --git a/kaffeine/src/input/dvb/kevents.cpp b/kaffeine/src/input/dvb/kevents.cpp new file mode 100644 index 0000000..c24d1c4 --- /dev/null +++ b/kaffeine/src/input/dvb/kevents.cpp @@ -0,0 +1,478 @@ +/* + * kevents.cpp + * + * Copyright (C) 2004-2007 Christophe Thommeret <hftom@free.fr> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include <qlayout.h> +#include <qfile.h> +#include <qdir.h> +#include <qpopupmenu.h> +#include <qcursor.h> +#include <qwhatsthis.h> +#include <qcheckbox.h> +#include <qtooltip.h> + +#include <klocale.h> +#include <kiconloader.h> + +#include "kevents.h" +#include "channeldesc.h" +#include "dvbevents.h" +#include "dvbstream.h" + + + +EListViewItem::EListViewItem( QListView *parent, QString chanName, QString eBegin, QString eDuration, QString eTitle, EventDesc *desc ) : KListViewItem( parent, chanName, eBegin, eDuration, eTitle ) +{ + event = desc; +} + + + +int EListViewItem::compare( QListViewItem *i, int col, bool ascending ) const +{ + EListViewItem *ei = (EListViewItem*)i; + + if ( col != 1 ) + return QListViewItem::compare( i, col, ascending ); + + if ( event->startDateTime<ei->event->startDateTime ) + return -1; + if ( event->startDateTime==ei->event->startDateTime ) + return 0; + return 1; +} + + + +KEvents::KEvents( QPtrList<ChannelDesc> *chans, QPtrList<DvbStream> *d, EventTable *t, QWidget *parent, QSize size ) : QDialog( parent ) +{ + dvb = d; + events = t; + channels = chans; + + setCaption( i18n("Electronic Program Guide") ); + + QGridLayout *grid = new QGridLayout( this, 1, 1, 11, 6, "grid"); + QHBoxLayout *hbox = new QHBoxLayout( 0, 0, 6, "hbox" ); + QVBoxLayout *vbox = new QVBoxLayout( 0, 0, 6 , "vbox"); + + resetBtn = new KPushButton( i18n("Refresh"), this ); + hbox->addWidget( resetBtn ); + allBtn = new KPushButton( i18n("Scheduled"), this ); + hbox->addWidget( allBtn ); + currentNextBtn = new KPushButton( i18n("Current/Next"), this ); + hbox->addWidget( currentNextBtn ); + currentChannelEpgBtn = new KPushButton( i18n("Current Channel"), this ); + hbox->addWidget( currentChannelEpgBtn ); + + QSpacerItem* spacer = new QSpacerItem( 20, 20, QSizePolicy::Expanding, QSizePolicy::Minimum ); + hbox->addItem( spacer ); + + vbox->addLayout( hbox); + + hbox = new QHBoxLayout(); + + searchBtn = new QToolButton( this ); + searchBtn->setAutoRaise( true ); + QToolTip::add( searchBtn, i18n("Electronic Program Guide Search")); + hbox->addWidget( searchBtn ); + + QLabel* filterLabel = new QLabel( i18n("Search") + ":", this ); + hbox->addWidget( filterLabel ); + + searchLineEdit = new KLineEdit(this); + hbox->addWidget( searchLineEdit ); + + tvradioCb = new QCheckBox(i18n("TV "), this ); + QToolTip::add( tvradioCb, i18n("Search TV Channels only (omit Radio)")); + tvradioCb->setChecked(true); + hbox->addWidget( tvradioCb); + + titleCb = new QCheckBox(i18n("Titles "), this ); + QToolTip::add( titleCb, i18n("Search Event Titles only (omit Description)")); + titleCb->setChecked(true); + hbox->addWidget( titleCb); + + ftaCb = new QCheckBox(i18n("FTA "), this ); + QToolTip::add( ftaCb, i18n("Search Free to Air Channels only (omit PayTV)")); + ftaCb->setChecked(false); + hbox->addWidget( ftaCb); + + vbox->addLayout( hbox ); + + grid->addLayout( vbox, 0, 0 ); + + listView = new KListView( this, "listView" ); + listView->addColumn( i18n( "Channel" ) ); + listView->addColumn( i18n( "Begin" ) ); + listView->addColumn( i18n( "Duration" ) ); + listView->addColumn( i18n( "Title" ) ); + listView->setResizePolicy( KListView::AutoOneFit ); + listView->setAllColumnsShowFocus( TRUE ); + listView->setFullWidth( TRUE ); + grid->addWidget( listView, 1, 0 ); + grid->setRowStretch( 1, 4 ); + + textBrow = new QTextBrowser( this ); + grid->addWidget( textBrow, 2, 0 ); + grid->setRowStretch( 2, 2 ); + + KIconLoader *icon = new KIconLoader(); + resetBtn->setGuiItem( KGuiItem(i18n("Refresh"), icon->loadIconSet("reload", KIcon::Small) ) ); + allBtn->setGuiItem( KGuiItem(i18n("Scheduled"), icon->loadIconSet("date", KIcon::Small) ) ); + currentNextBtn->setGuiItem( KGuiItem(i18n("Current/Next"), icon->loadIconSet("toggle_log", KIcon::Small) ) ); + currentChannelEpgBtn->setGuiItem( KGuiItem(i18n("Current Channel"), icon->loadIconSet("date", KIcon::Small) ) ); + searchBtn->setIconSet( icon->loadIconSet("locationbar_erase", KIcon::Small) ); + + new EListViewItem( (QListView*)listView, "Une chaine", "99/99/99 99:99 9999", "99:99 99", "un titre de programme", 0 ); + + resize( size ); + connect( resetBtn , SIGNAL( pressed() ), this, SLOT( reset() ) ); + connect( allBtn , SIGNAL( clicked() ), this, SLOT( setScheduled() ) ); + connect( currentNextBtn , SIGNAL( clicked() ), this, SLOT( setCurrentNext() ) ); + connect( currentChannelEpgBtn, SIGNAL( clicked() ), this, SLOT( setCurrentChannelEpg() ) ); + connect( searchBtn, SIGNAL( clicked() ), this, SLOT(resetSearch()) ); + connect( searchLineEdit, SIGNAL( returnPressed() ), this, SLOT( epgSearch() ) ); + + connect( listView, SIGNAL( mouseButtonClicked(int,QListViewItem*,const QPoint&,int) ), + this, SLOT(mouseClickedSlot(int,QListViewItem*,const QPoint&,int)) ); + + connect( listView, SIGNAL(doubleClicked(QListViewItem*,const QPoint &,int)), + this, SLOT(zap(QListViewItem*,const QPoint &,int)) ); + + setMode( 1 ); + delete icon; +} + +void KEvents::resetSearch() +{ + searchLineEdit->clear(); +} + +void KEvents::checkEpgSearch(QString searchword) +{ + int i, j, k, m, n, l; + EventSource *esrc; + EventTsid *et; + EventSid *es; + EventDesc *desc; + EListViewItem *itt=0; + ChannelDesc *ch; + QString s, begin, duration, title; + bool found; + + for( k=0; k<events->getNSource(); k++ ) { + if ( !(esrc=events->getNEventSource( k )) ) + continue; + for ( m=0; m<esrc->getNTsid(); m++ ) { + if ( !(et=esrc->getNEventTsid( m )) ) + continue; + for ( n=0; n<et->getNSid(); n++ ) { + if ( !(es=et->getNEventSid( n )) ) + continue; + for ( j=0; j<es->getNDesc(); j++ ) { + if ( !(desc=es->getEventDesc( j )) ) + continue; + + if ( desc->title.isEmpty() ) + continue; + + for ( i=0; i<(int)channels->count(); i++ ) { + ch = channels->at(i); + if ( desc->source==ch->tp.source && desc->nid==ch->tp.nid && desc->sid==ch->sid && desc->tsid==ch->tp.tsid ) { + if(tvradioCb->isChecked() && ch->type==2) + break; + + if(ftaCb->isChecked() && ch->fta==1) + break; + + found=false; + if(desc->title.upper().find(searchword.upper())!=-1) + found=true; + + if(!desc->subtitle.isEmpty()) { + if(desc->subtitle.upper().find(searchword.upper())!=-1) + found=true; + } + + if(!titleCb->isChecked()) { + if(!found) { + for ( l=0; l<(int)desc->extEvents.count(); l++ ) { + s = *desc->extEvents.at(l); + if(!s.isEmpty()) { + if(s.upper().find(searchword.upper())!=-1) { + found=true; + s=""; + break; + } + } + } + } + if(!found) { + for ( l=0; l<(int)desc->shortEvents.count(); l++ ) { + s = desc->shortEvents.at(l)->name; + if(!s.isEmpty()) { + if(s.upper().find(searchword.upper())!=-1) { + found=true; + s=""; + break; + } + } + s = desc->shortEvents.at(l)->text; + if(!s.isEmpty()) { + if(s.upper().find(searchword.upper())!=-1) { + found=true; + s=""; + break; + } + } + } + } + } + if(!found) + break; + + begin = KGlobal::locale()->formatDateTime( desc->startDateTime ); + duration = desc->duration.toString("hh:mm"); + title = desc->title; + + itt = new EListViewItem( (QListView*)listView, ch->name, begin, duration, title, desc ); + + if ( !ch->pix.isNull() ) + itt->setPixmap( 0, ch->pix ); + } + } + } + } + } + } +} + +void KEvents::epgSearch() +{ + + QString text = searchLineEdit->text(); + if (text.stripWhiteSpace().isEmpty()) return; + + listView->clear(); + checkEpgSearch(text); +} + +void KEvents::setCurrentChannelEpg() +{ + ChannelDesc curchan; + int i; + for ( i=0; i<(int)dvb->count(); i++ ) { + if ( dvb->at(i)->hasLive() ) { + curchan = dvb->at(i)->getLiveChannel(); + break; + } + } + if ( !curchan.name.isEmpty() ) + setMode( 2, curchan.name ); + +} + +void KEvents::zap( QListViewItem* it, const QPoint &p, int col ) +{ + QPoint pt=p; + int c=col; + c++; + + if ( it->text(0) != QString::null ) + emit zapTo( it->text(0) ); +} + + + +void KEvents::mouseClickedSlot( int btn, QListViewItem *it, const QPoint &p, int c ) +{ + int i=c; + QPoint pt=p; + QString s; + + if ( !it ) + return; + EListViewItem *ei = (EListViewItem*)it; + + switch ( btn ) { + case Qt::RightButton : { + QPopupMenu *pop = new QPopupMenu(); + pop->insertItem( i18n("View All Programs"), 1 ); + pop->insertSeparator(); + pop->insertItem( i18n("Add to Timers"), 2 ); + if ( ei->event->running==4 ) + pop->setItemEnabled( 2, false ); + i = 0; + i = pop->exec( QCursor::pos() ); + switch ( i ) { + case 0 : + break; + case 1 : + setMode( 2, it->text(0) ); + break; + case 2 : + emit addTimer( it->text(0), it->text(3), ei->event->startDateTime, ei->event->duration ); + break; + } + delete pop; + break; + } + case Qt::LeftButton : { + s = "<qt><h3><font color=\"darkblue\">"; + s = s+it->text(0)+"</font></h3>"; + if ( !ei->event->title.isEmpty() ) { + s = s+"<b><font color=\"darkgreen\"><big>"; + s = s+ei->event->title; + s = s+"</big></font></b><br>"; + } + if ( !ei->event->subtitle.isEmpty() ) { + s = s+"<b><font color=\"#A69631\">"; + s = s+ei->event->subtitle; + s = s+"</font></b><br>"; + } + s = s+"<br><font color=\"darkred\">"; + s = s+KGlobal::locale()->formatDateTime( ei->event->startDateTime, false )+"<br>"; + s = s+ei->event->duration.toString("hh:mm"); + s = s+"</font><br><br>"; + for ( i=0; i<(int)ei->event->shortEvents.count(); i++ ) { + s = s+"<p>"; + s = s + ei->event->shortEvents.at(i)->name; + if (!ei->event->shortEvents.at(i)->name.isEmpty() && !ei->event->shortEvents.at(i)->text.isEmpty()) { + s = s + " : "; + } + s = s + ei->event->shortEvents.at(i)->text; + s = s + "</p>"; + } + for ( i=0; i<(int)ei->event->extEvents.count(); i++ ) { + s = s+ *ei->event->extEvents.at(i); + } + s = s+"</qt>"; + textBrow->setText( s ); + break; + } + } +} + + + +void KEvents::setCurrentNext() +{ + setMode( 1 ); +} + + + +void KEvents::setScheduled() +{ + QListViewItem *it = listView->currentItem(); + if ( !it ) + return; + setMode( 2, it->text(0) ); +} + + + +void KEvents::setMode( int m, QString name ) +{ + int i; + + mode = m; + if ( !name.isEmpty() ) { + currentNextBtn->show(); + allBtn->hide(); + for ( i=0; i<(int)channels->count(); i++ ) { + if ( channels->at(i)->name==name ) { + chan = channels->at(i); + break; + } + } + } + else { + chan = 0; + currentNextBtn->hide(); + allBtn->show(); + } + reset(); +} + + + +void KEvents::reset() +{ + listView->clear(); + checkNewEvent(); +} + + + +void KEvents::checkNewEvent() +{ + int i; + EventSource *esrc; + EventSid *es; + EventDesc *desc; + EListViewItem *itt=0; + ChannelDesc *ch; + QString s, t, channel, begin, duration, title; + + if ( mode==2 ) { + if ( !chan ) + return; + if ( !(esrc=events->getEventSource( chan->tp.source )) ) + return; + if ( !(es=esrc->getEventSid( chan->tp.nid, chan->tp.tsid, chan->sid )) ) + return; + i = 0; + while ( (desc=es->getEventDesc(i)) ) { + ++i; + begin = KGlobal::locale()->formatDateTime( desc->startDateTime ); + duration = desc->duration.toString("hh:mm"); + title = desc->title; + if ( title.isEmpty() ) + continue; + itt = new EListViewItem( (QListView*)listView, chan->name, begin, duration, title, desc ); + if ( !chan->pix.isNull() ) + itt->setPixmap( 0, chan->pix ); + } + return; + } + + for ( i=0; i<(int)channels->count(); i++ ) { + ch = channels->at(i); + if ( (desc=events->getEventDesc( ch->tp.source, ch->tp.nid, ch->tp.tsid, ch->sid, 0 )) ) { + begin = KGlobal::locale()->formatDateTime( desc->startDateTime ); + duration = desc->duration.toString("hh:mm"); + title = desc->title; + if ( title.isEmpty() ) + continue; + itt = new EListViewItem( (QListView*)listView, ch->name, begin, duration, title, desc ); + if ( !ch->pix.isNull() ) + itt->setPixmap( 0, ch->pix ); + } + } +} + + + +KEvents::~KEvents() +{ +} + +#include "kevents.moc" diff --git a/kaffeine/src/input/dvb/kevents.h b/kaffeine/src/input/dvb/kevents.h new file mode 100644 index 0000000..3779452 --- /dev/null +++ b/kaffeine/src/input/dvb/kevents.h @@ -0,0 +1,98 @@ +/* + * kevents.h + * + * Copyright (C) 2004-2007 Christophe Thommeret <hftom@free.fr> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef KEVENTS_H +#define KEVENTS_H + +#include <qtimer.h> +#include <qdialog.h> +#include <qdatetime.h> +#include <qtextbrowser.h> + +#include <klistview.h> +#include <kpushbutton.h> +#include <klineedit.h> + +class EventDesc; +class DvbStream; +class EventTable; +class ChannelDesc; + + +class EListViewItem : public KListViewItem +{ + +public: + + EListViewItem( QListView *parent, QString chanName, QString eBegin, QString eDuration, QString eTitle, EventDesc *desc ); + virtual int compare( QListViewItem *i, int col, bool ascending ) const; + + EventDesc *event; +}; + + + +class KEvents : public QDialog +{ + Q_OBJECT + +public: + + KEvents( QPtrList<ChannelDesc> *chans, QPtrList<DvbStream> *d, EventTable *t, QWidget *parent, QSize size ); + ~KEvents(); + +private slots: + + void mouseClickedSlot( int btn, QListViewItem *it, const QPoint &p, int c ); + void reset(); + void setMode( int m, QString name="" ); + void setScheduled(); + void setCurrentNext(); + void setCurrentChannelEpg(); + void epgSearch(); + void resetSearch(); + void zap( QListViewItem* it, const QPoint &p, int col ); + +private: + void checkEpgSearch(QString searchword); + void checkNewEvent(); + + QPtrList<DvbStream> *dvb; + EventTable *events; + KListView *listView; + KPushButton *resetBtn, *currentNextBtn, *allBtn, *currentChannelEpgBtn; + QToolButton *searchBtn; + QCheckBox *titleCb,*tvradioCb,*ftaCb; + QPtrList<ChannelDesc> *channels; + QTextBrowser *textBrow; + int mode; + ChannelDesc *chan; + +protected: + + KLineEdit *searchLineEdit; + +signals: + + void addTimer( QString channel, QString name, QDateTime begin, QTime duration ); + void zapTo( const QString &channel ); +}; + +#endif /* KEVENTS_H */ diff --git a/kaffeine/src/input/dvb/kgradprogress.cpp b/kaffeine/src/input/dvb/kgradprogress.cpp new file mode 100644 index 0000000..092cfb3 --- /dev/null +++ b/kaffeine/src/input/dvb/kgradprogress.cpp @@ -0,0 +1,136 @@ +/* + * kgradprogress.cpp + * + * Copyright (C) 2003-2005 Christophe Thommeret <hftom@free.fr> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include <qpainter.h> +#include <qlabel.h> + +#include "kgradprogress.h" + + + +KGradProgress::KGradProgress( QWidget *parent ) : QLabel( parent ) +{ + barPix = 0; + colorUp = QColor( 0, 255, 0 ); + colorDown = QColor( 255, 0, 0 ); + current = 0; + setFrameStyle( QFrame::Box | QFrame::Plain ); + setLineWidth(1); + setMidLineWidth(0); + setSizePolicy( QSizePolicy::MinimumExpanding, QSizePolicy::Preferred ); +} + + + +void KGradProgress::setProgress( int progress ) +{ + current = progress; + draw(); + repaint(false); +} + + + +void KGradProgress::draw() +{ + int i, j; + int a, b; + int off = frameWidth(); + int h = height() - ( 2*off ); + int w = width() - ( 2*off ); + int per; + QString s; + QFont f; + + s = s.setNum( current )+"%"; + per = current*w/100; + + if ( barPix ) delete barPix; + barPix = new QPixmap( w, h, -1, QPixmap::BestOptim ); + QPainter p( barPix ); + p.fillRect( 0, 0, w, h, paletteBackgroundColor() ); + + for ( j=0; j<per; j++ ) { + if ( j<(w/2) ) { + a = 255; + b = 2*j*255/w; + } + else { + a = 255-(2*(j-w/2)*255/w); + b = 255; + } + p.setPen( QColor( a, b, 0 ) ); + for ( i=0; i<h; i++ ) p.drawPoint( j+off, i+off ); + } + + f = font(); + f.setPointSize( int(h/1.2) ); + p.setFont( f ); + p.setPen( QColor( 0, 0, 0 ) ); + p.drawText( w/2, (h/2)+(f.pointSize()/2), s ); + p.end(); +} + + + +void KGradProgress::resizeEvent( QResizeEvent *e ) +{ + QSize s=e->size(); + draw(); +} + + + +void KGradProgress::paintEvent(QPaintEvent *event) +{ + int x, y, w, h; + + x = y = frameWidth(); + w = width() - (2*x); + h = height() - (2*y); + + QLabel::paintEvent( event ); + + bitBlt( this, x, y, barPix, 0, 0, w, h, CopyROP ); +} + + + +QSize KGradProgress::sizeHint() +{ + QLabel lab( "This is a progress bar.", 0 ); + return QSize( lab.width(), int(font().pointSize()*1.2) ); +} + + + +QSizePolicy KGradProgress::sizePolicy() +{ + return QSizePolicy( QSizePolicy::MinimumExpanding, QSizePolicy::Preferred ); +} + + + +KGradProgress::~KGradProgress() +{ + delete barPix; +} + +#include "kgradprogress.moc" diff --git a/kaffeine/src/input/dvb/kgradprogress.h b/kaffeine/src/input/dvb/kgradprogress.h new file mode 100644 index 0000000..a55591e --- /dev/null +++ b/kaffeine/src/input/dvb/kgradprogress.h @@ -0,0 +1,59 @@ +/* + * kgradprocess.h + * + * Copyright (C) 2003-2005 Christophe Thommeret <hftom@free.fr> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef KGRADPROGRESS_H +#define KGRADPROGRESS_H + +#include <qlabel.h> +#include <qpixmap.h> + + + +class KGradProgress : public QLabel +{ + + Q_OBJECT + +public: + + KGradProgress( QWidget *parent ); + ~KGradProgress(); + virtual void paintEvent(QPaintEvent *event); + virtual QSize sizeHint(); + virtual QSizePolicy sizePolicy(); + +public slots: + + void setProgress( int progress ); + +protected: + + virtual void resizeEvent( QResizeEvent *e ); + +private: + + void draw(); + + QPixmap *barPix; + QColor colorDown, colorUp; + int current; +}; + +#endif /* KGRADPROGRESS_H */ diff --git a/kaffeine/src/input/dvb/krecord.cpp b/kaffeine/src/input/dvb/krecord.cpp new file mode 100644 index 0000000..7e14036 --- /dev/null +++ b/kaffeine/src/input/dvb/krecord.cpp @@ -0,0 +1,295 @@ +/* + * krecord.cpp + * + * Copyright (C) 2004-2005 Christophe Thommeret <hftom@free.fr> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include <qlayout.h> +#include <qlabel.h> +#include <qfile.h> +#include <qdir.h> +#include <qframe.h> + +#include <klocale.h> +#include <kiconloader.h> +#include <kmessagebox.h> + +#include "krecord.h" + + + +KRecord::KRecord( QStringList chanList, QPtrList<RecTimer> *t, QWidget *parent, QSize size ) : QDialog( parent ) +{ + timers = t; + channelsList = chanList; + + QVBoxLayout *vb = new QVBoxLayout( 0, 0, 6 ); + QLabel *lab = new QLabel( i18n("Timers list:"), this ); + vb->addWidget( lab ); + + list = new KListView( this ); + list->addColumn( "" ); + list->addColumn( i18n( "Name" ) ); + list->addColumn( i18n( "Channel" ) ); + list->addColumn( i18n( "Begin" ) ); + list->addColumn( i18n( "Duration" ) ); + list->setResizePolicy( KListView::AutoOneFit ); + list->setAllColumnsShowFocus( true ); + list->setFullWidth( true ); + QListViewItem * item = new QListViewItem( list, 0 ); + item->setText( 0, "00" ); + item->setText( 1, "Un nom assez long mais pas trop" ); + item->setText( 2, "Une chaine du meme calibre" ); + item->setText( 3, "00:00 00/00/00mm" ); + item->setText( 4, "00:00mm" ); + vb->addWidget( list ); + + QVBoxLayout *vb1 = new QVBoxLayout( 0, 0, 6 ); + newBtn = new KPushButton(i18n("New"), this); + vb1->addWidget( newBtn ); + editBtn = new KPushButton(i18n("Edit"), this); + vb1->addWidget( editBtn ); + deleteBtn = new KPushButton(i18n("Delete"), this); + vb1->addWidget( deleteBtn ); + vb1->addItem( new QSpacerItem( 20, 20, QSizePolicy::Minimum, QSizePolicy::MinimumExpanding ) ); + + QHBoxLayout *hb = new QHBoxLayout( 0, 0, 6 ); + hb->addLayout( vb ); + hb->addLayout( vb1 ); + + QHBoxLayout *hb1 = new QHBoxLayout( 0 ); + hb1->addItem( new QSpacerItem( 20, 20, QSizePolicy::MinimumExpanding, QSizePolicy::Minimum ) ); + okBtn = new KPushButton(i18n("Close"), this); + hb1->addWidget( okBtn ); + + QVBoxLayout *vb2 = new QVBoxLayout( this, 6, 6 ); + vb2->addLayout( hb ); + QFrame *line = new QFrame( this, "line1" ); + line->setFrameStyle( QFrame::HLine ); + line->setFrameShadow( QFrame::Sunken ); + line->setFrameShape( QFrame::HLine ); + vb2->addWidget( line ); + vb2->addLayout( hb1 ); + + KIconLoader *icon = new KIconLoader(); + newBtn->setGuiItem( KGuiItem(i18n("New"), icon->loadIconSet("filenew", KIcon::Small) ) ); + editBtn->setGuiItem( KGuiItem(i18n("Edit"), icon->loadIconSet("edit", KIcon::Small) ) ); + //editBtn->setEnabled( false ); + deleteBtn->setGuiItem( KGuiItem(i18n("Stop/Delete"), icon->loadIconSet("editcut", KIcon::Small) ) ); + okBtn->setGuiItem( KGuiItem(i18n("Close"), icon->loadIconSet("exit", KIcon::Small) ) ); + + isRecording = icon->loadIcon("player_record", KIcon::Small); + yesRepeat = icon->loadIcon("reload", KIcon::Small); + + setCaption( i18n("Timers") ); + + connect( okBtn, SIGNAL(clicked()), this, SLOT(accept()) ); + connect( newBtn, SIGNAL(clicked()), this, SLOT(newTimer()) ); + connect( deleteBtn, SIGNAL(clicked()), this, SLOT(deleteTimer()) ); + connect( editBtn, SIGNAL(clicked()), this, SLOT(editTimer()) ); + + refresh(); + resize( size ); + delete icon; +} + + + +void KRecord::refresh() +{ + QListViewItem *after, *itt; + RecTimer *ti; + int i; + QString s; + + list->clear(); + list->setSorting( -1 ); + for ( i=0; i<(int)timers->count(); i++ ) { + ti = timers->at(i); + after = where( ti ); + /*if ( ti->running ) s = ">"; + else s = ""; + s = s+ti->name;*/ + s = ti->name; + itt = new KListViewItem( (QListView*)list, "", s, ti->channel, KGlobal::locale()->formatDateTime( ti->begin ), ti->duration.toString("hh:mm") ); + if ( ti->mode ) + itt->setPixmap( 0, yesRepeat ); + if ( ti->running ) + itt->setPixmap( 1, isRecording ); + if ( after ) + itt->moveItem( after ); + } +} + + + +void KRecord::newTimer() +{ + QListViewItem *itt, *after; + RecTimer *t = new RecTimer(); + + t->running = 0; + t->mode = 0; + + KTimerEditor dlg( true, channelsList, *t, this ); + int ret=dlg.exec(); + if ( ret==KTimerEditor::Accepted ) { + *t = dlg.timer; + after = where( t, true ); + itt = new KListViewItem( (QListView*)list, "", t->name, t->channel, KGlobal::locale()->formatDateTime( t->begin ), t->duration.toString("hh:mm") ); + if ( t->mode ) + itt->setPixmap( 0, yesRepeat ); + if ( t->running ) + itt->setPixmap( 1, isRecording ); + if ( after ) + itt->moveItem( after ); + } + else delete t; +} + + + +void KRecord::editTimer() +{ + QListViewItem *it, *after; + int i=0; + RecTimer *t, *tn=0; + + it = list->firstChild(); + while ( it!=0 ) { + if ( it->isSelected() ) + break; + it = it->nextSibling(); + } + if ( !it ) + return; + + for ( i=0; i<(int)timers->count(); i++ ) { + t = timers->at(i); + if ( t->name==it->text(1) && t->channel==it->text(2) ) { + tn = t; + break; + } + } + + if ( !tn ) + return; + + KTimerEditor dlg( false, channelsList, *tn, this ); + int ret=dlg.exec(); + if ( ret==KTimerEditor::Accepted ) { + for ( i=0; i<(int)timers->count(); i++ ) { + if ( timers->at(i)==tn ) { + if ( tn->running ) { + int ms = tn->begin.time().secsTo( QTime::currentTime() ); + ms = ((dlg.timer.duration.hour()*3600+dlg.timer.duration.minute()*60)-ms)*1000; + if ( ms<2000 ) + ms = 0; + tn->duration = dlg.timer.duration; + emit updateTimer( tn, ms ); + if ( ms ) + refresh(); + } + else { + timers->remove( tn ); + t = new RecTimer(); + *t = dlg.timer; + after = where( t, true ); + refresh(); + } + break; + } + } + } +} + + + +void KRecord::deleteTimer() +{ + QListViewItem *it; + int i=0, ret; + KIconLoader *icon = new KIconLoader(); + + it = list->firstChild(); + while ( it!=0 ) { + if ( it->isSelected() ) { + if ( timers->at(i)->mode ) + ret = KMessageBox::questionYesNoCancel( this, i18n("This timer is repeated. Do you want to skip the current job or delete the timer?"), i18n("Warning"), KGuiItem(i18n("Skip Current"), icon->loadIconSet("next", KIcon::Small) ), KGuiItem(i18n("Delete"), icon->loadIconSet("editcut", KIcon::Small) ) ); + else + ret = KMessageBox::questionYesNo( this, i18n("Delete the selected timer?") ); + if ( ret==KMessageBox::Yes ) { + emit updateTimer( timers->at(i), 0 ); + } + else if ( ret==KMessageBox::No && timers->at(i)->mode ) { + timers->at(i)->mode=0; + emit updateTimer( timers->at(i), 0 ); + } + break; + } + i++; + it = it->nextSibling(); + } + + delete icon; +} + + + +QListViewItem* KRecord::where( RecTimer *rt, bool add ) +{ + QListViewItem *it, *ret=0; + int i, r=0; + RecTimer *t; + + for ( i=0; i<(int)timers->count(); i++ ) { + t = timers->at(i); + if ( rt->begin>t->begin ) + r=i+1; + } + if ( add ) + timers->insert( r, rt ); + if ( !r ) + return ret; + + it = list->firstChild(); + i=0; + while ( it!=0 ) { + if ( i==(r-1) ) { + ret = it; + break; + } + i++; + it = it->nextSibling(); + } + return ret; +} + + + +void KRecord::accept() +{ + done( Accepted ); +} + + + +KRecord::~KRecord() +{ +} + +#include "krecord.moc" diff --git a/kaffeine/src/input/dvb/krecord.h b/kaffeine/src/input/dvb/krecord.h new file mode 100644 index 0000000..6a9f1f3 --- /dev/null +++ b/kaffeine/src/input/dvb/krecord.h @@ -0,0 +1,69 @@ +/* + * krecord.h + * + * Copyright (C) 2004-2005 Christophe Thommeret <hftom@free.fr> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef KRECORD_H +#define KRECORD_H + +#include <qdialog.h> +#include <qpixmap.h> + +#include <kpushbutton.h> +#include <klistview.h> + +#include "channeldesc.h" +#include "ktimereditor.h" + + + +class KRecord : public QDialog +{ + Q_OBJECT + +public: + + KRecord( QStringList chanList, QPtrList<RecTimer> *t, QWidget *parent, QSize size ); + ~KRecord(); + + QStringList channelsList; + +protected slots: + + virtual void accept(); + void newTimer(); + void editTimer(); + void deleteTimer(); + void refresh(); + +private: + + QListViewItem* where( RecTimer *rt, bool add=false ); + + KPushButton *newBtn, *editBtn, *deleteBtn, *okBtn; + KListView *list; + QPtrList<RecTimer> *timers; + QPixmap isRecording, yesRepeat; + +signals: + + void updateTimer(RecTimer*, int); + +}; + +#endif /* KRECORD_H */ diff --git a/kaffeine/src/input/dvb/ktimereditor.cpp b/kaffeine/src/input/dvb/ktimereditor.cpp new file mode 100644 index 0000000..63993c0 --- /dev/null +++ b/kaffeine/src/input/dvb/ktimereditor.cpp @@ -0,0 +1,231 @@ +/* + * ktimereditor.cpp + * + * Copyright (C) 2004-2005 Christophe Thommeret <hftom@free.fr> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include <qlayout.h> +#include <qlabel.h> + +#include <klocale.h> +#include <kiconloader.h> +#include <kmessagebox.h> + +#include "ktimereditor.h" + + + +KTimerEditor::KTimerEditor( bool newone, QStringList &chanList, RecTimer t, QWidget *parent ) : QDialog( parent ) +{ + int i; + + QGridLayout *grid = new QGridLayout( 0, 1, 1, 11, 6 ); + QLabel *lab = new QLabel( i18n("Name:"), this ); + grid->addWidget( lab, 0, 0 ); + nameLe = new QLineEdit( this ); + grid->addWidget( nameLe, 0, 1 ); + lab = new QLabel( i18n("Channel:"), this ); + grid->addWidget( lab, 1, 0 ); + channelComb = new QComboBox( this ); + grid->addWidget( channelComb, 1, 1 ); + lab = new QLabel( i18n("Begin:"), this ); + grid->addWidget( lab, 2, 0 ); + begin = new QDateTimeEdit( this ); + grid->addWidget( begin, 2, 1 ); + lab = new QLabel( i18n("Duration:"), this ); + grid->addWidget( lab, 3, 0 ); + duration = new QTimeEdit( this ); + grid->addWidget( duration, 3, 1 ); + lab = new QLabel( i18n("End:"), this ); + grid->addWidget( lab, 4, 0 ); + end = new QDateTimeEdit( this ); + grid->addWidget( end, 4, 1 ); + repeatBtn = new KPushButton( this ); + grid->addWidget( repeatBtn, 5, 0 ); + repeatLab = new QLabel( this ); + grid->addWidget( repeatLab, 5, 1 ); + + QFrame *line = new QFrame( this, "line1" ); + line->setFrameStyle( QFrame::HLine ); + line->setFrameShadow( QFrame::Sunken ); + line->setFrameShape( QFrame::HLine ); + + QHBoxLayout *hb = new QHBoxLayout( 0, 0, 6 ); + cancelBtn = new KPushButton( this ); + hb->addWidget( cancelBtn ); + hb->addItem( new QSpacerItem( 20, 20, QSizePolicy::MinimumExpanding, QSizePolicy::Minimum ) ); + okBtn = new KPushButton( this ); + okBtn->setDefault( true ); + hb->addWidget( okBtn ); + + QVBoxLayout *vb = new QVBoxLayout( this, 6, 6 ); + vb->addLayout( grid ); + vb->addItem( new QSpacerItem( 20, 20, QSizePolicy::Minimum, QSizePolicy::MinimumExpanding ) ); + vb->addWidget( line ); + vb->addLayout( hb ); + + timer = t; + + + //begin->dateEdit()->setOrder( QDateEdit::DMY ); + channelComb->insertStringList( chanList ); + + if ( newone ) { + begin->setDateTime( QDateTime::currentDateTime() ); + duration->setTime( QTime(2,0,0) ); + } + else { + nameLe->setText( timer.name ); + for ( i=0; i<channelComb->count(); i++ ) { + if ( channelComb->text(i)==timer.channel ) { + channelComb->setCurrentItem(i); + break; + } + } + begin->setDateTime( timer.begin ); + duration->setTime( timer.duration ); + if ( timer.running ) { + nameLe->setEnabled( false ); + channelComb->setEnabled( false ); + begin->setEnabled( false ); + repeatBtn->setEnabled( false ); + } + } + switch ( timer.mode ) { + case CronTimer::Noone : repeatLab->setText( i18n("None") ); break; + case CronTimer::Daily : repeatLab->setText( i18n("Daily") ); break; + case CronTimer::Weekly : repeatLab->setText( i18n("Weekly") ); break; + case CronTimer::Monthly : repeatLab->setText( i18n("Monthly") ); break; + default : repeatLab->setText( i18n("Custom") ); + } + + KIconLoader *icon = new KIconLoader(); + cancelBtn->setGuiItem( KStdGuiItem::cancel() ); + okBtn->setGuiItem( KStdGuiItem::ok() ); + repeatBtn->setGuiItem( KGuiItem(i18n("Repeat..."), icon->loadIconSet("reload", KIcon::Small) ) ); + + setCaption( i18n("Timer Editor") ); + + connect( okBtn, SIGNAL(clicked()), this, SLOT(accept()) ); + connect( cancelBtn, SIGNAL(clicked()), this, SLOT(reject()) ); + connect( repeatBtn, SIGNAL(clicked()), this, SLOT(setRepeat()) ); + connect( begin, SIGNAL(valueChanged(const QDateTime&)), this, SLOT(setMaxEnd(const QDateTime&)) ); + connect( end, SIGNAL(valueChanged(const QDateTime&)), this, SLOT(setDuration(const QDateTime&)) ); + connect( duration, SIGNAL(valueChanged(const QTime&)), this, SLOT(setEnd(const QTime&)) ); + setMaxEnd( begin->dateTime() ); + delete icon; +} + + + +void KTimerEditor::setMaxEnd( const QDateTime &dt ) +{ + QDateTime max = dt.addSecs( 23*3600+59*60+59 ); + end->dateEdit()->setMinValue( dt.date() ); + end->dateEdit()->setMaxValue( max.date() ); + setEnd( duration->time() ); +} + + + +void KTimerEditor::setDuration( const QDateTime &dt ) +{ + disconnect( duration, SIGNAL(valueChanged(const QTime&)), this, SLOT(setEnd(const QTime&)) ); + duration->setTime( QTime().addSecs( begin->dateTime().secsTo( dt ) ) ); + connect( duration, SIGNAL(valueChanged(const QTime&)), this, SLOT(setEnd(const QTime&)) ); +} + + + +void KTimerEditor::setEnd( const QTime &t ) +{ + disconnect( end, SIGNAL(valueChanged(const QDateTime&)), this, SLOT(setDuration(const QDateTime&)) ); + end->setDateTime( begin->dateTime().addSecs( QTime().secsTo( t ) ) ); + connect( end, SIGNAL(valueChanged(const QDateTime&)), this, SLOT(setDuration(const QDateTime&)) ); +} + + + +void KTimerEditor::setRepeat() +{ + CronTimer dlg( timer.mode, this ); + + if ( dlg.exec()==CronTimer::Accepted ) + timer.mode = dlg.getMode(); + switch ( timer.mode ) { + case CronTimer::Noone : repeatLab->setText( i18n("None") ); break; + case CronTimer::Daily : repeatLab->setText( i18n("Daily") ); break; + case CronTimer::Weekly : repeatLab->setText( i18n("Weekly") ); break; + case CronTimer::Monthly : repeatLab->setText( i18n("Monthly") ); break; + default : repeatLab->setText( i18n("Custom") ); + } +} + + + +void KTimerEditor::accept() +{ + if ( nameLe->text().stripWhiteSpace().isEmpty() ) { + KMessageBox::sorry( this, i18n("You must give it a name!") ); + nameLe->setFocus(); + return; + } + + if ( nameLe->text().stripWhiteSpace().contains("/") ) + goto stop; + if ( nameLe->text().stripWhiteSpace().contains(">") ) + goto stop; + if ( nameLe->text().stripWhiteSpace().contains("<") ) + goto stop; + if ( nameLe->text().stripWhiteSpace().contains("\\") ) + goto stop; + if ( nameLe->text().stripWhiteSpace().contains(":") ) + goto stop; + if ( nameLe->text().stripWhiteSpace().contains("\"") ) + goto stop; + if ( nameLe->text().stripWhiteSpace().contains("|") ) + goto stop; + + if ( duration->time()<QTime(0,1) ) { + KMessageBox::sorry( this, i18n("Duration must be at least 1 minute!") ); + duration->setFocus(); + return; + } + + timer.duration = duration->time(); + if ( timer.running ) + done( Accepted ); + + timer.name = nameLe->text().stripWhiteSpace(); + timer.channel = channelComb->currentText(); + timer.begin = begin->dateTime(); + done( Accepted ); + return; + +stop: + KMessageBox::sorry( this, i18n("Name must not contain any of the following characters: > < \\ / : \" |") ); + nameLe->setFocus(); + return; +} + + + +KTimerEditor::~KTimerEditor() +{ +} + +#include "ktimereditor.moc" diff --git a/kaffeine/src/input/dvb/ktimereditor.h b/kaffeine/src/input/dvb/ktimereditor.h new file mode 100644 index 0000000..dfe1683 --- /dev/null +++ b/kaffeine/src/input/dvb/ktimereditor.h @@ -0,0 +1,67 @@ +/* + * ktimereditor.h + * + * Copyright (C) 2004-2005 Christophe Thommeret <hftom@free.fr> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef KTIMEREDITOR_H +#define KTIMEREDITOR_H + +#include <qdialog.h> +#include <qcombobox.h> +#include <qlineedit.h> +#include <qdatetimeedit.h> +#include <qlabel.h> + +#include <kpushbutton.h> + +#include "channeldesc.h" +#include "gdvb.h" +#include "crontimer.h" + + + +class KTimerEditor : public QDialog +{ + Q_OBJECT + +public: + + KTimerEditor( bool newone, QStringList &chanList, RecTimer t, QWidget *parent ); + ~KTimerEditor(); + + KPushButton *okBtn, *cancelBtn, *repeatBtn; + QLabel *repeatLab; + QLineEdit *nameLe; + QComboBox *channelComb; + QDateTimeEdit *begin, *end; + QTimeEdit *duration; + RecTimer timer; + +public slots: + + void setRepeat(); + +protected slots: + + virtual void accept(); + void setDuration( const QDateTime &dt ); + void setEnd( const QTime &t ); + void setMaxEnd( const QDateTime &dt ); +}; + +#endif /* KTIMEREDITOR_H */ diff --git a/kaffeine/src/input/dvb/lib/Makefile.am b/kaffeine/src/input/dvb/lib/Makefile.am new file mode 100644 index 0000000..aa4701c --- /dev/null +++ b/kaffeine/src/input/dvb/lib/Makefile.am @@ -0,0 +1 @@ +SUBDIRS = libdvbapi libdvben50221 libucsi diff --git a/kaffeine/src/input/dvb/lib/libdvbapi/Makefile.am b/kaffeine/src/input/dvb/lib/libdvbapi/Makefile.am new file mode 100644 index 0000000..59f288b --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libdvbapi/Makefile.am @@ -0,0 +1,11 @@ +noinst_LTLIBRARIES = libdvbapi.la + +INCLUDES = -I$(top_srcdir)/kaffeine/src/input/dvb/lib + +libdvbapi_la_SOURCES = diseqc.c \ + dvbca.c \ + dvbdemux.c \ + dvbfe.c \ + dvbnet.c + +CFLAGS = -g -O2 -Wall -Wshadow -Wpointer-arith -Wstrict-prototypes -fPIC diff --git a/kaffeine/src/input/dvb/lib/libdvbapi/diseqc.c b/kaffeine/src/input/dvb/lib/libdvbapi/diseqc.c new file mode 100644 index 0000000..8c8771d --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libdvbapi/diseqc.c @@ -0,0 +1,141 @@ +/* + libdvbfe - a DVB frontend library + + Copyright (C) 2005 Manu Abraham <manu@kromtek.com> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA +*/ + +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <sys/ioctl.h> +#include <fcntl.h> +#include <linux/dvb/frontend.h> +#include "diseqc.h" +#include <libdvbmisc/dvbmisc.h> + + +int verbose = 1; + +int set_22k_tone(int fd, dvbfe_sec_tone_mode_t tone) +{ + int ret = 0; + + if (fd > 0) { + switch (tone) { + case DVBFE_SEC_TONE_OFF: + ret = ioctl(fd, FE_SET_TONE, DVBFE_SEC_TONE_OFF); + break; + case DVBFE_SEC_TONE_ON: + ret = ioctl(fd, FE_SET_TONE, DVBFE_SEC_TONE_ON); + break; + default: + print(verbose, ERROR, 1, "Invalid command !"); + break; + } + if (ret == -1) + print(verbose, ERROR, 1, "IOCTL failed !"); + } else + print(verbose, ERROR, 1, "Device open error !"); + + return ret; +} + +int set_tone_data_burst(int fd, dvbfe_sec_mini_cmd_t minicmd) +{ + int ret = 0; + + if (fd > 0) { + switch (minicmd) { + case DVBFE_SEC_MINI_A: + ret = ioctl(fd, FE_DISEQC_SEND_BURST, DVBFE_SEC_MINI_A); + break; + case DVBFE_SEC_MINI_B: + ret = ioctl(fd, FE_DISEQC_SEND_BURST, DVBFE_SEC_MINI_B); + break; + default: + print(verbose, ERROR, 1, "Invalid command"); + break; + } + if (ret == -1) + print(verbose, ERROR, 1, "IOCTL failed"); + } else + print(verbose, ERROR, 1, "Device open error !"); + + return ret; +} + +int set_polarization(int fd, dvbfe_sec_voltage_t polarization) +{ + int ret = 0; + + if (fd > 0) { + switch (polarization) { + case DVBFE_SEC_VOLTAGE_13: + ret = ioctl(fd, FE_SET_VOLTAGE, DVBFE_SEC_VOLTAGE_13); + break; + case DVBFE_SEC_VOLTAGE_18: + ret = ioctl(fd, FE_SET_VOLTAGE, DVBFE_SEC_VOLTAGE_18); + break; + default: + print(verbose, ERROR, 1, "Invalid command"); + break; + } + if (ret == -1) + print(verbose, ERROR, 1, "IOCTL failed"); + } else + print(verbose, ERROR, 1, "Device open error !"); + + return ret; +} + +int do_diseqc_cmd(int fd, uint8_t cmd, uint8_t address, uint8_t *data) +{ + int ret = 0; + uint8_t length; + struct diseqc_cmd diseqc_message; + + memcpy(&diseqc_message.message[0], &msgtbl->command[1], 6); + length = msgtbl->command[0]; + diseqc_message.length = length; + + /* Set Address */ + diseqc_message.message[2] = address; + switch (length) { + case 6: + /* Set Data */ + diseqc_message.message[5] = data[2]; + case 5: + /* Set Data */ + diseqc_message.message[4] = data[1]; + case 4: + /* Set Data */ + diseqc_message.message[3] = data[0]; + case 3: + /* Only cmd */ + break; + default: + return -EINVAL; + } + + if (fd > 0) { + ret = ioctl(fd, cmd, &diseqc_message); + if (ret == -1) + print(verbose, ERROR, 1, "IOCTL failed"); + + } else + print(verbose, ERROR, 1, "Device open error !"); + + return ret; +} diff --git a/kaffeine/src/input/dvb/lib/libdvbapi/diseqc.h b/kaffeine/src/input/dvb/lib/libdvbapi/diseqc.h new file mode 100644 index 0000000..fc8ffd4 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libdvbapi/diseqc.h @@ -0,0 +1,171 @@ +/* + libdvbfe - a DVB frontend library + + Copyright (C) 2005 Manu Abraham <manu@kromtek.com> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA +*/ + +#ifndef DISEQC_H +#define DISEQC_H + +#include <stdlib.h> +#include <stdint.h> + +/* Addresses */ +#define DISEQCxx_MASTER 0x00 +#define SMATV_MASTER 0x10 +#define LNB_MASTER 0x10 +#define SWITCHER_MASTER 0x10 +#define LNB 0x11 +#define LNB_LOOP 0x12 +#define SWITCHER_DC 0x14 +#define SWITCHER_DC_LOOP 0x15 +#define POL_CONTROLLER 0x21 +#define POSITIONER_MASTER 0x30 +#define POSITIONER_POLAR 0x31 +#define POSITIONER_ELEVATION 0x32 + +/* Commands */ +#define DISEQC_SET_LOW_LO 0 +#define DISEQC10_SET_VERT_POL 1 +#define DISEQC10_SET_SAT_POS_A 2 +#define DISEQC10_SET_SWITCH_OPT_A 3 +#define DISEQC10_SET_HIGH_LO 4 +#define DISEQC10_SET_HORIZ_POL 5 +#define DISEQC10_SET_SAT_POS_B 6 + +#define DISEQC10_SET_SWITCH_OPT_B 7 +#define DISEQC11_SET_SWITCH1_INP_A 8 +#define DISEQC11_SET_SWITCH2_INP_A 9 +#define DISEQC11_SET_SWITCH3_INP_A 10 +#define DISEQC11_SET_SWITCH4_INP_A 11 +#define DISEQC11_SET_SWITCH1_INP_B 12 +#define DISEQC11_SET_SWITCH2_INP_B 13 +#define DISEQC11_SET_SWITCH3_INP_B 14 +#define DISEQC11_SET_SWITCH4_INP_B 15 + +#define DISEQCxx_SET_BUS_SLEEP 16 +#define DISEQCxx_SET_BUS_AWAKE 17 +#define DISEQC11_SET_CHAN_FREQ 18 +#define DISEQC11_SET_RCVR_CHAN 19 +#define DISEQC12_SET_MOTOR_HALT 20 +#define DISEQC12_SET_LIMITS_OFF 21 +#define DISEQC12_SET_LIMITS_ON 22 +#define DISEQC22_GET_MOTOR_STATE 23 +#define DISEQC12_SET_MOTOR_WEST 24 +#define DISEQC12_SET_MOTOR_EAST 25 +#define DISEQC12_SET_WEST_LIMIT 26 +#define DISEQC12_SET_EAST_LIMIT 27 +#define DISEQC12_STEP_MOTOR_UP 28 //??????? +#define DISEQC12_STEP_MOTOR_DOWN 29 + +struct diseqc_cmd { + uint8_t message[6]; + uint8_t length; +}; + +struct cmd_types { + uint8_t command[7]; + char *cmd_descr; +}; + +typedef enum dvbfe_sec_voltage { + DVBFE_SEC_VOLTAGE_13, + DVBFE_SEC_VOLTAGE_18, + DVBFE_SEC_VOLTAGE_OFF +} dvbfe_sec_voltage_t; + +typedef enum dvbfe_sec_tone_mode { + DVBFE_SEC_TONE_ON, + DVBFE_SEC_TONE_OFF +} dvbfe_sec_tone_mode_t; + +typedef enum dvbfe_sec_mini_cmd { + DVBFE_SEC_MINI_A, + DVBFE_SEC_MINI_B +} dvbfe_sec_mini_cmd_t; + + +struct cmd_types msgtbl[] = { + + { { 0x03, 0xe0, 0x00, 0x20, 0x00, 0x00, 0x00 }, "DISEQC_SET_LOW_LO" }, + { { 0x03, 0xe0, 0x00, 0x21, 0x00, 0x00, 0x00 }, "DISEQC10_SET_VERT_POL" }, + { { 0x03, 0xe0, 0x00, 0x22, 0x00, 0x00, 0x00 }, "DISEQC10_SET_SAT_POS_A" }, + { { 0x03, 0xe0, 0x00, 0x23, 0x00, 0x00, 0x00 }, "DISEQC10_SET_SWITCH_OPT_A" }, + { { 0x03, 0xe0, 0x00, 0x24, 0x00, 0x00, 0x00 }, "DISEQC10_SET_HIGH_LO" }, + { { 0x03, 0xe0, 0x00, 0x25, 0x00, 0x00, 0x00 }, "DISEQC10_SET_HORIZ_POL" }, + { { 0x03, 0xe0, 0x00, 0x26, 0x00, 0x00, 0x00 }, "DISEQC10_SET_SAT_POS_B" }, + + { { 0x03, 0xe0, 0x00, 0x27, 0x00, 0x00, 0x00 }, "DISEQC10_SET_SWITCH_OPT_B" }, + { { 0x03, 0xe0, 0x00, 0x28, 0x00, 0x00, 0x00 }, "DISEQC11_SET_SWITCH1_INP_A" }, + { { 0x03, 0xe0, 0x00, 0x29, 0x00, 0x00, 0x00 }, "DISEQC11_SET_SWITCH2_INP_A" }, + { { 0x03, 0xe0, 0x00, 0x2a, 0x00, 0x00, 0x00 }, "DISEQC11_SET_SWITCH3_INP_A" }, + { { 0x03, 0xe0, 0x00, 0x2b, 0x00, 0x00, 0x00 }, "DISEQC11_SET_SWITCH4_INP_A" }, + { { 0x03, 0xe0, 0x00, 0x2c, 0x00, 0x00, 0x00 }, "DISEQC11_SET_SWITCH1_INP_B" }, + { { 0x03, 0xe0, 0x00, 0x2d, 0x00, 0x00, 0x00 }, "DISEQC11_SET_SWITCH2_INP_B" }, + { { 0x03, 0xe0, 0x00, 0x2e, 0x00, 0x00, 0x00 }, "DISEQC11_SET_SWITCH3_INP_B" }, + { { 0x03, 0xe0, 0x00, 0x2f, 0x00, 0x00, 0x00 }, "DISEQC11_SET_SWITCH4_INP_B" }, + + { { 0x03, 0xe0, 0x00, 0x30, 0x00, 0x00, 0x00 }, "DISEQCxx_SET_BUS_SLEEP" }, + { { 0x03, 0xe0, 0x00, 0x31, 0x00, 0x00, 0x00 }, "DISEQCxx_SET_BUS_AWAKE" }, + { { 0x06, 0x0e, 0x00, 0x05, 0x80, 0x00, 0x00 }, "DISEQC11_SET_CHAN_FREQ" }, + { { 0x05, 0xe0, 0x00, 0x59, 0x00, 0x00, 0x00 }, "DISEQC11_SET_RCVR_CHAN" }, + + { { 0x03, 0xe0, 0x00, 0x60, 0x00, 0x00, 0x00 }, "DISEQC12_SET_MOTOR_HALT" }, + { { 0x03, 0xe0, 0x00, 0x63, 0x00, 0x00, 0x00 }, "DISEQC12_SET_LIMITS_OFF" }, + { { 0x04, 0xe0, 0x00, 0x6a, 0x00, 0x00, 0x00 }, "DISEQC12_SET_LIMITS_ON" }, + { { 0x03, 0xe0, 0x00, 0x64, 0x00, 0x00, 0x00 }, "DISEQC22_GET_MOTOR_STATE" } , + { { 0x04, 0xe1, 0x00, 0x69, 0x00, 0x00, 0x00 }, "DISEQC12_SET_MOTOR_WEST" }, + { { 0x04, 0xe1, 0x00, 0x68, 0x00, 0x00, 0x00 }, "DISEQC12_SET_MOTOR_EAST" }, + { { 0x03, 0xe1, 0x00, 0x67, 0x00, 0x00, 0x00 }, "DISEQC12_SET_WEST_LIMIT" }, + { { 0x03, 0xe1, 0x00, 0x66, 0x00, 0x00, 0x00 }, "DISEQC12_SET_EAST_LIMIT" }, + { { 0x04, 0xe2, 0x00, 0x68, 0x00, 0x00, 0x00 }, "DISEQC12_STEP_MOTOR_UP" }, + { { 0x04, 0xe2, 0x00, 0x69, 0x00, 0x00, 0x00 }, "DISEQC12_STEP_MOTOR_DOWN"}, + + { {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, NULL } +}; + + +/* + * Tone/Data Burst control + * @param fd, FD opened with libdvbfe_open(). + * @param tone, SEC_TONE_ON/SEC_TONE_OFF + */ +extern int set_22k_tone(int fd, dvbfe_sec_tone_mode_t tone); + +/* + * 22khz Tone control + * @param fd, FD opened with libdvbfe_open(). + * @param adapter, minicmd, SEC_MINI_A/SEC_MINI_B + */ +extern int set_tone_data_burst(int fd, dvbfe_sec_mini_cmd_t minicmd); + +/* + * H/V polarization control + * @param fd, FD opened with libdvbfe_open(). + * @param polarization, SEC_VOLTAGE_13/SEC_VOLTAGE_18/SEC_VOLTAGE_OFF + */ +extern int set_polarization(int fd, dvbfe_sec_voltage_t polarization); + +/* + * Send a DiSEqC Command + * @param fd, FD opened with libdvbfe_open(). + * @param cmd, the defined diseqc commands + * @param address, the address of the DiSEqC device to be controlled + * @param data, a pointer to am array containing the data to be sent + * max. length of data, that can be sent is 3 bytes + */ +extern int do_diseqc_command(int fd, uint8_t cmd, uint8_t address, uint8_t *data); + +#endif diff --git a/kaffeine/src/input/dvb/lib/libdvbapi/dvbca.c b/kaffeine/src/input/dvb/lib/libdvbapi/dvbca.c new file mode 100644 index 0000000..8261cd2 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libdvbapi/dvbca.c @@ -0,0 +1,159 @@ +/* + * libdvbca - interface onto raw CA devices + * + * Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include <sys/param.h> +#include <sys/ioctl.h> +#include <fcntl.h> +#include <unistd.h> +#include <ctype.h> +#include <errno.h> +#include <linux/dvb/ca.h> +#include "dvbca.h" + + +int dvbca_open(int adapter, int cadevice) +{ + char filename[PATH_MAX+1]; + int fd; + + sprintf(filename, "/dev/dvb/adapter%i/ca%i", adapter, cadevice); + if ((fd = open(filename, O_RDWR)) < 0) { + // if that failed, try a flat /dev structure + sprintf(filename, "/dev/dvb%i.ca%i", adapter, cadevice); + fd = open(filename, O_RDWR); + } + + return fd; +} + +int dvbca_reset(int fd, uint8_t slot) +{ + return ioctl(fd, CA_RESET, (1 << slot)); +} + +int dvbca_get_interface_type(int fd, uint8_t slot) +{ + ca_slot_info_t info; + + info.num = slot; + if (ioctl(fd, CA_GET_SLOT_INFO, &info)) + return -1; + + if (info.type & CA_CI_LINK) + return DVBCA_INTERFACE_LINK; + if (info.type & CA_CI) + return DVBCA_INTERFACE_HLCI; + + return -1; +} + +int dvbca_get_cam_state(int fd, uint8_t slot) +{ + ca_slot_info_t info; + + info.num = slot; + if (ioctl(fd, CA_GET_SLOT_INFO, &info)) + return -1; + + if (info.flags == 0) + return DVBCA_CAMSTATE_MISSING; + if (info.flags & CA_CI_MODULE_READY) + return DVBCA_CAMSTATE_READY; + if (info.flags & CA_CI_MODULE_PRESENT) + return DVBCA_CAMSTATE_INITIALISING; + + return -1; +} + +int dvbca_link_write(int fd, uint8_t slot, uint8_t connection_id, + uint8_t *data, uint16_t data_length) +{ + uint8_t *buf = malloc(data_length + 2); + if (buf == NULL) + return -1; + + buf[0] = slot; + buf[1] = connection_id; + memcpy(buf+2, data, data_length); + + int result = write(fd, buf, data_length+2); + free(buf); + return result; +} + +int dvbca_link_read(int fd, uint8_t *slot, uint8_t *connection_id, + uint8_t *data, uint16_t data_length) +{ + int size; + + uint8_t *buf = malloc(data_length + 2); + if (buf == NULL) + return -1; + + if ((size = read(fd, buf, data_length+2)) < 2) + return -1; + + *slot = buf[0]; + *connection_id = buf[1]; + memcpy(data, buf+2, size-2); + free(buf); + + return size - 2; +} + +int dvbca_hlci_write(int fd, uint8_t *data, uint16_t data_length) +{ + struct ca_msg msg; + + if (data_length > 256) { + return -1; + } + memset(&msg, 0, sizeof(msg)); + msg.length = data_length; + + memcpy(msg.msg, data, data_length); + + return ioctl(fd, CA_SEND_MSG, &msg); +} + +int dvbca_hlci_read(int fd, uint32_t app_tag, uint8_t *data, + uint16_t data_length) +{ + struct ca_msg msg; + + if (data_length > 256) { + data_length = 256; + } + memset(&msg, 0, sizeof(msg)); + msg.length = data_length; + msg.msg[0] = app_tag >> 16; + msg.msg[1] = app_tag >> 8; + msg.msg[2] = app_tag; + + int status = ioctl(fd, CA_GET_MSG, &msg); + if (status < 0) return status; + + if (msg.length > data_length) msg.length = data_length; + memcpy(data, msg.msg, msg.length); + return msg.length; +} diff --git a/kaffeine/src/input/dvb/lib/libdvbapi/dvbca.h b/kaffeine/src/input/dvb/lib/libdvbapi/dvbca.h new file mode 100644 index 0000000..c65423b --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libdvbapi/dvbca.h @@ -0,0 +1,135 @@ +/* + * libdvbca - interface onto raw CA devices + * + * Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef LIBDVBCA_H +#define LIBDVBCA_H 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <stdint.h> + +/** + * The types of CA interface we support. + */ +#define DVBCA_INTERFACE_LINK 0 +#define DVBCA_INTERFACE_HLCI 1 + +/** + * States a CAM in a slot can be in. + */ +#define DVBCA_CAMSTATE_MISSING 0 +#define DVBCA_CAMSTATE_INITIALISING 1 +#define DVBCA_CAMSTATE_READY 2 + + +/** + * Open a CA device. Multiple CAMs can be accessed through a CA device. + * + * @param adapter Index of the DVB adapter. + * @param cadevice Index of the CA device on that adapter (usually 0). + * @return A unix file descriptor on success, or -1 on failure. + */ +extern int dvbca_open(int adapter, int cadevice); + +/** + * Reset a CAM. + * + * @param fd File handle opened with dvbca_open. + * @param slot Slot where the requested CAM is in. + * @return 0 on success, -1 on failure. + */ +extern int dvbca_reset(int fd, uint8_t slot); + +/** + * Get the interface type of a CAM. + * + * @param fd File handle opened with dvbca_open. + * @param slot Slot where the requested CAM is in. + * @return One of the DVBCA_INTERFACE_* values, or -1 on failure. + */ +extern int dvbca_get_interface_type(int fd, uint8_t slot); + +/** + * Get the state of a CAM. + * + * @param fd File handle opened with dvbca_open. + * @param slot Slot where the requested CAM is in. + * @return One of the DVBCA_CAMSTATE_* values, or -1 on failure. + */ +extern int dvbca_get_cam_state(int fd, uint8_t slot); + +/** + * Write a message to a CAM using a link-layer interface. + * + * @param fd File handle opened with dvbca_open. + * @param slot Slot where the requested CAM is in. + * @param connection_id Connection ID of the message. + * @param data Data to write. + * @param data_length Number of bytes to write. + * @return 0 on success, or -1 on failure. + */ +extern int dvbca_link_write(int fd, uint8_t slot, uint8_t connection_id, + uint8_t *data, uint16_t data_length); + +/** + * Read a message from a CAM using a link-layer interface. + * + * @param fd File handle opened with dvbca_open. + * @param slot Slot where the responding CAM is in. + * @param connection_id Destination for the connection ID the message came from. + * @param data Data that was read. + * @param data_length Max number of bytes to read. + * @return Number of bytes read on success, or -1 on failure. + */ +extern int dvbca_link_read(int fd, uint8_t *slot, uint8_t *connection_id, + uint8_t *data, uint16_t data_length); + +// FIXME how do we determine which CAM slot of a CA is meant? +/** + * Write a message to a CAM using an HLCI interface. + * + * @param fd File handle opened with dvbca_open. + * @param data Data to write. + * @param data_length Number of bytes to write. + * @return 0 on success, or -1 on failure. + */ +extern int dvbca_hlci_write(int fd, uint8_t *data, uint16_t data_length); + +// FIXME how do we determine which CAM slot of a CA is meant? +/** + * Read a message from a CAM using an HLCI interface. + * + * @param fd File handle opened with dvbca_open. + * @param app_tag Application layer tag giving the message type to read. + * @param data Data that was read. + * @param data_length Max number of bytes to read. + * @return Number of bytes read on success, or -1 on failure. + */ +extern int dvbca_hlci_read(int fd, uint32_t app_tag, uint8_t *data, + uint16_t data_length); + +#ifdef __cplusplus +} +#endif + +#endif // LIBDVBCA_H diff --git a/kaffeine/src/input/dvb/lib/libdvbapi/dvbdemux.c b/kaffeine/src/input/dvb/lib/libdvbapi/dvbdemux.c new file mode 100644 index 0000000..aebad34 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libdvbapi/dvbdemux.c @@ -0,0 +1,243 @@ +/* + * libdvbdemux - a DVB demux library + * + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include <sys/param.h> +#include <sys/ioctl.h> +#include <fcntl.h> +#include <unistd.h> +#include <ctype.h> +#include <errno.h> +#include <linux/dvb/dmx.h> +#include "dvbdemux.h" + + +int dvbdemux_open_demux(int adapter, int demuxdevice, int nonblocking) +{ + char filename[PATH_MAX+1]; + int flags = O_RDWR; + int fd; + + if (nonblocking) + flags |= O_NONBLOCK; + + sprintf(filename, "/dev/dvb/adapter%i/demux%i", adapter, demuxdevice); + if ((fd = open(filename, flags)) < 0) { + // if that failed, try a flat /dev structure + sprintf(filename, "/dev/dvb%i.demux%i", adapter, demuxdevice); + fd = open(filename, flags); + } + + return fd; +} + +int dvbdemux_open_dvr(int adapter, int dvrdevice, int readonly, int nonblocking) +{ + char filename[PATH_MAX+1]; + int flags = O_RDWR; + int fd; + + if (readonly) + flags = O_RDONLY; + if (nonblocking) + flags |= O_NONBLOCK; + + sprintf(filename, "/dev/dvb/adapter%i/dvr%i", adapter, dvrdevice); + if ((fd = open(filename, flags)) < 0) { + // if that failed, try a flat /dev structure + sprintf(filename, "/dev/dvb%i.dvr%i", adapter, dvrdevice); + fd = open(filename, flags); + } + + return fd; +} + +int dvbdemux_set_section_filter(int fd, int pid, + uint8_t filter[18], uint8_t mask[18], + int start, int checkcrc) +{ + struct dmx_sct_filter_params sctfilter; + + memset(&sctfilter, 0, sizeof(sctfilter)); + sctfilter.pid = pid; + memcpy(sctfilter.filter.filter, filter, 1); + memcpy(sctfilter.filter.filter+1, filter+3, 15); + memcpy(sctfilter.filter.mask, mask, 1); + memcpy(sctfilter.filter.mask+1, mask+3, 15); + memset(sctfilter.filter.mode, 0, 16); + if (start) + sctfilter.flags |= DMX_IMMEDIATE_START; + if (checkcrc) + sctfilter.flags |= DMX_CHECK_CRC; + + return ioctl(fd, DMX_SET_FILTER, &sctfilter); +} + +int dvbdemux_set_pes_filter(int fd, int pid, + int input, int output, + int pestype, + int start) +{ + struct dmx_pes_filter_params filter; + + memset(&filter, 0, sizeof(filter)); + filter.pid = pid; + + switch(input) { + case DVBDEMUX_INPUT_FRONTEND: + filter.input = DMX_IN_FRONTEND; + break; + + case DVBDEMUX_INPUT_DVR: + filter.input = DMX_IN_DVR; + break; + + default: + return -EINVAL; + } + + switch(output) { + case DVBDEMUX_OUTPUT_DECODER: + filter.output = DMX_OUT_DECODER; + break; + + case DVBDEMUX_OUTPUT_DEMUX: + filter.output = DMX_OUT_TAP; + break; + + case DVBDEMUX_OUTPUT_DVR: + filter.output = DMX_OUT_TS_TAP; + break; + + default: + return -EINVAL; + } + + switch(pestype) { + case DVBDEMUX_PESTYPE_AUDIO: + filter.pes_type = DMX_PES_AUDIO; + break; + + case DVBDEMUX_PESTYPE_VIDEO: + filter.pes_type = DMX_PES_VIDEO; + break; + + case DVBDEMUX_PESTYPE_TELETEXT: + filter.pes_type = DMX_PES_TELETEXT; + break; + + case DVBDEMUX_PESTYPE_SUBTITLE: + filter.pes_type = DMX_PES_SUBTITLE; + break; + + case DVBDEMUX_PESTYPE_PCR: + filter.pes_type = DMX_PES_PCR; + break; + + default: + return -EINVAL; + } + + if (start) + filter.flags |= DMX_IMMEDIATE_START; + + return ioctl(fd, DMX_SET_PES_FILTER, &filter); +} + +int dvbdemux_set_pid_filter(int fd, int pid, + int input, int output, + int start) +{ + struct dmx_pes_filter_params filter; + + memset(&filter, 0, sizeof(filter)); + if (pid == -1) + filter.pid = 0x2000; + else + filter.pid = pid; + + switch(input) { + case DVBDEMUX_INPUT_FRONTEND: + filter.input = DMX_IN_FRONTEND; + break; + + case DVBDEMUX_INPUT_DVR: + filter.input = DMX_IN_DVR; + break; + + default: + return -EINVAL; + } + + switch(output) { + case DVBDEMUX_OUTPUT_DECODER: + filter.output = DMX_OUT_DECODER; + break; + + case DVBDEMUX_OUTPUT_DEMUX: + filter.output = DMX_OUT_TAP; + break; + + case DVBDEMUX_OUTPUT_DVR: + filter.output = DMX_OUT_TS_TAP; + break; + + default: + return -EINVAL; + } + + filter.pes_type = DMX_PES_OTHER; + + if (start) + filter.flags |= DMX_IMMEDIATE_START; + + return ioctl(fd, DMX_SET_PES_FILTER, &filter); +} + +int dvbdemux_start(int fd) +{ + return ioctl(fd, DMX_START); +} + +int dvbdemux_stop(int fd) +{ + return ioctl(fd, DMX_STOP); +} + +int dvbdemux_get_stc(int fd, uint64_t *stc) +{ + struct dmx_stc _stc; + int result; + + memset(stc, 0, sizeof(_stc)); + if ((result = ioctl(fd, DMX_GET_STC, &_stc)) != 0) { + return result; + } + + *stc = _stc.stc / _stc.base; + return 0; +} + +int dvbdemux_set_buffer(int fd, int bufsize) +{ + return ioctl(fd, DMX_SET_BUFFER_SIZE, bufsize); +} diff --git a/kaffeine/src/input/dvb/lib/libdvbapi/dvbdemux.h b/kaffeine/src/input/dvb/lib/libdvbapi/dvbdemux.h new file mode 100644 index 0000000..3fe4a4b --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libdvbapi/dvbdemux.h @@ -0,0 +1,202 @@ +/* + * libdvbdemux - a DVB demux library + * + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef LIBDVBDEMUX_H +#define LIBDVBDEMUX_H 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <stdint.h> + +/** + * Source of the data to be demuxed. + * + * FRONTEND. The data will be read from the frontend on the adapter. + * + * DVR. The data will be read from the DVR device of the adapter (of course, + * you need to write data TO the DVR device as well). + */ +#define DVBDEMUX_INPUT_FRONTEND 0 +#define DVBDEMUX_INPUT_DVR 1 + +/** + * Destination of the demuxed data. + * + * DECODER. Sends the data directly to a hardware decoder (if present). + * + * DEMUX. Sends the PID stream to the current demux file descriptor. HOWEVER, the + * data will be the payload *only* - transport stream headers will be stripped. + * + * DVR sends the data to the DVR device. The data will be the complete transport + * stream packets with headers intact. Note: if multiple filters specify + * DVBDEMUX_OUTPUT_DVR, the individual PID streams will be re-multiplexed + * together. + */ +#define DVBDEMUX_OUTPUT_DECODER 0 +#define DVBDEMUX_OUTPUT_DEMUX 1 +#define DVBDEMUX_OUTPUT_DVR 2 + +/** + * PES types. + */ +#define DVBDEMUX_PESTYPE_AUDIO 0 +#define DVBDEMUX_PESTYPE_VIDEO 1 +#define DVBDEMUX_PESTYPE_TELETEXT 2 +#define DVBDEMUX_PESTYPE_SUBTITLE 3 +#define DVBDEMUX_PESTYPE_PCR 4 + +/** + * Open a demux device. Can be called multiple times. These let you setup a + * single filter per FD. It can can also be read() from if you use a section + * filter, or create a pes_filter or raw_filter with output DVBDEMUX_OUTPUT_DEMUX. + * + * @param adapter Index of the DVB adapter. + * @param demuxdevice Index of the demux device on that adapter (usually 0). + * @param nonblocking If 1, frontend will be opened in nonblocking mode. + * @return A unix file descriptor on success, or -1 on failure. + */ +extern int dvbdemux_open_demux(int adapter, int demuxdevice, int nonblocking); + +/** + * Open a DVR device. May be opened for writing once, or multiple times in readonly + * mode. It is used to either write() transport stream data to be demuxed + * (if input == DVBDEMUX_INPUT_DVR), or to read() a stream of demuxed data + * (if output == DVBDEMUX_OUTPUT_DVR). + * + * Note, all demux filters with output set to DVBDEMUX_OUTPUT_DVR will be + * multiplexed together and output their data on this device. + * + * @param adapter Index of the DVB adapter. + * @param dvrdevice Index of the dvr device on that adapter (usually 0) + * @param readonly If 1, frontend will be opened in readonly mode only. + * @param nonblocking If 1, frontend will be opened in nonblocking mode. + * @return A unix file descriptor on success, or -1 on failure. + */ +extern int dvbdemux_open_dvr(int adapter, int dvrdevice, int readonly, int nonblocking); + +/** + * Set filter for the first 18 bytes of decoded SI table sections. Note that + * bytes 1 and 2 are _not_ filtered since they contain the length field. + * + * Conceptually, the driver computes the following for each filtered bit. + * + * (filter[X].bit[Y] & mask[X].bit[Y]) == (header[X].bit[Y] & mask[X].bit[Y]) + * + * Any sections which do not match this criteria for every bit will be discarded. + * + * The SI data is always read from the frontend, and is always returned by + * read()ing the demux fd. FIXME: check this statement! + * + * @param fd FD as opened with dvbdemux_open_demux() above. + * @param pid PID of the stream. + * @param filter The filter values of the first 18 bytes of the desired sections. + * @param mask Bitmask indicating which bits in the filter array should be tested + * (if a bit is 1, it will be tested). + * @param start If 1, the filter will be started immediately. Otherwise you must + * call dvbdemux_start() manually. + * @param checkcrc If 1, the driver will check the CRC on the table sections. + * Any bad sections will be dropped. + * @return 0 on success, nonzero on failure. + */ +extern int dvbdemux_set_section_filter(int fd, int pid, + uint8_t filter[18], uint8_t mask[18], + int start, int checkcrc); + +/** + * Set filter for a stream of PES data. This call can only used for cards + * equipped with a hardware decoder. + * + * @param fd FD as opened with dvbdemux_open_demux() above. + * @param pid PID of the stream. + * @param input One of DVBDEMUX_INPUT_*. + * @param output One of DVBDEMUX_OUTPUT_*. + * @param pestype One of DVBDEMUX_PESTYPE_* - this tells the decoder the type + * of data in this stream. + * @param start If 1, the filter will be started immediately. Otherwise you must + * call dvbdemux_start() manually. + * @return 0 on success, nonzero on failure. + */ +extern int dvbdemux_set_pes_filter(int fd, int pid, + int input, int output, + int pestype, + int start); + +/** + * Create a pid filter - this will extract transport stream packets for a + * specified PID. + * + * Note: The wildcard PID can only be used on "budget" cards. + * + * @param fd FD as opened with dvbdemux_open_demux() above. + * @param pid PID to retrieve, or use -1 as a wildcard for ALL PIDs. + * @param input One of DVBDEMUX_INPUT_*. + * @param output One of DVBDEMUX_OUTPUT_*. + * @param start If 1, the filter will be started immediately. Otherwise you must + * call dvbdemux_start() manually. + * @return 0 on success, nonzero on failure. + */ +extern int dvbdemux_set_pid_filter(int fd, int pid, + int input, int output, + int start); + +/** + * Start a demux going. + * + * @param fd FD as opened with dvbdemux_open_demux() above. + * @return 0 on success, nonzero on failure. + */ +extern int dvbdemux_start(int fd); + +/** + * Stop a demux. + * + * @param fd FD as opened with dvbdemux_open_demux() above. + * @return 0 on success, nonzero on failure. + */ +extern int dvbdemux_stop(int fd); + +/** + * Retrieve the current STC from the demux. This call can only used for cards + * equipped with a hardware decoder. + * + * @param fd FD as opened with dvbdemux_open_demux() above. + * @param stc Where to put the retrieved STC value (in 90kHz clock). + * @return 0 on success, nonzero on failure. + */ +extern int dvbdemux_get_stc(int fd, uint64_t *stc); + +/** + * Change the internal buffer size used by the demuxer. The default buffer size + * is 8192 bytes. Can only be used if the demux in question is stopped. + * + * @param fd FD as opened with dvbdemux_open_demux() above. + * @param bufsize New buffer size to use. + * @return 0 on success, nonzero on failure. + */ +extern int dvbdemux_set_buffer(int fd, int bufsize); + +#ifdef __cplusplus +} +#endif + +#endif // LIBDVBDEMUX_H diff --git a/kaffeine/src/input/dvb/lib/libdvbapi/dvbfe.c b/kaffeine/src/input/dvb/lib/libdvbapi/dvbfe.c new file mode 100644 index 0000000..fc6ecf4 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libdvbapi/dvbfe.c @@ -0,0 +1,760 @@ +/* + * libdvbfe - a DVB frontend library + * + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#define _GNU_SOURCE +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include <sys/param.h> +#include <sys/ioctl.h> +#include <sys/time.h> +#include <fcntl.h> +#include <unistd.h> +#include <ctype.h> +#include <errno.h> +#include <linux/dvb/frontend.h> +#include "dvbfe.h" + +#define GET_INFO_MIN_DELAY_US 100000 + +static int dvbfe_spectral_inversion_to_kapi[][2] = +{ + { DVBFE_INVERSION_OFF, INVERSION_OFF }, + { DVBFE_INVERSION_ON, INVERSION_ON }, + { DVBFE_INVERSION_AUTO, INVERSION_AUTO }, + { -1, -1 } +}; + +static int dvbfe_code_rate_to_kapi[][2] = +{ + { DVBFE_FEC_NONE, FEC_NONE }, + { DVBFE_FEC_1_2, FEC_1_2 }, + { DVBFE_FEC_2_3, FEC_2_3 }, + { DVBFE_FEC_3_4, FEC_3_4 }, + { DVBFE_FEC_4_5, FEC_4_5 }, + { DVBFE_FEC_5_6, FEC_5_6 }, + { DVBFE_FEC_6_7, FEC_6_7 }, + { DVBFE_FEC_7_8, FEC_7_8 }, + { DVBFE_FEC_8_9, FEC_8_9 }, + { DVBFE_FEC_AUTO, FEC_AUTO }, + { -1, -1 } +}; + +static int dvbfe_dvbt_const_to_kapi[][2] = +{ + { DVBFE_DVBT_CONST_QPSK, FE_QPSK }, + { DVBFE_DVBT_CONST_QAM_16, QAM_16 }, + { DVBFE_DVBT_CONST_QAM_32, QAM_32 }, + { DVBFE_DVBT_CONST_QAM_64, QAM_64 }, + { DVBFE_DVBT_CONST_QAM_128, QAM_128 }, + { DVBFE_DVBT_CONST_QAM_256, QAM_256 }, + { DVBFE_DVBT_CONST_AUTO, QAM_AUTO }, + { -1, -1 } +}; + +static int dvbfe_dvbc_mod_to_kapi[][2] = +{ + { DVBFE_DVBC_MOD_QAM_16, QAM_16 }, + { DVBFE_DVBC_MOD_QAM_32, QAM_32 }, + { DVBFE_DVBC_MOD_QAM_64, QAM_64 }, + { DVBFE_DVBC_MOD_QAM_128, QAM_128 }, + { DVBFE_DVBC_MOD_QAM_256, QAM_256 }, + { DVBFE_DVBC_MOD_AUTO, QAM_AUTO }, + { -1, -1 } +}; + +static int dvbfe_atsc_mod_to_kapi[][2] = +{ + { DVBFE_ATSC_MOD_QAM_64, QAM_64 }, + { DVBFE_ATSC_MOD_QAM_256, QAM_256 }, + { DVBFE_ATSC_MOD_VSB_8, VSB_8 }, + { DVBFE_ATSC_MOD_VSB_16, VSB_16 }, + { DVBFE_ATSC_MOD_AUTO, QAM_AUTO }, + { -1, -1 } +}; + +static int dvbfe_dvbt_transmit_mode_to_kapi[][2] = +{ + { DVBFE_DVBT_TRANSMISSION_MODE_2K, TRANSMISSION_MODE_2K }, + { DVBFE_DVBT_TRANSMISSION_MODE_8K, TRANSMISSION_MODE_8K }, + { DVBFE_DVBT_TRANSMISSION_MODE_AUTO, TRANSMISSION_MODE_AUTO }, + { -1, -1 } +}; + +static int dvbfe_dvbt_bandwidth_to_kapi[][2] = +{ + { DVBFE_DVBT_BANDWIDTH_8_MHZ, BANDWIDTH_8_MHZ }, + { DVBFE_DVBT_BANDWIDTH_7_MHZ, BANDWIDTH_7_MHZ }, + { DVBFE_DVBT_BANDWIDTH_6_MHZ, BANDWIDTH_6_MHZ }, + { DVBFE_DVBT_BANDWIDTH_AUTO, BANDWIDTH_AUTO }, + { -1, -1 } +}; + +static int dvbfe_dvbt_guard_interval_to_kapi[][2] = +{ + { DVBFE_DVBT_GUARD_INTERVAL_1_32, GUARD_INTERVAL_1_32}, + { DVBFE_DVBT_GUARD_INTERVAL_1_16, GUARD_INTERVAL_1_16}, + { DVBFE_DVBT_GUARD_INTERVAL_1_8, GUARD_INTERVAL_1_8}, + { DVBFE_DVBT_GUARD_INTERVAL_1_4, GUARD_INTERVAL_1_4}, + { DVBFE_DVBT_GUARD_INTERVAL_AUTO, GUARD_INTERVAL_AUTO}, + { -1, -1 } +}; + +static int dvbfe_dvbt_hierarchy_to_kapi[][2] = +{ + { DVBFE_DVBT_HIERARCHY_NONE, HIERARCHY_NONE }, + { DVBFE_DVBT_HIERARCHY_1, HIERARCHY_1 }, + { DVBFE_DVBT_HIERARCHY_2, HIERARCHY_2 }, + { DVBFE_DVBT_HIERARCHY_4, HIERARCHY_4 }, + { DVBFE_DVBT_HIERARCHY_AUTO, HIERARCHY_AUTO }, + { -1, -1 } +}; + +static int lookupval(int val, int reverse, int table[][2]) +{ + int i =0; + + while(table[i][0] != -1) { + if (!reverse) { + if (val == table[i][0]) { + return table[i][1]; + } + } else { + if (val == table[i][1]) { + return table[i][0]; + } + } + i++; + } + + return -1; +} + + +struct dvbfe_handle_prv { + int fd; + dvbfe_type_t type; + char *name; + struct timeval nextinfotime; + struct dvbfe_info cachedinfo; + int cachedreturnval; +}; + +dvbfe_handle_t dvbfe_open(int adapter, int frontend, int readonly) +{ + char filename[PATH_MAX+1]; + struct dvbfe_handle_prv *fehandle; + int fd; + struct dvb_frontend_info info; + + // flags + int flags = O_RDWR; + if (readonly) { + flags = O_RDONLY; + } + + // open it (try normal /dev structure first) + sprintf(filename, "/dev/dvb/adapter%i/frontend%i", adapter, frontend); + if ((fd = open(filename, flags)) < 0) { + // if that failed, try a flat /dev structure + sprintf(filename, "/dev/dvb%i.frontend%i", adapter, frontend); + if ((fd = open(filename, flags)) < 0) { + return NULL; + } + } + + // determine fe type + if (ioctl(fd, FE_GET_INFO, &info)) { + close(fd); + return NULL; + } + + // setup structure + fehandle = (struct dvbfe_handle_prv*) malloc(sizeof(struct dvbfe_handle_prv)); + memset(fehandle, 0, sizeof(struct dvbfe_handle_prv)); + fehandle->fd = fd; + switch(info.type) { + case FE_QPSK: + fehandle->type = DVBFE_TYPE_DVBS; + break; + + case FE_QAM: + fehandle->type = DVBFE_TYPE_DVBC; + break; + + case FE_OFDM: + fehandle->type = DVBFE_TYPE_DVBT; + break; + + case FE_ATSC: + fehandle->type = DVBFE_TYPE_ATSC; + break; + } + fehandle->name = strndup(info.name, sizeof(info.name)); + + // done + return fehandle; +} + +void dvbfe_close(dvbfe_handle_t _fehandle) +{ + struct dvbfe_handle_prv *fehandle = (struct dvbfe_handle_prv*) _fehandle; + + close(fehandle->fd); + free(fehandle->name); + free(fehandle); +} + +int dvbfe_get_info(dvbfe_handle_t _fehandle, dvbfe_info_mask_t querymask, struct dvbfe_info *result) +{ + int returnval = 0; + fe_status_t status; + struct dvb_frontend_parameters kparams; + struct dvbfe_handle_prv *fehandle = (struct dvbfe_handle_prv*) _fehandle; + struct timeval curtime; + + // limit how often this is called to reduce bus traffic + gettimeofday(&curtime, NULL); + if ((curtime.tv_sec < fehandle->nextinfotime.tv_sec) || + ((curtime.tv_sec == fehandle->nextinfotime.tv_sec) && (curtime.tv_usec < fehandle->nextinfotime.tv_usec))) { + memcpy(result, &fehandle->cachedinfo, sizeof(struct dvbfe_info)); + return fehandle->cachedreturnval; + } + + // retrieve the requested values + memset(result, 0, sizeof(result)); + result->type = fehandle->type; + result->name = fehandle->name; + if (querymask & DVBFE_INFO_LOCKSTATUS) { + if (!ioctl(fehandle->fd, FE_READ_STATUS, &status)) { + returnval |= DVBFE_INFO_LOCKSTATUS; + if (status & FE_HAS_SIGNAL) + result->signal = 1; + + if (status & FE_HAS_CARRIER) + result->carrier = 1; + + if (status & FE_HAS_VITERBI) + result->viterbi = 1; + + if (status & FE_HAS_SYNC) + result->sync = 1; + + if (status & FE_HAS_LOCK) + result->lock = 1; + } + } + if (querymask & DVBFE_INFO_FEPARAMS) { + if (!ioctl(fehandle->fd, FE_GET_FRONTEND, &kparams)) { + returnval |= DVBFE_INFO_FEPARAMS; + result->feparams.frequency = kparams.frequency; + result->feparams.inversion = lookupval(kparams.inversion, 1, dvbfe_spectral_inversion_to_kapi); + switch(fehandle->type) { + case FE_QPSK: + result->feparams.u.dvbs.symbol_rate = kparams.u.qpsk.symbol_rate; + result->feparams.u.dvbs.fec_inner = + lookupval(kparams.u.qpsk.fec_inner, 1, dvbfe_code_rate_to_kapi); + break; + + case FE_QAM: + result->feparams.u.dvbc.symbol_rate = kparams.u.qam.symbol_rate; + result->feparams.u.dvbc.fec_inner = + lookupval(kparams.u.qam.fec_inner, 1, dvbfe_code_rate_to_kapi); + result->feparams.u.dvbc.modulation = + lookupval(kparams.u.qam.modulation, 1, dvbfe_dvbc_mod_to_kapi); + break; + + case FE_OFDM: + result->feparams.u.dvbt.bandwidth = + lookupval(kparams.u.ofdm.bandwidth, 1, dvbfe_dvbt_bandwidth_to_kapi); + result->feparams.u.dvbt.code_rate_HP = + lookupval(kparams.u.ofdm.code_rate_HP, 1, dvbfe_code_rate_to_kapi); + result->feparams.u.dvbt.code_rate_LP = + lookupval(kparams.u.ofdm.code_rate_LP, 1, dvbfe_code_rate_to_kapi); + result->feparams.u.dvbt.constellation = + lookupval(kparams.u.ofdm.constellation, 1, dvbfe_dvbt_const_to_kapi); + result->feparams.u.dvbt.transmission_mode = + lookupval(kparams.u.ofdm.transmission_mode, 1, dvbfe_dvbt_transmit_mode_to_kapi); + result->feparams.u.dvbt.guard_interval = + lookupval(kparams.u.ofdm.guard_interval, 1, dvbfe_dvbt_guard_interval_to_kapi); + result->feparams.u.dvbt.hierarchy_information = + lookupval(kparams.u.ofdm.hierarchy_information, 1, dvbfe_dvbt_hierarchy_to_kapi); + break; + + case FE_ATSC: + result->feparams.u.atsc.modulation = + lookupval(kparams.u.vsb.modulation, 1, dvbfe_atsc_mod_to_kapi); + break; + } + } + + } + if (querymask & DVBFE_INFO_BER) { + if (!ioctl(fehandle->fd, FE_READ_BER, &result->ber)) + returnval |= DVBFE_INFO_BER; + } + if (querymask & DVBFE_INFO_SIGNAL_STRENGTH) { + if (!ioctl(fehandle->fd, FE_READ_SIGNAL_STRENGTH, &result->signal_strength)) + returnval |= DVBFE_INFO_SIGNAL_STRENGTH; + } + if (querymask & DVBFE_INFO_SNR) { + if (!ioctl(fehandle->fd, FE_READ_SNR, &result->snr)) + returnval |= DVBFE_INFO_SNR; + } + if (querymask & DVBFE_INFO_UNCORRECTED_BLOCKS) { + if (!ioctl(fehandle->fd, FE_READ_UNCORRECTED_BLOCKS, &result->ucblocks)) + returnval |= DVBFE_INFO_UNCORRECTED_BLOCKS; + } + + // setup for next poll + gettimeofday(&fehandle->nextinfotime, NULL); + fehandle->nextinfotime.tv_usec += GET_INFO_MIN_DELAY_US; + if (fehandle->nextinfotime.tv_usec >= 1000000) { + fehandle->nextinfotime.tv_usec -= 1000000; + fehandle->nextinfotime.tv_sec++; + } + memcpy(&fehandle->cachedinfo, result, sizeof(struct dvbfe_info)); + fehandle->cachedreturnval = returnval; + + // done + return returnval; +} + +int dvbfe_set(dvbfe_handle_t _fehandle, struct dvbfe_parameters *params, int timeout) +{ + struct dvb_frontend_parameters kparams; + struct dvbfe_handle_prv *fehandle = (struct dvbfe_handle_prv*) _fehandle; + int res; + struct timeval endtime; + fe_status_t status; + + kparams.frequency = params->frequency; + kparams.inversion = lookupval(params->inversion, 0, dvbfe_spectral_inversion_to_kapi); + switch(fehandle->type) { + case FE_QPSK: + kparams.u.qpsk.symbol_rate = params->u.dvbs.symbol_rate; + kparams.u.qpsk.fec_inner = lookupval(params->u.dvbs.fec_inner, 0, dvbfe_code_rate_to_kapi); + break; + + case FE_QAM: + kparams.u.qam.symbol_rate = params->u.dvbc.symbol_rate; + kparams.u.qam.fec_inner = lookupval(params->u.dvbc.fec_inner, 0, dvbfe_code_rate_to_kapi); + kparams.u.qam.modulation = lookupval(params->u.dvbc.modulation, 0, dvbfe_dvbc_mod_to_kapi); + break; + + case FE_OFDM: + kparams.u.ofdm.bandwidth = lookupval(params->u.dvbt.bandwidth, 0, dvbfe_dvbt_bandwidth_to_kapi); + kparams.u.ofdm.code_rate_HP = lookupval(params->u.dvbt.code_rate_HP, 0, dvbfe_code_rate_to_kapi); + kparams.u.ofdm.code_rate_LP = lookupval(params->u.dvbt.code_rate_LP, 0, dvbfe_code_rate_to_kapi); + kparams.u.ofdm.constellation = lookupval(params->u.dvbt.constellation, 0, dvbfe_dvbt_const_to_kapi); + kparams.u.ofdm.transmission_mode = + lookupval(params->u.dvbt.transmission_mode, 0, dvbfe_dvbt_transmit_mode_to_kapi); + kparams.u.ofdm.guard_interval = + lookupval(params->u.dvbt.guard_interval, 0, dvbfe_dvbt_guard_interval_to_kapi); + kparams.u.ofdm.hierarchy_information = + lookupval(params->u.dvbt.hierarchy_information, 0, dvbfe_dvbt_hierarchy_to_kapi); + break; + + case FE_ATSC: + kparams.u.vsb.modulation = lookupval(params->u.atsc.modulation, 0, dvbfe_atsc_mod_to_kapi); + break; + + default: + return -EINVAL; + } + + // set it and check for error + res = ioctl(fehandle->fd, FE_SET_FRONTEND, &kparams); + if (res) + return res; + + // 0 => return immediately + if (timeout == 0) { + return 0; + } + + /* calculate timeout */ + if (timeout > 0) { + gettimeofday(&endtime, NULL); + timeout *= 1000; + endtime.tv_sec += timeout / 1000000; + endtime.tv_usec += timeout % 1000000; + } + + /* wait for a lock */ + while(1) { + /* has it locked? */ + if (!ioctl(fehandle->fd, FE_READ_STATUS, &status)) { + if (status & FE_HAS_LOCK) { + break; + } + } + + /* check for timeout */ + if (timeout > 0) { + struct timeval curtime; + gettimeofday(&curtime, NULL); + if ((curtime.tv_sec > endtime.tv_sec) || + ((curtime.tv_sec == endtime.tv_sec) && (curtime.tv_usec >= endtime.tv_usec))) { + break; + } + } + + /* delay for a bit */ + usleep(100000); + } + + /* exit */ + if (status & FE_HAS_LOCK) + return 0; + return -ETIMEDOUT; +} + +void dvbfe_poll(dvbfe_handle_t fehandle) +{ + // no implementation required yet +} + + + + + + + +int dvbfe_diseqc_command(dvbfe_handle_t _fehandle, char *command) +{ + int i = 0; + int waittime; + int status; + struct dvb_diseqc_master_cmd master_cmd; + unsigned int tmpcmd[6]; + struct dvbfe_handle_prv *fehandle = (struct dvbfe_handle_prv*) _fehandle; + char value_s[20]; + int value_i; + int addr; + + while(command[i]) { + /* kill whitespace */ + if (isspace(command[i])) { + i++; + continue; + } + + switch(command[i]) { + case 't': + if ((status = ioctl(fehandle->fd, FE_SET_TONE, SEC_TONE_OFF)) != 0) + return status; + break; + + case 'T': + if ((status = ioctl(fehandle->fd, FE_SET_TONE, SEC_TONE_ON)) != 0) + return status; + break; + + case '_': + if ((status = ioctl(fehandle->fd, FE_SET_VOLTAGE, SEC_VOLTAGE_OFF)) != 0) + return status; + break; + + case 'v': + if ((status = ioctl(fehandle->fd, FE_SET_VOLTAGE, SEC_VOLTAGE_13)) != 0) + return status; + break; + + case 'V': + if ((status = ioctl(fehandle->fd, FE_SET_VOLTAGE, SEC_VOLTAGE_18)) != 0) + return status; + break; + + case 'A': + if ((status = ioctl(fehandle->fd, FE_DISEQC_SEND_BURST, SEC_MINI_A)) != 0) + return status; + break; + + case 'B': + if ((status = ioctl(fehandle->fd, FE_DISEQC_SEND_BURST, SEC_MINI_B)) != 0) + return status; + break; + + case '+': + ioctl(fehandle->fd, FE_ENABLE_HIGH_LNB_VOLTAGE, 1); + /* don't care if this one is not supported */ + break; + + case '-': + ioctl(fehandle->fd, FE_ENABLE_HIGH_LNB_VOLTAGE, 0); + /* don't care if this one is not supported */ + break; + + case 'W': + waittime = atoi(command + i + 1); + if (waittime == 0) { + return -EINVAL; + } + usleep(waittime * 1000); + while(command[i] && !isspace(command[i])) + i++; + break; + + case '.': // extended command + { + i++; + + if (!strncmp(command+i, "D(", 2)) { + i += 2; + + master_cmd.msg_len = + sscanf(command+i, "%x %x %x %x %x %x", + tmpcmd, tmpcmd+1, tmpcmd+2, tmpcmd+3, tmpcmd+4, tmpcmd+5); + if (master_cmd.msg_len == 0) + return -EINVAL; + master_cmd.msg[0] = tmpcmd[0]; + master_cmd.msg[1] = tmpcmd[1]; + master_cmd.msg[2] = tmpcmd[2]; + master_cmd.msg[3] = tmpcmd[3]; + master_cmd.msg[4] = tmpcmd[4]; + master_cmd.msg[5] = tmpcmd[5]; + + if ((status = ioctl(fehandle->fd, FE_DISEQC_SEND_MASTER_CMD, &master_cmd)) != 0) + return status; + } else if (!strncmp(command+i, "Dband(", 6)) { + if (sscanf(command+i+6, "%i %2s", &addr, value_s) != 2) + return -EINVAL; + if (!strncmp(value_s, "lo", 2)) { + master_cmd.msg[0] = 0xe0; + master_cmd.msg[1] = addr; + master_cmd.msg[2] = 0x20; + master_cmd.msg_len = 3; + } else if (!strncmp(value_s, "hi", 2)) { + master_cmd.msg[0] = 0xe0; + master_cmd.msg[1] = addr; + master_cmd.msg[2] = 0x24; + master_cmd.msg_len = 3; + } else { + return -EINVAL; + } + if ((status = ioctl(fehandle->fd, FE_DISEQC_SEND_MASTER_CMD, &master_cmd)) != 0) + return status; + + } else if ((!strncmp(command+i, "Dpolarisation(", 14) || + (!strncmp(command+i, "Dpolarization(", 14)))) { + if (sscanf(command+i+14, "%i %1s", &addr, value_s) != 2) + return -EINVAL; + switch(*value_s) { + case 'H': + case 'L': + master_cmd.msg[0] = 0xe0; + master_cmd.msg[1] = addr; + master_cmd.msg[2] = 0x25; + master_cmd.msg_len = 3; + break; + + case 'V': + case 'R': + master_cmd.msg[0] = 0xe0; + master_cmd.msg[1] = addr; + master_cmd.msg[2] = 0x21; + master_cmd.msg_len = 3; + break; + + default: + return -EINVAL; + } + if ((status = ioctl(fehandle->fd, FE_DISEQC_SEND_MASTER_CMD, &master_cmd)) != 0) + return status; + + } else if (!strncmp(command+i, "Dsatellite_position(", 20)) { + if (sscanf(command+i+20, "%i %1s", &addr, value_s) != 2) + return -EINVAL; + switch(*value_s) { + case 'A': + case 'C': + master_cmd.msg[0] = 0xe0; + master_cmd.msg[1] = addr; + master_cmd.msg[2] = 0x22; + master_cmd.msg_len = 3; + break; + + case 'B': + case 'D': + master_cmd.msg[0] = 0xe0; + master_cmd.msg[1] = addr; + master_cmd.msg[2] = 0x26; + master_cmd.msg_len = 3; + break; + + default: + return -EINVAL; + } + if ((status = ioctl(fehandle->fd, FE_DISEQC_SEND_MASTER_CMD, &master_cmd)) != 0) + return status; + + } else if (!strncmp(command+i, "Dswitch_option(", 15)) { + if (sscanf(command+i+15, "%i %1s", &addr, value_s) != 2) + return -EINVAL; + switch(*value_s) { + case 'A': + master_cmd.msg[0] = 0xe0; + master_cmd.msg[1] = addr; + master_cmd.msg[2] = 0x23; + master_cmd.msg_len = 3; + break; + + case 'B': + master_cmd.msg[0] = 0xe0; + master_cmd.msg[1] = addr; + master_cmd.msg[2] = 0x27; + master_cmd.msg_len = 3; + break; + + default: + return -EINVAL; + } + if ((status = ioctl(fehandle->fd, FE_DISEQC_SEND_MASTER_CMD, &master_cmd)) != 0) + return status; + + } else if (!strncmp(command+i, "Dport_pins(", 11)) { + int mask; + if (sscanf(command+i+11, "%i %i %i", &addr, &mask, &value_i) != 3) + return -EINVAL; + + if (mask & 0x0f) { + master_cmd.msg[0] = 0xe0; + master_cmd.msg[1] = addr; + master_cmd.msg[2] = 0x38; + master_cmd.msg[3] = ((mask & 0x0f) << 4) | (value_i & 0x0f); + master_cmd.msg_len = 4; + + if ((status = ioctl(fehandle->fd, FE_DISEQC_SEND_MASTER_CMD, &master_cmd)) != 0) + return status; + } + if (mask & 0xf0) { + master_cmd.msg[0] = 0xe0; + master_cmd.msg[1] = addr; + master_cmd.msg[2] = 0x39; + master_cmd.msg[3] = (mask & 0xf0) | ((value_i & 0xf0) >> 4); + master_cmd.msg_len = 4; + + if ((status = ioctl(fehandle->fd, FE_DISEQC_SEND_MASTER_CMD, &master_cmd)) != 0) + return status; + } + + } else if (!strncmp(command+i, "Dgoto_preset(", 13)) { + if (sscanf(command+i+13, "%i %i", &addr, &value_i) != 2) + return -EINVAL; + + master_cmd.msg[0] = 0xe0; + master_cmd.msg[1] = addr; + master_cmd.msg[2] = 0x3b; + master_cmd.msg[3] = value_i; + master_cmd.msg_len = 4; + + if ((status = ioctl(fehandle->fd, FE_DISEQC_SEND_MASTER_CMD, &master_cmd)) != 0) + return status; + + } else if (!strncmp(command+i, "Dgoto_angle(", 12)) { + int integer = 0; + int fraction = 0; + char *tmp; + + if (sscanf(command+i+12, "%i %s", &addr, value_s) != 2) + return -EINVAL; + + // parse the integer and fractional parts using fixed point + integer = atoi(value_s); + tmp = strchr(value_s, '.'); + if (tmp != NULL) { + tmp++; + tmp[3] = 0; + fraction = ((atoi(tmp) * 16000) / 1000000) & 0xf; + } + + // generate the command + master_cmd.msg[0] = 0xe0; + master_cmd.msg[1] = addr; + master_cmd.msg[2] = 0x6e; + if (integer < -256) { + return -EINVAL; + } else if (integer < 0) { + integer = -integer; + master_cmd.msg[3] = 0xf0; + } else if (integer < 256) { + master_cmd.msg[3] = 0x00; + } else if (integer < 512) { + integer -= 256; + master_cmd.msg[3] = 0x10; + } else { + return -EINVAL; + } + master_cmd.msg[3] |= ((integer / 16) & 0x0f); + integer = integer % 16; + master_cmd.msg[4] |= ((integer & 0x0f) << 4) | fraction; + master_cmd.msg_len = 5; + + if ((status = ioctl(fehandle->fd, FE_DISEQC_SEND_MASTER_CMD, &master_cmd)) != 0) + return status; + + } else if (!strncmp(command+i, "dishnetworks(", 13)) { + if (sscanf(command+i+13, "%i", tmpcmd) != 1) + return -EINVAL; + + if ((status = ioctl(fehandle->fd, FE_DISHNETWORK_SEND_LEGACY_CMD, tmpcmd)) != 0) + return status; + } + + /* skip to the end... */ + while(command[i] && (command[i] != ')')) + i++; + break; + } + + + default: + return -EINVAL; + } + + i++; + } + + return 0; +} + +int dvbfe_diseqc_read(dvbfe_handle_t _fehandle, int timeout, unsigned char *buf, unsigned int len) +{ + struct dvb_diseqc_slave_reply reply; + int result; + struct dvbfe_handle_prv *fehandle = (struct dvbfe_handle_prv*) _fehandle; + + if (len > 4) + len = 4; + + reply.timeout = timeout; + reply.msg_len = len; + + if ((result = ioctl(fehandle->fd, FE_DISEQC_RECV_SLAVE_REPLY, reply)) != 0) + return result; + + if (reply.msg_len < len) + len = reply.msg_len; + memcpy(buf, reply.msg, len); + + return len; +} diff --git a/kaffeine/src/input/dvb/lib/libdvbapi/dvbfe.h b/kaffeine/src/input/dvb/lib/libdvbapi/dvbfe.h new file mode 100644 index 0000000..9eb03b7 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libdvbapi/dvbfe.h @@ -0,0 +1,308 @@ +/* + * libdvbfe - a DVB frontend library + * + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef LIBDVBFE_H +#define LIBDVBFE_H 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <stdint.h> + +/** + * The types of frontend we support. + */ +typedef enum dvbfe_type { + DVBFE_TYPE_DVBS, + DVBFE_TYPE_DVBC, + DVBFE_TYPE_DVBT, + DVBFE_TYPE_ATSC, +} dvbfe_type_t; + +typedef enum dvbfe_polarization { + DVBFE_POLARIZATION_H, + DVBFE_POLARIZATION_V, + DVBFE_POLARIZATION_L, + DVBFE_POLARIZATION_R, +} dvbfe_polarization_t; + +typedef enum dvbfe_spectral_inversion { + DVBFE_INVERSION_OFF, + DVBFE_INVERSION_ON, + DVBFE_INVERSION_AUTO +} dvbfe_spectral_inversion_t; + +typedef enum dvbfe_code_rate { + DVBFE_FEC_NONE, + DVBFE_FEC_1_2, + DVBFE_FEC_2_3, + DVBFE_FEC_3_4, + DVBFE_FEC_4_5, + DVBFE_FEC_5_6, + DVBFE_FEC_6_7, + DVBFE_FEC_7_8, + DVBFE_FEC_8_9, + DVBFE_FEC_AUTO +} dvbfe_code_rate_t; + +typedef enum dvbfe_dvbt_const { + DVBFE_DVBT_CONST_QPSK, + DVBFE_DVBT_CONST_QAM_16, + DVBFE_DVBT_CONST_QAM_32, + DVBFE_DVBT_CONST_QAM_64, + DVBFE_DVBT_CONST_QAM_128, + DVBFE_DVBT_CONST_QAM_256, + DVBFE_DVBT_CONST_AUTO +} dvbfe_dvbt_const_t; + +typedef enum dvbfe_dvbc_mod { + DVBFE_DVBC_MOD_QAM_16, + DVBFE_DVBC_MOD_QAM_32, + DVBFE_DVBC_MOD_QAM_64, + DVBFE_DVBC_MOD_QAM_128, + DVBFE_DVBC_MOD_QAM_256, + DVBFE_DVBC_MOD_AUTO, +} dvbfe_dvbc_mod_t; + +typedef enum dvbfe_atsc_mod { + DVBFE_ATSC_MOD_QAM_64, + DVBFE_ATSC_MOD_QAM_256, + DVBFE_ATSC_MOD_VSB_8, + DVBFE_ATSC_MOD_VSB_16, + DVBFE_ATSC_MOD_AUTO +} dvbfe_atsc_mod_t; + +typedef enum dvbfe_dvbt_transmit_mode { + DVBFE_DVBT_TRANSMISSION_MODE_2K, + DVBFE_DVBT_TRANSMISSION_MODE_8K, + DVBFE_DVBT_TRANSMISSION_MODE_AUTO +} dvbfe_dvbt_transmit_mode_t; + +typedef enum dvbfe_dvbt_bandwidth { + DVBFE_DVBT_BANDWIDTH_8_MHZ, + DVBFE_DVBT_BANDWIDTH_7_MHZ, + DVBFE_DVBT_BANDWIDTH_6_MHZ, + DVBFE_DVBT_BANDWIDTH_AUTO +} dvbfe_dvbt_bandwidth_t; + +typedef enum dvbfe_dvbt_guard_interval { + DVBFE_DVBT_GUARD_INTERVAL_1_32, + DVBFE_DVBT_GUARD_INTERVAL_1_16, + DVBFE_DVBT_GUARD_INTERVAL_1_8, + DVBFE_DVBT_GUARD_INTERVAL_1_4, + DVBFE_DVBT_GUARD_INTERVAL_AUTO +} dvbfe_dvbt_guard_interval_t; + +typedef enum dvbfe_dvbt_hierarchy { + DVBFE_DVBT_HIERARCHY_NONE, + DVBFE_DVBT_HIERARCHY_1, + DVBFE_DVBT_HIERARCHY_2, + DVBFE_DVBT_HIERARCHY_4, + DVBFE_DVBT_HIERARCHY_AUTO +} dvbfe_dvbt_hierarchy_t; + +/** + * Structure used to store and communicate frontend parameters. + */ +struct dvbfe_parameters { + uint32_t frequency; + dvbfe_spectral_inversion_t inversion; + union { + struct { + uint32_t symbol_rate; + dvbfe_code_rate_t fec_inner; + dvbfe_polarization_t polarization; + } dvbs; + + struct { + uint32_t symbol_rate; + dvbfe_code_rate_t fec_inner; + dvbfe_dvbc_mod_t modulation; + } dvbc; + + struct { + dvbfe_dvbt_bandwidth_t bandwidth; + dvbfe_code_rate_t code_rate_HP; + dvbfe_code_rate_t code_rate_LP; + dvbfe_dvbt_const_t constellation; + dvbfe_dvbt_transmit_mode_t transmission_mode; + dvbfe_dvbt_guard_interval_t guard_interval; + dvbfe_dvbt_hierarchy_t hierarchy_information; + } dvbt; + + struct { + dvbfe_atsc_mod_t modulation; + } atsc; + } u; +}; + +/** + * Mask of values used in the dvbfe_get_info() call. + */ +typedef enum dvbfe_info_mask { + DVBFE_INFO_LOCKSTATUS = 0x01, + DVBFE_INFO_FEPARAMS = 0x02, + DVBFE_INFO_BER = 0x04, + DVBFE_INFO_SIGNAL_STRENGTH = 0x08, + DVBFE_INFO_SNR = 0x10, + DVBFE_INFO_UNCORRECTED_BLOCKS = 0x20, +} dvbfe_info_mask_t; + +/** + * Structure containing values used by the dvbfe_get_info() call. + */ +struct dvbfe_info { + dvbfe_type_t type; /* always retrieved */ + const char *name; /* always retrieved */ + unsigned int signal : 1; /* } DVBFE_INFO_LOCKSTATUS */ + unsigned int carrier : 1; /* } */ + unsigned int viterbi : 1; /* } */ + unsigned int sync : 1; /* } */ + unsigned int lock : 1; /* } */ + struct dvbfe_parameters feparams; /* DVBFE_INFO_FEPARAMS */ + uint32_t ber; /* DVBFE_INFO_BER */ + uint16_t signal_strength; /* DVBFE_INFO_SIGNAL_STRENGTH */ + uint16_t snr; /* DVBFE_INFO_SNR */ + uint32_t ucblocks; /* DVBFE_INFO_UNCORRECTED_BLOCKS */ +}; + +/** + * Frontend handle datatype. + */ +typedef void *dvbfe_handle_t; + +/** + * Open a DVB frontend. + * + * @param adapter DVB adapter ID. + * @param frontend Frontend ID of that adapter to open. + * @param readonly If 1, frontend will be opened in readonly mode only. + * @return A handle on success, or NULL on failure. + */ +extern dvbfe_handle_t dvbfe_open(int adapter, int frontend, int readonly); + +/** + * Close a DVB frontend. + * + * @param fehandle Handle opened with dvbfe_open(). + */ +extern void dvbfe_close(dvbfe_handle_t handle); + +/** + * Set the frontend tuning parameters. + * + * @param fehandle Handle opened with dvbfe_open(). + * @param params Params to set. + * @param timeout <0 => wait forever for lock. 0=>return immediately, >0=> + * number of milliseconds to wait for a lock. + * @return 0 on locked (or if timeout==0 and everything else worked), or + * nonzero on failure (including no lock). + */ +extern int dvbfe_set(dvbfe_handle_t fehandle, struct dvbfe_parameters *params, int timeout); + +/** + * Call this function regularly from a loop to maintain the frontend lock. + * + * @param fehandle Handle opened with dvbfe_open(). + */ +extern void dvbfe_poll(dvbfe_handle_t fehandle); + +/** + * Retrieve information about the frontend. + * + * @param fehandle Handle opened with dvbfe_open(). + * @param querymask ORed bitmask of desired DVBFE_INFO_* values. + * @param result Where to put the retrieved results. + * @return ORed bitmask of DVBFE_INFO_* indicating which values were read successfully. + */ +extern int dvbfe_get_info(dvbfe_handle_t fehandle, dvbfe_info_mask_t querymask, struct dvbfe_info *result); + +/** + * Execute a DISEQC command string. + * + * A diseqc command consists of a sequence of the following codes, separated by + * whitespace: + * Simple commands: + * t - turn 22kHz tone off. + * T - turn 22kHz tone on. + * _ - set voltage to 0v (i.e. off). + * v - set voltage to 13v. + * V - set voltage to 18v. + * + - Enable high LNB voltage. + * - - Disable high LNB voltage. + * A - send DISEQC mini command A. + * B - send DISEQC mini command B. + * Wii - Delay for ii milliseconds. + * + * Extended commands: + * .dishnetworks(<value>) - Send a dish networks legacy command <value> + * .D(<value> ...) - Send a raw diseqc master command. The command may be up + * to 6 bytes long. + * .Dband(<addr> <lo|hi>) - Set frequency band hi or lo. + * .Dpolarisation(<addr> <V|H|L|R>) - Set polarisation. + * .Dsatellite_position(<addr> <A|B>) - Set "satellite position" input switch. + * .Dswitch_option(<addr> <A|B>) - Set "switch option" input switch. + * .Dport_pins(<addr> <mask> <value>) - Set all input switches. Mask and value + * are hex-ascii 8 bit bytes. Only bits with a corresponding '1' in mask + * will be changed. + * .Dgoto_preset(<addr> <index>) - Set a positioner to a preset index (integer) + * .Dgoto_angle(<addr> <angle>) - Set a positioner to a given angle + * (e.g. 49.6). The angle may range between -180 to 496. It may include a + * fractional part. + * + * All integer values use standard notation - no prefix=>decimal, 0x=>hex etc. + * + * Set <addr> to 0 if you just have a simple DISEQC setup (e.g. one switch). See + * the DISEQC specification at http://www.eutelsat.org/ for full information. + * + * Comments begin with '#' - any characters after this will be ignored + * to the end of the line. + * + * Examples: + * S-19.2E 11700000 V 9750000 t v W15 .D(E0 10 38 F0) W15 A W15 t + * S-19.2E 99999999 V 10600000 t v W15 .D(E0 10 38 F1) W15 A W15 T + * S-19.2E 11700000 H 9750000 t V W15 .D(E0 10 38 F2) W15 A W15 t + * S-19.2E 99999999 H 10600000 t V W15 .D(E0 10 38 F3) W15 A W15 T + * + * @param fehandle Handle opened with dvbfe_open(). + * @param command Command to execute. + * @return 0 on success, nonzero on failure. + */ +extern int dvbfe_diseqc_command(dvbfe_handle_t fehandle, char *command); + +/** + * Read a DISEQC response from the frontend. + * + * @param fehandle Handle opened with dvbfe_open(). + * @param timeout Timeout for DISEQC response. + * @param buf Buffer to store response in. + * @param len Number of bytes in buffer. + * @return >= 0 on success (number of received bytes), <0 on failure. + */ +extern int dvbfe_diseqc_read(dvbfe_handle_t fehandle, int timeout, unsigned char *buf, unsigned int len); + +#ifdef __cplusplus +} +#endif + +#endif // LIBDVBFE_H diff --git a/kaffeine/src/input/dvb/lib/libdvbapi/dvbnet.c b/kaffeine/src/input/dvb/lib/libdvbapi/dvbnet.c new file mode 100644 index 0000000..d6ee632 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libdvbapi/dvbnet.c @@ -0,0 +1,99 @@ +/* + * libdvbnet - a DVB network support library + * + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include <sys/param.h> +#include <fcntl.h> +#include <unistd.h> +#include <sys/ioctl.h> +#include <linux/dvb/net.h> +#include <errno.h> +#include "dvbnet.h" + +int dvbnet_open(int adapter, int netdeviceid) +{ + char filename[PATH_MAX+1]; + int fd; + + sprintf(filename, "/dev/dvb/adapter%i/net%i", adapter, netdeviceid); + if ((fd = open(filename, O_RDWR)) < 0) { + // if that failed, try a flat /dev structure + sprintf(filename, "/dev/dvb%i.net%i", adapter, netdeviceid); + fd = open(filename, O_RDWR); + } + + return fd; +} + +int dvbnet_add_interface(int fd, uint16_t pid, int encapsulation) +{ + struct dvb_net_if params; + + memset(¶ms, 0, sizeof(params)); + params.pid = pid; + + switch(encapsulation) { + case DVBNET_ENCAP_MPE: + params.feedtype = DVB_NET_FEEDTYPE_MPE; + break; + + case DVBNET_ENCAP_ULE: + params.feedtype = DVB_NET_FEEDTYPE_ULE; + break; + + default: + return -EINVAL; + } + return ioctl(fd, NET_ADD_IF, ¶ms); +} + +int dvbnet_get_interface(int fd, int ifnum, uint16_t *pid, int *encapsulation) +{ + struct dvb_net_if info; + int res; + + memset(&info, 0, sizeof(struct dvb_net_if)); + info.if_num = ifnum; + + if ((res = ioctl(fd, NET_GET_IF, &info)) < 0) + return res; + + *pid = info.pid; + switch(info.feedtype) { + case DVB_NET_FEEDTYPE_MPE: + *encapsulation = DVBNET_ENCAP_MPE; + break; + + case DVB_NET_FEEDTYPE_ULE: + *encapsulation = DVBNET_ENCAP_ULE; + break; + + default: + return -EINVAL; + } + return 0; +} + +int dvbnet_remove_interface(int fd, int ifnum) +{ + return ioctl(fd, NET_REMOVE_IF, ifnum); +} diff --git a/kaffeine/src/input/dvb/lib/libdvbapi/dvbnet.h b/kaffeine/src/input/dvb/lib/libdvbapi/dvbnet.h new file mode 100644 index 0000000..426e540 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libdvbapi/dvbnet.h @@ -0,0 +1,87 @@ +/* + * libdvbnet - a DVB network support library + * + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef LIBDVBNET_H +#define LIBDVBNET_H 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <stdint.h> + +/** + * Possible encapsulations of data. + */ +typedef enum dvbnet_encap { + DVBNET_ENCAP_MPE, + DVBNET_ENCAP_ULE, +} dvbnet_encap_t; + +/** + * The maximum allowed number of dvb network devices per adapter netdevice. + */ +#define DVBNET_MAX_INTERFACES 10 + +/** + * Open a DVB net interface. + * + * @param adapter DVB adapter ID. + * @param netdeviceid Network control interface of that adapter to open. + * @return A unix file descriptor on success, or -1 on failure. + */ +extern int dvbnet_open(int adapter, int netdeviceid); + +/** + * Create a new DVBNET interface. + * + * @param fd FD opened with libdvbnet_open(). + * @param pid PID of the stream containing the network data. + * @param encapsulation Encapsulation type of the stream (one of DVBNET_ENCAP_*). + * @return 0 on success, nonzero on failure. + */ +extern int dvbnet_add_interface(int fd, uint16_t pid, int encapsulation); + +/** + * Get details of a DVBNET interface. + * + * @param fd FD opened with libdvbnet_open(). + * @param ifnum Index of interface to retrieve. + * @param pid The PID of the interface. + * @param encapsulation The encapsulation of the interface (DVBNET_ENCAP_*). + * @return 0 on success, nonzero on failure. + */ +extern int dvbnet_get_interface(int fd, int ifnum, uint16_t *pid, int *encapsulation); + +/** + * Remove a DVBNET interface. + * + * @param fd FD opened with libdvbnet_open(). + * @param ifnum Index of interface to remove. + * @return 0 on success, nonzero on failure. + */ +extern int dvbnet_remove_interface(int fd, int ifnum); + +#ifdef __cplusplus +} +#endif + +#endif // LIBDVBNET_H diff --git a/kaffeine/src/input/dvb/lib/libdvben50221/Makefile.am b/kaffeine/src/input/dvb/lib/libdvben50221/Makefile.am new file mode 100644 index 0000000..7c9764a --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libdvben50221/Makefile.am @@ -0,0 +1,21 @@ +noinst_LTLIBRARIES = libdvben50221.la + +INCLUDES = -I$(top_srcdir)/kaffeine/src/input/dvb/lib + +libdvben50221_la_SOURCES = asn_1.c \ + en50221_app_ai.c \ + en50221_app_auth.c \ + en50221_app_ca.c \ + en50221_app_datetime.c \ + en50221_app_dvb.c \ + en50221_app_epg.c \ + en50221_app_lowspeed.c \ + en50221_app_mmi.c \ + en50221_app_rm.c \ + en50221_app_smartcard.c \ + en50221_app_teletext.c \ + en50221_app_utils.c \ + en50221_session.c \ + en50221_transport.c + +CFLAGS = -g -O2 -DLOG_LEVEL=1 -Wall -Wshadow -Wpointer-arith -Wstrict-prototypes -fPIC diff --git a/kaffeine/src/input/dvb/lib/libdvben50221/asn_1.c b/kaffeine/src/input/dvb/lib/libdvben50221/asn_1.c new file mode 100644 index 0000000..8cc528f --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libdvben50221/asn_1.c @@ -0,0 +1,81 @@ +/* + ASN.1 routines, implementation for libdvben50221 + an implementation for the High Level Common Interface + + Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com) + Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net) + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of + the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include <stdio.h> +#include "asn_1.h" + +int asn_1_decode(uint16_t *length, uint8_t *asn_1_array, uint32_t asn_1_array_len) +{ + uint8_t length_field; + + if (asn_1_array_len < 1) + return -1; + length_field = asn_1_array[0]; + + if (length_field < 0x80) { + // there is only one word + *length = length_field & 0x7f; + return 1; + } else if (length_field == 0x81) { + if (asn_1_array_len < 2) + return -1; + + *length = asn_1_array[1]; + return 2; + } else if (length_field == 0x82) { + if (asn_1_array_len < 3) + return -1; + + *length = (asn_1_array[1] << 8) | asn_1_array[2]; + return 3; + } + + return -1; +} + +int asn_1_encode(uint16_t length, uint8_t *asn_1_array, uint32_t asn_1_array_len) +{ + if (length < 0x80) { + if (asn_1_array_len < 1) + return -1; + + asn_1_array[0] = length & 0x7f; + return 1; + } else if (length < 0x100) { + if (asn_1_array_len < 2) + return -1; + + asn_1_array[0] = 0x81; + asn_1_array[1] = length; + return 2; + } else { + if (asn_1_array_len < 3) + return -1; + + asn_1_array[0] = 0x82; + asn_1_array[1] = length >> 8; + asn_1_array[2] = length; + return 3; + } + + // never reached +} diff --git a/kaffeine/src/input/dvb/lib/libdvben50221/asn_1.h b/kaffeine/src/input/dvb/lib/libdvben50221/asn_1.h new file mode 100644 index 0000000..00d636b --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libdvben50221/asn_1.h @@ -0,0 +1,41 @@ +/* + ASN.1 routines, implementation for libdvben50221 + an implementation for the High Level Common Interface + + Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com) + Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net) + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of + the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef __ASN_1_H__ +#define __ASN_1_H__ + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <stdlib.h> +#include <stdint.h> + +int asn_1_decode(uint16_t *length, uint8_t *asn_1_array, uint32_t asn_1_array_len); +int asn_1_encode(uint16_t length, uint8_t *asn_1_array, uint32_t asn_1_array_len); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_ai.c b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_ai.c new file mode 100644 index 0000000..6facef0 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_ai.c @@ -0,0 +1,185 @@ +/* + en50221 encoder An implementation for libdvb + an implementation for the en50221 transport layer + + Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com) + Copyright (C) 2005 Julian Scheel (julian at jusst dot de) + Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net) + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of + the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include <string.h> +#include <libdvbmisc/dvbmisc.h> +#include <pthread.h> +#include "en50221_app_ai.h" +#include "en50221_app_tags.h" +#include "asn_1.h" + +struct en50221_app_ai_private { + struct en50221_app_send_functions *funcs; + + en50221_app_ai_callback callback; + void *callback_arg; + + pthread_mutex_t lock; +}; + +static int en50221_app_ai_parse_app_info(struct en50221_app_ai_private *private, + uint8_t slot_id, uint16_t session_number, + uint8_t *data, uint32_t data_length); + + +en50221_app_ai en50221_app_ai_create(struct en50221_app_send_functions *funcs) +{ + struct en50221_app_ai_private *private = NULL; + + // create structure and set it up + private = malloc(sizeof(struct en50221_app_ai_private)); + if (private == NULL) { + return NULL; + } + private->funcs = funcs; + private->callback = NULL; + + pthread_mutex_init(&private->lock, NULL); + + // done + return private; +} + +void en50221_app_ai_destroy(en50221_app_ai ai) +{ + struct en50221_app_ai_private *private = (struct en50221_app_ai_private *) ai; + + pthread_mutex_destroy(&private->lock); + free(private); +} + +void en50221_app_ai_register_callback(en50221_app_ai ai, en50221_app_ai_callback callback, void *arg) +{ + struct en50221_app_ai_private *private = (struct en50221_app_ai_private *) ai; + + pthread_mutex_lock(&private->lock); + private->callback = callback; + private->callback_arg = arg; + pthread_mutex_unlock(&private->lock); +} + +int en50221_app_ai_enquiry(en50221_app_ai ai, uint16_t session_number) +{ + struct en50221_app_ai_private *private = (struct en50221_app_ai_private *) ai; + uint8_t data[4]; + + data[0] = (TAG_APP_INFO_ENQUIRY >> 16) & 0xFF; + data[1] = (TAG_APP_INFO_ENQUIRY >> 8) & 0xFF; + data[2] = TAG_APP_INFO_ENQUIRY & 0xFF; + data[3] = 0; + + return private->funcs->send_data(private->funcs->arg, session_number, data, 4); +} + +int en50221_app_ai_entermenu(en50221_app_ai ai, uint16_t session_number) +{ + struct en50221_app_ai_private *private = (struct en50221_app_ai_private *) ai; + uint8_t data[4]; + + data[0] = (TAG_ENTER_MENU >> 16) & 0xFF; + data[1] = (TAG_ENTER_MENU >> 8) & 0xFF; + data[2] = TAG_ENTER_MENU & 0xFF; + data[3] = 0; + + return private->funcs->send_data(private->funcs->arg, session_number, data, 4); +} + +int en50221_app_ai_message(en50221_app_ai ai, + uint8_t slot_id, + uint16_t session_number, + uint32_t resource_id, + uint8_t *data, uint32_t data_length) +{ + struct en50221_app_ai_private *private = (struct en50221_app_ai_private *) ai; + (void) resource_id; + + // get the tag + if (data_length < 3) { + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + return -1; + } + uint32_t tag = (data[0] << 16) | (data[1] << 8) | data[2]; + + switch(tag) + { + case TAG_APP_INFO: + return en50221_app_ai_parse_app_info(private, slot_id, session_number, data+3, data_length-3); + } + + print(LOG_LEVEL, ERROR, 1, "Received unexpected tag %x\n", tag); + return -1; +} + + + + + + + +static int en50221_app_ai_parse_app_info(struct en50221_app_ai_private *private, + uint8_t slot_id, uint16_t session_number, + uint8_t *data, uint32_t data_length) +{ + // parse the length field + int length_field_len; + uint16_t asn_data_length; + if ((length_field_len = asn_1_decode(&asn_data_length, data, data_length)) < 0) { + print(LOG_LEVEL, ERROR, 1, "Received data with invalid length from module on slot %02x\n", slot_id); + return -1; + } + + // check it + if (asn_data_length < 6) { + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + return -1; + } + if (asn_data_length > (data_length - length_field_len)) { + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + return -1; + } + uint8_t *app_info = data + length_field_len; + + // parse the fields + uint8_t application_type = app_info[0]; + uint16_t application_manufacturer = (app_info[1] << 8) | app_info[2]; + uint16_t manufacturer_code = (app_info[3] << 8) | app_info[4]; + uint8_t menu_string_length = app_info[5]; + uint8_t *menu_string = app_info + 6; + + // check the menu_string_length + if (menu_string_length > (asn_data_length-6)) { + print(LOG_LEVEL, ERROR, 1, "Received bad menu string length - adjusting\n"); + menu_string_length = asn_data_length-6; + } + + // tell the app + pthread_mutex_lock(&private->lock); + en50221_app_ai_callback cb = private->callback; + void *cb_arg = private->callback_arg; + pthread_mutex_unlock(&private->lock); + if (cb) { + return cb(cb_arg, slot_id, session_number, application_type, + application_manufacturer, manufacturer_code, menu_string_length, menu_string); + } + return 0; +} diff --git a/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_ai.h b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_ai.h new file mode 100644 index 0000000..4def877 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_ai.h @@ -0,0 +1,129 @@ +/* + en50221 encoder An implementation for libdvb + an implementation for the en50221 transport layer + + Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com) + Copyright (C) 2005 Julian Scheel (julian at jusst dot de) + Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net) + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of + the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef __EN50221_APPLICATION_AI_H__ +#define __EN50221_APPLICATION_AI_H__ + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <stdlib.h> +#include <stdint.h> +#include <libdvben50221/en50221_app_utils.h> + +#define EN50221_APP_AI_RESOURCEID MKRID(2,1,1) + +#define APPLICATION_TYPE_CA 0x01 +#define APPLICATION_TYPE_EPG 0x02 + +/** + * Type definition for application callback function - called when we receive + * an application info object. + * + * @param arg Private argument. + * @param slot_id Slot id concerned. + * @param session_number Resource id concerned. + * @param application_type Type of application. + * @param application_manufacturer Manufacturer of application. + * @param manufacturer_code Manufacturer specific code. + * @param menu_string_length Length of menu string. + * @param menu_string The menu string itself. + * @return 0 on success, -1 on failure. + */ +typedef int (*en50221_app_ai_callback)(void *arg, uint8_t slot_id, uint16_t session_number, + uint8_t application_type, uint16_t application_manufacturer, + uint16_t manufacturer_code, uint8_t menu_string_length, + uint8_t *menu_string); + +/** + * Opaque type representing an application information resource. + */ +typedef void *en50221_app_ai; + +/** + * Create an instance of an application information resource. + * + * @param funcs Send functions to use. + * @return Instance, or NULL on failure. + */ +extern en50221_app_ai en50221_app_ai_create(struct en50221_app_send_functions *funcs); + +/** + * Destroy an instance of an application information resource. + * + * @param ai Instance to destroy. + */ +extern void en50221_app_ai_destroy(en50221_app_ai ai); + +/** + * Register a callback for reception of application_info objects. + * + * @param ai Application information instance. + * @param callback Callback function. + * @param arg Private argument passed during calls to the callback. + */ +extern void en50221_app_ai_register_callback(en50221_app_ai ai, en50221_app_ai_callback, void *arg); + +/** + * send a enquiry for the app_info provided by a module + * + * @param ai Application information instance. + * @param session_number Session to send on. + * @return 0 on success, -1 on failure. + */ +extern int en50221_app_ai_enquiry(en50221_app_ai ai, uint16_t session_number); + +/** + * send a enter_menu tag, this will make the application + * open a new MMI session to provide a Menu, or so. + * + * @param ai Application information instance. + * @param session_number Session to send on. + * @return 0 on success, -1 on failure. + */ +extern int en50221_app_ai_entermenu(en50221_app_ai ai, uint16_t session_number); + +/** + * Pass data received for this resource into it for parsing. + * + * @param ai Application information instance. + * @param slot_id Slot ID concerned. + * @param session_number Session number concerned. + * @param resource_id Resource ID concerned. + * @param data The data. + * @param data_length Length of data in bytes. + * @return 0 on success, -1 on failure. + */ +extern int en50221_app_ai_message(en50221_app_ai ai, + uint8_t slot_id, + uint16_t session_number, + uint32_t resource_id, + uint8_t *data, uint32_t data_length); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_auth.c b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_auth.c new file mode 100644 index 0000000..b062e3e --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_auth.c @@ -0,0 +1,179 @@ +/* + en50221 encoder An implementation for libdvb + an implementation for the en50221 transport layer + + Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com) + Copyright (C) 2005 Julian Scheel (julian at jusst dot de) + Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net) + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of + the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include <string.h> +#include <libdvbmisc/dvbmisc.h> +#include <pthread.h> +#include "en50221_app_auth.h" +#include "en50221_app_tags.h" +#include "asn_1.h" + +struct en50221_app_auth_private { + struct en50221_app_send_functions *funcs; + + en50221_app_auth_request_callback callback; + void *callback_arg; + + pthread_mutex_t lock; +}; + +static int en50221_app_auth_parse_request(struct en50221_app_auth_private *private, + uint8_t slot_id, uint16_t session_number, + uint8_t *data, uint32_t data_length); + + +en50221_app_auth en50221_app_auth_create(struct en50221_app_send_functions *funcs) +{ + struct en50221_app_auth_private *private = NULL; + + // create structure and set it up + private = malloc(sizeof(struct en50221_app_auth_private)); + if (private == NULL) { + return NULL; + } + private->funcs = funcs; + private->callback = NULL; + + pthread_mutex_init(&private->lock, NULL); + + // done + return private; +} + +void en50221_app_auth_destroy(en50221_app_auth auth) +{ + struct en50221_app_auth_private *private = (struct en50221_app_auth_private *) auth; + + pthread_mutex_destroy(&private->lock); + free(private); +} + +void en50221_app_auth_register_request_callback(en50221_app_auth auth, + en50221_app_auth_request_callback callback, void *arg) +{ + struct en50221_app_auth_private *private = (struct en50221_app_auth_private *) auth; + + pthread_mutex_lock(&private->lock); + private->callback = callback; + private->callback_arg = arg; + pthread_mutex_unlock(&private->lock); +} + +int en50221_app_auth_send(en50221_app_auth auth, + uint16_t session_number, + uint16_t auth_protocol_id, uint8_t *auth_data, + uint32_t auth_data_length) +{ + struct en50221_app_auth_private *private = (struct en50221_app_auth_private *) auth; + uint8_t buf[10]; + + // the header + buf[0] = (TAG_AUTH_RESP >> 16) & 0xFF; + buf[1] = (TAG_AUTH_RESP >> 8) & 0xFF; + buf[2] = TAG_AUTH_RESP & 0xFF; + + // encode the length field + int length_field_len; + if ((length_field_len = asn_1_encode(auth_data_length+2, buf+3, 3)) < 0) { + return -1; + } + + // the phase_id + buf[3+length_field_len] = auth_protocol_id>>8; + buf[3+length_field_len+1] = auth_protocol_id; + + // build the iovecs + struct iovec iov[2]; + iov[0].iov_base = buf; + iov[0].iov_len = 3+length_field_len+2; + iov[1].iov_base = auth_data; + iov[1].iov_len = auth_data_length; + + // sendit + return private->funcs->send_datav(private->funcs->arg, session_number, iov, 2); +} + +int en50221_app_auth_message(en50221_app_auth auth, + uint8_t slot_id, + uint16_t session_number, + uint32_t resource_id, + uint8_t *data, uint32_t data_length) +{ + struct en50221_app_auth_private *private = (struct en50221_app_auth_private *) auth; + (void) resource_id; + + // get the tag + if (data_length < 3) { + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + return -1; + } + uint32_t tag = (data[0] << 16) | (data[1] << 8) | data[2]; + + switch(tag) + { + case TAG_AUTH_REQ: + return en50221_app_auth_parse_request(private, slot_id, session_number, data+3, data_length-3); + } + + print(LOG_LEVEL, ERROR, 1, "Received unexpected tag %x\n", tag); + return -1; +} + + + +static int en50221_app_auth_parse_request(struct en50221_app_auth_private *private, + uint8_t slot_id, uint16_t session_number, + uint8_t *data, uint32_t data_length) +{ + // first of all, decode the length field + uint16_t asn_data_length; + int length_field_len; + if ((length_field_len = asn_1_decode(&asn_data_length, data, data_length)) < 0) { + print(LOG_LEVEL, ERROR, 1, "ASN.1 decode error\n"); + return -1; + } + + // check it + if (asn_data_length < 2) { + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + return -1; + } + if (asn_data_length > (data_length-length_field_len)) { + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + return -1; + } + uint8_t *auth_data = data + length_field_len; + + // process it + uint16_t auth_protocol_id = (auth_data[0]<<8) | auth_data[1]; + + // tell the app + pthread_mutex_lock(&private->lock); + en50221_app_auth_request_callback cb = private->callback; + void *cb_arg = private->callback_arg; + pthread_mutex_unlock(&private->lock); + if (cb) { + return cb(cb_arg, slot_id, session_number, auth_protocol_id, auth_data+2, asn_data_length-2); + } + return 0; +} diff --git a/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_auth.h b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_auth.h new file mode 100644 index 0000000..30d9c55 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_auth.h @@ -0,0 +1,119 @@ +/* + en50221 encoder An implementation for libdvb + an implementation for the en50221 transport layer + + Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com) + Copyright (C) 2005 Julian Scheel (julian at jusst dot de) + Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net) + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of + the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef __EN50221_APPLICATION_auth_H__ +#define __EN50221_APPLICATION_auth_H__ + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <stdlib.h> +#include <stdint.h> +#include <libdvben50221/en50221_app_utils.h> + +#define EN50221_APP_AUTH_RESOURCEID MKRID(16,1,1) + +/** + * Type definition for request - called when we receive a auth request from a CAM. + * + * @param arg Private argument. + * @param slot_id Slot id concerned. + * @param session_number Session number concerned. + * @param auth_protocol_id Auth protocol id. + * @param auth_data Data for the request. + * @param auth_data_lenghth Number of bytes. + * @return 0 on success, -1 on failure. + */ +typedef int (*en50221_app_auth_request_callback)(void *arg, uint8_t slot_id, uint16_t session_number, + uint16_t auth_protcol_id, uint8_t *auth_data, + uint32_t auth_data_length); + +/** + * Opaque type representing a auth resource. + */ +typedef void *en50221_app_auth; + +/** + * Create an instance of the auth resource. + * + * @param funcs Send functions to use. + * @return Instance, or NULL on failure. + */ +extern en50221_app_auth en50221_app_auth_create(struct en50221_app_send_functions *funcs); + +/** + * Destroy an instance of the auth resource. + * + * @param auth Instance to destroy. + */ +extern void en50221_app_auth_destroy(en50221_app_auth auth); + +/** + * Register the callback for when we receive a request. + * + * @param auth auth resource instance. + * @param callback The callback. Set to NULL to remove the callback completely. + * @param arg Private data passed as arg0 of the callback. + */ +extern void en50221_app_auth_register_request_callback(en50221_app_auth auth, + en50221_app_auth_request_callback callback, void *arg); + +/** + * Send an auth response to the CAM. + * + * @param auth auth resource instance. + * @param session_number Session number to send it on. + * @param auth_protocol_id Auth protocol id. + * @param auth_data Auth data. + * @param auth_data_length Number of bytes. + * @return 0 on success, -1 on failure. + */ +extern int en50221_app_auth_send(en50221_app_auth auth, + uint16_t session_number, + uint16_t auth_protocol_id, uint8_t *auth_data, + uint32_t auth_data_length); + +/** + * Pass data received for this resource into it for parsing. + * + * @param auth Authentication instance. + * @param slot_id Slot ID concerned. + * @param session_number Session number concerned. + * @param resource_id Resource ID concerned. + * @param data The data. + * @param data_length Length of data in bytes. + * @return 0 on success, -1 on failure. + */ +extern int en50221_app_auth_message(en50221_app_auth auth, + uint8_t slot_id, + uint16_t session_number, + uint32_t resource_id, + uint8_t *data, uint32_t data_length); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_ca.c b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_ca.c new file mode 100644 index 0000000..a1206fb --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_ca.c @@ -0,0 +1,615 @@ +/* + en50221 encoder An implementation for libdvb + an implementation for the en50221 transport layer + + Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com) + Copyright (C) 2005 Julian Scheel (julian at jusst dot de) + Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net) + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of + the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include <string.h> +#include <libdvbmisc/dvbmisc.h> +#include <pthread.h> +#include <libucsi/mpeg/descriptor.h> +#include "en50221_app_ca.h" +#include "asn_1.h" + +// tags supported by this resource +#define TAG_CA_INFO_ENQUIRY 0x9f8030 +#define TAG_CA_INFO 0x9f8031 +#define TAG_CA_PMT 0x9f8032 +#define TAG_CA_PMT_REPLY 0x9f8033 + +struct en50221_app_ca_private { + struct en50221_app_send_functions *funcs; + + en50221_app_ca_info_callback ca_info_callback; + void *ca_info_callback_arg; + + en50221_app_ca_pmt_reply_callback ca_pmt_reply_callback; + void *ca_pmt_reply_callback_arg; + + pthread_mutex_t lock; +}; + +struct ca_pmt_descriptor { + uint8_t *descriptor; + uint16_t length; + + struct ca_pmt_descriptor *next; +}; + +struct ca_pmt_stream { + uint8_t stream_type; + uint16_t pid; + struct ca_pmt_descriptor *descriptors; + uint32_t descriptors_length; + uint32_t descriptors_count; + + struct ca_pmt_stream *next; +}; + +static int en50221_ca_extract_pmt_descriptors(struct mpeg_pmt_section *pmt, struct ca_pmt_descriptor **outdescriptors); +static int en50221_ca_extract_streams(struct mpeg_pmt_section *pmt, struct ca_pmt_stream **outstreams); +static void en50221_ca_try_move_pmt_descriptors(struct ca_pmt_descriptor **pmt_descriptors, + struct ca_pmt_stream **pmt_streams); +static uint32_t en50221_ca_calculate_length(struct ca_pmt_descriptor *pmt_descriptors, + uint32_t *pmt_descriptors_length, + struct ca_pmt_stream *pmt_streams); +static int en50221_app_ca_parse_info(struct en50221_app_ca_private *private, + uint8_t slot_id, uint16_t session_number, + uint8_t *data, uint32_t data_length); +static int en50221_app_ca_parse_reply(struct en50221_app_ca_private *private, + uint8_t slot_id, uint16_t session_number, + uint8_t *data, uint32_t data_length); + + + +en50221_app_ca en50221_app_ca_create(struct en50221_app_send_functions *funcs) +{ + struct en50221_app_ca_private *private = NULL; + + // create structure and set it up + private = malloc(sizeof(struct en50221_app_ca_private)); + if (private == NULL) { + return NULL; + } + private->funcs = funcs; + private->ca_info_callback = NULL; + private->ca_pmt_reply_callback = NULL; + + pthread_mutex_init(&private->lock, NULL); + + // done + return private; +} + +void en50221_app_ca_destroy(en50221_app_ca ca) +{ + struct en50221_app_ca_private *private = (struct en50221_app_ca_private *) ca; + + pthread_mutex_destroy(&private->lock); + free(private); +} + +void en50221_app_ca_register_info_callback(en50221_app_ca ca, + en50221_app_ca_info_callback callback, void *arg) +{ + struct en50221_app_ca_private *private = (struct en50221_app_ca_private *) ca; + + pthread_mutex_lock(&private->lock); + private->ca_info_callback = callback; + private->ca_info_callback_arg = arg; + pthread_mutex_unlock(&private->lock); +} + +void en50221_app_ca_register_pmt_reply_callback(en50221_app_ca ca, + en50221_app_ca_pmt_reply_callback callback, void *arg) +{ + struct en50221_app_ca_private *private = (struct en50221_app_ca_private *) ca; + + pthread_mutex_lock(&private->lock); + private->ca_pmt_reply_callback = callback; + private->ca_pmt_reply_callback_arg = arg; + pthread_mutex_unlock(&private->lock); +} + +int en50221_app_ca_info_enq(en50221_app_ca ca, + uint16_t session_number) +{ + struct en50221_app_ca_private *private = (struct en50221_app_ca_private *) ca; + uint8_t data[4]; + + data[0] = (TAG_CA_INFO_ENQUIRY >> 16) & 0xFF; + data[1] = (TAG_CA_INFO_ENQUIRY >> 8) & 0xFF; + data[2] = TAG_CA_INFO_ENQUIRY & 0xFF; + data[3] = 0; + return private->funcs->send_data(private->funcs->arg, session_number, data, 4); +} + +int en50221_app_ca_pmt(en50221_app_ca ca, + uint16_t session_number, + uint8_t *ca_pmt, + uint32_t ca_pmt_length) +{ + struct en50221_app_ca_private *private = (struct en50221_app_ca_private *) ca; + uint8_t buf[10]; + + // set up the tag + buf[0] = (TAG_CA_PMT >> 16) & 0xFF; + buf[1] = (TAG_CA_PMT >> 8) & 0xFF; + buf[2] = TAG_CA_PMT & 0xFF; + + // encode the length field + int length_field_len; + if ((length_field_len = asn_1_encode(ca_pmt_length, buf+3, 3)) < 0) { + return -1; + } + + // build the iovecs + struct iovec iov[2]; + iov[0].iov_base = buf; + iov[0].iov_len = 3+length_field_len; + iov[1].iov_base = ca_pmt; + iov[1].iov_len = ca_pmt_length; + + // create the data and send it + return private->funcs->send_datav(private->funcs->arg, session_number, iov, 2); +} + +int en50221_app_ca_message(en50221_app_ca ca, + uint8_t slot_id, + uint16_t session_number, + uint32_t resource_id, + uint8_t *data, uint32_t data_length) +{ + struct en50221_app_ca_private *private = (struct en50221_app_ca_private *) ca; + (void)resource_id; + + // get the tag + if (data_length < 3) { + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + return -1; + } + uint32_t tag = (data[0] << 16) | (data[1] << 8) | data[2]; + + switch(tag) + { + case TAG_CA_INFO: + return en50221_app_ca_parse_info(private, slot_id, session_number, data+3, data_length-3); + case TAG_CA_PMT_REPLY: + return en50221_app_ca_parse_reply(private, slot_id, session_number, data+3, data_length-3); + } + + print(LOG_LEVEL, ERROR, 1, "Received unexpected tag %x\n", tag); + return -1; +} + +int en50221_ca_format_pmt(struct mpeg_pmt_section *pmt, uint8_t *data, uint32_t data_length, + int move_ca_descriptors, + uint8_t ca_pmt_list_management, uint8_t ca_pmt_cmd_id) +{ + struct ca_pmt_descriptor *pmt_descriptors = NULL; + uint32_t pmt_descriptors_length = 0; + struct ca_pmt_stream *pmt_streams = NULL; + uint32_t total_required_length = 0; + struct ca_pmt_descriptor *cur_d; + struct ca_pmt_stream *cur_s; + int result = -1; + + // extract the descriptors and streams + if (en50221_ca_extract_pmt_descriptors(pmt, &pmt_descriptors)) + goto cleanup; + if (en50221_ca_extract_streams(pmt, &pmt_streams)) + goto cleanup; + + // try and merge them if we have no PMT descriptors + if ((pmt_descriptors == NULL) && move_ca_descriptors) { + en50221_ca_try_move_pmt_descriptors(&pmt_descriptors, &pmt_streams); + } + + // calculate the length of all descriptors/streams and the total length required + total_required_length = en50221_ca_calculate_length(pmt_descriptors, &pmt_descriptors_length, pmt_streams); + + // ensure we were supplied with enough data + if (total_required_length > data_length) { + goto cleanup; + } + + // format the start of the PMT + uint32_t data_pos = 0; + data[data_pos++] = ca_pmt_list_management; + data[data_pos++] = mpeg_pmt_section_program_number(pmt) >> 8; + data[data_pos++] = mpeg_pmt_section_program_number(pmt); + data[data_pos++] = (pmt->head.version_number << 1) | pmt->head.current_next_indicator; + data[data_pos++] = (pmt_descriptors_length >> 8) & 0x0f; + data[data_pos++] = pmt_descriptors_length; + + // append the PMT descriptors + if (pmt_descriptors_length) { + data[data_pos++] = ca_pmt_cmd_id; + struct ca_pmt_descriptor *cur_d = pmt_descriptors; + while(cur_d) { + memcpy(data+data_pos, cur_d->descriptor, cur_d->length); + data_pos += cur_d->length; + cur_d = cur_d->next; + } + } + + // now, append the streams + cur_s = pmt_streams; + while(cur_s) { + data[data_pos++] = cur_s->stream_type; + data[data_pos++] = (cur_s->pid >> 8) & 0x1f; + data[data_pos++] = cur_s->pid; + data[data_pos++] = (cur_s->descriptors_length >> 8) & 0x0f; + data[data_pos++] = cur_s->descriptors_length; + + // append the stream descriptors + if (cur_s->descriptors_length) { + data[data_pos++] = ca_pmt_cmd_id; + struct ca_pmt_descriptor *cur_d = cur_s->descriptors; + while(cur_d) { + memcpy(data+data_pos, cur_d->descriptor, cur_d->length); + data_pos += cur_d->length; + cur_d = cur_d->next; + } + } + cur_s = cur_s->next; + } + result = data_pos; + + +cleanup: + // free the PMT descriptors + cur_d = pmt_descriptors; + while(cur_d) { + struct ca_pmt_descriptor *next = cur_d->next; + free(cur_d); + cur_d = next; + } + + // free the streams + cur_s = pmt_streams; + while(cur_s) { + struct ca_pmt_stream *next_s = cur_s->next; + + // free the stream descriptors + cur_d = cur_s->descriptors; + while(cur_d) { + struct ca_pmt_descriptor *next_d = cur_d->next; + free(cur_d); + cur_d = next_d; + } + + free(cur_s); + cur_s = next_s; + } + return result; +} + + + + + + + +static int en50221_ca_extract_pmt_descriptors(struct mpeg_pmt_section *pmt, struct ca_pmt_descriptor **outdescriptors) +{ + struct ca_pmt_descriptor *descriptors = NULL; + struct ca_pmt_descriptor *descriptors_tail = NULL; + struct ca_pmt_descriptor *cur_d; + + struct descriptor *cur_descriptor; + mpeg_pmt_section_descriptors_for_each(pmt, cur_descriptor) { + if (cur_descriptor->tag == dtag_mpeg_ca) { + // create a new structure for this one + struct ca_pmt_descriptor *new_d = malloc(sizeof(struct ca_pmt_descriptor)); + if (new_d == NULL) { + goto error_exit; + } + new_d->descriptor = (uint8_t*) cur_descriptor; + new_d->length = cur_descriptor->len+2; + new_d->next = NULL; + + // append it to the list + if (descriptors == NULL) { + descriptors = new_d; + } else { + descriptors_tail->next = new_d; + } + descriptors_tail = new_d; + } + } + *outdescriptors = descriptors; + return 0; + +error_exit: + cur_d = descriptors; + while(cur_d) { + struct ca_pmt_descriptor *next = cur_d->next; + free(cur_d); + cur_d = next; + } + return -1; +} + +static int en50221_ca_extract_streams(struct mpeg_pmt_section *pmt, struct ca_pmt_stream **outstreams) +{ + struct ca_pmt_stream *streams = NULL; + struct ca_pmt_stream *streams_tail = NULL; + struct mpeg_pmt_stream *cur_stream; + struct descriptor *cur_descriptor; + struct ca_pmt_stream *cur_s; + + mpeg_pmt_section_streams_for_each(pmt, cur_stream) { + struct ca_pmt_descriptor *descriptors_tail = NULL; + + // create a new structure + struct ca_pmt_stream *new_s = malloc(sizeof(struct ca_pmt_stream)); + if (new_s == NULL) { + goto exit_cleanup; + } + new_s->stream_type = cur_stream->stream_type; + new_s->pid = cur_stream->pid; + new_s->descriptors = NULL; + new_s->next = NULL; + new_s->descriptors_count = 0; + + // append it to the list + if (streams == NULL) { + streams = new_s; + } else { + streams_tail->next = new_s; + } + streams_tail = new_s; + + // now process the descriptors + mpeg_pmt_stream_descriptors_for_each(cur_stream, cur_descriptor) { + if (cur_descriptor->tag == dtag_mpeg_ca) { + // create a new structure + struct ca_pmt_descriptor *new_d = malloc(sizeof(struct ca_pmt_descriptor)); + if (new_d == NULL) { + goto exit_cleanup; + } + new_d->descriptor = (uint8_t*) cur_descriptor; + new_d->length = cur_descriptor->len+2; + new_d->next = NULL; + + // append it to the list + if (new_s->descriptors == NULL) { + new_s->descriptors = new_d; + } else { + descriptors_tail->next = new_d; + } + descriptors_tail = new_d; + new_s->descriptors_count++; + } + } + } + *outstreams = streams; + return 0; + +exit_cleanup: + // free the streams + cur_s = streams; + while(cur_s) { + struct ca_pmt_stream *next_s = cur_s->next; + + // free the stream descriptors + struct ca_pmt_descriptor *cur_d = cur_s->descriptors; + while(cur_d) { + struct ca_pmt_descriptor *next_d = cur_d->next; + free(cur_d); + cur_d = next_d; + } + + free(cur_s); + cur_s = next_s; + } + return -1; +} + +static void en50221_ca_try_move_pmt_descriptors(struct ca_pmt_descriptor **pmt_descriptors, + struct ca_pmt_stream **pmt_streams) +{ + // get the first stream + struct ca_pmt_stream *first_stream = *pmt_streams; + if (first_stream == NULL) + return; + + // Check that all the other streams with CA descriptors have exactly the same CA descriptors + struct ca_pmt_stream *cur_stream = first_stream->next; + while(cur_stream) { + // if there are differing numbers of descriptors, exit right now + if (cur_stream->descriptors_count != first_stream->descriptors_count) + return; + + // now verify the descriptors match + struct ca_pmt_descriptor *cur_descriptor = cur_stream->descriptors; + struct ca_pmt_descriptor *first_cur_descriptor = first_stream->descriptors; + while(cur_descriptor) { + // check the descriptors are the same length + if (cur_descriptor->length != first_cur_descriptor->length) + return; + + // check their contents match + if (memcmp(cur_descriptor->descriptor, first_cur_descriptor->descriptor, cur_descriptor->length)) { + return; + } + + // move to next + cur_descriptor = cur_descriptor->next; + first_cur_descriptor = first_cur_descriptor->next; + } + + // move to next + cur_stream = cur_stream->next; + } + + // if we end up here, all descriptors in all streams matched + + // hook the first stream's descriptors into the PMT's + *pmt_descriptors = first_stream->descriptors; + first_stream->descriptors = NULL; + first_stream->descriptors_count = 0; + + // now free up all the descriptors in the other streams + cur_stream = first_stream->next; + while(cur_stream) { + struct ca_pmt_descriptor *cur_descriptor = cur_stream->descriptors; + while(cur_descriptor) { + struct ca_pmt_descriptor *next = cur_descriptor->next; + free(cur_descriptor); + cur_descriptor=next; + } + cur_stream->descriptors = NULL; + cur_stream->descriptors_count = 0; + cur_stream = cur_stream->next; + } +} + +static uint32_t en50221_ca_calculate_length(struct ca_pmt_descriptor *pmt_descriptors, + uint32_t *pmt_descriptors_length, + struct ca_pmt_stream *pmt_streams) +{ + uint32_t total_required_length = 6; // header + struct ca_pmt_stream *cur_s; + + // calcuate the PMT descriptors length + (*pmt_descriptors_length) = 0; + struct ca_pmt_descriptor *cur_d = pmt_descriptors; + while(cur_d) { + (*pmt_descriptors_length) += cur_d->length; + cur_d = cur_d->next; + } + + // add on 1 byte for the ca_pmt_cmd_id if we have some descriptors. + if (*pmt_descriptors_length) + (*pmt_descriptors_length)++; + + // update the total required length + total_required_length += *pmt_descriptors_length; + + // calculate the length of descriptors in the streams + cur_s = pmt_streams; + while(cur_s) { + // calculate the size of descriptors in this stream + cur_s->descriptors_length = 0; + cur_d = cur_s->descriptors; + while(cur_d) { + cur_s->descriptors_length += cur_d->length; + cur_d = cur_d->next; + } + + // add on 1 byte for the ca_pmt_cmd_id if we have some descriptors. + if (cur_s->descriptors_length) + cur_s->descriptors_length++; + + // update the total required length; + total_required_length += 5 + cur_s->descriptors_length; + + cur_s = cur_s->next; + } + + // done + return total_required_length; +} + +static int en50221_app_ca_parse_info(struct en50221_app_ca_private *private, + uint8_t slot_id, uint16_t session_number, + uint8_t *data, uint32_t data_length) +{ + // first of all, decode the length field + uint16_t asn_data_length; + int length_field_len; + if ((length_field_len = asn_1_decode(&asn_data_length, data, data_length)) < 0) { + print(LOG_LEVEL, ERROR, 1, "ASN.1 decode error\n"); + return -1; + } + + // check it + if (asn_data_length > (data_length-length_field_len)) { + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + return -1; + } + data+=length_field_len; + + // parse + uint32_t ca_id_count = asn_data_length / 2; + + // byteswap the IDs + uint16_t *ids = (uint16_t*) data; + uint32_t i; + for(i=0; i<ca_id_count; i++) { + bswap16(data); + data+=2; + } + + // tell the app + pthread_mutex_lock(&private->lock); + en50221_app_ca_info_callback cb = private->ca_info_callback; + void *cb_arg = private->ca_info_callback_arg; + pthread_mutex_unlock(&private->lock); + if (cb) { + return cb(cb_arg, slot_id, session_number, ca_id_count, ids); + } + return 0; +} + +static int en50221_app_ca_parse_reply(struct en50221_app_ca_private *private, + uint8_t slot_id, uint16_t session_number, + uint8_t *data, uint32_t data_length) +{ + // first of all, decode the length field + uint16_t asn_data_length; + int length_field_len; + if ((length_field_len = asn_1_decode(&asn_data_length, data, data_length)) < 0) { + print(LOG_LEVEL, ERROR, 1, "ASN.1 decode error\n"); + return -1; + } + + // check it + if (asn_data_length < 4) { + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + return -1; + } + if (asn_data_length > (data_length-length_field_len)) { + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + return -1; + } + data += length_field_len; + data_length -= length_field_len; + + // process the reply table to fix endian issues + uint32_t pos = 4; + bswap16(data); + while(pos < asn_data_length) { + bswap16(data+pos); + pos+= 3; + } + + // tell the app + pthread_mutex_lock(&private->lock); + en50221_app_ca_pmt_reply_callback cb = private->ca_pmt_reply_callback; + void *cb_arg = private->ca_pmt_reply_callback_arg; + pthread_mutex_unlock(&private->lock); + if (cb) { + return cb(cb_arg, slot_id, session_number, (struct en50221_app_pmt_reply*) data, asn_data_length); + } + return 0; +} diff --git a/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_ca.h b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_ca.h new file mode 100644 index 0000000..ab29649 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_ca.h @@ -0,0 +1,254 @@ +/* + en50221 encoder An implementation for libdvb + an implementation for the en50221 transport layer + + Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com) + Copyright (C) 2005 Julian Scheel (julian at jusst dot de) + Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net) + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of + the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef __EN50221_APPLICATION_ca_H__ +#define __EN50221_APPLICATION_ca_H__ + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <stdlib.h> +#include <stdint.h> +#include <libdvben50221/en50221_app_utils.h> +#include <libucsi/mpeg/pmt_section.h> +#include <libucsi/dvb/descriptor.h> + +#define CA_LIST_MANAGEMENT_MORE 0x00 +#define CA_LIST_MANAGEMENT_FIRST 0x01 +#define CA_LIST_MANAGEMENT_LAST 0x02 +#define CA_LIST_MANAGEMENT_ONLY 0x03 +#define CA_LIST_MANAGEMENT_ADD 0x04 +#define CA_LIST_MANAGEMENT_UPDATE 0x05 + +#define CA_PMT_CMD_ID_OK_DESCRAMBLING 0x01 +#define CA_PMT_CMD_ID_OK_MMI 0x02 +#define CA_PMT_CMD_ID_QUERY 0x03 +#define CA_PMT_CMD_ID_NOT_SELECTED 0x04 + +#define CA_ENABLE_DESCRAMBLING_POSSIBLE 0x01 +#define CA_ENABLE_DESCRAMBLING_POSSIBLE_PURCHASE 0x02 +#define CA_ENABLE_DESCRAMBLING_POSSIBLE_TECHNICAL 0x03 +#define CA_ENABLE_DESCRAMBLING_NOT_POSSIBLE_NO_ENTITLEMENT 0x71 +#define CA_ENABLE_DESCRAMBLING_NOT_POSSIBLE_TECHNICAL 0x73 + + +#define EN50221_APP_CA_RESOURCEID MKRID(3,1,1) + +/** + * PMT reply structure. + */ +struct en50221_app_pmt_reply { + uint16_t program_number; + EBIT3(uint8_t reserved_1 : 2; , + uint8_t version_number : 5; , + uint8_t current_next_indicator : 1; ) + EBIT2(uint8_t CA_enable_flag : 1; , + uint8_t CA_enable : 7; ) + /* struct en50221_app_pmt_stream streams[] */ +} __attribute__((packed)); + +/** + * A stream within a pmt reply structure. + */ +struct en50221_app_pmt_stream { + EBIT2(uint16_t reserved_1 : 3; , + uint16_t es_pid :13; ) + EBIT2(uint8_t CA_enable_flag : 1; , + uint8_t CA_enable : 7; ) +} __attribute__((packed)); + +/** + * Convenience iterator for the streams field of the en50221_app_pmt_reply structure. + * + * @param pmt Pointer to the en50221_app_pmt_reply structure. + * @param pos Variable holding a pointer to the current en50221_app_pmt_stream. + * @param size Total size of the PMT reply. + */ +#define en50221_app_pmt_reply_streams_for_each(pmt, pos, size) \ + for ((pos) = en50221_app_pmt_reply_streams_first(pmt, size); \ + (pos); \ + (pos) = en50221_app_pmt_reply_streams_next(pmt, pos, size)) + + +/** + * Type definition for command - called when we receive a ca info response. + * + * @param arg Private argument. + * @param slot_id Slot id concerned. + * @param session_number Session number concerned. + * @param ca_id_count Number of ca_system_ids. + * @param ca_ids Pointer to list of ca_system_ids. + * @return 0 on success, -1 on failure. + */ +typedef int (*en50221_app_ca_info_callback)(void *arg, uint8_t slot_id, uint16_t session_number, + uint32_t ca_id_count, + uint16_t *ca_ids); + +/** + * Type definition for pmt_reply - called when we receive a pmt_reply. + * + * @param arg Private argument. + * @param slot_id Slot id concerned. + * @param session_number Session number concerned. + * @param reply Pointer to a struct en50221_app_pmt_reply. + * @param reply_size Total size of the struct en50221_app_pmt_reply in bytes. + * @return 0 on success, -1 on failure. + */ +typedef int (*en50221_app_ca_pmt_reply_callback)(void *arg, uint8_t slot_id, uint16_t session_number, + struct en50221_app_pmt_reply *reply, + uint32_t reply_size); + +/** + * Opaque type representing a ca resource. + */ +typedef void *en50221_app_ca; + +/** + * Create an instance of the ca resource. + * + * @param funcs Send functions to use. + * @return Instance, or NULL on failure. + */ +extern en50221_app_ca en50221_app_ca_create(struct en50221_app_send_functions *funcs); + +/** + * Destroy an instance of the ca resource. + * + * @param ca Instance to destroy. + */ +extern void en50221_app_ca_destroy(en50221_app_ca ca); + +/** + * Register the callback for when we receive a ca info. + * + * @param ca ca resource instance. + * @param callback The callback. Set to NULL to remove the callback completely. + * @param arg Private data passed as arg0 of the callback. + */ +extern void en50221_app_ca_register_info_callback(en50221_app_ca ca, + en50221_app_ca_info_callback callback, void *arg); + +/** + * Register the callback for when we receive a pmt_reply. + * + * @param ca ca resource instance. + * @param callback The callback. Set to NULL to remove the callback completely. + * @param arg Private data passed as arg0 of the callback. + */ +extern void en50221_app_ca_register_pmt_reply_callback(en50221_app_ca ca, + en50221_app_ca_pmt_reply_callback callback, void *arg); + +/** + * Send a ca_info_req to the CAM. + * + * @param ca ca resource instance. + * @param session_number Session number to send it on. + * @return 0 on success, -1 on failure. + */ +extern int en50221_app_ca_info_enq(en50221_app_ca ca, + uint16_t session_number); + +/** + * Send a ca_pmt structure to the CAM. + * + * @param ca ca resource instance. + * @param session_number Session number to send it on. + * @param ca_pmt A ca_pmt structure formatted with the en50221_ca_format_pmt() function. + * @param ca_pmt_length Length of ca_pmt structure in bytes. + * @return 0 on success, -1 on failure. + */ +extern int en50221_app_ca_pmt(en50221_app_ca ca, + uint16_t session_number, + uint8_t *ca_pmt, + uint32_t ca_pmt_length); + +/** + * Transform a libucsi PMT into a binary structure for sending to a CAM. + * + * @param pmt The source PMT structure. + * @param data Pointer to data buffer to write it to. + * @param data_length Number of bytes available in data buffer. + * @param move_ca_descriptors If non-zero, will attempt to move CA descriptors + * in order to reduce the size of the formatted CAPMT. + * @param ca_pmt_list_management One of the CA_LIST_MANAGEMENT_*. + * @param ca_pmt_cmd_id One of the CA_PMT_CMD_ID_*. + * @return Number of bytes used, or -1 on error. + */ +extern int en50221_ca_format_pmt(struct mpeg_pmt_section *pmt, + uint8_t *data, + uint32_t data_length, + int move_ca_descriptors, + uint8_t ca_pmt_list_management, uint8_t ca_pmt_cmd_id); + +/** + * Pass data received for this resource into it for parsing. + * + * @param ca CA instance. + * @param slot_id Slot ID concerned. + * @param session_number Session number concerned. + * @param resource_id Resource ID concerned. + * @param data The data. + * @param data_length Length of data in bytes. + * @return 0 on success, -1 on failure. + */ +extern int en50221_app_ca_message(en50221_app_ca ca, + uint8_t slot_id, + uint16_t session_number, + uint32_t resource_id, + uint8_t *data, uint32_t data_length); + + + + +static inline struct en50221_app_pmt_stream * + en50221_app_pmt_reply_streams_first(struct en50221_app_pmt_reply *reply, uint32_t reply_size) +{ + uint32_t pos = sizeof(struct en50221_app_pmt_reply); + + if (pos >= reply_size) + return NULL; + + return (struct en50221_app_pmt_stream *)((uint8_t *)reply+ pos); +} + +static inline struct en50221_app_pmt_stream * + en50221_app_pmt_reply_streams_next(struct en50221_app_pmt_reply * reply, + struct en50221_app_pmt_stream * pos, + uint32_t reply_size) +{ + uint8_t *end = (uint8_t*) reply + reply_size; + uint8_t *next = (uint8_t *) pos + sizeof(struct en50221_app_pmt_stream); + + if (next >= end) + return NULL; + + return (struct en50221_app_pmt_stream *) next; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_datetime.c b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_datetime.c new file mode 100644 index 0000000..5686443 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_datetime.c @@ -0,0 +1,169 @@ +/* + en50221 encoder An implementation for libdvb + an implementation for the en50221 transport layer + + Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com) + Copyright (C) 2005 Julian Scheel (julian at jusst dot de) + Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net) + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of + the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include <string.h> +#include <libdvbmisc/dvbmisc.h> +#include <pthread.h> +#include <libucsi/dvb/types.h> +#include "en50221_app_datetime.h" +#include "en50221_app_tags.h" +#include "asn_1.h" + +struct en50221_app_datetime_private { + struct en50221_app_send_functions *funcs; + + en50221_app_datetime_enquiry_callback callback; + void *callback_arg; + + pthread_mutex_t lock; +}; + +static int en50221_app_datetime_parse_enquiry(struct en50221_app_datetime_private *private, + uint8_t slot_id, uint16_t session_number, + uint8_t *data, uint32_t data_length); + + + +en50221_app_datetime en50221_app_datetime_create(struct en50221_app_send_functions *funcs) +{ + struct en50221_app_datetime_private *private = NULL; + + // create structure and set it up + private = malloc(sizeof(struct en50221_app_datetime_private)); + if (private == NULL) { + return NULL; + } + private->funcs = funcs; + private->callback = NULL; + + pthread_mutex_init(&private->lock, NULL); + + // done + return private; +} + +void en50221_app_datetime_destroy(en50221_app_datetime datetime) +{ + struct en50221_app_datetime_private *private = (struct en50221_app_datetime_private *) datetime; + + pthread_mutex_destroy(&private->lock); + free(private); +} + +void en50221_app_datetime_register_enquiry_callback(en50221_app_datetime datetime, + en50221_app_datetime_enquiry_callback callback, void *arg) +{ + struct en50221_app_datetime_private *private = (struct en50221_app_datetime_private *) datetime; + + pthread_mutex_lock(&private->lock); + private->callback = callback; + private->callback_arg = arg; + pthread_mutex_unlock(&private->lock); +} + +int en50221_app_datetime_send(en50221_app_datetime datetime, + uint16_t session_number, + time_t utc_time, + int time_offset) +{ + struct en50221_app_datetime_private *private = (struct en50221_app_datetime_private *) datetime; + uint8_t data[11]; + int data_length; + + data[0] = (TAG_DATE_TIME >> 16) & 0xFF; + data[1] = (TAG_DATE_TIME >> 8) & 0xFF; + data[2] = TAG_DATE_TIME & 0xFF; + if (time_offset != -1) { + data[3] = 7; + unixtime_to_dvbdate(utc_time, data+4); + data[9] = time_offset >> 8; + data[10] = time_offset; + data_length = 11; + } else { + data[3] = 5; + unixtime_to_dvbdate(utc_time, data+4); + data_length = 9; + } + return private->funcs->send_data(private->funcs->arg, session_number, data, data_length); +} + +int en50221_app_datetime_message(en50221_app_datetime datetime, + uint8_t slot_id, + uint16_t session_number, + uint32_t resource_id, + uint8_t *data, uint32_t data_length) +{ + struct en50221_app_datetime_private *private = (struct en50221_app_datetime_private *) datetime; + (void) resource_id; + + // get the tag + if (data_length < 3) { + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + return -1; + } + uint32_t tag = (data[0] << 16) | (data[1] << 8) | data[2]; + + switch(tag) + { + case TAG_DATE_TIME_ENQUIRY: + return en50221_app_datetime_parse_enquiry(private, slot_id, session_number, data+3, data_length-3); + } + + print(LOG_LEVEL, ERROR, 1, "Received unexpected tag %x\n", tag); + return -1; +} + + + + + + + + + + +static int en50221_app_datetime_parse_enquiry(struct en50221_app_datetime_private *private, + uint8_t slot_id, uint16_t session_number, + uint8_t *data, uint32_t data_length) +{ + // validate data + if (data_length != 2) { + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + return -1; + } + if (data[0] != 1) { + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + return -1; + } + uint8_t response_interval = data[1]; + + // tell the app + pthread_mutex_lock(&private->lock); + en50221_app_datetime_enquiry_callback cb = private->callback; + void *cb_arg = private->callback_arg; + pthread_mutex_unlock(&private->lock); + if (cb) { + return cb(cb_arg, slot_id, session_number, response_interval); + } + return 0; +} diff --git a/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_datetime.h b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_datetime.h new file mode 100644 index 0000000..5819fb4 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_datetime.h @@ -0,0 +1,116 @@ +/* + en50221 encoder An implementation for libdvb + an implementation for the en50221 transport layer + + Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com) + Copyright (C) 2005 Julian Scheel (julian at jusst dot de) + Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net) + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of + the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef __EN50221_APPLICATION_DATETIME_H__ +#define __EN50221_APPLICATION_DATETIME_H__ + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <stdlib.h> +#include <stdint.h> +#include <libdvben50221/en50221_app_utils.h> + +#define EN50221_APP_DATETIME_RESOURCEID MKRID(36,1,1) + +/** + * Type definition for enquiry - called when we receive a date/time enquiry from a CAM. + * + * @param arg Private argument. + * @param slot_id Slot id concerned. + * @param session_number Session number concerned. + * @param response_interval Response interval requested by CAM. + * @return 0 on success, -1 on failure. + */ +typedef int (*en50221_app_datetime_enquiry_callback)(void *arg, uint8_t slot_id, uint16_t session_number, + uint8_t response_interval); + +/** + * Opaque type representing a datetime resource. + */ +typedef void *en50221_app_datetime; + +/** + * Create an instance of the datetime resource. + * + * @param funcs Send functions to use. + * @return Instance, or NULL on failure. + */ +extern en50221_app_datetime en50221_app_datetime_create(struct en50221_app_send_functions *funcs); + +/** + * Destroy an instance of the datetime resource. + * + * @param datetime Instance to destroy. + */ +extern void en50221_app_datetime_destroy(en50221_app_datetime datetime); + +/** + * Register the callback for when we receive a enquiry request. + * + * @param datetime datetime resource instance. + * @param callback The callback. Set to NULL to remove the callback completely. + * @param arg Private data passed as arg0 of the callback. + */ +extern void en50221_app_datetime_register_enquiry_callback(en50221_app_datetime datetime, + en50221_app_datetime_enquiry_callback callback, void *arg); + +/** + * Send the time to the CAM. + * + * @param datetime datetime resource instance. + * @param session_number Session number to send it on. + * @param utc_time UTC time in unix time format. + * @param time_offset If -1, the field will not be transmitted, otherwise it is the offset between + * UTC and local time in minutes. + * @return 0 on success, -1 on failure. + */ +extern int en50221_app_datetime_send(en50221_app_datetime datetime, + uint16_t session_number, + time_t utc_time, + int time_offset); + +/** + * Pass data received for this resource into it for parsing. + * + * @param datetime datetime instance. + * @param slot_id Slot ID concerned. + * @param session_number Session number concerned. + * @param resource_id Resource ID concerned. + * @param data The data. + * @param data_length Length of data in bytes. + * @return 0 on success, -1 on failure. + */ +extern int en50221_app_datetime_message(en50221_app_datetime datetime, + uint8_t slot_id, + uint16_t session_number, + uint32_t resource_id, + uint8_t *data, uint32_t data_length); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_dvb.c b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_dvb.c new file mode 100644 index 0000000..82da884 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_dvb.c @@ -0,0 +1,263 @@ +/* + en50221 encoder An implementation for libdvb + an implementation for the en50221 transport layer + + Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com) + Copyright (C) 2005 Julian Scheel (julian at jusst dot de) + Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net) + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of + the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include <string.h> +#include <libdvbmisc/dvbmisc.h> +#include <pthread.h> +#include "en50221_app_dvb.h" +#include "en50221_app_tags.h" +#include "asn_1.h" + +struct en50221_app_dvb_private { + struct en50221_app_send_functions *funcs; + + en50221_app_dvb_tune_callback tune_callback; + void *tune_callback_arg; + + en50221_app_dvb_replace_callback replace_callback; + void *replace_callback_arg; + + en50221_app_dvb_clear_replace_callback clear_replace_callback; + void *clear_replace_callback_arg; + + pthread_mutex_t lock; +}; + +static int en50221_app_dvb_parse_tune(struct en50221_app_dvb_private *private, + uint8_t slot_id, uint16_t session_number, + uint8_t *data, uint32_t data_length); + +static int en50221_app_dvb_parse_replace(struct en50221_app_dvb_private *private, + uint8_t slot_id, uint16_t session_number, + uint8_t *data, uint32_t data_length); + +static int en50221_app_dvb_parse_clear_replace(struct en50221_app_dvb_private *private, + uint8_t slot_id, uint16_t session_number, + uint8_t *data, uint32_t data_length); + + + +en50221_app_dvb en50221_app_dvb_create(struct en50221_app_send_functions *funcs) +{ + struct en50221_app_dvb_private *private = NULL; + + // create structure and set it up + private = malloc(sizeof(struct en50221_app_dvb_private)); + if (private == NULL) { + return NULL; + } + private->funcs = funcs; + private->tune_callback = NULL; + private->replace_callback = NULL; + private->clear_replace_callback = NULL; + + pthread_mutex_init(&private->lock, NULL); + + // done + return private; +} + +void en50221_app_dvb_destroy(en50221_app_dvb dvb) +{ + struct en50221_app_dvb_private *private = (struct en50221_app_dvb_private *) dvb; + + pthread_mutex_destroy(&private->lock); + free(private); +} + +void en50221_app_dvb_register_tune_callback(en50221_app_dvb dvb, + en50221_app_dvb_tune_callback callback, void *arg) +{ + struct en50221_app_dvb_private *private = (struct en50221_app_dvb_private *) dvb; + + pthread_mutex_lock(&private->lock); + private->tune_callback = callback; + private->tune_callback_arg = arg; + pthread_mutex_unlock(&private->lock); +} + +void en50221_app_dvb_register_replace_callback(en50221_app_dvb dvb, + en50221_app_dvb_replace_callback callback, void *arg) +{ + struct en50221_app_dvb_private *private = (struct en50221_app_dvb_private *) dvb; + + pthread_mutex_lock(&private->lock); + private->replace_callback = callback; + private->replace_callback_arg = arg; + pthread_mutex_unlock(&private->lock); +} + +void en50221_app_dvb_register_clear_replace_callback(en50221_app_dvb dvb, + en50221_app_dvb_clear_replace_callback callback, void *arg) +{ + struct en50221_app_dvb_private *private = (struct en50221_app_dvb_private *) dvb; + + pthread_mutex_lock(&private->lock); + private->clear_replace_callback = callback; + private->clear_replace_callback_arg = arg; + pthread_mutex_unlock(&private->lock); +} + +int en50221_app_dvb_ask_release(en50221_app_dvb dvb, uint16_t session_number) +{ + struct en50221_app_dvb_private *private = (struct en50221_app_dvb_private *) dvb; + uint8_t data[4]; + + data[0] = (TAG_ASK_RELEASE >> 16) & 0xFF; + data[1] = (TAG_ASK_RELEASE >> 8) & 0xFF; + data[2] = TAG_ASK_RELEASE & 0xFF; + data[3] = 0; + + return private->funcs->send_data(private->funcs->arg, session_number, data, 4); +} + +int en50221_app_dvb_message(en50221_app_dvb dvb, + uint8_t slot_id, + uint16_t session_number, + uint32_t resource_id, + uint8_t *data, uint32_t data_length) +{ + struct en50221_app_dvb_private *private = (struct en50221_app_dvb_private *) dvb; + (void) resource_id; + + // get the tag + if (data_length < 3) { + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + return -1; + } + uint32_t tag = (data[0] << 16) | (data[1] << 8) | data[2]; + + switch(tag) + { + case TAG_TUNE: + return en50221_app_dvb_parse_tune(private, slot_id, session_number, data+3, data_length-3); + case TAG_REPLACE: + return en50221_app_dvb_parse_replace(private, slot_id, session_number, data+3, data_length-3); + case TAG_CLEAR_REPLACE: + return en50221_app_dvb_parse_clear_replace(private, slot_id, session_number, data+3, data_length-3); + } + + print(LOG_LEVEL, ERROR, 1, "Received unexpected tag %x\n", tag); + return -1; +} + + + + + + + + + + +static int en50221_app_dvb_parse_tune(struct en50221_app_dvb_private *private, + uint8_t slot_id, uint16_t session_number, + uint8_t *data, uint32_t data_length) +{ + // validate data + if (data_length < 9) { + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + return -1; + } + if (data[0] != 8) { + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + return -1; + } + uint8_t *tune_data = data+1; + + // parse it + uint16_t network_id = (tune_data[0] << 8) | tune_data[1]; + uint16_t original_network_id = (tune_data[2] << 8) | tune_data[3]; + uint16_t transport_stream_id = (tune_data[4] << 8) | tune_data[5]; + uint16_t service_id = (tune_data[6] << 8) | tune_data[7]; + + // tell the app + pthread_mutex_lock(&private->lock); + en50221_app_dvb_tune_callback cb = private->tune_callback; + void *cb_arg = private->tune_callback_arg; + pthread_mutex_unlock(&private->lock); + if (cb) { + return cb(cb_arg, slot_id, session_number, network_id, original_network_id, transport_stream_id, service_id); + } + return 0; +} + +static int en50221_app_dvb_parse_replace(struct en50221_app_dvb_private *private, + uint8_t slot_id, uint16_t session_number, + uint8_t *data, uint32_t data_length) +{ + // validate data + if (data_length < 6) { + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + return -1; + } + if (data[0] != 5) { + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + return -1; + } + uint8_t *replace_data = data+1; + + // parse it + uint8_t replacement_ref = replace_data[0]; + uint16_t replace_pid = ((replace_data[1] & 0x1f)<<8) | replace_data[2]; + uint16_t replacement_pid = ((replace_data[3] & 0x1f)<<8) | replace_data[4]; + + // tell the app + pthread_mutex_lock(&private->lock); + en50221_app_dvb_replace_callback cb = private->replace_callback; + void *cb_arg = private->replace_callback_arg; + pthread_mutex_unlock(&private->lock); + if (cb) { + return cb(cb_arg, slot_id, session_number, replacement_ref, replace_pid, replacement_pid); + } + return 0; +} + +static int en50221_app_dvb_parse_clear_replace(struct en50221_app_dvb_private *private, + uint8_t slot_id, uint16_t session_number, + uint8_t *data, uint32_t data_length) +{ + // validate data + if (data_length < 2) { + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + return -1; + } + if (data[0] != 1) { + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + return -1; + } + uint8_t *replace_data = data+1; + + // parse it + uint8_t replacement_ref = replace_data[0]; + + // tell the app + pthread_mutex_lock(&private->lock); + en50221_app_dvb_clear_replace_callback cb = private->clear_replace_callback; + void *cb_arg = private->clear_replace_callback_arg; + pthread_mutex_unlock(&private->lock); + if (cb) { + return cb(cb_arg, slot_id, session_number, replacement_ref); + } + return 0; +} diff --git a/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_dvb.h b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_dvb.h new file mode 100644 index 0000000..221f58a --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_dvb.h @@ -0,0 +1,164 @@ +/* + en50221 encoder An implementation for libdvb + an implementation for the en50221 transport layer + + Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com) + Copyright (C) 2005 Julian Scheel (julian at jusst dot de) + Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net) + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of + the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef __EN50221_APPLICATION_DVB_H__ +#define __EN50221_APPLICATION_DVB_H__ + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <stdlib.h> +#include <stdint.h> +#include <libdvben50221/en50221_app_utils.h> + +#define EN50221_APP_DVB_RESOURCEID MKRID(32,1,1) + + +/** + * Type definition for tune - called when we receive a tune request from a CAM. + * + * @param arg Private argument. + * @param slot_id Slot id concerned. + * @param session_number Session number concerned. + * @param network_id Network id requested by CAM. + * @param original_network_id Original Network id requested by CAM. + * @param transport_stream_id Transport stream id requested by CAM. + * @param service_id Service id requested by CAM. + * @return 0 on success, -1 on failure. + */ +typedef int (*en50221_app_dvb_tune_callback)(void *arg, uint8_t slot_id, uint16_t session_number, + uint16_t network_id, uint32_t original_network_id, + uint16_t transport_stream_id, uint16_t service_id); + +/** + * Type definition for replace - called when we receive a replace request from a CAM. + * + * @param arg Private argument. + * @param slot_id Slot id concerned. + * @param session_number Session number concerned. + * @param replacement_ref Replacement ref. + * @param replaced_pid PID to replace. + * @param replacement_pid PID to replace it with. + * @return 0 on success, -1 on failure. + */ +typedef int (*en50221_app_dvb_replace_callback)(void *arg, uint8_t slot_id, uint16_t session_number, + uint8_t replacement_ref, + uint16_t replaced_pid, uint16_t replacement_pid); + + +/** + * Type definition for clear_replace - called when we receive a clear_replace request from a CAM. + * + * @param arg Private argument. + * @param slot_id Slot id concerned. + * @param session_number Session number concerned. + * @param replacement_ref Replacement ref. + * @return 0 on success, -1 on failure. + */ +typedef int (*en50221_app_dvb_clear_replace_callback)(void *arg, uint8_t slot_id, uint16_t session_number, + uint8_t replacement_ref); + + +/** + * Opaque type representing a dvb resource. + */ +typedef void *en50221_app_dvb; + +/** + * Create an instance of the dvb resource. + * + * @param funcs Send functions to use. + * @return Instance, or NULL on failure. + */ +extern en50221_app_dvb en50221_app_dvb_create(struct en50221_app_send_functions *funcs); + +/** + * Destroy an instance of the dvb resource. + * + * @param dvb Instance to destroy. + */ +extern void en50221_app_dvb_destroy(en50221_app_dvb dvb); + +/** + * Register the callback for when we receive a tune request. + * + * @param dvb DVB resource instance. + * @param callback The callback. Set to NULL to remove the callback completely. + * @param arg Private data passed as arg0 of the callback. + */ +extern void en50221_app_dvb_register_tune_callback(en50221_app_dvb dvb, + en50221_app_dvb_tune_callback callback, void *arg); + +/** + * Register the callback for when we receive a replace request. + * + * @param dvb DVB resource instance. + * @param callback The callback. Set to NULL to remove the callback completely. + * @param arg Private data passed as arg0 of the callback. + */ +extern void en50221_app_dvb_register_replace_callback(en50221_app_dvb dvb, + en50221_app_dvb_replace_callback callback, void *arg); + +/** + * Register the callback for when we receive a clear replace request. + * + * @param dvb DVB resource instance. + * @param callback The callback. Set to NULL to remove the callback completely. + * @param arg Private data passed as arg0 of the callback. + */ +extern void en50221_app_dvb_register_clear_replace_callback(en50221_app_dvb dvb, + en50221_app_dvb_clear_replace_callback callback, void *arg); + +/** + * Send an ask release request to the CAM. + * + * @param dvb DVB resource instance. + * @param session_number Session number to send it on. + * @return 0 on success, -1 on failure. + */ +extern int en50221_app_dvb_ask_release(en50221_app_dvb dvb, uint16_t session_number); + +/** + * Pass data received for this resource into it for parsing. + * + * @param dvb dvb instance. + * @param slot_id Slot ID concerned. + * @param session_number Session number concerned. + * @param resource_id Resource ID concerned. + * @param data The data. + * @param data_length Length of data in bytes. + * @return 0 on success, -1 on failure. + */ +extern int en50221_app_dvb_message(en50221_app_dvb dvb, + uint8_t slot_id, + uint16_t session_number, + uint32_t resource_id, + uint8_t *data, uint32_t data_length); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_epg.c b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_epg.c new file mode 100644 index 0000000..dba09b0 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_epg.c @@ -0,0 +1,166 @@ +/* + en50221 encoder An implementation for libdvb + an implementation for the en50221 transport layer + + Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com) + Copyright (C) 2005 Julian Scheel (julian at jusst dot de) + Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net) + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of + the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include <string.h> +#include <libdvbmisc/dvbmisc.h> +#include <pthread.h> +#include <libucsi/dvb/types.h> +#include "en50221_app_epg.h" +#include "en50221_app_tags.h" +#include "asn_1.h" + +struct en50221_app_epg_private { + struct en50221_app_send_functions *funcs; + + en50221_app_epg_reply_callback callback; + void *callback_arg; + + pthread_mutex_t lock; +}; + +static int en50221_app_epg_parse_reply(struct en50221_app_epg_private *private, + uint8_t slot_id, uint16_t session_number, + uint8_t *data, uint32_t data_length); + + + +en50221_app_epg en50221_app_epg_create(struct en50221_app_send_functions *funcs) +{ + struct en50221_app_epg_private *private = NULL; + + // create structure and set it up + private = malloc(sizeof(struct en50221_app_epg_private)); + if (private == NULL) { + return NULL; + } + private->funcs = funcs; + private->callback = NULL; + + pthread_mutex_init(&private->lock, NULL); + + // done + return private; +} + +void en50221_app_epg_destroy(en50221_app_epg epg) +{ + struct en50221_app_epg_private *private = (struct en50221_app_epg_private *) epg; + + pthread_mutex_destroy(&private->lock); + free(private); +} + +void en50221_app_epg_register_enquiry_callback(en50221_app_epg epg, + en50221_app_epg_reply_callback callback, void *arg) +{ + struct en50221_app_epg_private *private = (struct en50221_app_epg_private *) epg; + + pthread_mutex_lock(&private->lock); + private->callback = callback; + private->callback_arg = arg; + pthread_mutex_unlock(&private->lock); +} + +int en50221_app_epg_enquire(en50221_app_epg epg, + uint16_t session_number, + uint8_t command_id, + uint16_t network_id, + uint16_t original_network_id, + uint16_t transport_stream_id, + uint16_t service_id, + uint16_t event_id) +{ + struct en50221_app_epg_private *private = (struct en50221_app_epg_private *) epg; + uint8_t data[15]; + + data[0] = (TAG_EPG_ENQUIRY >> 16) & 0xFF; + data[1] = (TAG_EPG_ENQUIRY >> 8) & 0xFF; + data[2] = TAG_EPG_ENQUIRY & 0xFF; + data[3] = 11; + data[4] = command_id; + data[5] = network_id >> 8; + data[6] = network_id; + data[7] = original_network_id >> 8; + data[8] = original_network_id; + data[9] = transport_stream_id >> 8; + data[10] = transport_stream_id; + data[11] = service_id >> 8; + data[12] = service_id; + data[13] = event_id >> 8; + data[14] = event_id; + return private->funcs->send_data(private->funcs->arg, session_number, data, 15); +} + +int en50221_app_epg_message(en50221_app_epg epg, + uint8_t slot_id, + uint16_t session_number, + uint32_t resource_id, + uint8_t *data, uint32_t data_length) +{ + struct en50221_app_epg_private *private = (struct en50221_app_epg_private *) epg; + (void) resource_id; + + // get the tag + if (data_length < 3) { + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + return -1; + } + uint32_t tag = (data[0] << 16) | (data[1] << 8) | data[2]; + + switch(tag) + { + case TAG_EPG_REPLY: + return en50221_app_epg_parse_reply(private, slot_id, session_number, data+3, data_length-3); + } + + print(LOG_LEVEL, ERROR, 1, "Received unexpected tag %x\n", tag); + return -1; +} + + + +static int en50221_app_epg_parse_reply(struct en50221_app_epg_private *private, + uint8_t slot_id, uint16_t session_number, + uint8_t *data, uint32_t data_length) +{ + // validate data + if (data_length != 2) { + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + return -1; + } + if (data[0] != 1) { + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + return -1; + } + uint8_t event_status = data[1]; + + // tell the app + pthread_mutex_lock(&private->lock); + en50221_app_epg_reply_callback cb = private->callback; + void *cb_arg = private->callback_arg; + pthread_mutex_unlock(&private->lock); + if (cb) { + return cb(cb_arg, slot_id, session_number, event_status); + } + return 0; +} diff --git a/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_epg.h b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_epg.h new file mode 100644 index 0000000..c3c4c59 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_epg.h @@ -0,0 +1,136 @@ +/* + en50221 encoder An implementation for libdvb + an implementation for the en50221 transport layer + + Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com) + Copyright (C) 2005 Julian Scheel (julian at jusst dot de) + Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net) + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of + the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef __EN50221_APPLICATION_epg_H__ +#define __EN50221_APPLICATION_epg_H__ + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <stdlib.h> +#include <stdint.h> +#include <libdvben50221/en50221_app_utils.h> + +#define EPG_COMMAND_ID_MMI 0x02 +#define EPG_COMMAND_ID_QUERY 0x03 + +#define EPG_EVENTSTATUS_ENTITLEMENT_UNKNOWN 0x00 +#define EPG_EVENTSTATUS_ENTITLEMENT_AVAILABLE 0x01 +#define EPG_EVENTSTATUS_ENTITLEMENT_NOT_AVAILABLE 0x02 +#define EPG_EVENTSTATUS_MMI_DIALOGUE_REQUIRED 0x03 +#define EPG_EVENTSTATUS_MMI_COMPLETE_UNKNOWN 0x04 +#define EPG_EVENTSTATUS_MMI_COMPLETE_AVAILABLE 0x05 +#define EPG_EVENTSTATUS_MMI_COMPLETE_NOT_AVAILABLE 0x06 + +#define EN50221_APP_EPG_RESOURCEID(INSTANCE_NUM) MKRID(120,(INSTANCE_NUM),1) + + + +/** + * Type definition for reply - called when we receive an EPG reply from a CAM. + * + * @param arg Private argument. + * @param slot_id Slot id concerned. + * @param session_number Session number concerned. + * @param event_status One of the EPG_EVENTSTATUS_* values. + * @return 0 on success, -1 on failure. + */ +typedef int (*en50221_app_epg_reply_callback)(void *arg, uint8_t slot_id, uint16_t session_number, + uint8_t event_status); + +/** + * Opaque type representing a epg resource. + */ +typedef void *en50221_app_epg; + +/** + * Create an instance of the epg resource. + * + * @param funcs Send functions to use. + * @return Instance, or NULL on failure. + */ +extern en50221_app_epg en50221_app_epg_create(struct en50221_app_send_functions *funcs); + +/** + * Destroy an instance of the epg resource. + * + * @param epg Instance to destroy. + */ +extern void en50221_app_epg_destroy(en50221_app_epg epg); + +/** + * Register the callback for when we receive a enquiry response. + * + * @param epg epg resource instance. + * @param callback The callback. Set to NULL to remove the callback completely. + * @param arg Private data passed as arg0 of the callback. + */ +extern void en50221_app_epg_register_reply_callback(en50221_app_epg epg, + en50221_app_epg_reply_callback callback, void *arg); + +/** + * Enquire about the entitlement status for an EPG entry. + * + * @param epg epg resource instance. + * @param session_number Session number to send it on. + * @param command_id One of the EPG_COMMAND_ID_* fields. + * @param network_id Network ID concerned. + * @param original_network_id Original network ID concerned. + * @param transport_stream_id Transport stream ID concerned. + * @param service_id Service ID concerned. + * @param event_id Event ID concerned. + * @return 0 on success, -1 on failure. + */ +extern int en50221_app_epg_enquire(en50221_app_epg epg, + uint16_t session_number, + uint8_t command_id, + uint16_t network_id, + uint16_t original_network_id, + uint16_t transport_stream_id, + uint16_t service_id, + uint16_t event_id); + +/** + * Pass data received for this resource into it for parsing. + * + * @param epg epg instance. + * @param slot_id Slot ID concerned. + * @param session_number Session number concerned. + * @param resource_id Resource ID concerned. + * @param data The data. + * @param data_length Length of data in bytes. + * @return 0 on success, -1 on failure. + */ +extern int en50221_app_epg_message(en50221_app_epg epg, + uint8_t slot_id, + uint16_t session_number, + uint32_t resource_id, + uint8_t *data, uint32_t data_length); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_lowspeed.c b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_lowspeed.c new file mode 100644 index 0000000..25d088f --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_lowspeed.c @@ -0,0 +1,514 @@ +/* + en50221 encoder An implementation for libdvb + an implementation for the en50221 transport layer + + Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com) + Copyright (C) 2005 Julian Scheel (julian at jusst dot de) + Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net) + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of + the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include <string.h> +#include <libdvbmisc/dvbmisc.h> +#include <pthread.h> +#include "en50221_app_lowspeed.h" +#include "en50221_app_tags.h" +#include "asn_1.h" + +struct en50221_app_lowspeed_session { + uint16_t session_number; + uint8_t *block_chain; + uint32_t block_length; + + struct en50221_app_lowspeed_session *next; +}; + +struct en50221_app_lowspeed_private { + struct en50221_app_send_functions *funcs; + + en50221_app_lowspeed_command_callback command_callback; + void *command_callback_arg; + + en50221_app_lowspeed_send_callback send_callback; + void *send_callback_arg; + + struct en50221_app_lowspeed_session *sessions; + + pthread_mutex_t lock; +}; + +static int en50221_app_lowspeed_parse_connect_on_channel(struct en50221_app_lowspeed_command *command, + uint8_t *data, + int data_length); +static int en50221_app_lowspeed_parse_command(struct en50221_app_lowspeed_private *private, + uint8_t slot_id, uint16_t session_number, + uint8_t *data, uint32_t data_length); +static int en50221_app_lowspeed_parse_send(struct en50221_app_lowspeed_private *private, + uint8_t slot_id, uint16_t session_number, int more_last, + uint8_t *data, uint32_t data_length); + + + +en50221_app_lowspeed en50221_app_lowspeed_create(struct en50221_app_send_functions *funcs) +{ + struct en50221_app_lowspeed_private *private = NULL; + + // create structure and set it up + private = malloc(sizeof(struct en50221_app_lowspeed_private)); + if (private == NULL) { + return NULL; + } + private->funcs = funcs; + private->command_callback = NULL; + private->send_callback = NULL; + private->sessions = NULL; + + pthread_mutex_init(&private->lock, NULL); + + // done + return private; +} + +void en50221_app_lowspeed_destroy(en50221_app_lowspeed lowspeed) +{ + struct en50221_app_lowspeed_private *private = (struct en50221_app_lowspeed_private *) lowspeed; + + struct en50221_app_lowspeed_session *cur_s = private->sessions; + while(cur_s) { + struct en50221_app_lowspeed_session *next = cur_s->next; + if (cur_s->block_chain) + free(cur_s->block_chain); + free(cur_s); + cur_s = next; + } + + pthread_mutex_destroy(&private->lock); + free(private); +} + +void en50221_app_lowspeed_clear_session(en50221_app_lowspeed lowspeed, uint16_t session_number) +{ + struct en50221_app_lowspeed_private *private = (struct en50221_app_lowspeed_private *) lowspeed; + + pthread_mutex_lock(&private->lock); + struct en50221_app_lowspeed_session *cur_s = private->sessions; + struct en50221_app_lowspeed_session *prev_s = NULL; + while(cur_s) { + if (cur_s->session_number == session_number) { + if (cur_s->block_chain) + free(cur_s->block_chain); + if (prev_s) { + prev_s->next = cur_s->next; + } else { + private->sessions = cur_s->next; + } + free(cur_s); + return; + } + + prev_s = cur_s; + cur_s=cur_s->next; + } + pthread_mutex_unlock(&private->lock); +} + +void en50221_app_lowspeed_register_command_callback(en50221_app_lowspeed lowspeed, + en50221_app_lowspeed_command_callback callback, void *arg) +{ + struct en50221_app_lowspeed_private *private = (struct en50221_app_lowspeed_private *) lowspeed; + + pthread_mutex_lock(&private->lock); + private->command_callback = callback; + private->command_callback_arg = arg; + pthread_mutex_unlock(&private->lock); +} + +void en50221_app_lowspeed_register_send_callback(en50221_app_lowspeed lowspeed, + en50221_app_lowspeed_send_callback callback, void *arg) +{ + struct en50221_app_lowspeed_private *private = (struct en50221_app_lowspeed_private *) lowspeed; + + pthread_mutex_lock(&private->lock); + private->send_callback = callback; + private->send_callback_arg = arg; + pthread_mutex_unlock(&private->lock); +} + +int en50221_app_lowspeed_send_comms_reply(en50221_app_lowspeed lowspeed, + uint16_t session_number, + uint8_t comms_reply_id, + uint8_t return_value) +{ + struct en50221_app_lowspeed_private *private = (struct en50221_app_lowspeed_private *) lowspeed; + uint8_t data[6]; + + data[0] = (TAG_COMMS_REPLY >> 16) & 0xFF; + data[1] = (TAG_COMMS_REPLY >> 8) & 0xFF; + data[2] = TAG_COMMS_REPLY & 0xFF; + data[3] = 2; + data[4] = comms_reply_id; + data[5] = return_value; + return private->funcs->send_data(private->funcs->arg, session_number, data, 6); +} + +int en50221_app_lowspeed_send_comms_data(en50221_app_lowspeed lowspeed, + uint16_t session_number, + uint8_t phase_id, + uint32_t tx_data_length, + uint8_t *tx_data) +{ + struct en50221_app_lowspeed_private *private = (struct en50221_app_lowspeed_private *) lowspeed; + uint8_t buf[10]; + + // the spec defines this limit + if (tx_data_length > 254) { + return -1; + } + + // set up the tag + buf[0] = (TAG_COMMS_RECV_LAST >> 16) & 0xFF; + buf[1] = (TAG_COMMS_RECV_LAST >> 8) & 0xFF; + buf[2] = TAG_COMMS_RECV_LAST & 0xFF; + + // encode the length field + int length_field_len; + if ((length_field_len = asn_1_encode(tx_data_length+1, buf+3, 3)) < 0) { + return -1; + } + + // the phase_id + buf[3+length_field_len] = phase_id; + + // build the iovecs + struct iovec iov[2]; + iov[0].iov_base = buf; + iov[0].iov_len = 3+length_field_len+1; + iov[1].iov_base = tx_data; + iov[1].iov_len = tx_data_length; + + // create the data and send it + return private->funcs->send_datav(private->funcs->arg, session_number, iov, 2); +} + +int en50221_app_lowspeed_message(en50221_app_lowspeed lowspeed, + uint8_t slot_id, + uint16_t session_number, + uint32_t resource_id, + uint8_t *data, uint32_t data_length) +{ + struct en50221_app_lowspeed_private *private = (struct en50221_app_lowspeed_private *) lowspeed; + (void)resource_id; + + // get the tag + if (data_length < 3) { + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + return -1; + } + uint32_t tag = (data[0] << 16) | (data[1] << 8) | data[2]; + + switch(tag) + { + case TAG_COMMS_COMMAND: + return en50221_app_lowspeed_parse_command(private, slot_id, session_number, data+3, data_length-3); + case TAG_COMMS_SEND_LAST: + return en50221_app_lowspeed_parse_send(private, slot_id, session_number, 1, data+3, data_length-3); + case TAG_COMMS_SEND_MORE: + return en50221_app_lowspeed_parse_send(private, slot_id, session_number, 0, data+3, data_length-3); + } + + print(LOG_LEVEL, ERROR, 1, "Received unexpected tag %x\n", tag); + return -1; +} + + + +static int en50221_app_lowspeed_parse_connect_on_channel(struct en50221_app_lowspeed_command *command, + uint8_t *data, + int data_length) +{ + if (data_length < 3) { + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + return -1; + } + + // check the tag + uint32_t tag = (data[0] << 16) | (data[1] << 8) | data[2]; + if (tag != TAG_CONNECTION_DESCRIPTOR) { + print(LOG_LEVEL, ERROR, 1, "Received bad CONNECT_ON_CHANNEL\n"); + return -1; + } + data+=3; + data_length-=3; + + // parse the descriptor-length-field + uint16_t asn_data_length; + int length_field_len; + if ((length_field_len = asn_1_decode(&asn_data_length, data, data_length)) < 0) { + print(LOG_LEVEL, ERROR, 1, "ASN.1 decode error\n"); + return -1; + } + data+=length_field_len; + data_length-=length_field_len; + + // check length field + if (asn_data_length > data_length) { + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + return -1; + } + if (asn_data_length < 1) { + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + return -1; + } + + // get the descriptor type + command->u.connect_on_channel.descriptor_type = data[0]; + data++; + data_length--; + asn_data_length--; + + // deal with the descriptor itself + switch(command->u.connect_on_channel.descriptor_type) { + case CONNECTION_DESCRIPTOR_TYPE_TELEPHONE: + { + // get the raw descriptor and validate length + struct descriptor *d = (struct descriptor*) data; + if (asn_data_length < 2) { + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + return -1; + } + if (asn_data_length != (2 + d->len)) { + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + return -1; + } + if (d->tag != dtag_dvb_telephone) { + print(LOG_LEVEL, ERROR, 1, "Received invalid telephone descriptor\n"); + return -1; + } + + // parse the telephone descriptor + command->u.connect_on_channel.descriptor.telephone = dvb_telephone_descriptor_codec(d); + if (command->u.connect_on_channel.descriptor.telephone == NULL) { + print(LOG_LEVEL, ERROR, 1, "Received invalid telephone descriptor\n"); + return -1; + } + data += 2 + d->len; + data_length -= 2 + d->len; + break; + } + case CONNECTION_DESCRIPTOR_TYPE_CABLE: + if (asn_data_length != 1) { + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + return -1; + } + command->u.connect_on_channel.descriptor.cable_channel_id = data[0]; + data++; + data_length--; + break; + default: + print(LOG_LEVEL, ERROR, 1, "Received unknown connection descriptor %02x\n", + command->u.connect_on_channel.descriptor_type); + return -1; + } + + // parse the last bit + if (data_length != 2) { + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + return -1; + } + command->u.connect_on_channel.retry_count = data[0]; + command->u.connect_on_channel.timeout = data[1]; + + // ok + return 0; +} + +static int en50221_app_lowspeed_parse_command(struct en50221_app_lowspeed_private *private, + uint8_t slot_id, uint16_t session_number, + uint8_t *data, uint32_t data_length) +{ + // first of all, decode the length field + uint16_t asn_data_length; + int length_field_len; + if ((length_field_len = asn_1_decode(&asn_data_length, data, data_length)) < 0) { + print(LOG_LEVEL, ERROR, 1, "ASN.1 decode error\n"); + return -1; + } + + // check it + if (asn_data_length < 1) { + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + return -1; + } + if (asn_data_length > (data_length-length_field_len)) { + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + return -1; + } + data+=length_field_len; + + // get command id + uint8_t command_id = data[0]; + data++; + asn_data_length--; + + // parse the command + struct en50221_app_lowspeed_command command; + switch(command_id) { + case COMMS_COMMAND_ID_CONNECT_ON_CHANNEL: + if (en50221_app_lowspeed_parse_connect_on_channel(&command, data, asn_data_length)) { + return -1; + } + break; + case COMMS_COMMAND_ID_SET_PARAMS: + if (asn_data_length != 2) { + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + return -1; + } + command.u.set_params.buffer_size = data[0]; + command.u.set_params.timeout = data[1]; + break; + case COMMS_COMMAND_ID_GET_NEXT_BUFFER: + if (asn_data_length != 1) { + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + return -1; + } + command.u.get_next_buffer.phase_id = data[0]; + break; + + case COMMS_COMMAND_ID_DISCONNECT_ON_CHANNEL: + case COMMS_COMMAND_ID_ENQUIRE_STATUS: + break; + + default: + print(LOG_LEVEL, ERROR, 1, "Received unexpected command_id %02x\n", command_id); + return -1; + } + + // tell the app + pthread_mutex_lock(&private->lock); + en50221_app_lowspeed_command_callback cb = private->command_callback; + void *cb_arg = private->command_callback_arg; + pthread_mutex_unlock(&private->lock); + if (cb) { + return cb(cb_arg, slot_id, session_number, command_id, &command); + } + return 0; +} + +static int en50221_app_lowspeed_parse_send(struct en50221_app_lowspeed_private *private, + uint8_t slot_id, uint16_t session_number, int more_last, + uint8_t *data, uint32_t data_length) +{ + // first of all, decode the length field + uint16_t asn_data_length; + int length_field_len; + if ((length_field_len = asn_1_decode(&asn_data_length, data, data_length)) < 0) { + print(LOG_LEVEL, ERROR, 1, "ASN.1 decode error\n"); + return -1; + } + + // check it + if (asn_data_length > (data_length-length_field_len)) { + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + return -1; + } + + // skip over the length field + data += length_field_len; + + // find previous session + pthread_mutex_lock(&private->lock); + struct en50221_app_lowspeed_session *cur_s = private->sessions; + while(cur_s) { + if (cur_s->session_number == session_number) + break; + cur_s=cur_s->next; + } + + // more data is still to come + if (!more_last) { + // if there was no previous session, create one + if (cur_s == NULL) { + cur_s = malloc(sizeof(struct en50221_app_lowspeed_session)); + if (cur_s == NULL) { + print(LOG_LEVEL, ERROR, 1, "Ran out of memory\n"); + pthread_mutex_unlock(&private->lock); + return -1; + } + cur_s->session_number = session_number; + cur_s->block_chain = NULL; + cur_s->block_length = 0; + cur_s->next = private->sessions; + private->sessions = cur_s; + } + + // append the data + uint8_t *new_data = realloc(cur_s->block_chain, cur_s->block_length + asn_data_length); + if (new_data == NULL) { + print(LOG_LEVEL, ERROR, 1, "Ran out of memory\n"); + pthread_mutex_unlock(&private->lock); + return -1; + } + memcpy(new_data + cur_s->block_length, data, asn_data_length); + cur_s->block_chain = new_data; + cur_s->block_length += asn_data_length; + + // done + pthread_mutex_unlock(&private->lock); + return 0; + } + + // we hit the last of a possible chain of fragments + int do_free = 0; + if (cur_s != NULL) { + // we have a preceding fragment - need to append + uint8_t *new_data = realloc(cur_s->block_chain, cur_s->block_length + asn_data_length); + if (new_data == NULL) { + print(LOG_LEVEL, ERROR, 1, "Ran out of memory\n"); + pthread_mutex_unlock(&private->lock); + return -1; + } + memcpy(new_data + cur_s->block_length, data, asn_data_length); + asn_data_length = cur_s->block_length + asn_data_length; + data = new_data; + cur_s->block_chain = NULL; + cur_s->block_length = 0; + do_free = 1; + } + + // check the reassembled data length + if (asn_data_length < 1) { + pthread_mutex_unlock(&private->lock); + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + if (do_free) free(data); + return -1; + } + + // now, parse the data + uint8_t phase_id = data[0]; + + // tell the app + en50221_app_lowspeed_send_callback cb = private->send_callback; + void *cb_arg = private->send_callback_arg; + pthread_mutex_unlock(&private->lock); + int cbstatus = 0; + if (cb) { + cbstatus = cb(cb_arg, slot_id, session_number, phase_id, data+1, asn_data_length-1); + } + + // done + if (do_free) free(data); + return cbstatus; +} diff --git a/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_lowspeed.h b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_lowspeed.h new file mode 100644 index 0000000..9f58ad9 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_lowspeed.h @@ -0,0 +1,210 @@ +/* + en50221 encoder An implementation for libdvb + an implementation for the en50221 transport layer + + Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com) + Copyright (C) 2005 Julian Scheel (julian at jusst dot de) + Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net) + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of + the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef __EN50221_APPLICATION_LOWSPEED_H__ +#define __EN50221_APPLICATION_LOWSPEED_H__ + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <stdlib.h> +#include <stdint.h> +#include <libdvben50221/en50221_app_utils.h> +#include <libucsi/dvb/descriptor.h> + +#define COMMS_COMMAND_ID_CONNECT_ON_CHANNEL 0x01 +#define COMMS_COMMAND_ID_DISCONNECT_ON_CHANNEL 0x02 +#define COMMS_COMMAND_ID_SET_PARAMS 0x03 +#define COMMS_COMMAND_ID_ENQUIRE_STATUS 0x04 +#define COMMS_COMMAND_ID_GET_NEXT_BUFFER 0x05 + +#define CONNECTION_DESCRIPTOR_TYPE_TELEPHONE 0x01 +#define CONNECTION_DESCRIPTOR_TYPE_CABLE 0x02 + +#define COMMS_REPLY_ID_CONNECT_ACK 0x01 +#define COMMS_REPLY_ID_DISCONNECT_ACK 0x02 +#define COMMS_REPLY_ID_SET_PARAMS_ACK 0x03 +#define COMMS_REPLY_ID_STATUS_REPLY 0x04 +#define COMMS_REPLY_ID_GET_NEXT_BUFFER_ACK 0x05 +#define COMMS_REPLY_ID_SEND_ACK 0x06 + +#define EN50221_APP_LOWSPEED_RESOURCEID(DEVICE_TYPE, DEVICE_NUMBER) MKRID(96,((DEVICE_TYPE)<<2)|((DEVICE_NUMBER) & 0x03),1) + + +/** + * Structure holding information on a received comms command. + */ +struct en50221_app_lowspeed_command { + union { + struct { + uint8_t descriptor_type; // CONNECTION_DESCRIPTOR_TYPE_* + uint8_t retry_count; + uint8_t timeout; + union { + struct dvb_telephone_descriptor *telephone; + uint8_t cable_channel_id; + } descriptor; + } connect_on_channel; + + struct { + uint8_t buffer_size; + uint8_t timeout; + } set_params; + + struct { + uint8_t phase_id; + } get_next_buffer; + } u; +}; + +/** + * Type definition for command - called when we receive a comms command. + * + * @param arg Private argument. + * @param slot_id Slot id concerned. + * @param session_number Session number concerned. + * @param command_id One of the COMMS_COMMAND_ID_* values + * @param command Pointer to a lowspeed command structure containing the command data. + * @return 0 on success, -1 on failure. + */ +typedef int (*en50221_app_lowspeed_command_callback)(void *arg, uint8_t slot_id, uint16_t session_number, + uint8_t command_id, + struct en50221_app_lowspeed_command *command); + +/** + * Type definition for send - called when we receive data to send. The block can be segmented into + * multiple pieces - last_more indicates the details of this. + * + * @param arg Private argument. + * @param slot_id Slot id concerned. + * @param session_number Session number concerned. + * @param phase_id Comms phase id. + * @param data The data. + * @param length Number of bytes. + * @return 0 on success, -1 on failure. + */ +typedef int (*en50221_app_lowspeed_send_callback)(void *arg, uint8_t slot_id, uint16_t session_number, + uint8_t phase_id, uint8_t *data, uint32_t length); + +/** + * Opaque type representing a lowspeed resource. + */ +typedef void *en50221_app_lowspeed; + +/** + * Create an instance of the lowspeed resource. + * + * @param funcs Send functions to use. + * @return Instance, or NULL on failure. + */ +extern en50221_app_lowspeed en50221_app_lowspeed_create(struct en50221_app_send_functions *funcs); + +/** + * Destroy an instance of the lowspeed resource. + * + * @param lowspeed Instance to destroy. + */ +extern void en50221_app_lowspeed_destroy(en50221_app_lowspeed lowspeed); + +/** + * Informs the lowspeed object that a session to it has been closed - cleans up internal state. + * + * @param lowspeed lowspeed resource instance. + * @param session_number The session concerned. + */ +extern void en50221_app_lowspeed_clear_session(en50221_app_lowspeed lowspeed, uint16_t session_number); + +/** + * Register the callback for when we receive a comms command. + * + * @param lowspeed lowspeed resource instance. + * @param callback The callback. Set to NULL to remove the callback completely. + * @param arg Private data passed as arg0 of the callback. + */ +extern void en50221_app_lowspeed_register_command_callback(en50221_app_lowspeed lowspeed, + en50221_app_lowspeed_command_callback callback, void *arg); + +/** + * Register the callback for when we receive data to send. + * + * @param lowspeed lowspeed resource instance. + * @param callback The callback. Set to NULL to remove the callback completely. + * @param arg Private data passed as arg0 of the callback. + */ +extern void en50221_app_lowspeed_register_send_callback(en50221_app_lowspeed lowspeed, + en50221_app_lowspeed_send_callback callback, void *arg); + +/** + * Send a comms reply to the CAM. + * + * @param lowspeed lowspeed resource instance. + * @param session_number Session number to send it on. + * @param comms_reply_id One of the COMMS_REPLY_ID_* values. + * @param return_value Comms reply specific value. + * @return 0 on success, -1 on failure. + */ +extern int en50221_app_lowspeed_send_comms_reply(en50221_app_lowspeed lowspeed, + uint16_t session_number, + uint8_t comms_reply_id, + uint8_t return_value); + +/** + * Send received data to the CAM. + * + * @param lowspeed lowspeed resource instance. + * @param session_number Session number to send it on. + * @param phase_id Comms phase id. + * @param tx_data_length Length of data in bytes (max 254 bytes as per spec). + * @param tx_data Data. + * @return 0 on success, -1 on failure. + */ +extern int en50221_app_lowspeed_send_comms_data(en50221_app_lowspeed lowspeed, + uint16_t session_number, + uint8_t phase_id, + uint32_t tx_data_length, + uint8_t *tx_data); + +/** + * Pass data received for this resource into it for parsing. + * + * @param lowspeed lowspeed instance. + * @param slot_id Slot ID concerned. + * @param session_number Session number concerned. + * @param resource_id Resource ID concerned. + * @param data The data. + * @param data_length Length of data in bytes. + * @return 0 on success, -1 on failure. + */ +extern int en50221_app_lowspeed_message(en50221_app_lowspeed lowspeed, + uint8_t slot_id, + uint16_t session_number, + uint32_t resource_id, + uint8_t *data, uint32_t data_length); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_mmi.c b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_mmi.c new file mode 100644 index 0000000..ab5c6e4 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_mmi.c @@ -0,0 +1,1316 @@ +/* + en50221 encoder An implementation for libdvb + an implementation for the en50221 transport layer + + Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com) + Copyright (C) 2005 Julian Scheel (julian at jusst dot de) + Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net) + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of + the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include <string.h> +#include <libdvbmisc/dvbmisc.h> +#include <pthread.h> +#include <libucsi/dvb/types.h> +#include "en50221_app_mmi.h" +#include "en50221_app_tags.h" +#include "asn_1.h" + +struct en50221_app_mmi_session { + uint16_t session_number; + + uint8_t *menu_block_chain; + uint32_t menu_block_length; + + uint8_t *list_block_chain; + uint32_t list_block_length; + + uint8_t *subtitlesegment_block_chain; + uint32_t subtitlesegment_block_length; + + uint8_t *subtitledownload_block_chain; + uint32_t subtitledownload_block_length; + + struct en50221_app_mmi_session *next; +}; + +struct en50221_app_mmi_private { + struct en50221_app_send_functions *funcs; + struct en50221_app_mmi_session *sessions; + + en50221_app_mmi_close_callback closecallback; + void *closecallback_arg; + + en50221_app_mmi_display_control_callback displaycontrolcallback; + void *displaycontrolcallback_arg; + + en50221_app_mmi_keypad_control_callback keypadcontrolcallback; + void *keypadcontrolcallback_arg; + + en50221_app_mmi_subtitle_segment_callback subtitlesegmentcallback; + void *subtitlesegmentcallback_arg; + + en50221_app_mmi_scene_end_mark_callback sceneendmarkcallback; + void *sceneendmarkcallback_arg; + + en50221_app_mmi_scene_control_callback scenecontrolcallback; + void *scenecontrolcallback_arg; + + en50221_app_mmi_subtitle_download_callback subtitledownloadcallback; + void *subtitledownloadcallback_arg; + + en50221_app_mmi_flush_download_callback flushdownloadcallback; + void *flushdownloadcallback_arg; + + en50221_app_mmi_enq_callback enqcallback; + void *enqcallback_arg; + + en50221_app_mmi_menu_callback menucallback; + void *menucallback_arg; + + en50221_app_mmi_list_callback listcallback; + void *listcallback_arg; + + pthread_mutex_t lock; +}; + +static int en50221_app_mmi_parse_close(struct en50221_app_mmi_private *private, + uint8_t slot_id, uint16_t session_number, + uint8_t *data, uint32_t data_length); +static int en50221_app_mmi_parse_display_control(struct en50221_app_mmi_private *private, + uint8_t slot_id, uint16_t session_number, + uint8_t *data, uint32_t data_length); +static int en50221_app_mmi_parse_keypad_control(struct en50221_app_mmi_private *private, + uint8_t slot_id, uint16_t session_number, + uint8_t *data, uint32_t data_length); +static int en50221_app_mmi_parse_enq(struct en50221_app_mmi_private *private, + uint8_t slot_id, uint16_t session_number, + uint8_t *data, uint32_t data_length); +static int en50221_app_mmi_parse_list_menu(struct en50221_app_mmi_private *private, + uint8_t slot_id, uint16_t session_number, uint32_t tag_id, + int more_last, uint8_t *data, uint32_t data_length); +static int en50221_app_mmi_parse_subtitle(struct en50221_app_mmi_private *private, + uint8_t slot_id, uint16_t session_number, uint32_t tag_id, + int more_last, uint8_t *data, uint32_t data_length); +static int en50221_app_mmi_parse_scene_end_mark(struct en50221_app_mmi_private *private, + uint8_t slot_id, uint16_t session_number, + uint8_t *data, uint32_t data_length); +static int en50221_app_mmi_parse_scene_control(struct en50221_app_mmi_private *private, + uint8_t slot_id, uint16_t session_number, + uint8_t *data, uint32_t data_length); +static int en50221_app_mmi_parse_subtitle(struct en50221_app_mmi_private *private, + uint8_t slot_id, uint16_t session_number, uint32_t tag_id, + int more_last, uint8_t *data, uint32_t data_length); +static int en50221_app_mmi_parse_flush_download(struct en50221_app_mmi_private *private, + uint8_t slot_id, uint16_t session_number, + uint8_t *data, uint32_t data_length); +static int en50221_app_mmi_defragment(struct en50221_app_mmi_private *private, + uint16_t session_number, + uint32_t tag_id, + int more_last, + uint8_t *indata, + uint32_t indata_length, + uint8_t **outdata, + uint32_t *outdata_length); +static int en50221_app_mmi_defragment_text(uint8_t *data, + uint32_t data_length, + uint8_t **outdata, + uint32_t *outdata_length, + uint32_t *outconsumed); + + + +en50221_app_mmi en50221_app_mmi_create(struct en50221_app_send_functions *funcs) +{ + struct en50221_app_mmi_private *private = NULL; + + // create structure and set it up + private = malloc(sizeof(struct en50221_app_mmi_private)); + if (private == NULL) { + return NULL; + } + private->funcs = funcs; + private->closecallback = NULL; + private->displaycontrolcallback = NULL; + private->keypadcontrolcallback = NULL; + private->subtitlesegmentcallback = NULL; + private->sceneendmarkcallback = NULL; + private->scenecontrolcallback = NULL; + private->subtitledownloadcallback = NULL; + private->flushdownloadcallback = NULL; + private->enqcallback = NULL; + private->menucallback = NULL; + private->listcallback = NULL; + private->sessions = NULL; + + pthread_mutex_init(&private->lock, NULL); + + // done + return private; +} + +void en50221_app_mmi_destroy(en50221_app_mmi mmi) +{ + struct en50221_app_mmi_private *private = (struct en50221_app_mmi_private *) mmi; + + struct en50221_app_mmi_session *cur_s = private->sessions; + while(cur_s) { + struct en50221_app_mmi_session *next = cur_s->next; + if (cur_s->menu_block_chain) + free(cur_s->menu_block_chain); + if (cur_s->list_block_chain) + free(cur_s->list_block_chain); + if (cur_s->subtitlesegment_block_chain) + free(cur_s->subtitlesegment_block_chain); + if (cur_s->subtitledownload_block_chain) + free(cur_s->subtitledownload_block_chain); + free(cur_s); + cur_s = next; + } + + pthread_mutex_destroy(&private->lock); + free(private); +} + +void en50221_app_mmi_clear_session(en50221_app_mmi mmi, uint16_t session_number) +{ + struct en50221_app_mmi_private *private = (struct en50221_app_mmi_private *) mmi; + + pthread_mutex_lock(&private->lock); + struct en50221_app_mmi_session *cur_s = private->sessions; + struct en50221_app_mmi_session *prev_s = NULL; + while(cur_s) { + if (cur_s->session_number == session_number) { + if (cur_s->menu_block_chain) + free(cur_s->menu_block_chain); + if (cur_s->list_block_chain) + free(cur_s->list_block_chain); + if (cur_s->subtitlesegment_block_chain) + free(cur_s->subtitlesegment_block_chain); + if (cur_s->subtitledownload_block_chain) + free(cur_s->subtitledownload_block_chain); + if (prev_s) { + prev_s->next = cur_s->next; + } else { + private->sessions = cur_s->next; + } + free(cur_s); + return; + } + + prev_s = cur_s; + cur_s=cur_s->next; + } + pthread_mutex_unlock(&private->lock); +} + +void en50221_app_mmi_register_close_callback(en50221_app_mmi mmi, + en50221_app_mmi_close_callback callback, void *arg) +{ + struct en50221_app_mmi_private *private = (struct en50221_app_mmi_private *) mmi; + + pthread_mutex_lock(&private->lock); + private->closecallback = callback; + private->closecallback_arg = arg; + pthread_mutex_unlock(&private->lock); +} + +void en50221_app_mmi_register_display_control_callback(en50221_app_mmi mmi, + en50221_app_mmi_display_control_callback callback, void *arg) +{ + struct en50221_app_mmi_private *private = (struct en50221_app_mmi_private *) mmi; + + pthread_mutex_lock(&private->lock); + private->displaycontrolcallback = callback; + private->displaycontrolcallback_arg = arg; + pthread_mutex_unlock(&private->lock); +} + +void en50221_app_mmi_register_keypad_control_callback(en50221_app_mmi mmi, + en50221_app_mmi_keypad_control_callback callback, void *arg) +{ + struct en50221_app_mmi_private *private = (struct en50221_app_mmi_private *) mmi; + + pthread_mutex_lock(&private->lock); + private->keypadcontrolcallback = callback; + private->keypadcontrolcallback_arg = arg; + pthread_mutex_unlock(&private->lock); +} + +void en50221_app_mmi_register_subtitle_segment_callback(en50221_app_mmi mmi, + en50221_app_mmi_subtitle_segment_callback callback, void *arg) +{ + struct en50221_app_mmi_private *private = (struct en50221_app_mmi_private *) mmi; + + pthread_mutex_lock(&private->lock); + private->subtitlesegmentcallback = callback; + private->subtitlesegmentcallback_arg = arg; + pthread_mutex_unlock(&private->lock); +} + +void en50221_app_mmi_register_scene_end_mark_callback(en50221_app_mmi mmi, + en50221_app_mmi_scene_end_mark_callback callback, void *arg) +{ + struct en50221_app_mmi_private *private = (struct en50221_app_mmi_private *) mmi; + + pthread_mutex_lock(&private->lock); + private->sceneendmarkcallback = callback; + private->sceneendmarkcallback_arg = arg; + pthread_mutex_unlock(&private->lock); +} + +void en50221_app_mmi_register_scene_control_callback(en50221_app_mmi mmi, + en50221_app_mmi_scene_control_callback callback, void *arg) +{ + struct en50221_app_mmi_private *private = (struct en50221_app_mmi_private *) mmi; + + pthread_mutex_lock(&private->lock); + private->scenecontrolcallback = callback; + private->scenecontrolcallback_arg = arg; + pthread_mutex_unlock(&private->lock); +} + +void en50221_app_mmi_register_subtitle_download_callback(en50221_app_mmi mmi, + en50221_app_mmi_subtitle_download_callback callback, void *arg) +{ + struct en50221_app_mmi_private *private = (struct en50221_app_mmi_private *) mmi; + + pthread_mutex_lock(&private->lock); + private->subtitledownloadcallback = callback; + private->subtitledownloadcallback_arg = arg; + pthread_mutex_unlock(&private->lock); +} + +void en50221_app_mmi_register_flush_download_callback(en50221_app_mmi mmi, + en50221_app_mmi_flush_download_callback callback, void *arg) +{ + struct en50221_app_mmi_private *private = (struct en50221_app_mmi_private *) mmi; + + pthread_mutex_lock(&private->lock); + private->flushdownloadcallback = callback; + private->flushdownloadcallback_arg = arg; + pthread_mutex_unlock(&private->lock); +} + +void en50221_app_mmi_register_enq_callback(en50221_app_mmi mmi, + en50221_app_mmi_enq_callback callback, void *arg) +{ + struct en50221_app_mmi_private *private = (struct en50221_app_mmi_private *) mmi; + + pthread_mutex_lock(&private->lock); + private->enqcallback = callback; + private->enqcallback_arg = arg; + pthread_mutex_unlock(&private->lock); +} + +void en50221_app_mmi_register_menu_callback(en50221_app_mmi mmi, + en50221_app_mmi_menu_callback callback, void *arg) +{ + struct en50221_app_mmi_private *private = (struct en50221_app_mmi_private *) mmi; + + pthread_mutex_lock(&private->lock); + private->menucallback = callback; + private->menucallback_arg = arg; + pthread_mutex_unlock(&private->lock); +} + +void en50221_app_mmi_register_list_callback(en50221_app_mmi mmi, + en50221_app_mmi_list_callback callback, void *arg) +{ + struct en50221_app_mmi_private *private = (struct en50221_app_mmi_private *) mmi; + + pthread_mutex_lock(&private->lock); + private->listcallback = callback; + private->listcallback_arg = arg; + pthread_mutex_unlock(&private->lock); +} + +int en50221_app_mmi_close(en50221_app_mmi mmi, + uint16_t session_number, + uint8_t cmd_id, + uint8_t delay) +{ + struct en50221_app_mmi_private *private = (struct en50221_app_mmi_private *) mmi; + uint8_t data[6]; + int data_length = 5; + + data[0] = (TAG_CLOSE_MMI >> 16) & 0xFF; + data[1] = (TAG_CLOSE_MMI >> 8) & 0xFF; + data[2] = TAG_CLOSE_MMI & 0xFF; + data[3] = 1; + data[4] = cmd_id; + if (cmd_id == MMI_CLOSE_MMI_CMD_ID_DELAY) { + data[3] = 2; + data[5] = delay; + data_length = 6; + } + return private->funcs->send_data(private->funcs->arg, session_number, data, data_length); +} + +int en50221_app_mmi_display_reply(en50221_app_mmi mmi, + uint16_t session_number, + uint8_t reply_id, + struct en502221_app_mmi_display_reply_details *details) +{ + struct en50221_app_mmi_private *private = (struct en50221_app_mmi_private *) mmi; + uint8_t data[32]; + struct iovec iov[2]; + uint32_t iov_count; + int length_field_len; + + // fill out the start of the header + data[0] = (TAG_DISPLAY_REPLY >> 16) & 0xFF; + data[1] = (TAG_DISPLAY_REPLY >> 8) & 0xFF; + data[2] = TAG_DISPLAY_REPLY & 0xFF; + + switch(reply_id) { + case MMI_DISPLAY_REPLY_ID_MMI_MODE_ACK: + data[3] = 2; + data[4] = reply_id; + data[5] = details->u.mode_ack.mmi_mode; + iov[0].iov_base = data; + iov[0].iov_len = 6; + iov_count = 1; + break; + + case MMI_DISPLAY_REPLY_ID_LIST_DISPLAY_CHAR_TABLES: + case MMI_DISPLAY_REPLY_ID_LIST_INPUT_CHAR_TABLES: + if ((length_field_len = asn_1_encode(details->u.char_table.table_length+1, data+3, 3)) < 0) { + return -1; + } + data[3+length_field_len] = reply_id; + iov[0].iov_base = data; + iov[0].iov_len = 3+length_field_len+1; + iov[1].iov_base = details->u.char_table.table; + iov[1].iov_len = details->u.char_table.table_length; + iov_count = 2; + break; + + case MMI_DISPLAY_REPLY_ID_LIST_OVERLAY_GFX_CHARACTERISTICS: + case MMI_DISPLAY_REPLY_ID_LIST_FULLSCREEN_GFX_CHARACTERISTICS: + { + if ((length_field_len = asn_1_encode(1+9+(details->u.gfx.num_pixel_depths*2), data+3, 3)) < 0) { + return -1; + } + data[3+length_field_len] = reply_id; + data[3+length_field_len+1] = details->u.gfx.width >> 8; + data[3+length_field_len+2] = details->u.gfx.width; + data[3+length_field_len+3] = details->u.gfx.height >> 8; + data[3+length_field_len+4] = details->u.gfx.height; + data[3+length_field_len+5] = ((details->u.gfx.aspect_ratio & 0x0f) << 4) | + ((details->u.gfx.gfx_relation_to_video & 0x07) << 1) | + (details->u.gfx.multiple_depths & 1); + data[3+length_field_len+6] = details->u.gfx.display_bytes >> 4; + data[3+length_field_len+7] = ((details->u.gfx.display_bytes & 0x0f) << 4) | + ((details->u.gfx.composition_buffer_bytes & 0xf0) >> 4); + data[3+length_field_len+8] = ((details->u.gfx.composition_buffer_bytes & 0x0f) << 4) | + ((details->u.gfx.object_cache_bytes & 0xf0) >> 4); + data[3+length_field_len+9] = ((details->u.gfx.object_cache_bytes & 0x0f) << 4) | + (details->u.gfx.num_pixel_depths & 0x0f); + + // render the pixel depths themselves + uint8_t *pixdepths = alloca(details->u.gfx.num_pixel_depths * 2); + if (pixdepths == NULL) { + return -1; + } + uint32_t i; + for(i=0; i < details->u.gfx.num_pixel_depths; i++) { + pixdepths[0] = ((details->u.gfx.pixel_depths[i].display_depth & 0x07) << 5) | + ((details->u.gfx.pixel_depths[i].pixels_per_byte & 0x07) << 2); + pixdepths[1] = details->u.gfx.pixel_depths[i].region_overhead; + pixdepths+=2; + } + + // make up the iovs + iov[0].iov_base = data; + iov[0].iov_len = 3+length_field_len+10; + iov[1].iov_base = pixdepths; + iov[1].iov_len = details->u.gfx.num_pixel_depths *2; + iov_count = 2; + break; + } + + default: + data[3] = 1; + data[4] = reply_id; + iov[0].iov_base = data; + iov[0].iov_len = 5; + iov_count = 1; + break; + } + + // sendit + return private->funcs->send_datav(private->funcs->arg, session_number, iov, iov_count); +} + +int en50221_app_mmi_keypress(en50221_app_mmi mmi, + uint16_t session_number, + uint8_t keycode) +{ + struct en50221_app_mmi_private *private = (struct en50221_app_mmi_private *) mmi; + uint8_t data[5]; + + data[0] = (TAG_KEYPRESS >> 16) & 0xFF; + data[1] = (TAG_KEYPRESS >> 8) & 0xFF; + data[2] = TAG_KEYPRESS & 0xFF; + data[3] = 1; + data[4] = keycode; + return private->funcs->send_data(private->funcs->arg, session_number, data, 5); +} + +int en50221_app_mmi_display_message(en50221_app_mmi mmi, + uint16_t session_number, + uint8_t display_message_id) +{ + struct en50221_app_mmi_private *private = (struct en50221_app_mmi_private *) mmi; + uint8_t data[5]; + + data[0] = (TAG_DISPLAY_MESSAGE >> 16) & 0xFF; + data[1] = (TAG_DISPLAY_MESSAGE >> 8) & 0xFF; + data[2] = TAG_DISPLAY_MESSAGE & 0xFF; + data[3] = 1; + data[4] = display_message_id; + return private->funcs->send_data(private->funcs->arg, session_number, data, 5); +} + +int en50221_app_mmi_scene_done(en50221_app_mmi mmi, + uint16_t session_number, + uint8_t decoder_continue, + uint8_t scene_reveal, + uint8_t scene_tag) +{ + struct en50221_app_mmi_private *private = (struct en50221_app_mmi_private *) mmi; + uint8_t data[5]; + + data[0] = (TAG_SCENE_DONE >> 16) & 0xFF; + data[1] = (TAG_SCENE_DONE >> 8) & 0xFF; + data[2] = TAG_SCENE_DONE & 0xFF; + data[3] = 1; + data[4] = (decoder_continue ? 0x80 : 0x00) | + (scene_reveal ? 0x40 : 0x00) | + (scene_tag & 0x0f); + return private->funcs->send_data(private->funcs->arg, session_number, data, 5); +} + +int en50221_app_mmi_download_reply(en50221_app_mmi mmi, + uint16_t session_number, + uint16_t object_id, + uint8_t download_reply_id) +{ + struct en50221_app_mmi_private *private = (struct en50221_app_mmi_private *) mmi; + uint8_t data[7]; + + data[0] = (TAG_DOWNLOAD_REPLY >> 16) & 0xFF; + data[1] = (TAG_DOWNLOAD_REPLY >> 8) & 0xFF; + data[2] = TAG_DOWNLOAD_REPLY & 0xFF; + data[3] = 3; + data[4] = object_id >> 8; + data[5] = object_id; + data[6] = download_reply_id; + return private->funcs->send_data(private->funcs->arg, session_number, data, 7); +} + +int en50221_app_mmi_answ(en50221_app_mmi mmi, + uint16_t session_number, + uint8_t answ_id, + uint8_t *text, + uint32_t text_count) +{ + struct en50221_app_mmi_private *private = (struct en50221_app_mmi_private *) mmi; + uint8_t buf[10]; + + // set up the tag + buf[0] = (TAG_ANSWER >> 16) & 0xFF; + buf[1] = (TAG_ANSWER >> 8) & 0xFF; + buf[2] = TAG_ANSWER & 0xFF; + + // encode the length field + struct iovec iov[2]; + int length_field_len = 0; + int iov_count = 1; + if (answ_id == MMI_ANSW_ID_ANSWER) { + if ((length_field_len = asn_1_encode(text_count+1, buf+3, 3)) < 0) { + return -1; + } + buf[3+length_field_len] = answ_id; + + iov[0].iov_base = buf; + iov[0].iov_len = 3+length_field_len+1; + iov[1].iov_base = text; + iov[1].iov_len = text_count; + iov_count=2; + } else { + buf[3] = 1; + buf[4] = answ_id; + iov[0].iov_base = buf; + iov[0].iov_len = 5; + iov_count = 1; + } + + // create the data and send it + return private->funcs->send_datav(private->funcs->arg, session_number, iov, iov_count); +} + +int en50221_app_mmi_menu_answ(en50221_app_mmi mmi, + uint16_t session_number, + uint8_t choice_ref) +{ + struct en50221_app_mmi_private *private = (struct en50221_app_mmi_private *) mmi; + uint8_t data[5]; + + data[0] = (TAG_MENU_ANSWER >> 16) & 0xFF; + data[1] = (TAG_MENU_ANSWER >> 8) & 0xFF; + data[2] = TAG_MENU_ANSWER & 0xFF; + data[3] = 1; + data[4] = choice_ref; + return private->funcs->send_data(private->funcs->arg, session_number, data, 5); +} + +int en50221_app_mmi_message(en50221_app_mmi mmi, + uint8_t slot_id, + uint16_t session_number, + uint32_t resource_id, + uint8_t *data, uint32_t data_length) +{ + struct en50221_app_mmi_private *private = (struct en50221_app_mmi_private *) mmi; + (void) resource_id; + + // get the tag + if (data_length < 3) { + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + return -1; + } + uint32_t tag = (data[0] << 16) | (data[1] << 8) | data[2]; + + switch(tag) + { + case TAG_CLOSE_MMI: + return en50221_app_mmi_parse_close(private, slot_id, session_number, data+3, data_length-3); + case TAG_DISPLAY_CONTROL: + return en50221_app_mmi_parse_display_control(private, slot_id, session_number, data+3, data_length-3); + case TAG_KEYPAD_CONTROL: + return en50221_app_mmi_parse_keypad_control(private, slot_id, session_number, data+3, data_length-3); + case TAG_ENQUIRY: + return en50221_app_mmi_parse_enq(private, slot_id, session_number, data+3, data_length-3); + case TAG_MENU_LAST: + return en50221_app_mmi_parse_list_menu(private, slot_id, session_number, tag, 1, data+3, data_length-3); + case TAG_MENU_MORE: + return en50221_app_mmi_parse_list_menu(private, slot_id, session_number, tag, 0, data+3, data_length-3); + case TAG_LIST_LAST: + return en50221_app_mmi_parse_list_menu(private, slot_id, session_number, tag, 1, data+3, data_length-3); + case TAG_LIST_MORE: + return en50221_app_mmi_parse_list_menu(private, slot_id, session_number, tag, 0, data+3, data_length-3); + case TAG_SUBTITLE_SEGMENT_LAST: + return en50221_app_mmi_parse_subtitle(private, slot_id, session_number, tag, 1, data+3, data_length-3); + case TAG_SUBTITLE_SEGMENT_MORE: + return en50221_app_mmi_parse_subtitle(private, slot_id, session_number, tag, 0, data+3, data_length-3); + case TAG_SCENE_END_MARK: + return en50221_app_mmi_parse_scene_end_mark(private, slot_id, session_number, data+3, data_length-3); + case TAG_SCENE_CONTROL: + return en50221_app_mmi_parse_scene_control(private, slot_id, session_number, data+3, data_length-3); + case TAG_SUBTITLE_DOWNLOAD_LAST: + return en50221_app_mmi_parse_subtitle(private, slot_id, session_number, tag, 1, data+3, data_length-3); + case TAG_SUBTITLE_DOWNLOAD_MORE: + return en50221_app_mmi_parse_subtitle(private, slot_id, session_number, tag, 0, data+3, data_length-3); + case TAG_FLUSH_DOWNLOAD: + return en50221_app_mmi_parse_flush_download(private, slot_id, session_number, data+3, data_length-3); + } + + print(LOG_LEVEL, ERROR, 1, "Received unexpected tag %x\n", tag); + return -1; +} + + + + + +static int en50221_app_mmi_parse_close(struct en50221_app_mmi_private *private, + uint8_t slot_id, uint16_t session_number, + uint8_t *data, uint32_t data_length) +{ + // validate data + if (data_length < 2) { + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + return -1; + } + if (data[0] > (data_length-1)) { + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + return -1; + } + uint8_t cmd_id = data[1]; + uint8_t delay = 0; + if (cmd_id == MMI_CLOSE_MMI_CMD_ID_DELAY) { + if (data[0] != 2) { + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + return -1; + } + delay = data[2]; + } + + // tell the app + pthread_mutex_lock(&private->lock); + en50221_app_mmi_close_callback cb = private->closecallback; + void *cb_arg = private->closecallback_arg; + pthread_mutex_unlock(&private->lock); + if (cb) { + return cb(cb_arg, slot_id, session_number, cmd_id, delay); + } + return 0; +} + +static int en50221_app_mmi_parse_display_control(struct en50221_app_mmi_private *private, + uint8_t slot_id, uint16_t session_number, + uint8_t *data, uint32_t data_length) +{ + // validate data + if (data_length < 2) { + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + return -1; + } + if (data[0] > (data_length-1)) { + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + return -1; + } + uint8_t cmd_id = data[1]; + uint8_t mmi_mode = 0; + if (cmd_id == MMI_DISPLAY_CONTROL_CMD_ID_SET_MMI_MODE) { + if (data[0] != 2) { + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + return -1; + } + mmi_mode = data[2]; + } + + // tell the app + pthread_mutex_lock(&private->lock); + en50221_app_mmi_display_control_callback cb = private->displaycontrolcallback; + void *cb_arg = private->displaycontrolcallback_arg; + pthread_mutex_unlock(&private->lock); + if (cb) { + return cb(cb_arg, slot_id, session_number, cmd_id, mmi_mode); + } + return 0; +} + +static int en50221_app_mmi_parse_keypad_control(struct en50221_app_mmi_private *private, + uint8_t slot_id, uint16_t session_number, + uint8_t *data, uint32_t data_length) +{ + // first of all, decode the length field + uint16_t asn_data_length; + int length_field_len; + if ((length_field_len = asn_1_decode(&asn_data_length, data, data_length)) < 0) { + print(LOG_LEVEL, ERROR, 1, "ASN.1 decode error\n"); + return -1; + } + + // check it + if (asn_data_length > (data_length-length_field_len)) { + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + return -1; + } + if (asn_data_length < 1) { + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + return -1; + } + + // skip over the length field + data += length_field_len; + + // extract the information + uint8_t cmd_id = data[0]; + uint8_t *keycodes = data+1; + + // tell the app + pthread_mutex_lock(&private->lock); + en50221_app_mmi_keypad_control_callback cb = private->keypadcontrolcallback; + void *cb_arg = private->keypadcontrolcallback_arg; + pthread_mutex_unlock(&private->lock); + if (cb) { + return cb(cb_arg, slot_id, session_number, cmd_id, keycodes, asn_data_length-1); + } + return 0; +} + +static int en50221_app_mmi_parse_enq(struct en50221_app_mmi_private *private, + uint8_t slot_id, uint16_t session_number, + uint8_t *data, uint32_t data_length) +{ + // first of all, decode the length field + uint16_t asn_data_length; + int length_field_len; + if ((length_field_len = asn_1_decode(&asn_data_length, data, data_length)) < 0) { + print(LOG_LEVEL, ERROR, 1, "ASN.1 decode error\n"); + return -1; + } + + // check it + if (asn_data_length > (data_length-length_field_len)) { + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + return -1; + } + if (asn_data_length < 2) { + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + return -1; + } + + // skip over the length field + data += length_field_len; + + // extract the information + uint8_t blind_answer = (data[0] & 0x01) ? 1 : 0; + uint8_t answer_length = data[1]; + uint8_t *text = data+2; + + // tell the app + pthread_mutex_lock(&private->lock); + en50221_app_mmi_enq_callback cb = private->enqcallback; + void *cb_arg = private->enqcallback_arg; + pthread_mutex_unlock(&private->lock); + if (cb) { + return cb(cb_arg, slot_id, session_number, blind_answer, answer_length, text, asn_data_length - 2); + } + return 0; +} + +static int en50221_app_mmi_parse_list_menu(struct en50221_app_mmi_private *private, + uint8_t slot_id, uint16_t session_number, uint32_t tag_id, + int more_last, uint8_t *data, uint32_t data_length) +{ + int result = 0; + uint8_t *text_flags = NULL; + struct en50221_app_mmi_text *text_data = NULL; + uint32_t i; + uint8_t text_count = 0; + + // first of all, decode the length field + uint16_t asn_data_length; + int length_field_len; + if ((length_field_len = asn_1_decode(&asn_data_length, data, data_length)) < 0) { + print(LOG_LEVEL, ERROR, 1, "ASN.1 decode error\n"); + return -1; + } + + // check it + if (asn_data_length > (data_length-length_field_len)) { + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + return -1; + } + + // skip over the length field + data += length_field_len; + + // defragment + pthread_mutex_lock(&private->lock); + uint8_t *outdata; + uint32_t outdata_length; + int dfstatus = en50221_app_mmi_defragment(private, session_number, tag_id, more_last, + data, asn_data_length, + &outdata, &outdata_length); + if (dfstatus <= 0) { + pthread_mutex_unlock(&private->lock); + return dfstatus; + } + data = outdata; + data_length = outdata_length; + + // check the reassembled data length + if (data_length < 1) { + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + pthread_mutex_unlock(&private->lock); + result = -1; + goto exit_cleanup; + } + + // now, parse the data + uint8_t choice_nb = data[0]; + text_count = choice_nb + 3; + if (choice_nb == 0xff) text_count = 3; + data++; + data_length--; + + // variables for extracted text state + text_flags = alloca(text_count); + if (text_flags == NULL) { + pthread_mutex_unlock(&private->lock); + result = -1; + goto exit_cleanup; + } + memset(text_flags, 0, text_count); + text_data = (struct en50221_app_mmi_text*) alloca(sizeof(struct en50221_app_mmi_text) * text_count); + if (text_data == NULL) { + pthread_mutex_unlock(&private->lock); + result = -1; + goto exit_cleanup; + } + memset(text_data, 0, sizeof(struct en50221_app_mmi_text) * text_count); + + // extract the text! + for(i=0; i<text_count; i++) { + uint32_t consumed = 0; + int cur_status = en50221_app_mmi_defragment_text(data, data_length, + &text_data[i].text, &text_data[i].text_length, + &consumed); + if (cur_status < 0) { + pthread_mutex_unlock(&private->lock); + result = -1; + goto exit_cleanup; + } + + text_flags[i] = cur_status; + data += consumed; + data_length -= consumed; + } + + // work out what to pass to the user + struct en50221_app_mmi_text *text_data_for_user = + (struct en50221_app_mmi_text*) alloca(sizeof(struct en50221_app_mmi_text) * text_count); + if (text_data_for_user == NULL) { + result = -1; + goto exit_cleanup; + } + memcpy(text_data_for_user, text_data, sizeof(struct en50221_app_mmi_text) * text_count); + struct en50221_app_mmi_text *text_ptr = NULL; + if (text_count > 3) { + text_ptr = &text_data_for_user[3]; + } + uint8_t *items_raw = NULL; + uint32_t items_raw_length = 0; + if (choice_nb == 0xff) { + items_raw = data; + items_raw_length = data_length; + } + + // do callback + result = 0; + switch(tag_id) { + case TAG_MENU_LAST: + { + en50221_app_mmi_menu_callback cb = private->menucallback; + void *cb_arg = private->menucallback_arg; + pthread_mutex_unlock(&private->lock); + if (cb) { + result = cb(cb_arg, slot_id, session_number, + &text_data_for_user[0], + &text_data_for_user[1], + &text_data_for_user[2], + text_count-3, + text_ptr, + items_raw_length, + items_raw); + } + break; + } + + case TAG_LIST_LAST: + { + en50221_app_mmi_list_callback cb = private->listcallback; + void *cb_arg = private->listcallback_arg; + pthread_mutex_unlock(&private->lock); + if (cb) { + result = cb(cb_arg, slot_id, session_number, + &text_data_for_user[0], + &text_data_for_user[1], + &text_data_for_user[2], + text_count-3, + text_ptr, + items_raw_length, + items_raw); + } + break; + } + + default: + pthread_mutex_unlock(&private->lock); + break; + } + +exit_cleanup: + if ((dfstatus == 2) && outdata) free(outdata); + if (text_flags && text_data) { + for(i=0; i< text_count; i++) { + if ((text_flags[i] == 2) && text_data[i].text) { + free(text_data[i].text); + } + } + } + return result; +} + +static int en50221_app_mmi_parse_subtitle(struct en50221_app_mmi_private *private, + uint8_t slot_id, uint16_t session_number, uint32_t tag_id, + int more_last, uint8_t *data, uint32_t data_length) +{ + // first of all, decode the length field + uint16_t asn_data_length; + int length_field_len; + if ((length_field_len = asn_1_decode(&asn_data_length, data, data_length)) < 0) { + print(LOG_LEVEL, ERROR, 1, "ASN.1 decode error\n"); + return -1; + } + + // check it + if (asn_data_length > (data_length-length_field_len)) { + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + return -1; + } + + // skip over the length field + data += length_field_len; + + // defragment + pthread_mutex_lock(&private->lock); + uint8_t *outdata; + uint32_t outdata_length; + int dfstatus = en50221_app_mmi_defragment(private, session_number, tag_id, more_last, + data, asn_data_length, + &outdata, &outdata_length); + if (dfstatus <= 0) { + pthread_mutex_unlock(&private->lock); + return dfstatus; + } + + // do callback + int cbstatus = 0; + switch(tag_id) { + case TAG_SUBTITLE_SEGMENT_LAST: + { + en50221_app_mmi_subtitle_segment_callback cb = private->subtitlesegmentcallback; + void *cb_arg = private->subtitlesegmentcallback_arg; + pthread_mutex_unlock(&private->lock); + if (cb) { + cbstatus = cb(cb_arg, slot_id, session_number, outdata, outdata_length); + } + break; + } + + case TAG_SUBTITLE_DOWNLOAD_LAST: + { + en50221_app_mmi_subtitle_download_callback cb = private->subtitledownloadcallback; + void *cb_arg = private->subtitledownloadcallback_arg; + pthread_mutex_unlock(&private->lock); + if (cb) { + cbstatus = cb(cb_arg, slot_id, session_number, outdata, outdata_length); + } + break; + } + } + + // free the data returned by the defragment call if asked to + if (dfstatus == 2) { + free(outdata); + } + + // done + return cbstatus; +} + +static int en50221_app_mmi_parse_scene_end_mark(struct en50221_app_mmi_private *private, + uint8_t slot_id, uint16_t session_number, + uint8_t *data, uint32_t data_length) +{ + // validate data + if (data_length != 2) { + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + return -1; + } + if (data[0] != 1) { + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + return -1; + } + uint8_t flags = data[1]; + + // tell the app + pthread_mutex_lock(&private->lock); + en50221_app_mmi_scene_end_mark_callback cb = private->sceneendmarkcallback; + void *cb_arg = private->sceneendmarkcallback_arg; + pthread_mutex_unlock(&private->lock); + if (cb) { + return cb(cb_arg, slot_id, session_number, + (flags & 0x80) ? 1 : 0, + (flags & 0x40) ? 1 : 0, + (flags & 0x20) ? 1 : 0, + flags & 0x0f); + } + return 0; +} + +static int en50221_app_mmi_parse_scene_control(struct en50221_app_mmi_private *private, + uint8_t slot_id, uint16_t session_number, + uint8_t *data, uint32_t data_length) +{ + // validate data + if (data_length != 2) { + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + return -1; + } + if (data[0] != 1) { + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + return -1; + } + uint8_t flags = data[1]; + + // tell the app + pthread_mutex_lock(&private->lock); + en50221_app_mmi_scene_control_callback cb = private->scenecontrolcallback; + void *cb_arg = private->scenecontrolcallback_arg; + pthread_mutex_unlock(&private->lock); + if (cb) { + return cb(cb_arg, slot_id, session_number, + (flags & 0x80) ? 1 : 0, + (flags & 0x40) ? 1 : 0, + flags & 0x0f); + } + return 0; +} + +static int en50221_app_mmi_parse_flush_download(struct en50221_app_mmi_private *private, + uint8_t slot_id, uint16_t session_number, + uint8_t *data, uint32_t data_length) +{ + // validate data + if (data_length != 1) { + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + return -1; + } + if (data[0] != 0) { + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + return -1; + } + + // tell the app + pthread_mutex_lock(&private->lock); + en50221_app_mmi_flush_download_callback cb = private->flushdownloadcallback; + void *cb_arg = private->flushdownloadcallback_arg; + pthread_mutex_unlock(&private->lock); + if (cb) { + return cb(cb_arg, slot_id, session_number); + } + return 0; +} + +static int en50221_app_mmi_defragment(struct en50221_app_mmi_private *private, + uint16_t session_number, + uint32_t tag_id, + int more_last, + uint8_t *indata, + uint32_t indata_length, + uint8_t **outdata, + uint32_t *outdata_length) +{ + struct en50221_app_mmi_session *cur_s = private->sessions; + while(cur_s) { + if (cur_s->session_number == session_number) + break; + cur_s=cur_s->next; + } + + // more data is still to come + if (!more_last) { + // if there was no previous session, create one + if (cur_s == NULL) { + cur_s = malloc(sizeof(struct en50221_app_mmi_session)); + if (cur_s == NULL) { + print(LOG_LEVEL, ERROR, 1, "Ran out of memory\n"); + return -1; + } + cur_s->session_number = session_number; + cur_s->menu_block_chain = NULL; + cur_s->menu_block_length = 0; + cur_s->list_block_chain = NULL; + cur_s->list_block_length = 0; + cur_s->subtitlesegment_block_chain = NULL; + cur_s->subtitlesegment_block_length = 0; + cur_s->subtitledownload_block_chain = NULL; + cur_s->subtitledownload_block_length = 0; + cur_s->next = private->sessions; + private->sessions = cur_s; + } + + // find the block/block_length to use + uint8_t **block_chain; + uint32_t *block_length; + switch(tag_id) { + case TAG_MENU_LAST: + case TAG_MENU_MORE: + block_chain = &cur_s->menu_block_chain; + block_length = &cur_s->menu_block_length; + break; + case TAG_LIST_LAST: + case TAG_LIST_MORE: + block_chain = &cur_s->list_block_chain; + block_length = &cur_s->list_block_length; + break; + case TAG_SUBTITLE_SEGMENT_LAST: + case TAG_SUBTITLE_SEGMENT_MORE: + block_chain = &cur_s->subtitlesegment_block_chain; + block_length = &cur_s->subtitlesegment_block_length; + break; + case TAG_SUBTITLE_DOWNLOAD_LAST: + case TAG_SUBTITLE_DOWNLOAD_MORE: + block_chain = &cur_s->subtitledownload_block_chain; + block_length = &cur_s->subtitledownload_block_length; + break; + default: + return -1; + } + + // append the data + uint8_t *new_data = realloc(*block_chain, *block_length + indata_length); + if (new_data == NULL) { + print(LOG_LEVEL, ERROR, 1, "Ran out of memory\n"); + return -1; + } + memcpy(new_data + *block_length, indata, indata_length); + *block_chain = new_data; + *block_length += indata_length; + + // success, but block not complete yet + return 0; + } + + // we hit the last of a possible chain of fragments + if (cur_s != NULL) { + // find the block/block_length to use + uint8_t **block_chain; + uint32_t *block_length; + switch(tag_id) { + case TAG_MENU_LAST: + case TAG_MENU_MORE: + block_chain = &cur_s->menu_block_chain; + block_length = &cur_s->menu_block_length; + break; + case TAG_LIST_LAST: + case TAG_LIST_MORE: + block_chain = &cur_s->list_block_chain; + block_length = &cur_s->list_block_length; + break; + case TAG_SUBTITLE_SEGMENT_LAST: + case TAG_SUBTITLE_SEGMENT_MORE: + block_chain = &cur_s->subtitlesegment_block_chain; + block_length = &cur_s->subtitlesegment_block_length; + break; + case TAG_SUBTITLE_DOWNLOAD_LAST: + case TAG_SUBTITLE_DOWNLOAD_MORE: + block_chain = &cur_s->subtitledownload_block_chain; + block_length = &cur_s->subtitledownload_block_length; + break; + default: + return -1; + } + + // we have a preceding fragment - need to append + uint8_t *new_data = realloc(*block_chain, *block_length + indata_length); + if (new_data == NULL) { + print(LOG_LEVEL, ERROR, 1, "Ran out of memory\n"); + return -1; + } + memcpy(new_data + *block_length, indata, indata_length); + *outdata_length = *block_length + indata_length; + *outdata = new_data; + *block_chain = NULL; + *block_length = 0; + + // success, and indicate to free the block when done + return 2; + } + + // success, but indicate it is not to be freed + *outdata_length = indata_length; + *outdata = indata; + return 1; +} + +static int en50221_app_mmi_defragment_text(uint8_t *data, + uint32_t data_length, + uint8_t **outdata, + uint32_t *outdata_length, + uint32_t *outconsumed) +{ + uint8_t *text = NULL; + uint32_t text_length = 0; + uint32_t consumed = 0; + + while(1) { + // get the tag + if (data_length < 3) { + print(LOG_LEVEL, ERROR, 1, "Short data\n"); + if (text) free(text); + return -1; + } + uint32_t tag = (data[0] << 16) | (data[1] << 8) | data[2]; + data += 3; + data_length -=3; + consumed += 3; + + // get the length of the data and adjust + uint16_t asn_data_length; + int length_field_len; + if ((length_field_len = asn_1_decode(&asn_data_length, data, data_length)) < 0) { + print(LOG_LEVEL, ERROR, 1, "ASN.1 decode error\n"); + if (text) free(text); + return -1; + } + data += length_field_len; + data_length -= length_field_len; + consumed += length_field_len; + + // deal with the tags + if (tag == TAG_TEXT_LAST) { + if (text == NULL) { + *outdata = data; + *outdata_length = asn_data_length; + *outconsumed = consumed + asn_data_length; + return 1; + } else { + // append the data + uint8_t *new_text = realloc(text, text_length + asn_data_length); + if (new_text == NULL) { + print(LOG_LEVEL, ERROR, 1, "Ran out of memory\n"); + if (text) free(text); + return -1; + } + memcpy(new_text + text_length, data, asn_data_length); + *outdata = new_text; + *outdata_length = text_length + asn_data_length; + *outconsumed = consumed + asn_data_length; + return 2; + } + + } else if (tag == TAG_TEXT_MORE) { + // append the data + uint8_t *new_text = realloc(text, text_length + asn_data_length); + if (new_text == NULL) { + print(LOG_LEVEL, ERROR, 1, "Ran out of memory\n"); + if (text) free(text); + return -1; + } + memcpy(new_text + text_length, data, asn_data_length); + text = new_text; + text_length += asn_data_length; + + // consume the data + data += asn_data_length; + data_length -= asn_data_length; + consumed += asn_data_length; + } else { + // unknown tag + print(LOG_LEVEL, ERROR, 1, "Unknown MMI text tag\n"); + if (text) free(text); + return -1; + } + } +} diff --git a/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_mmi.h b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_mmi.h new file mode 100644 index 0000000..b5e3abf --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_mmi.h @@ -0,0 +1,571 @@ +/* + en50221 encoder An implementation for libdvb + an implementation for the en50221 transport layer + + Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com) + Copyright (C) 2005 Julian Scheel (julian at jusst dot de) + Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net) + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of + the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef __EN50221_APPLICATION_mmi_H__ +#define __EN50221_APPLICATION_mmi_H__ + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <stdlib.h> +#include <stdint.h> +#include <libdvben50221/en50221_app_utils.h> + +#define EN50221_APP_MMI_RESOURCEID MKRID(64,1,1) + +#define MMI_CLOSE_MMI_CMD_ID_IMMEDIATE 0x00 +#define MMI_CLOSE_MMI_CMD_ID_DELAY 0x01 + +#define MMI_DISPLAY_CONTROL_CMD_ID_SET_MMI_MODE 0x01 +#define MMI_DISPLAY_CONTROL_CMD_ID_GET_DISPLAY_CHAR_TABLES 0x02 +#define MMI_DISPLAY_CONTROL_CMD_ID_GET_INPUT_CHAR_TABLES 0x03 +#define MMI_DISPLAY_CONTROL_CMD_ID_GET_OVERLAY_GFX_CHARACTERISTICS 0x04 +#define MMI_DISPLAY_CONTROL_CMD_ID_GET_FULLSCREEN_GFX_CHARACTERISTICS 0x05 + +#define MMI_DISPLAY_REPLY_ID_MMI_MODE_ACK 0x01 +#define MMI_DISPLAY_REPLY_ID_LIST_DISPLAY_CHAR_TABLES 0x02 +#define MMI_DISPLAY_REPLY_ID_LIST_INPUT_CHAR_TABLES 0x03 +#define MMI_DISPLAY_REPLY_ID_LIST_OVERLAY_GFX_CHARACTERISTICS 0x04 +#define MMI_DISPLAY_REPLY_ID_LIST_FULLSCREEN_GFX_CHARACTERISTICS 0x05 +#define MMI_DISPLAY_REPLY_ID_UNKNOWN_CMD_ID 0xF0 +#define MMI_DISPLAY_REPLY_ID_UNKNOWN_MMI_MODE 0xF1 +#define MMI_DISPLAY_REPLY_ID_UNKNOWN_CHAR_TABLE 0xF2 + +#define MMI_MODE_HIGH_LEVEL 0x01 +#define MMI_MODE_LOW_LEVEL_OVERLAY_GFX 0x02 +#define MMI_MODE_LOW_LEVEL_FULLSCREEN_GFX 0x03 + +#define MMI_KEYPAD_CONTROL_CMD_ID_INTERCEPT_ALL 0x01 +#define MMI_KEYPAD_CONTROL_CMD_ID_IGNORE_ALL 0x02 +#define MMI_KEYPAD_CONTROL_CMD_ID_INTERCEPT_SELECTED 0x03 +#define MMI_KEYPAD_CONTROL_CMD_ID_IGNORE_SELECTED 0x04 +#define MMI_KEYPAD_CONTROL_CMD_ID_REJECT_KEYPRESS 0x05 + +#define MMI_GFX_VIDEO_RELATION_NONE 0x00 +#define MMI_GFX_VIDEO_RELATION_MATCHES_EXACTLY 0x07 + +#define MMI_DISPLAY_MESSAGE_ID_OK 0x00 +#define MMI_DISPLAY_MESSAGE_ID_ERROR 0x01 +#define MMI_DISPLAY_MESSAGE_ID_OUT_OF_MEMORY 0x02 +#define MMI_DISPLAY_MESSAGE_ID_SUBTITLE_SYNTAX_ERROR 0x03 +#define MMI_DISPLAY_MESSAGE_ID_UNDEFINED_REGION 0x04 +#define MMI_DISPLAY_MESSAGE_ID_UNDEFINED_CLUT 0x05 +#define MMI_DISPLAY_MESSAGE_ID_UNDEFINED_OBJECT 0x06 +#define MMI_DISPLAY_MESSAGE_ID_INCOMPATABLE_OBJECT 0x07 +#define MMI_DISPLAY_MESSAGE_ID_UNKNOWN_CHARACTER 0x08 +#define MMI_DISPLAY_MESSAGE_ID_DISPLAY_CHANGED 0x09 + +#define MMI_DOWNLOAD_REPLY_ID_OK 0x00 +#define MMI_DOWNLOAD_REPLY_ID_NOT_OBJECT_SEGMENT 0x01 +#define MMI_DOWNLOAD_REPLY_ID_OUT_OF_MEMORY 0x02 + +#define MMI_ANSW_ID_CANCEL 0x00 +#define MMI_ANSW_ID_ANSWER 0x01 + +/** + * A pixel depth as supplied with display_reply details + */ +struct en50221_app_mmi_pixel_depth { + uint8_t display_depth; + uint8_t pixels_per_byte; + uint8_t region_overhead; +}; + +/** + * Details returned with a display_reply + */ +struct en502221_app_mmi_display_reply_details { + union { + struct { + uint16_t width; + uint16_t height; + uint8_t aspect_ratio; + uint8_t gfx_relation_to_video; /* one of MMI_GFX_VIDEO_RELATION_* */ + uint8_t multiple_depths; + uint16_t display_bytes; + uint8_t composition_buffer_bytes; + uint8_t object_cache_bytes; + uint8_t num_pixel_depths; + struct en50221_app_mmi_pixel_depth *pixel_depths; + } gfx; /* MMI_DISPLAY_REPLY_ID_LIST_OVERLAY_GFX_CHARACTERISTICS or + MMI_DISPLAY_REPLY_ID_LIST_FULLSCREEN_GFX_CHARACTERISTICS */ + + struct { + uint32_t table_length; + uint8_t *table; + } char_table; /* MMI_DISPLAY_REPLY_ID_LIST_DISPLAY_CHAR_TABLES or + MMI_DISPLAY_REPLY_ID_LIST_INPUT_CHAR_TABLES */ + + struct { + uint8_t mmi_mode; /* one of the MMI_MODE_* values */ + } mode_ack; /* for MMI_DISPLAY_REPLY_ID_MMI_MODE_ACK */ + } u; +}; + +/** + * Pointer to a text string. + */ +struct en50221_app_mmi_text { + uint8_t *text; + uint32_t text_length; +}; + +/** + * Type definition for close - called when we receive an mmi_close from a CAM. + * + * @param arg Private argument. + * @param slot_id Slot id concerned. + * @param session_number Session number concerned. + * @param cmd_id One of the MMI_CLOSE_MMI_CMD_ID_* values. + * @param delay Delay supplied with MMI_CLOSE_MMI_CMD_ID_DELAY. + * @return 0 on success, -1 on failure. + */ +typedef int (*en50221_app_mmi_close_callback)(void *arg, uint8_t slot_id, uint16_t session_number, + uint8_t cmd_id, uint8_t delay); + +/** + * Type definition for display_control callback. + * + * @param arg Private argument. + * @param slot_id Slot id concerned. + * @param session_number Session number concerned. + * @param cmd_id One of the MMI_DISPLAY_CONTROL_CMD_ID_* values. + * @param delay One of the MMI_MODE_* values. + * @return 0 on success, -1 on failure. + */ +typedef int (*en50221_app_mmi_display_control_callback)(void *arg, uint8_t slot_id, uint16_t session_number, + uint8_t cmd_id, uint8_t mmi_mode); + +/** + * Type definition for keypad_control callback. + * + * @param arg Private argument. + * @param slot_id Slot id concerned. + * @param session_number Session number concerned. + * @param cmd_id One of the MMI_KEYPAD_CONTROL_CMD_ID_* values. + * @param key_codes Pointer to the key codes. + * @param key_codes_count Number of key codes. + * @return 0 on success, -1 on failure. + */ +typedef int (*en50221_app_mmi_keypad_control_callback)(void *arg, uint8_t slot_id, uint16_t session_number, + uint8_t cmd_id, uint8_t *key_codes, uint32_t key_codes_count); + +/** + * Type definition for subtitle_segment callback. + * + * @param arg Private argument. + * @param slot_id Slot id concerned. + * @param session_number Session number concerned. + * @param segment Pointer to the segment data. + * @param segment_size Size of segment data. + * @return 0 on success, -1 on failure. + */ +typedef int (*en50221_app_mmi_subtitle_segment_callback)(void *arg, uint8_t slot_id, uint16_t session_number, + uint8_t *segment, uint32_t segment_size); + +/** + * Type definition for scene_end_mark callback. + * + * @param arg Private argument. + * @param slot_id Slot id concerned. + * @param session_number Session number concerned. + * @param decoder_continue_flag + * @param scene_reveal_flag + * @param send_scene_done + * @param scene_tag + * @return 0 on success, -1 on failure. + */ +typedef int (*en50221_app_mmi_scene_end_mark_callback)(void *arg, uint8_t slot_id, uint16_t session_number, + uint8_t decoder_continue_flag, uint8_t scene_reveal_flag, + uint8_t send_scene_done, uint8_t scene_tag); + +/** + * Type definition for scene_control callback. + * + * @param arg Private argument. + * @param slot_id Slot id concerned. + * @param session_number Session number concerned. + * @param decoder_continue_flag + * @param scene_reveal_flag + * @param scene_tag + * @return 0 on success, -1 on failure. + */ +typedef int (*en50221_app_mmi_scene_control_callback)(void *arg, uint8_t slot_id, uint16_t session_number, + uint8_t decoder_continue_flag, uint8_t scene_reveal_flag, + uint8_t scene_tag); + +/** + * Type definition for subtitle_download callback. + * + * @param arg Private argument. + * @param slot_id Slot id concerned. + * @param session_number Session number concerned. + * @param segment Pointer to the segment data. + * @param segment_size Size of segment data. + * @return 0 on success, -1 on failure. + */ +typedef int (*en50221_app_mmi_subtitle_download_callback)(void *arg, uint8_t slot_id, uint16_t session_number, + uint8_t *segment, uint32_t segment_size); + +/** + * Type definition for flush_download callback. + * + * @param arg Private argument. + * @param slot_id Slot id concerned. + * @param session_number Session number concerned. + * @return 0 on success, -1 on failure. + */ +typedef int (*en50221_app_mmi_flush_download_callback)(void *arg, uint8_t slot_id, uint16_t session_number); + +/** + * Type definition for enq callback. + * + * @param arg Private argument. + * @param slot_id Slot id concerned. + * @param session_number Session number concerned. + * @param blind_answer 1=>Obscure text input in some manner, + * @param expected_answer_length Expected max number of characters to be returned. + * @param text Pointer to the text data. + * @param text_size Size of text data. + * @return 0 on success, -1 on failure. + */ +typedef int (*en50221_app_mmi_enq_callback)(void *arg, uint8_t slot_id, uint16_t session_number, + uint8_t blind_answer, uint8_t expected_answer_length, + uint8_t *text, uint32_t text_size); + +/** + * Type definition for menu callback. + * + * @param arg Private argument. + * @param slot_id Slot id concerned. + * @param session_number Session number concerned. + * @param title Title text. + * @param sub_title Sub-Title text. + * @param bottom Bottom text. + * @param item_count Number of text elements in items. + * @param items Pointer to array of en50221_app_mmi_text structures which are standard menu choices, + * @param item_raw_length Length of item raw data. + * @param items_raw If nonstandard items were supplied, pointer to their data. + * @return 0 on success, -1 on failure. + */ +typedef int (*en50221_app_mmi_menu_callback)(void *arg, uint8_t slot_id, uint16_t session_number, + struct en50221_app_mmi_text *title, + struct en50221_app_mmi_text *sub_title, + struct en50221_app_mmi_text *bottom, + uint32_t item_count, struct en50221_app_mmi_text *items, + uint32_t item_raw_length, uint8_t *items_raw); + +/** + * Type definition for list callback. + * + * @param arg Private argument. + * @param slot_id Slot id concerned. + * @param session_number Session number concerned. + * @param title Title text. + * @param sub_title Sub-Title text. + * @param bottom Bottom text. + * @param item_count Number of text elements in items. + * @param items Pointer to array of en50221_app_mmi_text structures which are standard menu choices, + * @param item_raw_length Length of item raw data. + * @param items_raw If nonstandard items were supplied, pointer to their data. + * @return 0 on success, -1 on failure. + */ +typedef int (*en50221_app_mmi_list_callback)(void *arg, uint8_t slot_id, uint16_t session_number, + struct en50221_app_mmi_text *title, + struct en50221_app_mmi_text *sub_title, + struct en50221_app_mmi_text *bottom, + uint32_t item_count, struct en50221_app_mmi_text *items, + uint32_t item_raw_length, uint8_t *items_raw); + +/** + * Opaque type representing a mmi resource. + */ +typedef void *en50221_app_mmi; + +/** + * Create an instance of the mmi resource. + * + * @param funcs Send functions to use. + * @return Instance, or NULL on failure. + */ +extern en50221_app_mmi en50221_app_mmi_create(struct en50221_app_send_functions *funcs); + +/** + * Destroy an instance of the mmi resource. + * + * @param mmi Instance to destroy. + */ +extern void en50221_app_mmi_destroy(en50221_app_mmi mmi); + +/** + * Informs the mmi object that a session to it has been closed - cleans up internal state. + * + * @param mmi mmi resource instance. + * @param session_number The session concerned. + */ +extern void en50221_app_mmi_clear_session(en50221_app_mmi mmi, uint16_t session_number); + +/** + * Register the callback for when we receive an mmi_close request. + * + * @param mmi mmi resource instance. + * @param callback The callback. Set to NULL to remove the callback completely. + * @param arg Private data passed as arg0 of the callback. + */ +extern void en50221_app_mmi_register_close_callback(en50221_app_mmi mmi, + en50221_app_mmi_close_callback callback, void *arg); + +/** + * Register the callback for when we receive a display control request. + * + * @param mmi mmi resource instance. + * @param callback The callback. Set to NULL to remove the callback completely. + * @param arg Private data passed as arg0 of the callback. + */ +extern void en50221_app_mmi_register_display_control_callback(en50221_app_mmi mmi, + en50221_app_mmi_display_control_callback callback, void *arg); + +/** + * Register the callback for when we receive a keypad control request. + * + * @param mmi mmi resource instance. + * @param callback The callback. Set to NULL to remove the callback completely. + * @param arg Private data passed as arg0 of the callback. + */ +extern void en50221_app_mmi_register_keypad_control_callback(en50221_app_mmi mmi, + en50221_app_mmi_keypad_control_callback callback, void *arg); + +/** + * Register the callback for when we receive a subtitle segment request. + * + * @param mmi mmi resource instance. + * @param callback The callback. Set to NULL to remove the callback completely. + * @param arg Private data passed as arg0 of the callback. + */ +extern void en50221_app_mmi_register_subtitle_segment_callback(en50221_app_mmi mmi, + en50221_app_mmi_subtitle_segment_callback callback, void *arg); + +/** + * Register the callback for when we receive a scene end mark request. + * + * @param mmi mmi resource instance. + * @param callback The callback. Set to NULL to remove the callback completely. + * @param arg Private data passed as arg0 of the callback. + */ +extern void en50221_app_mmi_register_scene_end_mark_callback(en50221_app_mmi mmi, + en50221_app_mmi_scene_end_mark_callback callback, void *arg); + +/** + * Register the callback for when we receive a scene control request. + * + * @param mmi mmi resource instance. + * @param callback The callback. Set to NULL to remove the callback completely. + * @param arg Private data passed as arg0 of the callback. + */ +extern void en50221_app_mmi_register_scene_control_callback(en50221_app_mmi mmi, + en50221_app_mmi_scene_control_callback callback, void *arg); + +/** + * Register the callback for when we receive a subtitle download request. + * + * @param mmi mmi resource instance. + * @param callback The callback. Set to NULL to remove the callback completely. + * @param arg Private data passed as arg0 of the callback. + */ +extern void en50221_app_mmi_register_subtitle_download_callback(en50221_app_mmi mmi, + en50221_app_mmi_subtitle_download_callback callback, void *arg); + +/** + * Register the callback for when we receive a flush download request. + * + * @param mmi mmi resource instance. + * @param callback The callback. Set to NULL to remove the callback completely. + * @param arg Private data passed as arg0 of the callback. + */ +extern void en50221_app_mmi_register_flush_download_callback(en50221_app_mmi mmi, + en50221_app_mmi_flush_download_callback callback, void *arg); + +/** + * Register the callback for when we receive an enq request. + * + * @param mmi mmi resource instance. + * @param callback The callback. Set to NULL to remove the callback completely. + * @param arg Private data passed as arg0 of the callback. + */ +extern void en50221_app_mmi_register_enq_callback(en50221_app_mmi mmi, + en50221_app_mmi_enq_callback callback, void *arg); + +/** + * Register the callback for when we receive a menu request. + * + * @param mmi mmi resource instance. + * @param callback The callback. Set to NULL to remove the callback completely. + * @param arg Private data passed as arg0 of the callback. + */ +extern void en50221_app_mmi_register_menu_callback(en50221_app_mmi mmi, + en50221_app_mmi_menu_callback callback, void *arg); + +/** + * Register the callback for when we receive a list request. + * + * @param mmi mmi resource instance. + * @param callback The callback. Set to NULL to remove the callback completely. + * @param arg Private data passed as arg0 of the callback. + */ +extern void en50221_app_mmi_register_list_callback(en50221_app_mmi mmi, + en50221_app_mmi_list_callback callback, void *arg); + +/** + * Send an mmi_close to the cam. + * + * @param mmi mmi resource instance. + * @param session_number Session number to send it on. + * @param cmd_id One of the MMI_CLOSE_MMI_CMD_ID_* values. + * @param delay Delay to use if MMI_CLOSE_MMI_CMD_ID_DELAY specified. + * @return 0 on success, -1 on failure. + */ +extern int en50221_app_mmi_close(en50221_app_mmi mmi, + uint16_t session_number, + uint8_t cmd_id, + uint8_t delay); + +/** + * Send a display_reply to the cam. + * + * @param mmi mmi resource instance. + * @param session_number Session number to send it on. + * @param reply_id One of the MMI_DISPLAY_REPLY_ID_* values. + * @param details The details of the reply - can be NULL if the chosen reply_id does not need it. + * @return 0 on success, -1 on failure. + */ +extern int en50221_app_mmi_display_reply(en50221_app_mmi mmi, + uint16_t session_number, + uint8_t reply_id, + struct en502221_app_mmi_display_reply_details *details); + +/** + * Send a keypress to the cam. + * + * @param mmi mmi resource instance. + * @param session_number Session number to send it on. + * @param keycode The keycode. + * @return 0 on success, -1 on failure. + */ +extern int en50221_app_mmi_keypress(en50221_app_mmi mmi, + uint16_t session_number, + uint8_t keycode); + +/** + * Send a display message to the cam. + * + * @param mmi mmi resource instance. + * @param session_number Session number to send it on. + * @param display_message_id One of the MMI_DISPLAY_MESSAGE_ID_* values. + * @return 0 on success, -1 on failure. + */ +extern int en50221_app_mmi_display_message(en50221_app_mmi mmi, + uint16_t session_number, + uint8_t display_message_id); + +/** + * Send a scene done message to the cam. + * + * @param mmi mmi resource instance. + * @param session_number Session number to send it on. + * @param decoder_continue Copy of flag in scene_end_mark. + * @param scene_reveal Copy of flag in scene_end_mark. + * @param scene_tag Scene tag this responds to. + * @return 0 on success, -1 on failure. + */ +extern int en50221_app_mmi_scene_done(en50221_app_mmi mmi, + uint16_t session_number, + uint8_t decoder_continue, + uint8_t scene_reveal, + uint8_t scene_tag); + +/** + * Send a download reply to the cam. + * + * @param mmi mmi resource instance. + * @param session_number Session number to send it on. + * @param object_id Object id. + * @param download_reply_id One of the MMI_DOWNLOAD_REPLY_ID_* values. + * @return 0 on success, -1 on failure. + */ +extern int en50221_app_mmi_download_reply(en50221_app_mmi mmi, + uint16_t session_number, + uint16_t object_id, + uint8_t download_reply_id); + +/** + * Send an answ to the cam. + * + * @param mmi mmi resource instance. + * @param session_number Session number to send it on. + * @param answ_id One of the MMI_ANSW_ID_* values. + * @param text The text if MMI_ANSW_ID_ANSWER. + * @param text_count Length of text. + * @return 0 on success, -1 on failure. + */ +extern int en50221_app_mmi_answ(en50221_app_mmi mmi, + uint16_t session_number, + uint8_t answ_id, + uint8_t *text, + uint32_t text_count); + +/** + * Send a menu answ to the cam. + * + * @param mmi mmi resource instance. + * @param session_number Session number to send it on. + * @param choice_ref Option chosen by user (0=>canceled). + * @return 0 on success, -1 on failure. + */ +extern int en50221_app_mmi_menu_answ(en50221_app_mmi mmi, + uint16_t session_number, + uint8_t choice_ref); + +/** + * Pass data received for this resource into it for parsing. + * + * @param mmi mmi instance. + * @param slot_id Slot ID concerned. + * @param session_number Session number concerned. + * @param resource_id Resource ID concerned. + * @param data The data. + * @param data_length Length of data in bytes. + * @return 0 on success, -1 on failure. + */ +extern int en50221_app_mmi_message(en50221_app_mmi mmi, + uint8_t slot_id, + uint16_t session_number, + uint32_t resource_id, + uint8_t *data, uint32_t data_length); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_rm.c b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_rm.c new file mode 100644 index 0000000..7c57aba --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_rm.c @@ -0,0 +1,294 @@ +/* + en50221 encoder An implementation for libdvb + an implementation for the en50221 transport layer + + Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com) + Copyright (C) 2005 Julian Scheel (julian at jusst dot de) + Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net) + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of + the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include <string.h> +#include <libdvbmisc/dvbmisc.h> +#include <pthread.h> +#include <libucsi/endianops.h> +#include "en50221_app_rm.h" +#include "en50221_app_tags.h" +#include "asn_1.h" + +struct en50221_app_rm_private { + struct en50221_app_send_functions *funcs; + + en50221_app_rm_enq_callback enqcallback; + void *enqcallback_arg; + + en50221_app_rm_reply_callback replycallback; + void *replycallback_arg; + + en50221_app_rm_changed_callback changedcallback; + void *changedcallback_arg; + + pthread_mutex_t lock; +}; + +static int en50221_app_rm_parse_profile_enq(struct en50221_app_rm_private *private, + uint8_t slot_id, uint16_t session_number, + uint8_t *data, uint32_t data_length); +static int en50221_app_rm_parse_profile_reply(struct en50221_app_rm_private *private, + uint8_t slot_id, uint16_t session_number, + uint8_t *data, uint32_t data_length); +static int en50221_app_rm_parse_profile_change(struct en50221_app_rm_private *private, + uint8_t slot_id, uint16_t session_number, + uint8_t *data, uint32_t data_length); + + +en50221_app_rm en50221_app_rm_create(struct en50221_app_send_functions *funcs) +{ + struct en50221_app_rm_private *private = NULL; + + // create structure and set it up + private = malloc(sizeof(struct en50221_app_rm_private)); + if (private == NULL) { + return NULL; + } + private->funcs = funcs; + private->enqcallback = NULL; + private->replycallback = NULL; + private->changedcallback = NULL; + + pthread_mutex_init(&private->lock, NULL); + + // done + return private; +} + +void en50221_app_rm_destroy(en50221_app_rm rm) +{ + struct en50221_app_rm_private *private = (struct en50221_app_rm_private *) rm; + + pthread_mutex_destroy(&private->lock); + free(private); +} + +void en50221_app_rm_register_enq_callback(en50221_app_rm rm, + en50221_app_rm_enq_callback callback, void *arg) +{ + struct en50221_app_rm_private *private = (struct en50221_app_rm_private *) rm; + + pthread_mutex_lock(&private->lock); + private->enqcallback = callback; + private->enqcallback_arg = arg; + pthread_mutex_unlock(&private->lock); +} + +void en50221_app_rm_register_reply_callback(en50221_app_rm rm, + en50221_app_rm_reply_callback callback, void *arg) +{ + struct en50221_app_rm_private *private = (struct en50221_app_rm_private *) rm; + + pthread_mutex_lock(&private->lock); + private->replycallback = callback; + private->replycallback_arg = arg; + pthread_mutex_unlock(&private->lock); +} + +void en50221_app_rm_register_changed_callback(en50221_app_rm rm, + en50221_app_rm_changed_callback callback, void *arg) +{ + struct en50221_app_rm_private *private = (struct en50221_app_rm_private *) rm; + + pthread_mutex_lock(&private->lock); + private->changedcallback = callback; + private->changedcallback_arg = arg; + pthread_mutex_unlock(&private->lock); +} + +int en50221_app_rm_enq(en50221_app_rm rm, uint16_t session_number) +{ + struct en50221_app_rm_private *private = (struct en50221_app_rm_private *) rm; + uint8_t buf[4]; + + // set up the tag + buf[0] = (TAG_PROFILE_ENQUIRY >> 16) & 0xFF; + buf[1] = (TAG_PROFILE_ENQUIRY >> 8) & 0xFF; + buf[2] = TAG_PROFILE_ENQUIRY & 0xFF; + buf[3] = 0; + + // create the data and send it + return private->funcs->send_data(private->funcs->arg, session_number, buf, 4); +} + +int en50221_app_rm_reply(en50221_app_rm rm, uint16_t session_number, + uint32_t resource_id_count, + uint32_t *resource_ids) +{ + struct en50221_app_rm_private *private = (struct en50221_app_rm_private *) rm; + uint8_t buf[10]; + + // set up the tag + buf[0] = (TAG_PROFILE >> 16) & 0xFF; + buf[1] = (TAG_PROFILE >> 8) & 0xFF; + buf[2] = TAG_PROFILE & 0xFF; + + // encode the length field + int length_field_len; + if ((length_field_len = asn_1_encode(resource_id_count*4, buf+3, 3)) < 0) { + return -1; + } + + // copy the data and byteswap it + uint32_t *copy_resource_ids = alloca(4*resource_id_count); + if (copy_resource_ids == NULL) { + return -1; + } + uint8_t *data = (uint8_t*) copy_resource_ids; + memcpy(data, resource_ids, resource_id_count*4); + uint32_t i; + for(i=0; i<resource_id_count; i++) { + bswap32(data); + data+=4; + } + + // build the iovecs + struct iovec iov[2]; + iov[0].iov_base = buf; + iov[0].iov_len = 3+length_field_len; + iov[1].iov_base = (uint8_t*) copy_resource_ids; + iov[1].iov_len = resource_id_count * 4; + + // create the data and send it + return private->funcs->send_datav(private->funcs->arg, session_number, iov, 2); +} + +int en50221_app_rm_changed(en50221_app_rm rm, uint16_t session_number) +{ + struct en50221_app_rm_private *private = (struct en50221_app_rm_private *) rm; + uint8_t buf[4]; + + // set up the tag + buf[0] = (TAG_PROFILE_CHANGE >> 16) & 0xFF; + buf[1] = (TAG_PROFILE_CHANGE >> 8) & 0xFF; + buf[2] = TAG_PROFILE_CHANGE & 0xFF; + buf[3] = 0; + + // create the data and send it + return private->funcs->send_data(private->funcs->arg, session_number, buf, 4); +} + +int en50221_app_rm_message(en50221_app_rm rm, + uint8_t slot_id, + uint16_t session_number, + uint32_t resource_id, + uint8_t *data, uint32_t data_length) +{ + struct en50221_app_rm_private *private = (struct en50221_app_rm_private *) rm; + (void) resource_id; + + // get the tag + if (data_length < 3) { + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + return -1; + } + uint32_t tag = (data[0] << 16) | (data[1] << 8) | data[2]; + + // dispatch it + switch(tag) + { + case TAG_PROFILE_ENQUIRY: + return en50221_app_rm_parse_profile_enq(private, slot_id, session_number, data+3, data_length-3); + case TAG_PROFILE: + return en50221_app_rm_parse_profile_reply(private, slot_id, session_number, data+3, data_length-3); + case TAG_PROFILE_CHANGE: + return en50221_app_rm_parse_profile_change(private, slot_id, session_number, data+3, data_length-3); + } + + print(LOG_LEVEL, ERROR, 1, "Received unexpected tag %x\n", tag); + return -1; +} + + +static int en50221_app_rm_parse_profile_enq(struct en50221_app_rm_private *private, + uint8_t slot_id, uint16_t session_number, + uint8_t *data, uint32_t data_length) +{ + (void)data; + (void)data_length; + + pthread_mutex_lock(&private->lock); + en50221_app_rm_enq_callback cb = private->enqcallback; + void *cb_arg = private->enqcallback_arg; + pthread_mutex_unlock(&private->lock); + if (cb) { + return cb(cb_arg, slot_id, session_number); + } + return 0; +} + +static int en50221_app_rm_parse_profile_reply(struct en50221_app_rm_private *private, + uint8_t slot_id, uint16_t session_number, + uint8_t *data, uint32_t data_length) +{ + // first of all, decode the length field + uint16_t asn_data_length; + int length_field_len; + if ((length_field_len = asn_1_decode(&asn_data_length, data, data_length)) < 0) { + print(LOG_LEVEL, ERROR, 1, "ASN.1 decode error\n"); + return -1; + } + + // check it + if (asn_data_length > (data_length-length_field_len)) { + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + return -1; + } + uint32_t resources_count = asn_data_length / 4; + uint32_t *resource_ids = (uint32_t*) (data+length_field_len); + data += length_field_len; + + // byteswap it + uint32_t i; + for(i=0; i< resources_count; i++) { + bswap32(data); + data+=4; + } + + // inform observer + pthread_mutex_lock(&private->lock); + en50221_app_rm_reply_callback cb = private->replycallback; + void *cb_arg = private->replycallback_arg; + pthread_mutex_unlock(&private->lock); + if (cb) { + return cb(cb_arg, slot_id, session_number, resources_count, resource_ids); + } + return 0; +} + +static int en50221_app_rm_parse_profile_change(struct en50221_app_rm_private *private, + uint8_t slot_id, uint16_t session_number, + uint8_t *data, uint32_t data_length) +{ + (void)data; + (void)data_length; + + pthread_mutex_lock(&private->lock); + en50221_app_rm_changed_callback cb = private->changedcallback; + void *cb_arg = private->changedcallback_arg; + pthread_mutex_unlock(&private->lock); + if (cb) { + return cb(cb_arg, slot_id, session_number); + } + return 0; +} diff --git a/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_rm.h b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_rm.h new file mode 100644 index 0000000..696065d --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_rm.h @@ -0,0 +1,178 @@ +/* + en50221 encoder An implementation for libdvb + an implementation for the en50221 transport layer + + Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com) + Copyright (C) 2005 Julian Scheel (julian at jusst dot de) + Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net) + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of + the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef __EN50221_APPLICATION_RM_H__ +#define __EN50221_APPLICATION_RM_H__ + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <stdlib.h> +#include <stdint.h> +#include <libdvben50221/en50221_app_utils.h> + +#define EN50221_APP_RM_RESOURCEID MKRID(1,1,1) + +/** + * Type definition for profile_enq callback function - called when we receive + * a profile_enq from a CAM. + * + * @param arg Private argument. + * @param slot_id Slot id concerned. + * @param session_number Session number concerned. + * @return 0 on success, -1 on failure. + */ +typedef int (*en50221_app_rm_enq_callback)(void *arg, uint8_t slot_id, uint16_t session_number); + +/** + * Type definition for profile_reply callback function - called when we receive + * a profile_reply from a CAM. + * + * @param arg Private argument. + * @param slot_id Slot id concerned. + * @param session_number Session number concerned. + * @param resource_id_count Number of resource_ids. + * @param resource_ids The resource ids themselves. + * @return 0 on success, -1 on failure. + */ +typedef int (*en50221_app_rm_reply_callback)(void *arg, uint8_t slot_id, uint16_t session_number, + uint32_t resource_id_count, + uint32_t *resource_ids); +/** + * Type definition for profile_changed callback function - called when we receive + * a profile_changed from a CAM. + * + * @param arg Private argument. + * @param slot_id Slot id concerned. + * @param session_number Session number concerned. + * @return 0 on success, -1 on failure. + */ +typedef int (*en50221_app_rm_changed_callback)(void *arg, uint8_t slot_id, uint16_t session_number); + + + +/** + * Opaque type representing a resource manager. + */ +typedef void *en50221_app_rm; + +/** + * Create an instance of the resource manager. + * + * @param funcs Send functions to use. + * @return Instance, or NULL on failure. + */ +extern en50221_app_rm en50221_app_rm_create(struct en50221_app_send_functions *funcs); + +/** + * Destroy an instance of the resource manager. + * + * @param rm Instance to destroy. + */ +extern void en50221_app_rm_destroy(en50221_app_rm rm); + +/** + * Register the callback for when we receive a profile_enq from a CAM. + * + * @param rm Resource manager instance. + * @param callback The callback. Set to NULL to remove the callback completely. + * @param arg Private data passed as arg0 of the callback. + */ +extern void en50221_app_rm_register_enq_callback(en50221_app_rm rm, + en50221_app_rm_enq_callback callback, void *arg); + +/** + * Register the callback for when we receive a profile_reply from a CAM. + * + * @param rm Resource manager instance. + * @param callback The callback. Set to NULL to remove the callback completely. + * @param arg Private data passed as arg0 of the callback. + */ +extern void en50221_app_rm_register_reply_callback(en50221_app_rm rm, + en50221_app_rm_reply_callback callback, void *arg); + +/** + * Register the callback for when we receive a profile_changed from a CAM. + * + * @param rm Resource manager instance. + * @param callback The callback. Set to NULL to remove the callback completely. + * @param arg Private data passed as arg0 of the callback. + */ +extern void en50221_app_rm_register_changed_callback(en50221_app_rm rm, + en50221_app_rm_changed_callback callback, void *arg); + +/** + * Send a profile_enq to a CAM. + * + * @param rm Resource manager resource instance. + * @param session_number Session number to send it on. + * @return 0 on success, -1 on failure. + */ +extern int en50221_app_rm_enq(en50221_app_rm rm, uint16_t session_number); + +/** + * Send a profile_reply to a CAM. + * + * @param rm Resource manager resource instance. + * @param session_number Session number to send it on. + * @param resource_id_count Number of resource ids. + * @param resource_ids The resource IDs themselves + * @return 0 on success, -1 on failure. + */ +extern int en50221_app_rm_reply(en50221_app_rm rm, uint16_t session_number, + uint32_t resource_id_count, + uint32_t *resource_ids); + +/** + * Send a profile_changed to a CAM. + * + * @param rm Resource manager resource instance. + * @param session_number Session number to send it on. + * @return 0 on success, -1 on failure. + */ +extern int en50221_app_rm_changed(en50221_app_rm rm, uint16_t session_number); + +/** + * Pass data received for this resource into it for parsing. + * + * @param rm rm instance. + * @param slot_id Slot ID concerned. + * @param session_number Session number concerned. + * @param resource_id Resource ID concerned. + * @param data The data. + * @param data_length Length of data in bytes. + * @return 0 on success, -1 on failure. + */ +extern int en50221_app_rm_message(en50221_app_rm rm, + uint8_t slot_id, + uint16_t session_number, + uint32_t resource_id, + uint8_t *data, uint32_t data_length); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_smartcard.c b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_smartcard.c new file mode 100644 index 0000000..83015ae --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_smartcard.c @@ -0,0 +1,293 @@ +/* + en50221 encoder An implementation for libdvb + an implementation for the en50221 transport layer + + Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com) + Copyright (C) 2005 Julian Scheel (julian at jusst dot de) + Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net) + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of + the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include <string.h> +#include <libdvbmisc/dvbmisc.h> +#include <pthread.h> +#include "en50221_app_smartcard.h" +#include "en50221_app_tags.h" +#include "asn_1.h" + +struct en50221_app_smartcard_private { + struct en50221_app_send_functions *funcs; + + en50221_app_smartcard_command_callback command_callback; + void *command_callback_arg; + + en50221_app_smartcard_send_callback send_callback; + void *send_callback_arg; + + pthread_mutex_t lock; +}; + +static int en50221_app_smartcard_parse_command(struct en50221_app_smartcard_private *private, + uint8_t slot_id, uint16_t session_number, + uint8_t *data, uint32_t data_length); + +static int en50221_app_smartcard_parse_send(struct en50221_app_smartcard_private *private, + uint8_t slot_id, uint16_t session_number, + uint8_t *data, uint32_t data_length); + + +en50221_app_smartcard en50221_app_smartcard_create(struct en50221_app_send_functions *funcs) +{ + struct en50221_app_smartcard_private *private = NULL; + + // create structure and set it up + private = malloc(sizeof(struct en50221_app_smartcard_private)); + if (private == NULL) { + return NULL; + } + private->funcs = funcs; + private->command_callback = NULL; + private->send_callback = NULL; + + pthread_mutex_init(&private->lock, NULL); + + // done + return private; +} + +void en50221_app_smartcard_destroy(en50221_app_smartcard smartcard) +{ + struct en50221_app_smartcard_private *private = (struct en50221_app_smartcard_private *) smartcard; + + pthread_mutex_destroy(&private->lock); + free(private); +} + +void en50221_app_smartcard_register_command_callback(en50221_app_smartcard smartcard, + en50221_app_smartcard_command_callback callback, void *arg) +{ + struct en50221_app_smartcard_private *private = (struct en50221_app_smartcard_private *) smartcard; + + pthread_mutex_lock(&private->lock); + private->command_callback = callback; + private->command_callback_arg = arg; + pthread_mutex_unlock(&private->lock); +} + +void en50221_app_smartcard_register_send_callback(en50221_app_smartcard smartcard, + en50221_app_smartcard_send_callback callback, void *arg) +{ + struct en50221_app_smartcard_private *private = (struct en50221_app_smartcard_private *) smartcard; + + pthread_mutex_lock(&private->lock); + private->send_callback = callback; + private->send_callback_arg = arg; + pthread_mutex_unlock(&private->lock); +} + +int en50221_app_smartcard_command_reply(en50221_app_smartcard smartcard, + uint16_t session_number, + uint8_t reply_id, + uint8_t status, + uint8_t *data, + uint32_t data_length) +{ + struct en50221_app_smartcard_private *private = (struct en50221_app_smartcard_private *) smartcard; + uint8_t hdr[10]; + struct iovec iovec[2]; + int iov_count = 0; + + // the tag + hdr[0] = (TAG_SMARTCARD_REPLY >> 16) & 0xFF; + hdr[1] = (TAG_SMARTCARD_REPLY >> 8) & 0xFF; + hdr[2] = TAG_SMARTCARD_REPLY & 0xFF; + + // the rest of the data + if (reply_id == SMARTCARD_REPLY_ID_ANSW_TO_RESET) { + // encode the length field + int length_field_len; + if ((length_field_len = asn_1_encode(data_length+2, data+3, 3)) < 0) { + return -1; + } + + // the rest of the header + hdr[3+length_field_len] = reply_id; + hdr[3+length_field_len+1] = status; + iovec[0].iov_base = hdr; + iovec[0].iov_len = 3+length_field_len+2; + + // the data + iovec[1].iov_base = data; + iovec[1].iov_len = data_length; + iov_count = 2; + } else { + hdr[3] = 2; + hdr[4] = reply_id; + hdr[5] = status; + iovec[0].iov_base = data; + iovec[0].iov_len = 6; + iov_count = 1; + } + + return private->funcs->send_datav(private->funcs->arg, session_number, iovec, iov_count); +} + +int en50221_app_smartcard_receive(en50221_app_smartcard smartcard, + uint16_t session_number, + uint8_t *data, + uint32_t data_length, + uint8_t SW1, + uint8_t SW2) +{ + struct en50221_app_smartcard_private *private = (struct en50221_app_smartcard_private *) smartcard; + uint8_t buf[10]; + uint8_t trailer[10]; + + // set up the tag + buf[0] = (TAG_SMARTCARD_RCV >> 16) & 0xFF; + buf[1] = (TAG_SMARTCARD_RCV >> 8) & 0xFF; + buf[2] = TAG_SMARTCARD_RCV & 0xFF; + + // encode the length field + int length_field_len; + if ((length_field_len = asn_1_encode(data_length+2, buf+3, 3)) < 0) { + return -1; + } + + // set up the trailer + trailer[0] = SW1; + trailer[1] = SW2; + + // build the iovecs + struct iovec iov[3]; + iov[0].iov_base = buf; + iov[0].iov_len = 3+length_field_len; + iov[1].iov_base = data; + iov[1].iov_len = data_length; + iov[2].iov_base = trailer; + iov[2].iov_len = 2; + + // create the data and send it + return private->funcs->send_datav(private->funcs->arg, session_number, iov, 3); +} + +int en50221_app_smartcard_message(en50221_app_smartcard smartcard, + uint8_t slot_id, + uint16_t session_number, + uint32_t resource_id, + uint8_t *data, uint32_t data_length) +{ + struct en50221_app_smartcard_private *private = (struct en50221_app_smartcard_private *) smartcard; + (void)resource_id; + + // get the tag + if (data_length < 3) { + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + return -1; + } + uint32_t tag = (data[0] << 16) | (data[1] << 8) | data[2]; + + switch(tag) + { + case TAG_SMARTCARD_COMMAND: + return en50221_app_smartcard_parse_command(private, slot_id, session_number, data+3, data_length-3); + case TAG_SMARTCARD_SEND: + return en50221_app_smartcard_parse_send(private, slot_id, session_number, data+3, data_length-3); + } + + print(LOG_LEVEL, ERROR, 1, "Received unexpected tag %x\n", tag); + return -1; +} + + + + + + + +static int en50221_app_smartcard_parse_command(struct en50221_app_smartcard_private *private, + uint8_t slot_id, uint16_t session_number, + uint8_t *data, uint32_t data_length) +{ + if (data_length != 2) { + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + return -1; + } + if (data[0] != 1) { + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + return -1; + } + uint8_t command_id = data[1]; + + // tell the app + pthread_mutex_lock(&private->lock); + en50221_app_smartcard_command_callback cb = private->command_callback; + void *cb_arg = private->command_callback_arg; + pthread_mutex_unlock(&private->lock); + if (cb) { + return cb(cb_arg, slot_id, session_number, command_id); + } + return 0; +} + +static int en50221_app_smartcard_parse_send(struct en50221_app_smartcard_private *private, + uint8_t slot_id, uint16_t session_number, + uint8_t *data, uint32_t data_length) +{ + // first of all, decode the length field + uint16_t asn_data_length; + int length_field_len; + if ((length_field_len = asn_1_decode(&asn_data_length, data, data_length)) < 0) { + print(LOG_LEVEL, ERROR, 1, "ASN.1 decode error\n"); + return -1; + } + + // check it + if (asn_data_length < 8) { + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + return -1; + } + if (asn_data_length > (data_length-length_field_len)) { + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + return -1; + } + data += length_field_len; + + // parse + uint8_t CLA = data[0]; + uint8_t INS = data[1]; + uint8_t P1 = data[2]; + uint8_t P2 = data[3]; + uint16_t length_in = (data[4]<<8)|data[5]; + uint8_t *data_in = data + 6; + + // validate the length + if ((length_in + 8) != asn_data_length) { + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + return -1; + } + uint16_t length_out = (data[6+length_in]<<8)|data[6+length_in+1]; + + // tell the app + pthread_mutex_lock(&private->lock); + en50221_app_smartcard_send_callback cb = private->send_callback; + void *cb_arg = private->send_callback_arg; + pthread_mutex_unlock(&private->lock); + if (cb) { + return cb(cb_arg, slot_id, session_number, CLA, INS, P1, P2, data_in, length_in, length_out); + } + return 0; +} diff --git a/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_smartcard.h b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_smartcard.h new file mode 100644 index 0000000..56655c4 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_smartcard.h @@ -0,0 +1,191 @@ +/* + en50221 encoder An implementation for libdvb + an implementation for the en50221 transport layer + + Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com) + Copyright (C) 2005 Julian Scheel (julian at jusst dot de) + Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net) + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of + the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef __EN50221_APPLICATION_smartcard_H__ +#define __EN50221_APPLICATION_smartcard_H__ + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <stdlib.h> +#include <stdint.h> +#include <libdvben50221/en50221_app_utils.h> + +#define SMARTCARD_COMMAND_ID_CONNECT 0x01 +#define SMARTCARD_COMMAND_ID_DISCONNECT 0x02 +#define SMARTCARD_COMMAND_ID_POWERON_CARD 0x03 +#define SMARTCARD_COMMAND_ID_POWEROFF_CARD 0x04 +#define SMARTCARD_COMMAND_ID_RESET_CARD 0x05 +#define SMARTCARD_COMMAND_ID_RESET_STATUS 0x06 +#define SMARTCARD_COMMAND_ID_READ_ANSW_TO_RESET 0x07 + +#define SMARTCARD_REPLY_ID_CONNECTED 0x01 +#define SMARTCARD_REPLY_ID_FREE 0x02 +#define SMARTCARD_REPLY_ID_BUSY 0x03 +#define SMARTCARD_REPLY_ID_ANSW_TO_RESET 0x04 +#define SMARTCARD_REPLY_ID_NO_ANSW_TO_RESET 0x05 + +#define SMARTCARD_STATUS_CARD_INSERTED 0x01 +#define SMARTCARD_STATUS_CARD_REMOVED 0x02 +#define SMARTCARD_STATUS_CARD_IN_PLACE_POWEROFF 0x03 +#define SMARTCARD_STATUS_CARD_IN_PLACE_POWERON 0x04 +#define SMARTCARD_STATUS_CARD_NO_CARD 0x05 +#define SMARTCARD_STATUS_CARD_UNRESPONSIVE_CARD 0x06 +#define SMARTCARD_STATUS_CARD_REFUSED_CARD 0x07 + +#define EN50221_APP_SMARTCARD_RESOURCEID(DEVICE_NUMBER) MKRID(112, ((DEVICE_NUMBER)& 0x0f), 1) + + + +/** + * Type definition for command - called when we receive a command. + * + * @param arg Private argument. + * @param slot_id Slot id concerned. + * @param session_number Session number concerned. + * @param command_id One of the SMARTCARD_COMMAND_ID_* values + * @return 0 on success, -1 on failure. + */ +typedef int (*en50221_app_smartcard_command_callback)(void *arg, uint8_t slot_id, uint16_t session_number, + uint8_t command_id); + +/** + * Type definition for command - called when we receive a send command. + * + * @param arg Private argument. + * @param slot_id Slot id concerned. + * @param session_number Session number concerned. + * @param CLA CLA value. + * @param INS INS value. + * @param P1 P1 value. + * @param P2 P2 value. + * @param in Data to send to the card + * @param in_length Number of bytes to send. + * @param out_length Number of bytes expected. + * @return 0 on success, -1 on failure. + */ +typedef int (*en50221_app_smartcard_send_callback)(void *arg, uint8_t slot_id, uint16_t session_number, + uint8_t CLA, uint8_t INS, uint8_t P1, uint8_t P2, + uint8_t *in, uint32_t in_length, + uint32_t out_length); + +/** + * Opaque type representing a smartcard resource. + */ +typedef void *en50221_app_smartcard; + +/** + * Create an instance of the smartcard resource. + * + * @param funcs Send functions to use. + * @return Instance, or NULL on failure. + */ +extern en50221_app_smartcard en50221_app_smartcard_create(struct en50221_app_send_functions *funcs); + +/** + * Destroy an instance of the smartcard resource. + * + * @param smartcard Instance to destroy. + */ +extern void en50221_app_smartcard_destroy(en50221_app_smartcard smartcard); + +/** + * Register the callback for when we receive a comms command. + * + * @param smartcard smartcard resource instance. + * @param callback The callback. Set to NULL to remove the callback completely. + * @param arg Private data passed as arg0 of the callback. + */ +extern void en50221_app_smartcard_register_command_callback(en50221_app_smartcard smartcard, + en50221_app_smartcard_command_callback callback, void *arg); + +/** + * Register the callback for when we receive data to send. + * + * @param smartcard smartcard resource instance. + * @param callback The callback. Set to NULL to remove the callback completely. + * @param arg Private data passed as arg0 of the callback. + */ +extern void en50221_app_smartcard_register_send_callback(en50221_app_smartcard smartcard, + en50221_app_smartcard_send_callback callback, void *arg); + +/** + * Send a command response to the CAM. + * + * @param smartcard smartcard resource instance. + * @param session_number Session number to send it on. + * @param reply_id One of the SMARTCARD_REPLY_ID_* values. + * @param status One of the SMARTCARD_STATUS_* values. + * @param data Data to send when it is a SMARTCARD_REPLY_ID_ANSW_TO_RESET. + * @param data_length Length of data to send. + * @return 0 on success, -1 on failure. + */ +extern int en50221_app_smartcard_command_reply(en50221_app_smartcard smartcard, + uint16_t session_number, + uint8_t reply_id, + uint8_t status, + uint8_t *data, + uint32_t data_length); + +/** + * Send data received from a smartcart to the CAM. + * + * @param smartcard smartcard resource instance. + * @param session_number Session number to send it on. + * @param data Data to send when it is a SMARTCARD_REPLY_ID_ANSW_TO_RESET. + * @param data_length Length of data to send. + * @param SW1 SW1 value. + * @param SW2 SW2 value. + * @return 0 on success, -1 on failure. + */ +extern int en50221_app_smartcard_receive(en50221_app_smartcard smartcard, + uint16_t session_number, + uint8_t *data, + uint32_t data_length, + uint8_t SW1, + uint8_t SW2); + +/** + * Pass data received for this resource into it for parsing. + * + * @param smartcard smartcard instance. + * @param slot_id Slot ID concerned. + * @param session_number Session number concerned. + * @param resource_id Resource ID concerned. + * @param data The data. + * @param data_length Length of data in bytes. + * @return 0 on success, -1 on failure. + */ +extern int en50221_app_smartcard_message(en50221_app_smartcard smartcard, + uint8_t slot_id, + uint16_t session_number, + uint32_t resource_id, + uint8_t *data, uint32_t data_length); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_tags.h b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_tags.h new file mode 100644 index 0000000..2086a80 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_tags.h @@ -0,0 +1,104 @@ +/* + en50221 encoder An implementation for libdvb + an implementation for the en50221 transport layer + + Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com) + Copyright (C) 2005 Julian Scheel (julian at jusst dot de) + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of + the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef __EN50221_APP_TAGS_H__ +#define __EN50221_APP_TAGS_H__ + +/* Resource Manager */ +#define TAG_PROFILE_ENQUIRY 0x9f8010 +#define TAG_PROFILE 0x9f8011 +#define TAG_PROFILE_CHANGE 0x9f8012 + +/* Application Info */ +#define TAG_APP_INFO_ENQUIRY 0x9f8020 +#define TAG_APP_INFO 0x9f8021 +#define TAG_ENTER_MENU 0x9f8022 + +/* CA Support */ +#define TAG_CA_INFO_ENQUIRY 0x9f8030 +#define TAG_CA_INFO 0x9f8031 +#define TAG_CA_PMT 0x9f8032 +#define TAG_CA_PMT_REPLY 0x9f8033 + +/* Host Control */ +#define TAG_TUNE 0x9f8400 +#define TAG_REPLACE 0x9f8401 +#define TAG_CLEAR_REPLACE 0x9f8402 +#define TAG_ASK_RELEASE 0x9f8403 + +/* Date and Time */ +#define TAG_DATE_TIME_ENQUIRY 0x9f8440 +#define TAG_DATE_TIME 0x9f8441 + +/* Man Machine Interface (MMI) */ +#define TAG_CLOSE_MMI 0x9f8800 +#define TAG_DISPLAY_CONTROL 0x9f8801 +#define TAG_DISPLAY_REPLY 0x9f8802 +#define TAG_TEXT_LAST 0x9f8803 +#define TAG_TEXT_MORE 0x9f8804 +#define TAG_KEYPAD_CONTROL 0x9f8805 +#define TAG_KEYPRESS 0x9f8806 +#define TAG_ENQUIRY 0x9f8807 +#define TAG_ANSWER 0x9f8808 +#define TAG_MENU_LAST 0x9f8809 +#define TAG_MENU_MORE 0x9f880a +#define TAG_MENU_ANSWER 0x9f880b +#define TAG_LIST_LAST 0x9f880c +#define TAG_LIST_MORE 0x9f880d +#define TAG_SUBTITLE_SEGMENT_LAST 0x9f880e +#define TAG_SUBTITLE_SEGMENT_MORE 0x9f880f +#define TAG_DISPLAY_MESSAGE 0x9f8810 +#define TAG_SCENE_END_MARK 0x9f8811 +#define TAG_SCENE_DONE 0x9f8812 +#define TAG_SCENE_CONTROL 0x9f8813 +#define TAG_SUBTITLE_DOWNLOAD_LAST 0x9f8814 +#define TAG_SUBTITLE_DOWNLOAD_MORE 0x9f8815 +#define TAG_FLUSH_DOWNLOAD 0x9f8816 +#define TAG_DOWNLOAD_REPLY 0x9f8817 + +/* Low Speed Communications */ +#define TAG_COMMS_COMMAND 0x9f8c00 +#define TAG_CONNECTION_DESCRIPTOR 0x9f8c01 +#define TAG_COMMS_REPLY 0x9f8c02 +#define TAG_COMMS_SEND_LAST 0x9f8c03 +#define TAG_COMMS_SEND_MORE 0x9f8c04 +#define TAG_COMMS_RECV_LAST 0x9f8c05 +#define TAG_COMMS_RECV_MORE 0x9f8c06 + +/* Authentication */ +#define TAG_AUTH_REQ 0x9f8200 +#define TAG_AUTH_RESP 0x9f8201 + +/* Teletext */ +#define TAG_TELETEXT_EBU 0x9f9000 + +/* Smartcard */ +#define TAG_SMARTCARD_COMMAND 0x9f8e00 +#define TAG_SMARTCARD_REPLY 0x9f8e01 +#define TAG_SMARTCARD_SEND 0x9f8e02 +#define TAG_SMARTCARD_RCV 0x9f8e03 + +/* EPG */ +#define TAG_EPG_ENQUIRY 0x9f8f00 +#define TAG_EPG_REPLY 0x9f8f01 + +#endif diff --git a/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_teletext.c b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_teletext.c new file mode 100644 index 0000000..cc2ee41 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_teletext.c @@ -0,0 +1,139 @@ +/* + en50221 encoder An implementation for libdvb + an implementation for the en50221 transport layer + + Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com) + Copyright (C) 2005 Julian Scheel (julian at jusst dot de) + Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net) + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of + the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include <string.h> +#include <libdvbmisc/dvbmisc.h> +#include <pthread.h> +#include "en50221_app_teletext.h" +#include "en50221_app_tags.h" +#include "asn_1.h" + +struct en50221_app_teletext_private { + struct en50221_app_send_functions *funcs; + + en50221_app_teletext_callback callback; + void *callback_arg; + + pthread_mutex_t lock; +}; + +static int en50221_app_teletext_parse_ebu(struct en50221_app_teletext_private *private, + uint8_t slot_id, uint16_t session_number, + uint8_t *data, uint32_t data_length); + + + +en50221_app_teletext en50221_app_teletext_create(struct en50221_app_send_functions *funcs) +{ + struct en50221_app_teletext_private *private = NULL; + + // create structure and set it up + private = malloc(sizeof(struct en50221_app_teletext_private)); + if (private == NULL) { + return NULL; + } + private->funcs = funcs; + private->callback = NULL; + + pthread_mutex_init(&private->lock, NULL); + + // done + return private; +} + +void en50221_app_teletext_destroy(en50221_app_teletext teletext) +{ + struct en50221_app_teletext_private *private = (struct en50221_app_teletext_private *) teletext; + + pthread_mutex_destroy(&private->lock); + free(private); +} + +void en50221_app_teletext_register_callback(en50221_app_teletext teletext, + en50221_app_teletext_callback callback, void *arg) +{ + struct en50221_app_teletext_private *private = (struct en50221_app_teletext_private *) teletext; + + pthread_mutex_lock(&private->lock); + private->callback = callback; + private->callback_arg = arg; + pthread_mutex_unlock(&private->lock); +} + +int en50221_app_teletext_message(en50221_app_teletext teletext, + uint8_t slot_id, + uint16_t session_number, + uint32_t resource_id, + uint8_t *data, uint32_t data_length) +{ + struct en50221_app_teletext_private *private = (struct en50221_app_teletext_private *) teletext; + (void) resource_id; + + // get the tag + if (data_length < 3) { + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + return -1; + } + uint32_t tag = (data[0] << 16) | (data[1] << 8) | data[2]; + + switch(tag) + { + case TAG_TELETEXT_EBU: + return en50221_app_teletext_parse_ebu(private, slot_id, session_number, data+3, data_length-3); + } + + print(LOG_LEVEL, ERROR, 1, "Received unexpected tag %x\n", tag); + return -1; +} + + +static int en50221_app_teletext_parse_ebu(struct en50221_app_teletext_private *private, + uint8_t slot_id, uint16_t session_number, + uint8_t *data, uint32_t data_length) +{ + // first of all, decode the length field + uint16_t asn_data_length; + int length_field_len; + if ((length_field_len = asn_1_decode(&asn_data_length, data, data_length)) < 0) { + print(LOG_LEVEL, ERROR, 1, "ASN.1 decode error\n"); + return -1; + } + + // check it + if (asn_data_length > (data_length-length_field_len)) { + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + return -1; + } + uint8_t *teletext_data = data + length_field_len; + + // tell the app + pthread_mutex_lock(&private->lock); + en50221_app_teletext_callback cb = private->callback; + void *cb_arg = private->callback_arg; + pthread_mutex_unlock(&private->lock); + if (cb) { + return cb(cb_arg, slot_id, session_number, teletext_data, asn_data_length); + } + return 0; +} + diff --git a/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_teletext.h b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_teletext.h new file mode 100644 index 0000000..1164d94 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_teletext.h @@ -0,0 +1,104 @@ +/* + en50221 encoder An implementation for libdvb + an implementation for the en50221 transport layer + + Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com) + Copyright (C) 2005 Julian Scheel (julian at jusst dot de) + Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net) + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of + the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef __EN50221_APPLICATION_teletext_H__ +#define __EN50221_APPLICATION_teletext_H__ + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <stdlib.h> +#include <stdint.h> +#include <libdvben50221/en50221_app_utils.h> + +#define EN50221_APP_TELETEXT_RESOURCEID MKRID(128, 1, 1) + + +/** + * Type definition for request - called when we receive teletext from a CAM. + * + * @param arg Private argument. + * @param slot_id Slot id concerned. + * @param session_number Session number concerned. + * @param teletext_data Data for the request. + * @param teletext_data_lenghth Number of bytes. + * @return 0 on success, -1 on failure. + */ +typedef int (*en50221_app_teletext_callback)(void *arg, uint8_t slot_id, uint16_t session_number, + uint8_t *teletext_data, + uint32_t teletext_data_length); + +/** + * Opaque type representing a teletext resource. + */ +typedef void *en50221_app_teletext; + +/** + * Create an instance of the teletext resource. + * + * @param funcs Send functions to use. + * @return Instance, or NULL on failure. + */ +extern en50221_app_teletext en50221_app_teletext_create(struct en50221_app_send_functions *funcs); + +/** + * Destroy an instance of the teletext resource. + * + * @param teletext Instance to destroy. + */ +extern void en50221_app_teletext_destroy(en50221_app_teletext teletext); + +/** + * Register the callback for when we receive a request. + * + * @param teletext teletext resource instance. + * @param callback The callback. Set to NULL to remove the callback completely. + * @param arg Private data passed as arg0 of the callback. + */ +extern void en50221_app_teletext_register_callback(en50221_app_teletext teletext, + en50221_app_teletext_callback callback, void *arg); + +/** + * Pass data received for this resource into it for parsing. + * + * @param teletext teletext instance. + * @param slot_id Slot ID concerned. + * @param session_number Session number concerned. + * @param resource_id Resource ID concerned. + * @param data The data. + * @param data_length Length of data in bytes. + * @return 0 on success, -1 on failure. + */ +extern int en50221_app_teletext_message(en50221_app_teletext teletext, + uint8_t slot_id, + uint16_t session_number, + uint32_t resource_id, + uint8_t *data, uint32_t data_length); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_utils.c b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_utils.c new file mode 100644 index 0000000..af68846 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_utils.c @@ -0,0 +1,37 @@ +/* + en50221 encoder An implementation for libdvb + an implementation for the en50221 transport layer + + Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com) + Copyright (C) 2005 Julian Scheel (julian at jusst dot de) + Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net) + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of + the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "en50221_app_utils.h" + +struct en50221_app_public_resource_id * + en50221_app_decode_public_resource_id(struct en50221_app_public_resource_id *idf, uint32_t resource_id) +{ + // reject private resources + if ((resource_id & 0xc0000000) == 0xc0000000) + return NULL; + + idf->resource_class = (resource_id >> 16) & 0xffff; // use the resource_id as the MSBs of class + idf->resource_type = (resource_id >> 6) & 0x3ff; + idf->resource_version = resource_id & 0x3f; + return idf; +} diff --git a/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_utils.h b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_utils.h new file mode 100644 index 0000000..34ca68f --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_utils.h @@ -0,0 +1,105 @@ +/* + en50221 encoder An implementation for libdvb + an implementation for the en50221 transport layer + + Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com) + Copyright (C) 2005 Julian Scheel (julian at jusst dot de) + Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net) + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of + the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef __EN50221_APP_UTILS_H__ +#define __EN50221_APP_UTILS_H__ + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <stdlib.h> +#include <stdint.h> +#include <sys/uio.h> + +/** + * A decomposed public resource structure. + * + * we will ignore private resource (resource_id_type==3), + * because they are not used by any modules at all and + * would need special code for any private resource anyway. + */ +struct en50221_app_public_resource_id { + uint16_t resource_class; + uint16_t resource_type; + uint8_t resource_version; +}; + +/** + * An abstraction away from hardcoded send functions so different layers may be + * slotted in under the application layer. + */ +struct en50221_app_send_functions { + /** + * Argument to pass to these functions. + */ + void *arg; + + /** + * Send data. + */ + int (*send_data)(void *arg, uint16_t session_number, uint8_t *data, uint16_t data_length); + + /** + * Send vector data. + */ + int (*send_datav)(void *arg, uint16_t session_number, struct iovec *vector, int iov_count); +}; + +/** + * Make a host-endian uint32_t formatted resource id. + * + * @param CLASS Class of resource. + * @param TYPE Type of resource. + * @param VERSION Version of resource. + * @return Formatted resource id. + */ +#define MKRID(CLASS, TYPE, VERSION) ((((CLASS)&0xffff)<<16) | (((TYPE)&0x3ff)<<6) | ((VERSION)&0x3f)) + +/** + * Decode a host-endian public resource_id into an en50221_app_public_resource_id structure. + * + * @param idf Structure to write decoded resource_id into. + * @param resource_id ID to decode. + * @return Pointer to idf on success, or NULL if this is not a public resource. + */ +struct en50221_app_public_resource_id * + en50221_app_decode_public_resource_id(struct en50221_app_public_resource_id *idf, uint32_t resource_id); + +/** + * Encode an en50221_app_public_resource_id structure into a host-endian uint32_t. + * + * @param idf Structure to encode. + * @return The encoded value + */ +static inline uint32_t en50221_app_encode_public_resource_id(struct en50221_app_public_resource_id *idf) +{ + return MKRID(idf->resource_class, idf->resource_type, idf->resource_version); +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libdvben50221/en50221_errno.h b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_errno.h new file mode 100644 index 0000000..045a6a5 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_errno.h @@ -0,0 +1,52 @@ +/* + en50221 encoder An implementation for libdvb + an implementation for the en50221 session layer + + Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com) + Copyright (C) 2005 Julian Scheel (julian at jusst dot de) + Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net) + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of + the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef EN50221_ERRNO +#define EN50221_ERRNO 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#define EN50221ERR_CAREAD -1 /* error during read from CA device. */ +#define EN50221ERR_CAWRITE -2 /* error during write to CA device. */ +#define EN50221ERR_TIMEOUT -3 /* timeout occured waiting for a response from a device. */ +#define EN50221ERR_BADSLOTID -4 /* bad slot ID supplied by user - the offending slot_id will not be set. */ +#define EN50221ERR_BADCONNECTIONID -5 /* bad connection ID supplied by user. */ +#define EN50221ERR_BADSTATE -6 /* slot/connection in the wrong state. */ +#define EN50221ERR_BADCAMDATA -7 /* CAM supplied an invalid request. */ +#define EN50221ERR_OUTOFMEMORY -8 /* memory allocation failed. */ +#define EN50221ERR_ASNENCODE -9 /* ASN.1 encode failure - indicates library bug. */ +#define EN50221ERR_OUTOFCONNECTIONS -10 /* no more connections available. */ +#define EN50221ERR_OUTOFSLOTS -11 /* no more slots available - the offending slot_id will not be set. */ +#define EN50221ERR_IOVLIMIT -12 /* Too many struct iovecs were used. */ +#define EN50221ERR_BADSESSIONNUMBER -13 /* Bad session number suppplied by user. */ +#define EN50221ERR_OUTOFSESSIONS -14 /* no more sessions available. */ + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/kaffeine/src/input/dvb/lib/libdvben50221/en50221_session.c b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_session.c new file mode 100644 index 0000000..1cc9a2e --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_session.c @@ -0,0 +1,954 @@ +/* + en50221 encoder An implementation for libdvb + an implementation for the en50221 transport layer + + Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com) + Copyright (C) 2005 Julian Scheel (julian at jusst dot de) + Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net) + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of + the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <fcntl.h> +#include <sys/ioctl.h> +#include <time.h> +#include <libdvbmisc/dvbmisc.h> +#include <sys/uio.h> +#include <pthread.h> +#include "en50221_transport.h" +#include "en50221_session.h" +#include "en50221_errno.h" +#include "asn_1.h" + + +// these are the possible session statuses +#define S_STATUS_OPEN 0x00 // session is opened +#define S_STATUS_CLOSE_NO_RES 0xF0 // could not open session, no proper resource available +#define S_STATUS_CLOSE_RES_UNAVAILABLE 0xF1 // could not open session, resource unavailable +#define S_STATUS_CLOSE_RES_LOW_VERSION 0xF2 // could not open session, resource version too low +#define S_STATUS_CLOSE_RES_BUSY 0xF3 // could not open session, resource is busy + +#define ST_OPEN_SESSION_REQ 0x91 // h<--m +#define ST_OPEN_SESSION_RES 0x92 // h-->m +#define ST_CREATE_SESSION 0x93 // h-->m +#define ST_CREATE_SESSION_RES 0x94 // h<--m +#define ST_CLOSE_SESSION_REQ 0x95 // h<->m +#define ST_CLOSE_SESSION_RES 0x96 // h<->m +#define ST_SESSION_NUMBER 0x90 // h<->m + +#define S_STATE_IDLE 0x01 // this session is not in use +#define S_STATE_ACTIVE 0x02 // this session is in use +#define S_STATE_IN_CREATION 0x04 // this session waits for a ST_CREATE_SESSION_RES to become active +#define S_STATE_IN_DELETION 0x08 // this session waits for ST_CLOSE_SESSION_RES to become idle again + + +// for each session we store its identifier, the resource-id +// it is linked to and the callback of the specific resource +struct en50221_session { + uint8_t state; + uint32_t resource_id; + uint8_t slot_id; + uint8_t connection_id; + + en50221_sl_resource_callback callback; + void *callback_arg; + + pthread_mutex_t session_lock; +}; + +struct en50221_session_layer_private +{ + uint32_t max_sessions; + en50221_transport_layer tl; + + en50221_sl_lookup_callback lookup; + void *lookup_arg; + + en50221_sl_session_callback session; + void *session_arg; + + pthread_mutex_t global_lock; + pthread_mutex_t setcallback_lock; + + int error; + + struct en50221_session *sessions; +}; + +static void en50221_sl_transport_callback(void *arg, int reason, uint8_t *data, uint32_t data_length, + uint8_t slot_id, uint8_t connection_id); +static int en50221_sl_alloc_new_session(struct en50221_session_layer_private *private, + uint32_t resource_id, + uint8_t slot_id, + uint8_t connection_id, + en50221_sl_resource_callback callback, void* arg); + + + + +en50221_session_layer en50221_sl_create(en50221_transport_layer tl, + uint32_t max_sessions) +{ + struct en50221_session_layer_private *private = NULL; + uint32_t i; + + // setup structure + private = (struct en50221_session_layer_private*) malloc(sizeof(struct en50221_session_layer_private)); + if (private == NULL) + goto error_exit; + private->max_sessions = max_sessions; + private->lookup = NULL; + private->session = NULL; + private->tl = tl; + private->error = 0; + + // init the mutex + pthread_mutex_init(&private->global_lock, NULL); + pthread_mutex_init(&private->setcallback_lock, NULL); + + // create the slots + private->sessions = malloc(sizeof(struct en50221_session) * max_sessions); + if (private->sessions == NULL) + goto error_exit; + + // set them up + for(i=0; i< max_sessions; i++) { + private->sessions[i].state = S_STATE_IDLE; + private->sessions[i].callback = NULL; + + pthread_mutex_init(&private->sessions[i].session_lock, NULL); + } + + // register ourselves with the transport layer + en50221_tl_register_callback(tl, en50221_sl_transport_callback, private); + + return private; + +error_exit: + en50221_sl_destroy(private); + return NULL; +} + +void en50221_sl_destroy(en50221_session_layer sl) +{ + struct en50221_session_layer_private *private = (struct en50221_session_layer_private *) sl; + uint32_t i; + + if (private) { + if (private->sessions) { + for(i=0; i< private->max_sessions; i++) { + pthread_mutex_destroy(&private->sessions[i].session_lock); + } + free(private->sessions); + } + + pthread_mutex_destroy(&private->setcallback_lock); + pthread_mutex_destroy(&private->global_lock); + + free(private); + } +} + +int en50221_sl_get_error(en50221_session_layer tl) +{ + struct en50221_session_layer_private *private = (struct en50221_session_layer_private *) tl; + return private->error; +} + +void en50221_sl_register_lookup_callback(en50221_session_layer sl, en50221_sl_lookup_callback callback, void *arg) +{ + struct en50221_session_layer_private *private = (struct en50221_session_layer_private *) sl; + + pthread_mutex_lock(&private->setcallback_lock); + private->lookup = callback; + private->lookup_arg = arg; + pthread_mutex_unlock(&private->setcallback_lock); +} + +void en50221_sl_register_session_callback(en50221_session_layer sl, + en50221_sl_session_callback callback, void *arg) +{ + struct en50221_session_layer_private *private = (struct en50221_session_layer_private *) sl; + + pthread_mutex_lock(&private->setcallback_lock); + private->session = callback; + private->session_arg = arg; + pthread_mutex_unlock(&private->setcallback_lock); +} + +int en50221_sl_create_session(en50221_session_layer sl, int slot_id, uint8_t connection_id, uint32_t resource_id, + en50221_sl_resource_callback callback, void* arg) +{ + struct en50221_session_layer_private *private = (struct en50221_session_layer_private *) sl; + + // lookup next free session_id: + pthread_mutex_lock(&private->global_lock); + int session_number = en50221_sl_alloc_new_session(private, resource_id, slot_id, connection_id, callback, arg); + if (session_number == -1) { + pthread_mutex_unlock(&private->global_lock); + return -1; + } + pthread_mutex_unlock(&private->global_lock); + + // make up the header + uint8_t hdr[8]; + hdr[0] = ST_CREATE_SESSION; + hdr[1] = 6; + hdr[2] = resource_id >> 24; + hdr[3] = resource_id >> 16; + hdr[4] = resource_id >> 8; + hdr[5] = resource_id; + hdr[6] = session_number >> 8; + hdr[7] = session_number; + + // send this command + if (en50221_tl_send_data(private->tl, slot_id, connection_id, hdr, 8)) { + pthread_mutex_lock(&private->sessions[session_number].session_lock); + if (private->sessions[session_number].state == S_STATE_IN_CREATION) { + private->sessions[session_number].state = S_STATE_IDLE; + } + pthread_mutex_unlock(&private->sessions[session_number].session_lock); + + private->error = en50221_tl_get_error(private->tl); + return -1; + } + + // ok. + return session_number; +} + +int en50221_sl_destroy_session(en50221_session_layer sl, uint16_t session_number) +{ + struct en50221_session_layer_private *private = (struct en50221_session_layer_private *) sl; + + if (session_number >= private->max_sessions) { + private->error = EN50221ERR_BADSESSIONNUMBER; + return -1; + } + + pthread_mutex_lock(&private->sessions[session_number].session_lock); + if (!(private->sessions[session_number].state & (S_STATE_ACTIVE|S_STATE_IN_DELETION))) { + private->error = EN50221ERR_BADSESSIONNUMBER; + pthread_mutex_unlock(&private->sessions[session_number].session_lock); + return -1; + } + + // set the state + private->sessions[session_number].state = S_STATE_IN_DELETION; + + // get essential details + uint8_t slot_id = private->sessions[session_number].slot_id; + uint8_t connection_id = private->sessions[session_number].connection_id; + pthread_mutex_unlock(&private->sessions[session_number].session_lock); + + // sendit + uint8_t hdr[4]; + hdr[0] = ST_CLOSE_SESSION_REQ; + hdr[1] = 2; + hdr[2] = session_number >> 8; + hdr[3] = session_number; + if (en50221_tl_send_data(private->tl, slot_id, connection_id, hdr, 4)) { + pthread_mutex_lock(&private->sessions[session_number].session_lock); + if (private->sessions[session_number].state == S_STATE_IN_DELETION) { + private->sessions[session_number].state = S_STATE_IDLE; + } + pthread_mutex_unlock(&private->sessions[session_number].session_lock); + + private->error = en50221_tl_get_error(private->tl); + return -1; + } + + return 0; +} + +int en50221_sl_send_data(en50221_session_layer sl, uint16_t session_number, uint8_t *data, uint16_t data_length) +{ + struct en50221_session_layer_private *private = (struct en50221_session_layer_private *) sl; + + if (session_number >= private->max_sessions) { + private->error = EN50221ERR_BADSESSIONNUMBER; + return -1; + } + + pthread_mutex_lock(&private->sessions[session_number].session_lock); + if (private->sessions[session_number].state != S_STATE_ACTIVE) { + private->error = EN50221ERR_BADSESSIONNUMBER; + pthread_mutex_unlock(&private->sessions[session_number].session_lock); + return -1; + } + + // get essential details + uint8_t slot_id = private->sessions[session_number].slot_id; + uint8_t connection_id = private->sessions[session_number].connection_id; + pthread_mutex_unlock(&private->sessions[session_number].session_lock); + + // sendit + struct iovec iov[2]; + uint8_t hdr[4]; + hdr[0] = ST_SESSION_NUMBER; + hdr[1] = 2; + hdr[2] = session_number >> 8; + hdr[3] = session_number; + iov[0].iov_base = hdr; + iov[0].iov_len = 4; + iov[1].iov_base = data; + iov[1].iov_len = data_length; + if (en50221_tl_send_datav(private->tl, slot_id, connection_id, iov, 2)) { + private->error = en50221_tl_get_error(private->tl); + return -1; + } + + return 0; +} + +int en50221_sl_send_datav(en50221_session_layer sl, uint16_t session_number, + struct iovec *vector, int iov_count) +{ + struct en50221_session_layer_private *private = (struct en50221_session_layer_private *) sl; + + if (session_number >= private->max_sessions) { + private->error = EN50221ERR_BADSESSIONNUMBER; + return -1; + } + + pthread_mutex_lock(&private->sessions[session_number].session_lock); + if (private->sessions[session_number].state != S_STATE_ACTIVE) { + private->error = EN50221ERR_BADSESSIONNUMBER; + pthread_mutex_unlock(&private->sessions[session_number].session_lock); + return -1; + } + if (iov_count > 9) { + private->error = EN50221ERR_IOVLIMIT; + pthread_mutex_unlock(&private->sessions[session_number].session_lock); + return -1; + } + uint8_t slot_id = private->sessions[session_number].slot_id; + uint8_t connection_id = private->sessions[session_number].connection_id; + pthread_mutex_unlock(&private->sessions[session_number].session_lock); + + // make up the header + struct iovec out_iov[10]; + uint8_t hdr[4]; + hdr[0] = ST_SESSION_NUMBER; + hdr[1] = 2; + hdr[2] = session_number >> 8; + hdr[3] = session_number; + out_iov[0].iov_base = hdr; + out_iov[0].iov_len = 4; + + // make up the data + memcpy(&out_iov[1], vector, iov_count * sizeof(struct iovec)); + + // send this command + if (en50221_tl_send_datav(private->tl, slot_id, connection_id, out_iov, iov_count+1)) { + private->error = en50221_tl_get_error(private->tl); + return -1; + } + return 0; +} + +int en50221_sl_broadcast_data(en50221_session_layer sl, int slot_id, uint32_t resource_id, + uint8_t *data, uint16_t data_length) +{ + struct en50221_session_layer_private *private = (struct en50221_session_layer_private *) sl; + uint32_t i; + + for(i = 0; i < private->max_sessions; i++) + { + pthread_mutex_lock(&private->sessions[i].session_lock); + + if (private->sessions[i].state != S_STATE_ACTIVE) { + pthread_mutex_unlock(&private->sessions[i].session_lock); + continue; + } + if ((slot_id != -1) && (slot_id != private->sessions[i].slot_id)) { + pthread_mutex_unlock(&private->sessions[i].session_lock); + continue; + } + + if (private->sessions[i].resource_id == resource_id) { + pthread_mutex_unlock(&private->sessions[i].session_lock); + en50221_sl_send_data(sl, i, data, data_length); + } else { + pthread_mutex_unlock(&private->sessions[i].session_lock); + } + } + + return 0; +} + + + +static void en50221_sl_handle_open_session_request(struct en50221_session_layer_private *private, + uint8_t *data, uint32_t data_length, uint8_t slot_id, uint8_t connection_id) +{ + // check + if (data_length < 5) { + print(LOG_LEVEL, ERROR, 1, "Received data with invalid length from module on slot %02x\n", slot_id); + return; + } + if (data[0] != 4) { + print(LOG_LEVEL, ERROR, 1, "Received data with invalid length from module on slot %02x\n", slot_id); + return; + } + + // get the resource id + uint32_t requested_resource_id = (data[1] << 24) | (data[2] << 16) | (data[3] << 8) | data[4]; + + // get lookup callback details + pthread_mutex_lock(&private->setcallback_lock); + en50221_sl_lookup_callback lcb = private->lookup; + void *lcb_arg = private->lookup_arg; + pthread_mutex_unlock(&private->setcallback_lock); + + // first of all, lookup this resource id + int status = S_STATUS_CLOSE_NO_RES; + en50221_sl_resource_callback resource_callback = NULL; + void *resource_arg = NULL; + uint32_t connected_resource_id; + if (lcb) { + status = lcb(lcb_arg, slot_id, requested_resource_id, &resource_callback, &resource_arg, &connected_resource_id); + switch(status) { + case 0: + status = S_STATUS_OPEN; + break; + + case -1: + status = S_STATUS_CLOSE_NO_RES; + break; + + case -2: + status = S_STATUS_CLOSE_RES_LOW_VERSION; + break; + + case -3: + status = S_STATUS_CLOSE_RES_UNAVAILABLE; + break; + } + } + + // if we found it, get a new session for it + int session_number = -1; + if (status == S_STATUS_OPEN) { + // lookup next free session_id: + pthread_mutex_lock(&private->global_lock); + session_number = en50221_sl_alloc_new_session(private, connected_resource_id, slot_id, connection_id, + resource_callback, resource_arg); + pthread_mutex_unlock(&private->global_lock); + + if (session_number == -1) { + status = S_STATUS_CLOSE_NO_RES; + } else { + // inform upper layers/ check availability + pthread_mutex_lock(&private->setcallback_lock); + en50221_sl_session_callback cb = private->session; + void *cb_arg = private->session_arg; + pthread_mutex_unlock(&private->setcallback_lock); + if (cb) { + if (cb(cb_arg, S_SCALLBACK_REASON_CAMCONNECTING, slot_id, session_number, connected_resource_id)) { + status = S_STATUS_CLOSE_RES_BUSY; + } + } else { + status = S_STATUS_CLOSE_RES_UNAVAILABLE; + } + } + } + + // send response + uint8_t hdr[9]; + hdr[0] = ST_OPEN_SESSION_RES; + hdr[1] = 7; + hdr[2] = status; + hdr[3] = connected_resource_id >> 24; + hdr[4] = connected_resource_id >> 16; + hdr[5] = connected_resource_id >> 8; + hdr[6] = connected_resource_id; + hdr[7] = session_number >> 8; + hdr[8] = session_number; + if (en50221_tl_send_data(private->tl, slot_id, connection_id, hdr, 9)) { + print(LOG_LEVEL, ERROR, 1, "Transport layer error %i occurred\n", en50221_tl_get_error(private->tl)); + status = S_STATUS_CLOSE_NO_RES; + // fallthrough + } + + // inform upper layers what happened + if (session_number != -1) { + // setup session state apppropriately from upper layer response + pthread_mutex_lock(&private->sessions[session_number].session_lock); + if (status != S_STATUS_OPEN) { + private->sessions[session_number].state = S_STATE_IDLE; + } else { + private->sessions[session_number].state = S_STATE_ACTIVE; + } + pthread_mutex_unlock(&private->sessions[session_number].session_lock); + + // tell upper layers + if (private->sessions[session_number].state == S_STATE_ACTIVE) { + pthread_mutex_lock(&private->setcallback_lock); + en50221_sl_session_callback cb = private->session; + void *cb_arg = private->session_arg; + pthread_mutex_unlock(&private->setcallback_lock); + + if (status == S_STATUS_OPEN) { + if (cb) + cb(cb_arg, S_SCALLBACK_REASON_CAMCONNECTED, slot_id, session_number, connected_resource_id); + } else { + private->sessions[session_number].state = S_STATE_IDLE; + if (cb) + cb(cb_arg, S_SCALLBACK_REASON_CAMCONNECTFAIL, slot_id, session_number, connected_resource_id); + } + } + } +} + +static void en50221_sl_handle_close_session_request(struct en50221_session_layer_private *private, + uint8_t *data, uint32_t data_length, uint8_t slot_id, uint8_t connection_id) +{ + // check + if (data_length < 3) { + print(LOG_LEVEL, ERROR, 1, "Received data with invalid length from module on slot %02x\n", slot_id); + return; + } + if (data[0] != 2) { + print(LOG_LEVEL, ERROR, 1, "Received data with invalid length from module on slot %02x\n", slot_id); + return; + } + + // extract session number + uint16_t session_number = (data[1] << 8) | data[2]; + + // check session number is ok + uint8_t code = 0x00; + uint32_t resource_id = 0; + if (session_number >= private->max_sessions) { + code = 0xF0; // session close error + print(LOG_LEVEL, ERROR, 1, "Received bad session id %i\n", slot_id); + } else { + pthread_mutex_lock(&private->sessions[session_number].session_lock); + if (slot_id != private->sessions[session_number].slot_id) { + print(LOG_LEVEL, ERROR, 1, "Received unexpected session on invalid slot %i\n", slot_id); + code = 0xF0; // session close error + } + if (connection_id != private->sessions[session_number].connection_id) { + print(LOG_LEVEL, ERROR, 1, "Received unexpected session on invalid slot %i\n", slot_id); + code = 0xF0; // session close error + } + if (!(private->sessions[session_number].state & (S_STATE_ACTIVE|S_STATE_IN_DELETION))) { + print(LOG_LEVEL, ERROR, 1, "Received unexpected session on invalid slot %i\n", slot_id); + code = 0xF0; // session close error + } + + if (code == 0x00) { + private->sessions[session_number].state = S_STATE_IDLE; + code = 0x00; // close ok + } + resource_id = private->sessions[session_number].resource_id; + pthread_mutex_unlock(&private->sessions[session_number].session_lock); + } + + // make up the response + uint8_t hdr[5]; + hdr[0] = ST_CLOSE_SESSION_RES; + hdr[1] = 3; + hdr[2] = code; + hdr[3] = session_number >> 8; + hdr[4] = session_number; + + // sendit + if (en50221_tl_send_data(private->tl, slot_id, connection_id, hdr, 5)) { + print(LOG_LEVEL, ERROR, 1, "Transport layer reports error %i on slot %i\n", + en50221_tl_get_error(private->tl), slot_id); + } + + // callback to announce destruction to resource if it was ok + if (code == 0x00) { + pthread_mutex_lock(&private->setcallback_lock); + en50221_sl_session_callback cb = private->session; + void *cb_arg = private->session_arg; + pthread_mutex_unlock(&private->setcallback_lock); + + if (cb) + cb(cb_arg, S_SCALLBACK_REASON_CLOSE, slot_id, session_number, resource_id); + } +} + +static void en50221_sl_handle_create_session_response(struct en50221_session_layer_private *private, + uint8_t *data, uint32_t data_length, uint8_t slot_id, uint8_t connection_id) +{ + // check + if (data_length < 8) { + print(LOG_LEVEL, ERROR, 1, "Received data with invalid length from module on slot %02x\n", slot_id); + return; + } + if (data[0] != 7) { + print(LOG_LEVEL, ERROR, 1, "Received data with invalid length from module on slot %02x\n", slot_id); + return; + } + + // extract session number + uint16_t session_number = (data[5] << 8) | data[6]; + + // check session number is ok + if (session_number >= private->max_sessions) { + print(LOG_LEVEL, ERROR, 1, "Received bad session id %i\n", slot_id); + return; + } + + pthread_mutex_lock(&private->sessions[session_number].session_lock); + if (slot_id != private->sessions[session_number].slot_id) { + print(LOG_LEVEL, ERROR, 1, "Received unexpected session on invalid slot %i\n", slot_id); + pthread_mutex_unlock(&private->sessions[session_number].session_lock); + return; + } + if (connection_id != private->sessions[session_number].connection_id) { + print(LOG_LEVEL, ERROR, 1, "Received unexpected session on invalid slot %i\n", slot_id); + pthread_mutex_unlock(&private->sessions[session_number].session_lock); + return; + } + if (private->sessions[session_number].state != S_STATE_IN_CREATION) { + print(LOG_LEVEL, ERROR, 1, "Received unexpected session on invalid slot %i\n", slot_id); + pthread_mutex_unlock(&private->sessions[session_number].session_lock); + return; + } + + // extract status + if (data[1] != S_STATUS_OPEN) { + print(LOG_LEVEL, ERROR, 1, "Session creation failed 0x%02x\n", data[1]); + private->sessions[session_number].state = S_STATE_IDLE; + pthread_mutex_unlock(&private->sessions[session_number].session_lock); + + // inform upper layers + pthread_mutex_lock(&private->setcallback_lock); + en50221_sl_session_callback cb = private->session; + void *cb_arg = private->session_arg; + pthread_mutex_unlock(&private->setcallback_lock); + if (cb) + cb(cb_arg, S_SCALLBACK_REASON_CONNECTFAIL, slot_id, session_number, + private->sessions[session_number].resource_id); + return; + } + + // set it active + private->sessions[session_number].state = S_STATE_ACTIVE; + pthread_mutex_unlock(&private->sessions[session_number].session_lock); + + // inform upper layers + pthread_mutex_lock(&private->setcallback_lock); + en50221_sl_session_callback cb = private->session; + void *cb_arg = private->session_arg; + pthread_mutex_unlock(&private->setcallback_lock); + if (cb) + cb(cb_arg, S_SCALLBACK_REASON_CONNECTED, slot_id, session_number, + private->sessions[session_number].resource_id); +} + +static void en50221_sl_handle_close_session_response(struct en50221_session_layer_private *private, + uint8_t *data, uint32_t data_length, uint8_t slot_id, uint8_t connection_id) +{ + // check + if (data_length < 5) { + print(LOG_LEVEL, ERROR, 1, "Received data with invalid length from module on slot %02x\n", slot_id); + return; + } + if (data[0] != 4) { + print(LOG_LEVEL, ERROR, 1, "Received data with invalid length from module on slot %02x\n", slot_id); + return; + } + + // extract session number + uint16_t session_number = (data[2] << 8) | data[3]; + + // check session number is ok + if (session_number >= private->max_sessions) { + print(LOG_LEVEL, ERROR, 1, "Received bad session id %i\n", slot_id); + return; + } + + pthread_mutex_lock(&private->sessions[session_number].session_lock); + if (slot_id != private->sessions[session_number].slot_id) { + print(LOG_LEVEL, ERROR, 1, "Received unexpected session on invalid slot %i\n", slot_id); + pthread_mutex_unlock(&private->sessions[session_number].session_lock); + return; + } + if (connection_id != private->sessions[session_number].connection_id) { + print(LOG_LEVEL, ERROR, 1, "Received unexpected session on invalid slot %i\n", slot_id); + pthread_mutex_unlock(&private->sessions[session_number].session_lock); + return; + } + if (private->sessions[session_number].state != S_STATE_IN_DELETION) { + print(LOG_LEVEL, ERROR, 1, "Received unexpected session on invalid slot %i\n", slot_id); + pthread_mutex_unlock(&private->sessions[session_number].session_lock); + return; + } + + // extract status + if (data[1] != 0x00) { + print(LOG_LEVEL, ERROR, 1, "Session close failed 0x%02x\n", data[1]); + // just fallthrough anyway + } + + // completed + private->sessions[session_number].state = S_STATE_IDLE; + pthread_mutex_unlock(&private->sessions[session_number].session_lock); +} + +static void en50221_sl_handle_session_package(struct en50221_session_layer_private *private, + uint8_t *data, uint32_t data_length, + uint8_t slot_id, uint8_t connection_id) +{ + // check + if (data_length < 3) { + print(LOG_LEVEL, ERROR, 1, "Received data with invalid length from module on slot %i\n", slot_id); + return; + } + if (data[0] != 2) { + print(LOG_LEVEL, ERROR, 1, "Received data with invalid length from module on slot %i\n", slot_id); + return; + } + + // get session number + uint16_t session_number = (data[1] << 8) | data[2]; + + // check it + if (session_number >= private->max_sessions) { + print(LOG_LEVEL, ERROR, 1, "Received data with bad session_number from module on slot %i\n", slot_id); + return; + } + + pthread_mutex_lock(&private->sessions[session_number].session_lock); + if (slot_id != private->sessions[session_number].slot_id) { + print(LOG_LEVEL, ERROR, 1, "Received unexpected session on invalid slot %i\n", slot_id); + pthread_mutex_unlock(&private->sessions[session_number].session_lock); + return; + } + if (connection_id != private->sessions[session_number].connection_id) { + print(LOG_LEVEL, ERROR, 1, "Received unexpected session on invalid slot %i\n", slot_id); + pthread_mutex_unlock(&private->sessions[session_number].session_lock); + return; + } + if (private->sessions[session_number].state != S_STATE_ACTIVE) { + print(LOG_LEVEL, ERROR, 1, "Received data with bad session_number from module on slot %i\n", slot_id); + pthread_mutex_unlock(&private->sessions[session_number].session_lock); + return; + } + + en50221_sl_resource_callback cb = private->sessions[session_number].callback; + void *cb_arg = private->sessions[session_number].callback_arg; + uint32_t resource_id = private->sessions[session_number].resource_id; + pthread_mutex_unlock(&private->sessions[session_number].session_lock); + + // there can be > 1 APDU following the package - all for the same session/resource_id tho. + data += 3; + data_length -= 3; + while(data_length) { + // check length field + if (data_length < 3) { + print(LOG_LEVEL, ERROR, 1, "Received invalid sized session package from slot %i\n", slot_id); + return; + } + + // parse the APDU's length field + int length_field_len; + uint16_t asn_data_length; + if ((length_field_len = asn_1_decode(&asn_data_length, data+3, data_length-3)) < 0) { + print(LOG_LEVEL, ERROR, 1, "Received invalid sized session package from slot %i\n", slot_id); + return; + } + uint32_t apdu_length = 3 + length_field_len + asn_data_length; + + // check there is enough data + if (apdu_length > data_length) { + print(LOG_LEVEL, ERROR, 1, "Received invalid sized session package from slot %i\n", slot_id); + return; + } + + // pass the APDU up to the higher layers + if (cb) + cb(cb_arg, slot_id, session_number, resource_id, data, apdu_length); + + // next! + data += apdu_length; + data_length -= apdu_length; + } + +} + +static void en50221_sl_transport_callback(void *arg, int reason, uint8_t *data, uint32_t data_length, + uint8_t slot_id, uint8_t connection_id) +{ + struct en50221_session_layer_private *private = (struct en50221_session_layer_private *) arg; + uint32_t i; + + // deal with the reason for this callback + switch(reason) { + case T_CALLBACK_REASON_DATA: + // fallthrough into rest of this function + break; + + case T_CALLBACK_REASON_CONNECTIONOPEN: + { + pthread_mutex_lock(&private->setcallback_lock); + en50221_sl_session_callback cb = private->session; + void *cb_arg = private->session_arg; + pthread_mutex_unlock(&private->setcallback_lock); + + if (cb) + cb(cb_arg, S_SCALLBACK_REASON_TC_CONNECT, slot_id, connection_id, 0); + return; + } + + case T_CALLBACK_REASON_CAMCONNECTIONOPEN: + { + pthread_mutex_lock(&private->setcallback_lock); + en50221_sl_session_callback cb = private->session; + void *cb_arg = private->session_arg; + pthread_mutex_unlock(&private->setcallback_lock); + + if (cb) + cb(cb_arg, S_SCALLBACK_REASON_TC_CAMCONNECT, slot_id, connection_id, 0); + return; + } + + case T_CALLBACK_REASON_CONNECTIONCLOSE: + { + pthread_mutex_lock(&private->setcallback_lock); + en50221_sl_session_callback cb = private->session; + void *cb_arg = private->session_arg; + pthread_mutex_unlock(&private->setcallback_lock); + + for(i=0; i< private->max_sessions; i++) { + pthread_mutex_lock(&private->sessions[i].session_lock); + + if (private->sessions[i].state == S_STATE_IDLE) { + pthread_mutex_unlock(&private->sessions[i].session_lock); + continue; + } + if (private->sessions[i].connection_id != connection_id) { + pthread_mutex_unlock(&private->sessions[i].session_lock); + continue; + } + + private->sessions[i].state = S_STATE_IDLE; + + uint8_t slot_id = private->sessions[i].slot_id; + uint32_t resource_id = private->sessions[i].resource_id; + pthread_mutex_unlock(&private->sessions[i].session_lock); + + if (cb) + cb(cb_arg, S_SCALLBACK_REASON_CLOSE, slot_id, i, resource_id); + } + return; + } + + case T_CALLBACK_REASON_SLOTCLOSE: + { + pthread_mutex_lock(&private->setcallback_lock); + en50221_sl_session_callback cb = private->session; + void *cb_arg = private->session_arg; + pthread_mutex_unlock(&private->setcallback_lock); + + for(i=0; i< private->max_sessions; i++) { + pthread_mutex_lock(&private->sessions[i].session_lock); + + if (private->sessions[i].state == S_STATE_IDLE) { + pthread_mutex_unlock(&private->sessions[i].session_lock); + continue; + } + if (private->sessions[i].slot_id != slot_id) { + pthread_mutex_unlock(&private->sessions[i].session_lock); + continue; + } + private->sessions[i].state = S_STATE_IDLE; + + uint32_t resource_id = private->sessions[i].resource_id; + pthread_mutex_unlock(&private->sessions[i].session_lock); + + if (cb) + cb(cb_arg, S_SCALLBACK_REASON_CLOSE, slot_id, i, resource_id); + + } + return; + } + } + + // sanity check data length + if (data_length < 1) { + print(LOG_LEVEL, ERROR, 1, "Received data with invalid length from module on slot %i\n", slot_id); + return; + } + + // deal with the data + uint8_t spdu_tag = data[0]; + switch(spdu_tag) + { + case ST_OPEN_SESSION_REQ: + en50221_sl_handle_open_session_request(private, data+1, data_length-1, slot_id, connection_id); + break; + + case ST_CLOSE_SESSION_REQ: + en50221_sl_handle_close_session_request(private, data+1, data_length-1, slot_id, connection_id); + break; + + case ST_SESSION_NUMBER: + en50221_sl_handle_session_package(private, data+1, data_length-1, slot_id, connection_id); + break; + + case ST_CREATE_SESSION_RES: + en50221_sl_handle_create_session_response(private, data+1, data_length-1, slot_id, connection_id); + break; + + case ST_CLOSE_SESSION_RES: + en50221_sl_handle_close_session_response(private, data+1, data_length-1, slot_id, connection_id); + break; + + default: + print(LOG_LEVEL, ERROR, 1, "Received unknown session tag %02x from module on slot %i", spdu_tag, slot_id); + break; + } +} + +static int en50221_sl_alloc_new_session(struct en50221_session_layer_private *private, + uint32_t resource_id, + uint8_t slot_id, + uint8_t connection_id, + en50221_sl_resource_callback callback, void* arg) +{ + int session_number = -1; + uint32_t i; + for(i = 1; i < private->max_sessions; i++) { + if (private->sessions[i].state == S_STATE_IDLE) { + session_number = i; + break; + } + } + if (session_number == -1) { + private->error = EN50221ERR_OUTOFSESSIONS; + return -1; + } + + // setup the session + private->sessions[session_number].state = S_STATE_IN_CREATION; + private->sessions[session_number].resource_id = resource_id; + private->sessions[session_number].slot_id = slot_id; + private->sessions[session_number].connection_id = connection_id; + private->sessions[session_number].callback = callback; + private->sessions[session_number].callback_arg = arg; + + // ok + return session_number; +} diff --git a/kaffeine/src/input/dvb/lib/libdvben50221/en50221_session.h b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_session.h new file mode 100644 index 0000000..c7cc6a8 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_session.h @@ -0,0 +1,212 @@ +/* + en50221 encoder An implementation for libdvb + an implementation for the en50221 session layer + + Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com) + Copyright (C) 2005 Julian Scheel (julian@jusst.de) + Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net) + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of + the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +#ifndef __EN50221_SESSION_H__ +#define __EN50221_SESSION_H__ + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <stdlib.h> +#include <stdint.h> +#include <libdvben50221/en50221_transport.h> + +#define S_SCALLBACK_REASON_CAMCONNECTING 0x00 // CAM originated session connecting to resource (check for availability) +#define S_SCALLBACK_REASON_CAMCONNECTED 0x01 // CAM originated session connection established succesfully +#define S_SCALLBACK_REASON_CAMCONNECTFAIL 0x02 // CAM originated session connection failed +#define S_SCALLBACK_REASON_CONNECTED 0x03 // Host originated session ACKed by CAM. +#define S_SCALLBACK_REASON_CONNECTFAIL 0x04 // Host originated session NACKed by CAM. +#define S_SCALLBACK_REASON_CLOSE 0x05 // Session closed +#define S_SCALLBACK_REASON_TC_CONNECT 0x06 // A host originated transport connection has been established. +#define S_SCALLBACK_REASON_TC_CAMCONNECT 0x07 // A CAM originated transport connection has been established. + + +/** + * Opaque type representing a session layer. + */ +typedef void *en50221_session_layer; + +/** + * Type definition for resource callback function - called by session layer when data + * arrives for a particular resource. + * + * @param arg Private argument. + * @param slot_id Slot id concerned. + * @param session_number Session number. + * @param resource_id Resource id. + * @param data The data. + * @param data_length Length of data in bytes. + * @return 0 on success, or -1 on failure. + */ +typedef int (*en50221_sl_resource_callback)(void *arg, uint8_t slot_id, + uint16_t session_number, uint32_t resource_id, + uint8_t *data, uint32_t data_length); + +/** + * Type definition for resource lookup callback function - used by the session layer to + * look up requested resources. + * + * @param arg Private argument. + * @param slot_id Slot id the request came from. + * @param requested_resource_id Resource id requested. + * @param callback_out Output parameter for pointer to resource callback function. + * @param arg_out Output parameter for arg to pass to resource callback. + * @param resource_id_out Set this to the resource_id connected to (e.g. may differ from resource_id due to versions). + * @return 0 on success, + * -1 if the resource was not found, + * -2 if it exists, but had a lower version, or + * -3 if it exists, but was unavailable. + */ +typedef int (*en50221_sl_lookup_callback)(void *arg, uint8_t slot_id, uint32_t requested_resource_id, + en50221_sl_resource_callback *callback_out, void **arg_out, + uint32_t *resource_id_out); + + +/** + * Type definition for session callback function - used to inform top level code when a CAM + * modifies a session to a resource. + * + * @param arg Private argument. + * @param reason One of the S_CCALLBACK_REASON_* values above. + * @param slot_id Slot id concerned. + * @param session_number Session number. + * @param resource_id Resource id. + * @return 0 on sucess, or -1 on error. + */ +typedef int (*en50221_sl_session_callback)(void *arg, int reason, + uint8_t slot_id, uint16_t session_number, uint32_t resource_id); + +/** + * Construct a new instance of the session layer. + * + * @param tl The en50221_transport_layer instance to use. + * @param max_sessions Maximum number of sessions supported. + * @return The en50221_session_layer instance, or NULL on error. + */ +extern en50221_session_layer en50221_sl_create(en50221_transport_layer tl, uint32_t max_sessions); + +/** + * Destroy an instance of the session layer. + * + * @param tl The en50221_session_layer instance. + */ +extern void en50221_sl_destroy(en50221_session_layer sl); + +/** + * Gets the last error. + * + * @param tl The en50221_session_layer instance. + * @return One of the EN50221ERR_* values. + */ +extern int en50221_sl_get_error(en50221_session_layer tl); + +/** + * Register the callback for resource lookup. + * + * @param sl The en50221_session_layer instance. + * @param callback The callback. Set to NULL to remove the callback completely. + * @param arg Private data passed as arg0 of the callback. + */ +extern void en50221_sl_register_lookup_callback(en50221_session_layer sl, + en50221_sl_lookup_callback callback, void *arg); + +/** + * Register the callback for informing about session from a cam. + * + * @param sl The en50221_session_layer instance. + * @param callback The callback. Set to NULL to remove the callback completely. + * @param arg Private data passed as arg0 of the callback. + */ +extern void en50221_sl_register_session_callback(en50221_session_layer sl, + en50221_sl_session_callback callback, void *arg); + +/** + * Create a new session to a module in a slot. + * + * @param sl The en50221_session_layer instance. + * @param slot The slot to connect to. + * @param resource_id The resource_id to connect to. + * @param callback The callback for received data. + * @param arg Argument to pass to the callback. + * @return The new session_number, or -1 on error. + */ +extern int en50221_sl_create_session(en50221_session_layer sl, int slot_id, uint8_t connection_id, + uint32_t resource_id, + en50221_sl_resource_callback callback, void* arg); + +/** + * Destroy a session. + * + * @param sl The en50221_session_layer instance. + * @param session_number The session to destroy. + * @return 0 on success, or -1 on error. + */ +extern int en50221_sl_destroy_session(en50221_session_layer sl, uint16_t session_number); + +/** + * this function is used to take a data-block, pack into + * into a SPDU (SESSION_NUMBER) and send it to the transport layer + * + * @param sl The en50221_session_layer instance to use. + * @param session_number Session number concerned. + * @param data Data to send. + * @param data_length Length of data in bytes. + * @return 0 on success, or -1 on error. + */ +extern int en50221_sl_send_data(en50221_session_layer sl, uint16_t session_number, uint8_t *data, uint16_t data_length); + +/** + * this function is used to take a data-block, pack into + * into a SPDU (SESSION_NUMBER) and send it to the transport layer + * + * @param sl The en50221_session_layer instance to use. + * @param session_number Session number concerned. + * @param vector IOVEC to send. + * @param iov_count Number of elements in io vector. + * @return 0 on success, or -1 on error. + */ +extern int en50221_sl_send_datav(en50221_session_layer sl, uint16_t session_number, + struct iovec *vector, int iov_count); + +/** + * this is used to send a message to all sessions, linked + * to resource res + * + * @param tl The en50221_session_layer instance to use. + * @param slot_id Set to -1 to send to any slot. Other values will send to only that slot. + * @param resource_id Resource id concerned. + * @param data Data to send. + * @param data_length Length of data in bytes. + * @return 0 on success, or -1 on error. + */ +extern int en50221_sl_broadcast_data(en50221_session_layer sl, int slot_id, uint32_t resource_id, + uint8_t *data, uint16_t data_length); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libdvben50221/en50221_transport.c b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_transport.c new file mode 100644 index 0000000..ff7c936 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_transport.c @@ -0,0 +1,1240 @@ +/* + en50221 encoder An implementation for libdvb + an implementation for the en50221 transport layer + + Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com) + Copyright (C) 2005 Julian Scheel (julian at jusst dot de) + Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net) + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of + the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <pthread.h> +#include <fcntl.h> +#include <sys/ioctl.h> +#include <sys/poll.h> +#include <time.h> +#include <libdvbmisc/dvbmisc.h> +#include <libdvbapi/dvbca.h> +#include "en50221_errno.h" +#include "en50221_transport.h" +#include "asn_1.h" + +// these are the Transport Tags, like +// described in EN50221, Annex A.4.1.13 (pg70) +#define T_SB 0x80 // sb primitive h<--m +#define T_RCV 0x81 // receive primitive h-->m +#define T_CREATE_T_C 0x82 // create transport connection primitive h-->m +#define T_C_T_C_REPLY 0x83 // ctc reply primitive h<--m +#define T_DELETE_T_C 0x84 // delete tc primitive h<->m +#define T_D_T_C_REPLY 0x85 // dtc reply primitive h<->m +#define T_REQUEST_T_C 0x86 // request transport connection primitive h<--m +#define T_NEW_T_C 0x87 // new tc / reply to t_request primitive h-->m +#define T_T_C_ERROR 0x77 // error creating tc primitive h-->m +#define T_DATA_LAST 0xA0 // convey data from higher constructed h<->m + // layers +#define T_DATA_MORE 0xA1 // convey data from higher constructed h<->m + // layers + +struct en50221_message { + struct en50221_message *next; + uint32_t length; + uint8_t data[0]; +}; + +struct en50221_connection { + uint32_t state; // the current state: idle/in_delete/in_create/active + struct timeval tx_time; // time last request was sent from host->module, or 0 if ok + struct timeval last_poll_time; // time of last poll transmission + uint8_t *chain_buffer; // used to save parts of chained packets + uint32_t buffer_length; + + struct en50221_message *send_queue; + struct en50221_message *send_queue_tail; +}; + +struct en50221_slot { + int ca_hndl; + uint8_t slot; // CAM slot + struct en50221_connection *connections; + + pthread_mutex_t slot_lock; + + uint32_t response_timeout; + uint32_t poll_delay; +}; + +struct en50221_transport_layer_private +{ + uint8_t max_slots; + uint8_t max_connections_per_slot; + struct en50221_slot *slots; + struct pollfd *slot_pollfds; + int slots_changed; + + pthread_mutex_t global_lock; + pthread_mutex_t setcallback_lock; + + int error; + int error_slot; + + en50221_tl_callback callback; + void *callback_arg; +}; + +static int en50221_tl_process_data(struct en50221_transport_layer_private *tl, uint8_t slot_id, + uint8_t *data, uint32_t data_length); +static int en50221_tl_poll_tc(struct en50221_transport_layer_private *tl, uint8_t slot_id, uint8_t connection_id); +static int en50221_tl_alloc_new_tc(struct en50221_transport_layer_private *tl, uint8_t slot_id); +static void queue_message(struct en50221_transport_layer_private *tl, uint8_t slot_id, + uint8_t connection_id, struct en50221_message *msg); +static int en50221_tl_handle_create_tc_reply(struct en50221_transport_layer_private *private, + uint8_t slot_id, uint8_t connection_id); +static int en50221_tl_handle_delete_tc(struct en50221_transport_layer_private *private, + uint8_t slot_id, uint8_t connection_id); +static int en50221_tl_handle_delete_tc_reply(struct en50221_transport_layer_private *private, + uint8_t slot_id, uint8_t connection_id); +static int en50221_tl_handle_request_tc(struct en50221_transport_layer_private *private, + uint8_t slot_id, uint8_t connection_id); +static int en50221_tl_handle_data_more(struct en50221_transport_layer_private *private, + uint8_t slot_id, uint8_t connection_id, + uint8_t *data, uint32_t data_length); +static int en50221_tl_handle_data_last(struct en50221_transport_layer_private *private, + uint8_t slot_id, uint8_t connection_id, + uint8_t *data, uint32_t data_length); +static int en50221_tl_handle_sb(struct en50221_transport_layer_private *private, + uint8_t slot_id, uint8_t connection_id, + uint8_t *data, uint32_t data_length); + + +en50221_transport_layer en50221_tl_create(uint8_t max_slots, uint8_t max_connections_per_slot) +{ + struct en50221_transport_layer_private *private = NULL; + int i; + int j; + + // setup structure + private = (struct en50221_transport_layer_private*) malloc(sizeof(struct en50221_transport_layer_private)); + if (private == NULL) + goto error_exit; + private->max_slots = max_slots; + private->max_connections_per_slot = max_connections_per_slot; + private->slots = NULL; + private->slot_pollfds = NULL; + private->slots_changed = 1; + private->callback = NULL; + private->callback_arg = NULL; + private->error_slot = 0; + private->error = 0; + pthread_mutex_init(&private->global_lock, NULL); + pthread_mutex_init(&private->setcallback_lock, NULL); + + // create the slots + private->slots = malloc(sizeof(struct en50221_slot) * max_slots); + if (private->slots == NULL) + goto error_exit; + + // set them up + for(i=0; i< max_slots; i++) { + private->slots[i].ca_hndl = -1; + + // create the connections for this slot + private->slots[i].connections = malloc(sizeof(struct en50221_connection) * max_connections_per_slot); + if (private->slots[i].connections == NULL) + goto error_exit; + + // create a mutex for the slot + pthread_mutex_init(&private->slots[i].slot_lock, NULL); + + // set them up + for(j = 0; j < max_connections_per_slot; j++) { + private->slots[i].connections[j].state = T_STATE_IDLE; + private->slots[i].connections[j].tx_time.tv_sec = 0; + private->slots[i].connections[j].last_poll_time.tv_sec = 0; + private->slots[i].connections[j].last_poll_time.tv_usec = 0; + private->slots[i].connections[j].chain_buffer = NULL; + private->slots[i].connections[j].buffer_length = 0; + private->slots[i].connections[j].send_queue = NULL; + private->slots[i].connections[j].send_queue_tail = NULL; + } + } + + // create the pollfds + private->slot_pollfds = malloc(sizeof(struct pollfd) * max_slots); + if (private->slot_pollfds == NULL) { + goto error_exit; + } + memset(private->slot_pollfds, 0, sizeof(struct pollfd) * max_slots); + + return private; + +error_exit: + en50221_tl_destroy(private); + return NULL; +} + +// Destroy an instance of the transport layer +void en50221_tl_destroy(en50221_transport_layer tl) +{ + struct en50221_transport_layer_private *private = (struct en50221_transport_layer_private *) tl; + int i, j; + + if (private) { + if (private->slots) { + for(i=0; i< private->max_slots; i++) { + if (private->slots[i].connections) { + for(j=0; j<private->max_connections_per_slot; j++) { + if (private->slots[i].connections[j].chain_buffer) { + free(private->slots[i].connections[j].chain_buffer); + } + + struct en50221_message *cur_msg = private->slots[i].connections[j].send_queue; + while(cur_msg) { + struct en50221_message *next_msg = cur_msg->next; + free(cur_msg); + cur_msg = next_msg; + } + private->slots[i].connections[j].send_queue = NULL; + private->slots[i].connections[j].send_queue_tail = NULL; + } + free(private->slots[i].connections); + pthread_mutex_destroy(&private->slots[i].slot_lock); + } + } + free(private->slots); + } + if (private->slot_pollfds) { + free(private->slot_pollfds); + } + pthread_mutex_destroy(&private->setcallback_lock); + pthread_mutex_destroy(&private->global_lock); + free(private); + } +} + +// this can be called from the user-space app to +// register new slots that we should work with +int en50221_tl_register_slot(en50221_transport_layer tl, int ca_hndl, uint8_t slot, + uint32_t response_timeout, uint32_t poll_delay) +{ + struct en50221_transport_layer_private *private = (struct en50221_transport_layer_private *) tl; + + // lock + pthread_mutex_lock(&private->global_lock); + + // we browse through the array of slots + // to look for the first unused one + int i; + int16_t slot_id = -1; + for(i=0; i < private->max_slots; i++) { + if (private->slots[i].ca_hndl == -1) { + slot_id = i; + break; + } + } + if (slot_id == -1) { + private->error = EN50221ERR_OUTOFSLOTS; + pthread_mutex_unlock(&private->global_lock); + return -1; + } + + // set up the slot struct + pthread_mutex_lock(&private->slots[slot_id].slot_lock); + private->slots[slot_id].ca_hndl = ca_hndl; + private->slots[slot_id].slot = slot; + private->slots[slot_id].response_timeout = response_timeout; + private->slots[slot_id].poll_delay = poll_delay; + pthread_mutex_unlock(&private->slots[slot_id].slot_lock); + + private->slots_changed = 1; + pthread_mutex_unlock(&private->global_lock); + return slot_id; +} + +void en50221_tl_destroy_slot(en50221_transport_layer tl, uint8_t slot_id) +{ + struct en50221_transport_layer_private *private = (struct en50221_transport_layer_private *) tl; + int i; + + if (slot_id >= private->max_slots) + return; + + // lock + pthread_mutex_lock(&private->global_lock); + + // clear the slot + pthread_mutex_lock(&private->slots[slot_id].slot_lock); + private->slots[slot_id].ca_hndl = -1; + for(i=0; i<private->max_connections_per_slot; i++) { + private->slots[slot_id].connections[i].state = T_STATE_IDLE; + private->slots[slot_id].connections[i].tx_time.tv_sec = 0; + private->slots[slot_id].connections[i].last_poll_time.tv_sec = 0; + private->slots[slot_id].connections[i].last_poll_time.tv_usec = 0; + if (private->slots[slot_id].connections[i].chain_buffer) { + free(private->slots[slot_id].connections[i].chain_buffer); + } + private->slots[slot_id].connections[i].chain_buffer = NULL; + private->slots[slot_id].connections[i].buffer_length = 0; + + struct en50221_message *cur_msg = private->slots[slot_id].connections[i].send_queue; + while(cur_msg) { + struct en50221_message *next_msg = cur_msg->next; + free(cur_msg); + cur_msg = next_msg; + } + private->slots[slot_id].connections[i].send_queue = NULL; + private->slots[slot_id].connections[i].send_queue_tail = NULL; + } + pthread_mutex_unlock(&private->slots[slot_id].slot_lock); + + // tell upper layers + pthread_mutex_lock(&private->setcallback_lock); + en50221_tl_callback cb = private->callback; + void *cb_arg = private->callback_arg; + pthread_mutex_unlock(&private->setcallback_lock); + if (cb) + cb(cb_arg, T_CALLBACK_REASON_SLOTCLOSE, NULL, 0, slot_id, 0); + + private->slots_changed = 1; + pthread_mutex_unlock(&private->global_lock); +} + +int en50221_tl_poll(en50221_transport_layer tl) +{ + struct en50221_transport_layer_private *private = (struct en50221_transport_layer_private *) tl; + uint8_t data[4096]; + int slot_id; + int j; + + // make up pollfds if the slots have changed + pthread_mutex_lock(&private->global_lock); + if (private->slots_changed) { + for(slot_id = 0; slot_id < private->max_slots; slot_id++) { + if (private->slots[slot_id].ca_hndl != -1) { + private->slot_pollfds[slot_id].fd = private->slots[slot_id].ca_hndl; + private->slot_pollfds[slot_id].events = POLLIN|POLLPRI|POLLERR; + private->slot_pollfds[slot_id].revents = 0; + } else { + private->slot_pollfds[slot_id].fd = 0; + private->slot_pollfds[slot_id].events = 0; + private->slot_pollfds[slot_id].revents = 0; + } + } + private->slots_changed = 0; + } + pthread_mutex_unlock(&private->global_lock); + + // anything happened? + if (poll(private->slot_pollfds, private->max_slots, 10) < 0) { + private->error_slot = -1; + private->error = EN50221ERR_CAREAD; + return -1; + } + + // go through all slots (even though poll may not have reported any events + for(slot_id = 0; slot_id < private->max_slots; slot_id++) { + + // check if this slot is still used and get its handle + pthread_mutex_lock(&private->slots[slot_id].slot_lock); + if (private->slots[slot_id].ca_hndl == -1) { + pthread_mutex_unlock(&private->slots[slot_id].slot_lock); + continue; + } + int ca_hndl = private->slots[slot_id].ca_hndl; + + if (private->slot_pollfds[slot_id].revents & (POLLPRI | POLLIN)) { + // read data + uint8_t r_slot_id; + uint8_t connection_id; + int readcnt = dvbca_link_read(ca_hndl, &r_slot_id, &connection_id, data, sizeof(data)); + if (readcnt < 0) { + private->error_slot = slot_id; + private->error = EN50221ERR_CAREAD; + pthread_mutex_unlock(&private->slots[slot_id].slot_lock); + return -1; + } + + // process it if we got some + if (readcnt > 0) { + if (private->slots[slot_id].slot != r_slot_id) { + // this message is for an other CAM of the same CA + int new_slot_id; + for(new_slot_id = 0; new_slot_id < private->max_slots; new_slot_id++) { + if ((private->slots[new_slot_id].ca_hndl == ca_hndl) && (private->slots[new_slot_id].slot == r_slot_id)) + break; + } + if (new_slot_id != private->max_slots) { + // we found the requested CAM + pthread_mutex_lock(&private->slots[new_slot_id].slot_lock); + if (en50221_tl_process_data(private, new_slot_id, data, readcnt)) { + pthread_mutex_unlock(&private->slots[new_slot_id].slot_lock); + pthread_mutex_unlock(&private->slots[slot_id].slot_lock); + return -1; + } + pthread_mutex_unlock(&private->slots[new_slot_id].slot_lock); + } else { + private->error = EN50221ERR_BADSLOTID; + pthread_mutex_unlock(&private->slots[slot_id].slot_lock); + return -1; + } + } + else if (en50221_tl_process_data(private, slot_id, data, readcnt)) { + pthread_mutex_unlock(&private->slots[slot_id].slot_lock); + return -1; + } + } + } else if (private->slot_pollfds[slot_id].revents & POLLERR) { + // an error was reported + private->error_slot = slot_id; + private->error = EN50221ERR_CAREAD; + pthread_mutex_unlock(&private->slots[slot_id].slot_lock); + return -1; + } + + // poll the connections on this slot + check for timeouts + for(j=0; j < private->max_connections_per_slot; j++) { + // ignore connection if idle + if (private->slots[slot_id].connections[j].state == T_STATE_IDLE) { + continue; + } + + // send queued data + if (private->slots[slot_id].connections[j].state & (T_STATE_IN_CREATION|T_STATE_ACTIVE|T_STATE_ACTIVE_DELETEQUEUED)) { + // send data if there is some to go and we're not waiting for a response already + if (private->slots[slot_id].connections[j].send_queue && + (private->slots[slot_id].connections[j].tx_time.tv_sec == 0)) { + + // get the message + struct en50221_message *msg = private->slots[slot_id].connections[j].send_queue; + if (msg->next != NULL) { + private->slots[slot_id].connections[j].send_queue = msg->next; + } else { + private->slots[slot_id].connections[j].send_queue = NULL; + private->slots[slot_id].connections[j].send_queue_tail = NULL; + } + + // send the message + if (dvbca_link_write(private->slots[slot_id].ca_hndl, private->slots[slot_id].slot, j, msg->data, msg->length) < 0) { + free(msg); + pthread_mutex_unlock(&private->slots[slot_id].slot_lock); + private->error_slot = slot_id; + private->error = EN50221ERR_CAWRITE; + print(LOG_LEVEL, ERROR, 1, "CAWrite failed"); + return -1; + } + gettimeofday(&private->slots[slot_id].connections[j].tx_time, 0); + + // fixup connection state for T_DELETE_T_C + if (msg->length && (msg->data[0] == T_DELETE_T_C)) { + private->slots[slot_id].connections[j].state = T_STATE_IN_DELETION; + if (private->slots[slot_id].connections[j].chain_buffer) { + free(private->slots[slot_id].connections[j].chain_buffer); + } + private->slots[slot_id].connections[j].chain_buffer = NULL; + private->slots[slot_id].connections[j].buffer_length = 0; + } + + free(msg); + } + } + + // poll it if we're not expecting a reponse and the poll time has elapsed + if (private->slots[slot_id].connections[j].state & T_STATE_ACTIVE) { + if ((private->slots[slot_id].connections[j].tx_time.tv_sec == 0) && + (time_after(private->slots[slot_id].connections[j].last_poll_time, private->slots[slot_id].poll_delay))) { + + gettimeofday(&private->slots[slot_id].connections[j].last_poll_time, 0); + if (en50221_tl_poll_tc(private, slot_id, j)) { + pthread_mutex_unlock(&private->slots[slot_id].slot_lock); + return -1; + } + } + } + + // check for timeouts - in any state + if (private->slots[slot_id].connections[j].tx_time.tv_sec && + (time_after(private->slots[slot_id].connections[j].tx_time, private->slots[slot_id].response_timeout))) { + + if (private->slots[slot_id].connections[j].state & (T_STATE_IN_CREATION|T_STATE_IN_DELETION)) { + private->slots[slot_id].connections[j].state = T_STATE_IDLE; + } else if (private->slots[slot_id].connections[j].state & (T_STATE_ACTIVE|T_STATE_ACTIVE_DELETEQUEUED)) { + private->error_slot = slot_id; + private->error = EN50221ERR_TIMEOUT; + pthread_mutex_unlock(&private->slots[slot_id].slot_lock); + return -1; + } + } + } + pthread_mutex_unlock(&private->slots[slot_id].slot_lock); + } + + return 0; +} + +void en50221_tl_register_callback(en50221_transport_layer tl, en50221_tl_callback callback, void *arg) +{ + struct en50221_transport_layer_private *private = (struct en50221_transport_layer_private *) tl; + + pthread_mutex_lock(&private->setcallback_lock); + private->callback = callback; + private->callback_arg = arg; + pthread_mutex_unlock(&private->setcallback_lock); +} + +int en50221_tl_get_error_slot(en50221_transport_layer tl) +{ + struct en50221_transport_layer_private *private = (struct en50221_transport_layer_private *) tl; + return private->error_slot; +} + +int en50221_tl_get_error(en50221_transport_layer tl) +{ + struct en50221_transport_layer_private *private = (struct en50221_transport_layer_private *) tl; + return private->error; +} + +int en50221_tl_send_data(en50221_transport_layer tl, uint8_t slot_id, uint8_t connection_id, + uint8_t *data, uint32_t data_size) +{ + struct en50221_transport_layer_private *private = (struct en50221_transport_layer_private *) tl; + +#ifdef DEBUG_TXDATA + printf("[[[[[[[[[[[[[[[[[[[[\n"); + uint32_t ii=0; + for(ii=0;ii<data_size;ii++) { + printf("%02x: %02x\n", ii, data[ii]); + } + printf("]]]]]]]]]]]]]]]]]]]]\n"); +#endif + + if (slot_id >= private->max_slots) { + private->error = EN50221ERR_BADSLOTID; + return -1; + } + + pthread_mutex_lock(&private->slots[slot_id].slot_lock); + if (private->slots[slot_id].ca_hndl == -1) { + private->error = EN50221ERR_BADSLOTID; + pthread_mutex_unlock(&private->slots[slot_id].slot_lock); + return -1; + } + if (connection_id >= private->max_connections_per_slot) { + private->error_slot = slot_id; + private->error = EN50221ERR_BADCONNECTIONID; + pthread_mutex_unlock(&private->slots[slot_id].slot_lock); + return -1; + } + if (private->slots[slot_id].connections[connection_id].state != T_STATE_ACTIVE) { + private->error = EN50221ERR_BADCONNECTIONID; + pthread_mutex_unlock(&private->slots[slot_id].slot_lock); + return -1; + } + + // allocate msg structure + struct en50221_message *msg = malloc(sizeof(struct en50221_message)+data_size+10); + if (msg == NULL) { + private->error_slot = slot_id; + private->error = EN50221ERR_OUTOFMEMORY; + pthread_mutex_unlock(&private->slots[slot_id].slot_lock); + return -1; + } + + // make up data to send + int length_field_len; + msg->data[0] = T_DATA_LAST; + if ((length_field_len = asn_1_encode(data_size + 1, msg->data + 1, 3)) < 0) { + free(msg); + private->error_slot = slot_id; + private->error = EN50221ERR_ASNENCODE; + pthread_mutex_unlock(&private->slots[slot_id].slot_lock); + return -1; + } + msg->data[1 + length_field_len] = connection_id; + memcpy(msg->data+1+length_field_len+1, data, data_size); + msg->length = 1+length_field_len+1+data_size; + + // queue it for transmission + queue_message(private, slot_id, connection_id, msg); + + pthread_mutex_unlock(&private->slots[slot_id].slot_lock); + return 0; +} + +int en50221_tl_send_datav(en50221_transport_layer tl, uint8_t slot_id, uint8_t connection_id, + struct iovec *vector, int iov_count) +{ + struct en50221_transport_layer_private *private = (struct en50221_transport_layer_private *) tl; + +#ifdef DEBUG_TXDATA + printf("[[[[[[[[[[[[[[[[[[[[\n"); + uint32_t ii=0; + uint32_t iipos=0; + for(ii=0;ii<(uint32_t) iov_count;ii++) { + uint32_t jj; + for(jj=0; jj< vector[ii].iov_len; jj++) { + printf("%02x: %02x\n", jj+iipos, *((uint8_t*) (vector[ii].iov_base) +jj)); + } + iipos += vector[ii].iov_len; + } + printf("]]]]]]]]]]]]]]]]]]]]\n"); +#endif + + if (slot_id >= private->max_slots) { + private->error = EN50221ERR_BADSLOTID; + return -1; + } + + pthread_mutex_lock(&private->slots[slot_id].slot_lock); + if (private->slots[slot_id].ca_hndl == -1) { + private->error = EN50221ERR_BADSLOTID; + pthread_mutex_unlock(&private->slots[slot_id].slot_lock); + return -1; + } + if (connection_id >= private->max_connections_per_slot) { + private->error_slot = slot_id; + private->error = EN50221ERR_BADCONNECTIONID; + pthread_mutex_unlock(&private->slots[slot_id].slot_lock); + return -1; + } + if (private->slots[slot_id].connections[connection_id].state != T_STATE_ACTIVE) { + private->error = EN50221ERR_BADCONNECTIONID; + pthread_mutex_unlock(&private->slots[slot_id].slot_lock); + return -1; + } + + // calculate the total length of the data to send + uint32_t data_size = 0; + int i; + for(i=0; i< iov_count; i++) { + data_size += vector[i].iov_len; + } + + // allocate msg structure + struct en50221_message *msg = malloc(sizeof(struct en50221_message)+data_size+10); + if (msg == NULL) { + private->error_slot = slot_id; + private->error = EN50221ERR_OUTOFMEMORY; + pthread_mutex_unlock(&private->slots[slot_id].slot_lock); + return -1; + } + + // make up data to send + int length_field_len; + msg->data[0] = T_DATA_LAST; + if ((length_field_len = asn_1_encode(data_size + 1, msg->data + 1, 3)) < 0) { + free(msg); + private->error_slot = slot_id; + private->error = EN50221ERR_ASNENCODE; + pthread_mutex_unlock(&private->slots[slot_id].slot_lock); + return -1; + } + msg->data[1 + length_field_len] = connection_id; + msg->length = 1+length_field_len+1+data_size; + msg->next = NULL; + + // merge the iovecs + uint32_t pos = 1+length_field_len+1; + for(i=0; i< iov_count; i++) { + memcpy(msg->data+pos, vector[i].iov_base, vector[i].iov_len); + pos += vector[i].iov_len; + } + + // queue it for transmission + queue_message(private, slot_id, connection_id, msg); + + pthread_mutex_unlock(&private->slots[slot_id].slot_lock); + return 0; +} + +int en50221_tl_new_tc(en50221_transport_layer tl, uint8_t slot_id) +{ + struct en50221_transport_layer_private *private = (struct en50221_transport_layer_private *) tl; + + // check + if (slot_id >= private->max_slots) { + private->error = EN50221ERR_BADSLOTID; + return -1; + } + + pthread_mutex_lock(&private->slots[slot_id].slot_lock); + if (private->slots[slot_id].ca_hndl == -1) { + private->error = EN50221ERR_BADSLOTID; + pthread_mutex_unlock(&private->slots[slot_id].slot_lock); + return -1; + } + + // allocate a new connection if possible + int conid = en50221_tl_alloc_new_tc(private, slot_id); + if (conid == -1) { + private->error_slot = slot_id; + private->error = EN50221ERR_OUTOFCONNECTIONS; + pthread_mutex_unlock(&private->slots[slot_id].slot_lock); + return -1; + } + + // allocate msg structure + struct en50221_message *msg = malloc(sizeof(struct en50221_message)+3); + if (msg == NULL) { + private->error_slot = slot_id; + private->error = EN50221ERR_OUTOFMEMORY; + pthread_mutex_unlock(&private->slots[slot_id].slot_lock); + return -1; + } + + // make up the data to send + msg->data[0] = T_CREATE_T_C; + msg->data[1] = 1; + msg->data[2] = conid; + msg->length = 3; + msg->next = NULL; + + // queue it for transmission + queue_message(private, slot_id, conid, msg); + + // done + pthread_mutex_unlock(&private->slots[slot_id].slot_lock); + return conid; +} + +int en50221_tl_del_tc(en50221_transport_layer tl, uint8_t slot_id, uint8_t connection_id) +{ + struct en50221_transport_layer_private *private = (struct en50221_transport_layer_private *) tl; + + // check + if (slot_id >= private->max_slots) { + private->error = EN50221ERR_BADSLOTID; + return -1; + } + + pthread_mutex_lock(&private->slots[slot_id].slot_lock); + if (private->slots[slot_id].ca_hndl == -1) { + private->error = EN50221ERR_BADSLOTID; + pthread_mutex_unlock(&private->slots[slot_id].slot_lock); + return -1; + } + if (connection_id >= private->max_connections_per_slot) { + private->error_slot = slot_id; + private->error = EN50221ERR_BADCONNECTIONID; + pthread_mutex_unlock(&private->slots[slot_id].slot_lock); + return -1; + } + if (!(private->slots[slot_id].connections[connection_id].state & + (T_STATE_ACTIVE|T_STATE_IN_DELETION))) { + private->error_slot = slot_id; + private->error = EN50221ERR_BADSTATE; + pthread_mutex_unlock(&private->slots[slot_id].slot_lock); + return -1; + } + + // allocate msg structure + struct en50221_message *msg = malloc(sizeof(struct en50221_message)+3); + if (msg == NULL) { + private->error_slot = slot_id; + private->error = EN50221ERR_OUTOFMEMORY; + pthread_mutex_unlock(&private->slots[slot_id].slot_lock); + return -1; + } + + // make up the data to send + msg->data[0] = T_DELETE_T_C; + msg->data[1] = 1; + msg->data[2] = connection_id; + msg->length = 3; + msg->next = NULL; + + // queue it for transmission + queue_message(private, slot_id, connection_id, msg); + private->slots[slot_id].connections[connection_id].state = T_STATE_ACTIVE_DELETEQUEUED; + + pthread_mutex_unlock(&private->slots[slot_id].slot_lock); + return 0; +} + +int en50221_tl_get_connection_state(en50221_transport_layer tl, + uint8_t slot_id, uint8_t connection_id) +{ + struct en50221_transport_layer_private *private = (struct en50221_transport_layer_private *) tl; + + if (slot_id >= private->max_slots) { + private->error = EN50221ERR_BADSLOTID; + return -1; + } + + pthread_mutex_lock(&private->slots[slot_id].slot_lock); + if (private->slots[slot_id].ca_hndl == -1) { + private->error = EN50221ERR_BADSLOTID; + pthread_mutex_unlock(&private->slots[slot_id].slot_lock); + return -1; + } + if (connection_id >= private->max_connections_per_slot) { + private->error_slot = slot_id; + private->error = EN50221ERR_BADCONNECTIONID; + pthread_mutex_unlock(&private->slots[slot_id].slot_lock); + return -1; + } + int state = private->slots[slot_id].connections[connection_id].state; + pthread_mutex_unlock(&private->slots[slot_id].slot_lock); + + return state; +} + + + + +// ask the module for new data +static int en50221_tl_poll_tc(struct en50221_transport_layer_private *private, uint8_t slot_id, uint8_t connection_id) +{ + gettimeofday(&private->slots[slot_id].connections[connection_id].tx_time, 0); + + // send command + uint8_t hdr[3]; + hdr[0] = T_DATA_LAST; + hdr[1] = 1; + hdr[2] = connection_id; + if (dvbca_link_write(private->slots[slot_id].ca_hndl, private->slots[slot_id].slot, connection_id, hdr, 3) < 0) { + private->error_slot = slot_id; + private->error = EN50221ERR_CAWRITE; + return -1; + } + return 0; +} + +// handle incoming data +static int en50221_tl_process_data(struct en50221_transport_layer_private *private, uint8_t slot_id, + uint8_t *data, uint32_t data_length) +{ + int result; + +#ifdef DEBUG_RXDATA + printf("-------------------\n"); + uint32_t ii=0; + for(ii=0; ii< data_length; ii++) { + printf("%02x: %02x\n", ii, data[ii]); + } + printf("+++++++++++++++++++\n"); +#endif + + // process the received data + while(data_length) { + // parse the header + uint8_t tpdu_tag = data[0]; + uint16_t asn_data_length; + int length_field_len; + if ((length_field_len = asn_1_decode(&asn_data_length, data + 1, data_length - 1)) < 0) { + print(LOG_LEVEL, ERROR, 1, "Received data with invalid asn from module on slot %02x\n", slot_id); + private->error_slot = slot_id; + private->error = EN50221ERR_BADCAMDATA; + return -1; + } + if ((asn_data_length < 1) || (asn_data_length > (data_length-(1+length_field_len)))) { + print(LOG_LEVEL, ERROR, 1, "Received data with invalid length from module on slot %02x\n", slot_id); + private->error_slot = slot_id; + private->error = EN50221ERR_BADCAMDATA; + return -1; + } + uint8_t connection_id = data[1 + length_field_len]; + data += 1 + length_field_len + 1; + data_length -= (1 + length_field_len + 1); + asn_data_length--; + + // check the connection_id + if (connection_id >= private->max_connections_per_slot) { + print(LOG_LEVEL, ERROR, 1, "Received bad connection id %02x from module on slot %02x\n", connection_id, slot_id); + private->error_slot = slot_id; + private->error = EN50221ERR_BADCONNECTIONID; + return -1; + } + + // process the TPDUs + switch(tpdu_tag) { + case T_C_T_C_REPLY: + if ((result = en50221_tl_handle_create_tc_reply(private, slot_id, connection_id)) < 0) { + return -1; + } + break; + case T_DELETE_T_C: + if ((result = en50221_tl_handle_delete_tc(private, slot_id, connection_id)) < 0) { + return -1; + } + break; + case T_D_T_C_REPLY: + if ((result = en50221_tl_handle_delete_tc_reply(private, slot_id, connection_id)) < 0) { + return -1; + } + break; + case T_REQUEST_T_C: + if ((result = en50221_tl_handle_request_tc(private, slot_id, connection_id)) < 0) { + return -1; + } + break; + case T_DATA_MORE: + if ((result = en50221_tl_handle_data_more(private, slot_id, connection_id, data, asn_data_length)) < 0) { + return -1; + } + break; + case T_DATA_LAST: + if ((result = en50221_tl_handle_data_last(private, slot_id, connection_id, data, asn_data_length)) < 0) { + return -1; + } + break; + case T_SB: + if ((result = en50221_tl_handle_sb(private, slot_id, connection_id, data, asn_data_length)) < 0) { + return -1; + } + break; + default: + print(LOG_LEVEL, ERROR, 1, "Recieved unexpected TPDU tag %02x from module on slot %02x\n", + tpdu_tag, slot_id); + private->error_slot = slot_id; + private->error = EN50221ERR_BADCAMDATA; + return -1; + } + + // skip over the consumed data + data += asn_data_length; + data_length -= asn_data_length; + } + + return 0; +} + +static int en50221_tl_handle_create_tc_reply(struct en50221_transport_layer_private *private, + uint8_t slot_id, uint8_t connection_id) +{ + // set this connection to state active + if (private->slots[slot_id].connections[connection_id].state == T_STATE_IN_CREATION) { + private->slots[slot_id].connections[connection_id].state = T_STATE_ACTIVE; + private->slots[slot_id].connections[connection_id].tx_time.tv_sec = 0; + + // tell upper layers + pthread_mutex_lock(&private->setcallback_lock); + en50221_tl_callback cb = private->callback; + void *cb_arg = private->callback_arg; + pthread_mutex_unlock(&private->setcallback_lock); + if (cb) + cb(cb_arg, T_CALLBACK_REASON_CONNECTIONOPEN, NULL, 0, slot_id, connection_id); + } else { + print(LOG_LEVEL, ERROR, 1, "Received T_C_T_C_REPLY for connection not in " + "T_STATE_IN_CREATION from module on slot %02x\n", slot_id); + private->error_slot = slot_id; + private->error = EN50221ERR_BADCAMDATA; + return -1; + } + + return 0; +} + +static int en50221_tl_handle_delete_tc(struct en50221_transport_layer_private *private, + uint8_t slot_id, uint8_t connection_id) +{ + // immediately delete this connection and send D_T_C_REPLY + if (private->slots[slot_id].connections[connection_id].state & (T_STATE_ACTIVE|T_STATE_IN_DELETION)) + { + // clear down the slot + private->slots[slot_id].connections[connection_id].state = T_STATE_IDLE; + if (private->slots[slot_id].connections[connection_id].chain_buffer) { + free(private->slots[slot_id].connections[connection_id].chain_buffer); + } + private->slots[slot_id].connections[connection_id].chain_buffer = NULL; + private->slots[slot_id].connections[connection_id].buffer_length = 0; + + // send the reply + uint8_t hdr[3]; + hdr[0] = T_D_T_C_REPLY; + hdr[1] = 1; + hdr[2] = connection_id; + if (dvbca_link_write(private->slots[slot_id].ca_hndl, private->slots[slot_id].slot, connection_id, hdr, 3) < 0) { + private->error_slot = slot_id; + private->error = EN50221ERR_CAWRITE; + return -1; + } + + // tell upper layers + pthread_mutex_lock(&private->setcallback_lock); + en50221_tl_callback cb = private->callback; + void *cb_arg = private->callback_arg; + pthread_mutex_unlock(&private->setcallback_lock); + if (cb) + cb(cb_arg, T_CALLBACK_REASON_CONNECTIONCLOSE, NULL, 0, slot_id, connection_id); + } + else { + print(LOG_LEVEL, ERROR, 1, "Received T_DELETE_T_C for inactive connection from module on slot %02x\n", + slot_id); + private->error_slot = slot_id; + private->error = EN50221ERR_BADCAMDATA; + return -1; + } + + return 0; +} + +static int en50221_tl_handle_delete_tc_reply(struct en50221_transport_layer_private *private, + uint8_t slot_id, uint8_t connection_id) +{ + // delete this connection, should be in T_STATE_IN_DELETION already + if (private->slots[slot_id].connections[connection_id].state == T_STATE_IN_DELETION) { + private->slots[slot_id].connections[connection_id].state = T_STATE_IDLE; + } else { + print(LOG_LEVEL, ERROR, 1, "Received T_D_T_C_REPLY received for connection not in " + "T_STATE_IN_DELETION from module on slot %02x\n", slot_id); + private->error_slot = slot_id; + private->error = EN50221ERR_BADCAMDATA; + return -1; + } + + return 0; +} + +static int en50221_tl_handle_request_tc(struct en50221_transport_layer_private *private, + uint8_t slot_id, uint8_t connection_id) +{ + // allocate a new connection if possible + int conid = en50221_tl_alloc_new_tc(private, slot_id); + int ca_hndl = private->slots[slot_id].ca_hndl; + if (conid == -1) { + print(LOG_LEVEL, ERROR, 1, "Too many connections requested by module on slot %02x\n", slot_id); + + // send the error + uint8_t hdr[4]; + hdr[0] = T_T_C_ERROR; + hdr[1] = 2; + hdr[2] = connection_id; + hdr[3] = 1; + if (dvbca_link_write(ca_hndl, private->slots[slot_id].slot, connection_id, hdr, 4) < 0) { + private->error_slot = slot_id; + private->error = EN50221ERR_CAWRITE; + return -1; + } + private->slots[slot_id].connections[connection_id].tx_time.tv_sec = 0; + } else { + // send the NEW_T_C on the connection we received it on + uint8_t hdr[4]; + hdr[0] = T_NEW_T_C; + hdr[1] = 2; + hdr[2] = connection_id; + hdr[3] = conid; + if (dvbca_link_write(ca_hndl, private->slots[slot_id].slot, connection_id, hdr, 4) < 0) { + private->slots[slot_id].connections[conid].state = T_STATE_IDLE; + private->error_slot = slot_id; + private->error = EN50221ERR_CAWRITE; + return -1; + } + private->slots[slot_id].connections[connection_id].tx_time.tv_sec = 0; + + // send the CREATE_T_C on the new connnection + hdr[0] = T_CREATE_T_C; + hdr[1] = 1; + hdr[2] = conid; + if (dvbca_link_write(ca_hndl, private->slots[slot_id].slot, conid, hdr, 3) < 0) { + private->slots[slot_id].connections[conid].state = T_STATE_IDLE; + private->error_slot = slot_id; + private->error = EN50221ERR_CAWRITE; + return -1; + } + gettimeofday(&private->slots[slot_id].connections[conid].tx_time, 0); + + // tell upper layers + pthread_mutex_lock(&private->setcallback_lock); + en50221_tl_callback cb = private->callback; + void *cb_arg = private->callback_arg; + pthread_mutex_unlock(&private->setcallback_lock); + if (cb) + cb(cb_arg, T_CALLBACK_REASON_CAMCONNECTIONOPEN, NULL, 0, slot_id, conid); + } + + return 0; +} + +static int en50221_tl_handle_data_more(struct en50221_transport_layer_private *private, + uint8_t slot_id, uint8_t connection_id, + uint8_t *data, uint32_t data_length) +{ + // connection in correct state? + if (private->slots[slot_id].connections[connection_id].state != T_STATE_ACTIVE) { + print(LOG_LEVEL, ERROR, 1, "Received T_DATA_MORE for connection not in " + "T_STATE_ACTIVE from module on slot %02x\n", slot_id); + private->error_slot = slot_id; + private->error = EN50221ERR_BADCAMDATA; + return -1; + } + + // a chained data packet is coming in, save + // it to the buffer and wait for more + private->slots[slot_id].connections[connection_id].tx_time.tv_sec = 0; + int new_data_length = + private->slots[slot_id].connections[connection_id].buffer_length + data_length; + uint8_t *new_data_buffer = + realloc(private->slots[slot_id].connections[connection_id].chain_buffer, new_data_length); + if (new_data_buffer == NULL) { + private->error_slot = slot_id; + private->error = EN50221ERR_OUTOFMEMORY; + return -1; + } + private->slots[slot_id].connections[connection_id].chain_buffer = new_data_buffer; + + memcpy(private->slots[slot_id].connections[connection_id].chain_buffer + + private->slots[slot_id].connections[connection_id].buffer_length, + data, data_length); + private->slots[slot_id].connections[connection_id].buffer_length = new_data_length; + + return 0; +} + +static int en50221_tl_handle_data_last(struct en50221_transport_layer_private *private, + uint8_t slot_id, uint8_t connection_id, + uint8_t *data, uint32_t data_length) +{ + // connection in correct state? + if (private->slots[slot_id].connections[connection_id].state != T_STATE_ACTIVE) { + print(LOG_LEVEL, ERROR, 1, "Received T_DATA_LAST received for connection not in " + "T_STATE_ACTIVE from module on slot %02x\n", slot_id); + private->error_slot = slot_id; + private->error = EN50221ERR_BADCAMDATA; + return -1; + } + + // last package of a chain or single package comes in + private->slots[slot_id].connections[connection_id].tx_time.tv_sec = 0; + if (private->slots[slot_id].connections[connection_id].chain_buffer == NULL) + { + // single package => dispatch immediately + pthread_mutex_lock(&private->setcallback_lock); + en50221_tl_callback cb = private->callback; + void *cb_arg = private->callback_arg; + pthread_mutex_unlock(&private->setcallback_lock); + + if (cb && data_length) { + pthread_mutex_unlock(&private->slots[slot_id].slot_lock); + cb(cb_arg, T_CALLBACK_REASON_DATA, data, data_length, slot_id, connection_id); + pthread_mutex_lock(&private->slots[slot_id].slot_lock); + } + } + else + { + int new_data_length = private->slots[slot_id].connections[connection_id].buffer_length + data_length; + uint8_t *new_data_buffer = + realloc(private->slots[slot_id].connections[connection_id].chain_buffer, new_data_length); + if (new_data_buffer == NULL) { + private->error_slot = slot_id; + private->error = EN50221ERR_OUTOFMEMORY; + return -1; + } + + memcpy(new_data_buffer + private->slots[slot_id].connections[connection_id].buffer_length, data, data_length); + + // clean the buffer position + private->slots[slot_id].connections[connection_id].chain_buffer = NULL; + private->slots[slot_id].connections[connection_id].buffer_length = 0; + + // tell the upper layers + pthread_mutex_lock(&private->setcallback_lock); + en50221_tl_callback cb = private->callback; + void *cb_arg = private->callback_arg; + pthread_mutex_unlock(&private->setcallback_lock); + if (cb && data_length) { + pthread_mutex_unlock(&private->slots[slot_id].slot_lock); + cb(cb_arg, T_CALLBACK_REASON_DATA, new_data_buffer, new_data_length, slot_id, connection_id); + pthread_mutex_lock(&private->slots[slot_id].slot_lock); + } + + free(new_data_buffer); + } + + return 0; +} + +static int en50221_tl_handle_sb(struct en50221_transport_layer_private *private, + uint8_t slot_id, uint8_t connection_id, + uint8_t *data, uint32_t data_length) +{ + // is the connection id ok? + if (private->slots[slot_id].connections[connection_id].state != T_STATE_ACTIVE) { + print(LOG_LEVEL, ERROR, 1, "Received T_SB for connection not in T_STATE_ACTIVE from module on slot %02x\n", + slot_id); + private->error_slot = slot_id; + private->error = EN50221ERR_BADCAMDATA; + return -1; + } + + // did we get enough data in the T_SB? + if (data_length != 1) { + print(LOG_LEVEL, ERROR, 1, "Recieved T_SB with invalid length from module on slot %02x\n", slot_id); + private->error_slot = slot_id; + private->error = EN50221ERR_BADCAMDATA; + return -1; + } + + // tell it to send the data if it says there is some + if (data[0] & 0x80) { + int ca_hndl = private->slots[slot_id].ca_hndl; + + // send the RCV + uint8_t hdr[3]; + hdr[0] = T_RCV; + hdr[1] = 1; + hdr[2] = connection_id; + if (dvbca_link_write(ca_hndl, private->slots[slot_id].slot, connection_id, hdr, 3) < 0) { + private->error_slot = slot_id; + private->error = EN50221ERR_CAWRITE; + return -1; + } + gettimeofday(&private->slots[slot_id].connections[connection_id].tx_time, 0); + + } else { + // no data - indicate not waiting for anything now + private->slots[slot_id].connections[connection_id].tx_time.tv_sec = 0; + } + + return 0; +} + +static int en50221_tl_alloc_new_tc(struct en50221_transport_layer_private *private, uint8_t slot_id) +{ + // we browse through the array of connection + // types, to look for the first unused one + int i, conid = -1; + for(i=1; i < private->max_connections_per_slot; i++) { + if (private->slots[slot_id].connections[i].state == T_STATE_IDLE) { + conid = i; + break; + } + } + if (conid == -1) { + print(LOG_LEVEL, ERROR, 1, "CREATE_T_C failed: no more connections available\n"); + return -1; + } + + // set up the connection struct + private->slots[slot_id].connections[conid].state = T_STATE_IN_CREATION; + private->slots[slot_id].connections[conid].chain_buffer = NULL; + private->slots[slot_id].connections[conid].buffer_length = 0; + + return conid; +} + +static void queue_message(struct en50221_transport_layer_private *private, uint8_t slot_id, + uint8_t connection_id, struct en50221_message *msg) +{ + msg->next = NULL; + if (private->slots[slot_id].connections[connection_id].send_queue_tail) { + private->slots[slot_id].connections[connection_id].send_queue_tail->next = msg; + } else { + private->slots[slot_id].connections[connection_id].send_queue = msg; + private->slots[slot_id].connections[connection_id].send_queue_tail = msg; + } +} diff --git a/kaffeine/src/input/dvb/lib/libdvben50221/en50221_transport.h b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_transport.h new file mode 100644 index 0000000..59dc64c --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_transport.h @@ -0,0 +1,231 @@ +/* + en50221 encoder An implementation for libdvb + an implementation for the en50221 session layer + + Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com) + Copyright (C) 2005 Julian Scheel (julian at jusst dot de) + Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net) + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of + the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +#ifndef __EN50221_TRANSPORT_H__ +#define __EN50221_TRANSPORT_H__ + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <stdlib.h> +#include <stdint.h> +#include <sys/uio.h> + +/** + * Callback reasons. + */ +#define T_CALLBACK_REASON_CONNECTIONOPEN 0x00 // A connection we opened _to_ the cam has been ACKed +#define T_CALLBACK_REASON_CAMCONNECTIONOPEN 0x01 // The cam has opened a connection to _us_. +#define T_CALLBACK_REASON_DATA 0x02 // Data received +#define T_CALLBACK_REASON_CONNECTIONCLOSE 0x03 // The cam has told us to close a connection. +#define T_CALLBACK_REASON_SLOTCLOSE 0x04 // The cam in the supplied slot id has been removed. + +// these are the states a TC can be in +#define T_STATE_IDLE 0x01 // this transport connection is not in use +#define T_STATE_ACTIVE 0x02 // this transport connection is in use +#define T_STATE_ACTIVE_DELETEQUEUED 0x04 // this transport connection is about to be deleted +#define T_STATE_IN_CREATION 0x08 // this transport waits for a T_C_T_C_REPLY to become active +#define T_STATE_IN_DELETION 0x10 // this transport waits for T_D_T_C_REPLY to become idle again + +/** + * Opaque type representing a transport layer. + */ +typedef void *en50221_transport_layer; + +/** + * Type definition for callback function - used when events are received from a module. + * + * **IMPORTANT** For all callback reasons except T_CALLBACK_REASON_DATA, an internal lock is held in the + * transport layer. Therefore, to avoid deadlock, you *must not* call back into the transport layer for + * these reasons. + * + * However, for T_CALLBACK_REASON_DATA, the internal lock is not held, so calling back into the transport + * layer is fine in this case. + * + * @param arg Private data. + * @param reason One of the T_CALLBACK_REASON_* values. + * @param data The data. + * @param data_length Length of the data. + * @param slot_id Slot_id the data was received from. + * @param connection_id Connection_id the data was received from. + */ +typedef void (*en50221_tl_callback)(void *arg, int reason, + uint8_t *data, uint32_t data_length, + uint8_t slot_id, uint8_t connection_id); + + +/** + * Construct a new instance of the transport layer. + * + * @param max_slots Maximum number of slots to support. + * @param max_connections_per_slot Maximum connections per slot. + * @return The en50221_transport_layer instance, or NULL on error. + */ +extern en50221_transport_layer en50221_tl_create(uint8_t max_slots, uint8_t max_connections_per_slot); + +/** + * Destroy an instance of the transport layer. + * + * @param tl The en50221_transport_layer instance. + */ +extern void en50221_tl_destroy(en50221_transport_layer tl); + +/** + * Register a new slot with the library. + * + * @param tl The en50221_transport_layer instance. + * @param ca_hndl FD for talking to the slot. + * @param slot CAM slot where the requested CAM of the CA is in. + * @param response_timeout Maximum timeout in ms to a response we send before signalling a timeout. + * @param poll_delay Interval between polls in ms. + * @return slot_id on sucess, or -1 on error. + */ +extern int en50221_tl_register_slot(en50221_transport_layer tl, int ca_hndl, + uint8_t slot, uint32_t response_timeout, + uint32_t poll_delay); + +/** + * Destroy a registered slot - e.g. if a CAM is removed, or an error occurs. Does + * not attempt to reset the CAM. + * + * @param tl The en50221_transport_layer instance. + * @param slot_id Slot to destroy. + */ +extern void en50221_tl_destroy_slot(en50221_transport_layer tl, uint8_t slot_id); + +/** + * Performs one iteration of the transport layer poll - + * checking for incoming data furthermore it will handle + * the timeouts of certain commands like T_DELETE_T_C it + * should be called by the application regularly, generally + * faster than the poll delay. + * + * @param tl The en50221_transport_layer instance. + * @return 0 on succes, or -1 if there was an error of some sort. + */ +extern int en50221_tl_poll(en50221_transport_layer tl); + +/** + * Register the callback for data reception. + * + * @param tl The en50221_transport_layer instance. + * @param callback The callback. Set to NULL to remove the callback completely. + * @param arg Private data passed as arg0 of the callback. + */ +extern void en50221_tl_register_callback(en50221_transport_layer tl, + en50221_tl_callback callback, void *arg); + +/** + * Gets the ID of the slot an error occurred on. + * + * @param tl The en50221_transport_layer instance. + * @return The offending slot id. + */ +extern int en50221_tl_get_error_slot(en50221_transport_layer tl); + +/** + * Gets the last error. + * + * @param tl The en50221_transport_layer instance. + * @return One of the EN50221ERR_* values. + */ +extern int en50221_tl_get_error(en50221_transport_layer tl); + +/** + * This function is used to take a data-block, pack into + * into a TPDU (DATA_LAST) and send it to the device + * + * @param tl The en50221_transport_layer instance. + * @param slot_id ID of the slot. + * @param connection_id Connection id. + * @param data Data to send. + * @param data_length Number of bytes to send. + * @return 0 on success, or -1 on error. + */ +extern int en50221_tl_send_data(en50221_transport_layer tl, + uint8_t slot_id, uint8_t connection_id, + uint8_t *data, uint32_t data_length); + +/** + * This function is used to take a data-block, pack into + * into a TPDU (DATA_LAST) and send it to the device + * + * @param tl The en50221_transport_layer instance. + * @param slot_id ID of the slot. + * @param connection_id Connection id. + * @param vector iov to send. + * @param io_count Number of elements in vector. + * @return 0 on success, or -1 on error. + */ +extern int en50221_tl_send_datav(en50221_transport_layer tl, uint8_t slot_id, + uint8_t connection_id, struct iovec *vector, + int iov_count); + +/** + * Create a new transport connection to the cam. + * + * **IMPORTANT** When this function returns, it means the request to create a connection + * has been submitted. You will need to poll using en50221_tl_get_connection_state() to find out + * if/when the connection is established. A callback with T_CALLBACK_REASON_CONNECTIONOPEN reason + * will also be sent when it is acked by the CAM. + * + * @param tl The en50221_transport_layer instance. + * @param slot_id ID of the slot. + * @return The allocated connection id on success, or -1 on error. + */ +extern int en50221_tl_new_tc(en50221_transport_layer tl, uint8_t slot_id); + +/** + * Deallocates a transport connection. + * + * **IMPORTANT** When this function returns, it means the request to destroy a connection + * has been submitted. You will need to poll using en50221_tl_get_connection_state() to find out + * if/when the connection is destroyed. + * + * @param tl The en50221_transport_layer instance. + * @param slot_id ID of the slot. + * @param connection_id Connection id to send the request _on_. + * @return 0 on success, or -1 on error. + */ +extern int en50221_tl_del_tc(en50221_transport_layer tl, uint8_t slot_id, + uint8_t connection_id); + +/** + * Checks the state of a connection. + * + * @param tl The en50221_transport_layer instance. + * @param slot_id ID of the slot. + * @param connection_id Connection id to send the request _on_. + * @return One of the T_STATE_* values. + */ +extern int en50221_tl_get_connection_state(en50221_transport_layer tl, + uint8_t slot_id, uint8_t connection_id); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libdvbmisc/dvbmisc.h b/kaffeine/src/input/dvb/lib/libdvbmisc/dvbmisc.h new file mode 100644 index 0000000..75713f4 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libdvbmisc/dvbmisc.h @@ -0,0 +1,72 @@ +/* + libdvbmisc - DVB miscellaneous library + + Copyright (C) 2005 Manu Abraham <manu@kromtek.com> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA +*/ + +#ifndef DVB_MISC_H +#define DVB_MISC_H + +#include <stdarg.h> +#include <stdint.h> +#include <stdio.h> +#include <sys/time.h> + +#define ERROR 0 +#define NOTICE 1 +#define INFO 2 +#define DEBUG 3 + +#define print(x, y, z, fmt, arg...) do { \ + if (z) { \ + if ((x > ERROR) && (x > y)) \ + vprint("%s: " fmt "\n", __func__ , ##arg); \ + else if ((x > NOTICE) && (x > y)) \ + vprint("%s: " fmt "\n",__func__ , ##arg); \ + else if ((x > INFO) && (x > y)) \ + vprint("%s: " fmt "\n", __func__ , ##arg); \ + else if ((x > DEBUG) && (x > y)) \ + vprint("%s: " fmt "\n", __func__ , ##arg); \ + } else { \ + if (x > y) \ + vprint(fmt, ##arg); \ + } \ +} while(0) + +static inline void vprint(char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + vfprintf(stderr, fmt, args); + va_end(args); +} + +static inline int time_after(struct timeval oldtime, uint32_t delta_ms) +{ + // calculate the oldtime + add on the delta + uint64_t oldtime_ms = (oldtime.tv_sec * 1000) + (oldtime.tv_usec / 1000); + oldtime_ms += delta_ms; + + // calculate the nowtime + struct timeval nowtime; + gettimeofday(&nowtime, 0); + uint64_t nowtime_ms = (nowtime.tv_sec * 1000) + (nowtime.tv_usec / 1000); + + // check + return nowtime_ms > oldtime_ms; +} + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/Makefile.am b/kaffeine/src/input/dvb/lib/libucsi/Makefile.am new file mode 100644 index 0000000..071f310 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/Makefile.am @@ -0,0 +1,17 @@ +noinst_LTLIBRARIES = libucsi.la + +SUBDIRS = dvb mpeg . + +INCLUDES = -I$(top_srcdir)/kaffeine/src/input/dvb/lib + +libucsi_la_SOURCES = crc32.c \ + section_buf.c \ + transport_packet.c + +libucsi_la_LDFLAGS = ./mpeg \ + ./dvb + +libucsi_la_LIBADD = ./mpeg/libdvbmpeg.la \ + ./dvb/libdvbdvb.la + +CFLAGS = -g -O2 -Wall -Wshadow -Wpointer-arith -Wstrict-prototypes -fPIC diff --git a/kaffeine/src/input/dvb/lib/libucsi/atsc/descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/atsc/descriptor.h new file mode 100644 index 0000000..a18b29d --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/atsc/descriptor.h @@ -0,0 +1,70 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_ATSC_DESCRIPTOR_H +#define _UCSI_ATSC_DESCRIPTOR_H 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/endianops.h> + +/** + * Enumeration of ATSC descriptor tags. + */ +enum atsc_descriptor_tag { + +/* A 52/A describes a + * dtag_atsc_ac3_registration = 0x05, */ + +/* A90 describes a + * dtag_atsc_association_tag = 0x14, */ + + dtag_atsc_stuffing = 0x80, + dtag_atsc_ac3_audio = 0x81, + dtag_atsc_caption_service = 0x86, + dtag_atsc_content_advisory = 0x87, + dtag_atsc_ca = 0x88, + dtag_atsc_extended_channel_name = 0xa0, + dtag_atsc_service_location = 0xa1, + dtag_atsc_time_shifted_service = 0xa2, + dtag_atsc_component_name = 0xa3, + dtag_atsc_data_service = 0xa4, + dtag_atsc_pid_count = 0xa5, + dtag_atsc_download = 0xa6, + dtag_atsc_MPE = 0xa7, + dtag_atsc_dcc_departing_request = 0xa8, + dtag_atsc_dcc_arriving_request = 0xa9, + dtag_atsc_redistribution_control = 0xaa, + dtag_atsc_dcc_location_code = 0xab, + dtag_atsc_private_information = 0xad, + dtag_atsc_module_link = 0xb4, + dtag_atsc_crc32 = 0xb5, + dtag_atsc_group_link = 0xb8, +}; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/atsc/section.h b/kaffeine/src/input/dvb/lib/libucsi/atsc/section.h new file mode 100644 index 0000000..e693b9d --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/atsc/section.h @@ -0,0 +1,69 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_ATSC_SECTION_H +#define _UCSI_ATSC_SECTION_H 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +/** + * Enumeration of ATSC section tags. + */ +enum atsc_section_tag { +/* 0xC0-0xC6 [ATSC coordinated values which are defined in other standards.] */ + stag_atsc_master_guide = 0xc7, + stag_atsc_terrestrial_virtual_channel = 0xc8, + stag_atsc_cable_virtual_channel = 0xc9, + stag_atsc_rating_region = 0xca, + stag_atsc_event_informationen = 0xcb, + stag_atsc_extended_text = 0xcc, + stag_atsc_system_time = 0xcd, + + stag_atsc_data_event = 0xce, + stag_atsc_data_service = 0xcf, + stag_atsc_network_resources = 0xd1, + stag_atsc_long_term_serivce = 0xd2, +/* identical to DVB/ISO ? + 0x3F DSM-CC Addressable Section Table + 0x3B DSM-CC Section Table + 0x3C DSM-CC Section Table */ + + /* 0xCE-0xD2 [ATSC coordinated values which are defined in other standards.] */ + stag_atsc_directed_channel_change = 0xd3, + stag_atsc_directed_channel_change_selection_code = 0xd4, + + /* 0xD5-0xDF [ATSC coordinated values which are defined in other standards.] */ + stag_atsc_aggregate_event_information = 0xd6, + stag_atsc_aggregate_extended_text = 0xd7, + stag_atsc_satellite_virtual_channel = 0xda, + + /* 0xE0-0xE5 [Used in other systems] */ + /* 0xE6-0xFE [Reserved for future ATSC use] */ +}; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/crc32.c b/kaffeine/src/input/dvb/lib/libucsi/crc32.c new file mode 100644 index 0000000..dc1de5c --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/crc32.c @@ -0,0 +1,89 @@ +/** + * crc32 calculation routines. + * + * Copyright (c) 2005 by Andrew de Quincey <adq_dvb@lidskialf.net> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include <stdint.h> + +uint32_t crc32tbl[] = +{ + 0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, + 0x130476dc, 0x17c56b6b, 0x1a864db2, 0x1e475005, + 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61, + 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, + 0x4c11db70, 0x48d0c6c7, 0x4593e01e, 0x4152fda9, + 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75, + 0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, + 0x791d4014, 0x7ddc5da3, 0x709f7b7a, 0x745e66cd, + 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039, + 0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, + 0xbe2b5b58, 0xbaea46ef, 0xb7a96036, 0xb3687d81, + 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d, + 0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, + 0xc7361b4c, 0xc3f706fb, 0xceb42022, 0xca753d95, + 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1, + 0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, + 0x34867077, 0x30476dc0, 0x3d044b19, 0x39c556ae, + 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072, + 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, + 0x018aeb13, 0x054bf6a4, 0x0808d07d, 0x0cc9cdca, + 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde, + 0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, + 0x5e9f46bf, 0x5a5e5b08, 0x571d7dd1, 0x53dc6066, + 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba, + 0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, + 0xbfa1b04b, 0xbb60adfc, 0xb6238b25, 0xb2e29692, + 0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6, + 0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a, + 0xe0b41de7, 0xe4750050, 0xe9362689, 0xedf73b3e, + 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2, + 0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, + 0xd5b88683, 0xd1799b34, 0xdc3abded, 0xd8fba05a, + 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637, + 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, + 0x4f040d56, 0x4bc510e1, 0x46863638, 0x42472b8f, + 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53, + 0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, + 0x36194d42, 0x32d850f5, 0x3f9b762c, 0x3b5a6b9b, + 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff, + 0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, + 0xf12f560e, 0xf5ee4bb9, 0xf8ad6d60, 0xfc6c70d7, + 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b, + 0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, + 0xc423cd6a, 0xc0e2d0dd, 0xcda1f604, 0xc960ebb3, + 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7, + 0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, + 0x9b3660c6, 0x9ff77d71, 0x92b45ba8, 0x9675461f, + 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3, + 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, + 0x4e8ee645, 0x4a4ffbf2, 0x470cdd2b, 0x43cdc09c, + 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8, + 0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24, + 0x119b4be9, 0x155a565e, 0x18197087, 0x1cd86d30, + 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec, + 0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, + 0x2497d08d, 0x2056cd3a, 0x2d15ebe3, 0x29d4f654, + 0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0, + 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c, + 0xe3a1cbc1, 0xe760d676, 0xea23f0af, 0xeee2ed18, + 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4, + 0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, + 0x9abc8bd5, 0x9e7d9662, 0x933eb0bb, 0x97ffad0c, + 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668, + 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4 +}; diff --git a/kaffeine/src/input/dvb/lib/libucsi/crc32.h b/kaffeine/src/input/dvb/lib/libucsi/crc32.h new file mode 100644 index 0000000..5d77e84 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/crc32.h @@ -0,0 +1,58 @@ +/** + * crc32 calculation routines. + * + * Copyright (c) 2005 by Andrew de Quincey <adq_dvb@lidskialf.net> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_CRC32_H +#define _UCSI_CRC32_H 1 + +#include <stdint.h> + +#ifdef __cplusplus +extern "C" +{ +#endif + +#define CRC32_INIT (~0) + +extern uint32_t crc32tbl[]; + +/** + * Calculate a CRC32 over a piece of data. + * + * @param crc Current CRC value (use CRC32_INIT for first call). + * @param buf Buffer to calculate over. + * @param len Number of bytes. + * @return Calculated CRC. + */ +static inline uint32_t crc32(uint32_t crc, uint8_t* buf, int len) +{ + int i; + + for (i=0; i< len; i++) { + crc = (crc << 8) ^ crc32tbl[((crc >> 24) ^ buf[i]) & 0xff]; + } + + return crc; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/descriptor.h new file mode 100644 index 0000000..809936d --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/descriptor.h @@ -0,0 +1,129 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_DESCRIPTOR_H +#define _UCSI_DESCRIPTOR_H 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/endianops.h> +#include <stdint.h> +#include <stdlib.h> + +/** + * Generic descriptor header. + */ +struct descriptor { + uint8_t tag; + uint8_t len; +} __ucsi_packed; + +/** + * Retreive pointer to the next descriptor structure. + * + * @param buf The buffer of descriptors. + * @param len Size of the buffer. + * @param pos Current descriptor. + * @return Pointer to next descriptor, or NULL if there are none. + */ +static inline struct descriptor * + next_descriptor(uint8_t * buf, int len, struct descriptor * pos) +{ + uint8_t* next; + + if (pos == NULL) + return NULL; + + next = (uint8_t*) pos + 2 + pos->len; + if (next >= buf + len) + return NULL; + + return (struct descriptor *) next; +} + + +/** + * The unknown descriptor. + */ +struct unknown_descriptor { + struct descriptor d; + + /* uint8_t data [] */ +} __ucsi_packed; + +/** + * Retrieve pointer to the unknown descriptor's data field. + * + * @param d The descriptor. + * @return Pointer to the data field. + */ +static inline uint8_t * + unknown_descriptor_data(struct unknown_descriptor *d) +{ + return (uint8_t *) d + sizeof(struct unknown_descriptor); +} + +/** + * Retrieve size of unknown descriptor's data field. + * + * @param d The descriptor. + * @return Size of data field in bytes. + */ +static inline int + unknown_descriptor_data_size(struct unknown_descriptor *d) +{ + return d->d.len; +} + + + + + + + + + + +/******************************** PRIVATE CODE ********************************/ +static inline int verify_descriptors(uint8_t * buf, int len) +{ + int pos = 0; + + while (pos < len) { + if ((pos + 2) > len) + return -1; + + pos += 2 + buf[pos+1]; + } + + if (pos != len) + return -1; + + return 0; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/Makefile.am b/kaffeine/src/input/dvb/lib/libucsi/dvb/Makefile.am new file mode 100644 index 0000000..b358273 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/Makefile.am @@ -0,0 +1,19 @@ +noinst_LTLIBRARIES = libdvbdvb.la + +INCLUDES = -I$(top_srcdir)/kaffeine/src/input/dvb/lib + +libdvbdvb_la_SOURCES = bat_section.c \ + dit_section.c \ + eit_section.c \ + int_section.c \ + nit_section.c \ + rst_section.c \ + sdt_section.c \ + sit_section.c \ + st_section.c \ + tdt_section.c \ + tot_section.c \ + tva_container_section.c \ + types.c + +CFLAGS = -g -O2 -Wall -Wshadow -Wpointer-arith -Wstrict-prototypes -fPIC diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/ac3_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/ac3_descriptor.h new file mode 100644 index 0000000..d60e37b --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/ac3_descriptor.h @@ -0,0 +1,88 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_DVB_AC3_DESCRIPTOR +#define _UCSI_DVB_AC3_DESCRIPTOR 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/descriptor.h> +#include <libucsi/endianops.h> + +/** + * dvb_ac3_descriptor structure. + */ +struct dvb_ac3_descriptor { + struct descriptor d; + + EBIT5(uint8_t ac3_type_flag : 1; , + uint8_t bsid_flag : 1; , + uint8_t mainid_flag : 1; , + uint8_t asvc_flag : 1; , + uint8_t reserved : 4; ) + /* uint8_t additional_info[] */ +} __ucsi_packed; + +/** + * Process a dvb_ac3_descriptor. + * + * @param d Generic descriptor structure. + * @return dvb_ac3_descriptor pointer, or NULL on error. + */ +static inline struct dvb_ac3_descriptor* + dvb_ac3_descriptor_codec(struct descriptor* d) +{ + if (d->len < (sizeof(struct dvb_ac3_descriptor) - 2)) + return NULL; + + return (struct dvb_ac3_descriptor*) d; +} + +/** + * Retrieve pointer to additional_info field of a dvb_ac3_descriptor. + * + * @param d dvb_ac3_descriptor pointer. + * @return Pointer to additional_info field. + */ +static inline uint8_t *dvb_ac3_descriptor_additional_info(struct dvb_ac3_descriptor *d) +{ + return (uint8_t *) d + sizeof(struct dvb_ac3_descriptor); +} + +/** + * Determine length of additional_info field of a dvb_ac3_descriptor. + * + * @param d dvb_ac3_descriptor pointer. + * @return Length of field in bytes. + */ +static inline int dvb_ac3_descriptor_additional_info_length(struct dvb_ac3_descriptor *d) +{ + return d->d.len - 1; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/adaptation_field_data_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/adaptation_field_data_descriptor.h new file mode 100644 index 0000000..69a21b8 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/adaptation_field_data_descriptor.h @@ -0,0 +1,62 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_DVB_ADAPTATION_FIELD_DATA_DESCRIPTOR +#define _UCSI_DVB_ADAPTATION_FIELD_DATA_DESCRIPTOR 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/descriptor.h> +#include <libucsi/endianops.h> + +/** + * dvb_adaptation_field_data_descriptor structure. + */ +struct dvb_adaptation_field_data_descriptor { + struct descriptor d; + + EBIT2(uint8_t reserved : 7; , + uint8_t announcement_switching_data : 1; ) +} __ucsi_packed; + +/** + * Process a dvb_adaptation_field_data_descriptor. + * + * @param d Generic descriptor structure. + * @return Pointer to dvb_adaptation_field_data_descriptor, or NULL on error. + */ +static inline struct dvb_adaptation_field_data_descriptor* + dvb_adaptation_field_data_descriptor_codec(struct descriptor* d) +{ + if (d->len != (sizeof(struct dvb_adaptation_field_data_descriptor) - 2)) + return NULL; + + return (struct dvb_adaptation_field_data_descriptor*) d; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/ait_application_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/ait_application_descriptor.h new file mode 100644 index 0000000..877d9c0 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/ait_application_descriptor.h @@ -0,0 +1,204 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_DVB_AIT_APPLICATION_DESCRIPTOR +#define _UCSI_DVB_AIT_APPLICATION_DESCRIPTOR 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/descriptor.h> +#include <libucsi/endianops.h> + +/** + * Possible values for the visibility field. + */ +enum { + AVB_AIT_APPLICATION_VISIBILITY_HIDDEN = 0x00, + AVB_AIT_APPLICATION_VISIBILITY_APPSONLY = 0x01, + AVB_AIT_APPLICATION_VISIBILITY_VISIBLE = 0x03 +}; + +/** + * dvb_ait_application_descriptor structure. + */ +struct dvb_ait_application_descriptor { + struct descriptor d; + + uint8_t application_profiles_length; + /* struct dvb_ait_application_profile profiles [] */ + /* struct dvb_ait_application_descriptor_part2 part2 */ +} __ucsi_packed; + +/** + * An entry in the profiles field of a dvb_ait_application_descriptor. + */ +struct dvb_ait_application_profile { + uint16_t application_profile; + uint8_t version_major; + uint8_t version_minor; + uint8_t version_micro; +} __ucsi_packed; + +/** + * Second part of a dvb_ait_application_descriptor structure. + */ +struct dvb_ait_application_descriptor_part2 { + EBIT3(uint8_t service_bound_flag : 1; , + uint8_t visibility : 2; , + uint8_t reserved : 5; ) + uint8_t application_priority; + /* uint8_t transport_protocol_label[] */ +} __ucsi_packed; + +/** + * Process a dvb_ait_application_descriptor. + * + * @param d Generic descriptor pointer. + * @return dvb_ait_application_descriptor pointer, or NULL on error. + */ +static inline struct dvb_ait_application_descriptor* + dvb_ait_application_descriptor_codec(struct descriptor* d) +{ + uint32_t pos = 0; + uint32_t pos2 = 0; + uint32_t len = d->len + 2; + uint8_t* buf = (uint8_t*) d; + struct dvb_ait_application_descriptor *ret = + (struct dvb_ait_application_descriptor*) d; + + if (len < sizeof(struct dvb_ait_application_descriptor)) + return NULL; + + if (len < (sizeof(struct dvb_ait_application_descriptor) + ret->application_profiles_length)) + return NULL; + + if (ret->application_profiles_length % sizeof(struct dvb_ait_application_profile)) + return NULL; + + pos += sizeof(struct dvb_ait_application_descriptor); + pos2 = 0; + while(pos2 < ret->application_profiles_length) { + bswap16(buf + pos + pos2); + pos2 += sizeof(struct dvb_ait_application_descriptor); + } + pos += pos2; + + if (len < (pos + sizeof(struct dvb_ait_application_descriptor_part2))) + return NULL; + + return ret; +} + +/** + * Iterator for the profiles field of a dvb_ait_application_descriptor. + * + * @param d dvb_ait_application_descriptor pointer. + * @param pos Variable containing a pointer to the current dvb_ait_application_profile. + */ +#define dvb_ait_application_descriptor_profiles_for_each(d, pos) \ + for ((pos) = dvb_ait_application_descriptor_profiles_first(d); \ + (pos); \ + (pos) = dvb_ait_application_descriptor_profiles_next(d, pos)) + +/** + * Accessor for the part2 field of a dvb_ait_application_descriptor. + * + * @param d dvb_ait_application_descriptor pointer. + * @return dvb_ait_application_descriptor_part2 pointer. + */ +static inline struct dvb_ait_application_descriptor_part2* + dvb_ait_application_descriptor_part2(struct dvb_ait_application_descriptor* d) +{ + return (struct dvb_ait_application_descriptor_part2*) + ((uint8_t*) d + + sizeof(struct dvb_ait_application_descriptor) + + d->application_profiles_length); +} + +/** + * Accessor for the transport_protocol_label field of a dvb_ait_application_descriptor_part2. + * + * @param d dvb_ait_application_descriptor_part2 pointer. + * @return Pointer to the field. + */ +static inline uint8_t* + dvb_ait_application_descriptor_part2_transport_protocol_label(struct dvb_ait_application_descriptor_part2* d) +{ + return (uint8_t*) d + + sizeof(struct dvb_ait_application_descriptor_part2); +} + +/** + * Calculate the number of bytes in the transport_protocol_label field of a dvb_ait_application_descriptor_part2. + * + * @param d dvb_ait_application_descriptor pointer. + * @param part2 dvb_ait_application_descriptor_part2 pointer. + * @return Number of bytes. + */ +static inline int + dvb_ait_application_descriptor_part2_transport_protocol_label_length(struct dvb_ait_application_descriptor *d, + struct dvb_ait_application_descriptor_part2* part2) +{ + uint8_t *ptr = (uint8_t*) part2 + sizeof(struct dvb_ait_application_descriptor_part2); + uint8_t *end = (uint8_t*) d + d->d.len + 2; + + return (int) (end - ptr); +} + + + + + + +/******************************** PRIVATE CODE ********************************/ +static inline struct dvb_ait_application_profile* + dvb_ait_application_descriptor_profiles_first(struct dvb_ait_application_descriptor *d) +{ + if (d->application_profiles_length == 0) + return NULL; + + return (struct dvb_ait_application_profile *) + ((uint8_t*) d + sizeof(struct dvb_ait_application_descriptor)); +} + +static inline struct dvb_ait_application_profile* + dvb_ait_application_descriptor_profiles_next(struct dvb_ait_application_descriptor *d, + struct dvb_ait_application_profile *pos) +{ + uint8_t *end = (uint8_t*) d + + sizeof(struct dvb_ait_application_descriptor) + + d->application_profiles_length; + uint8_t *next = (uint8_t *) pos + sizeof(struct dvb_ait_application_profile); + + if (next >= end) + return NULL; + + return (struct dvb_ait_application_profile *) next; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/ait_application_icons_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/ait_application_icons_descriptor.h new file mode 100644 index 0000000..5ea5932 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/ait_application_icons_descriptor.h @@ -0,0 +1,157 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_DVB_AIT_APPLICATION_ICONS_DESCRIPTOR +#define _UCSI_DVB_AIT_APPLICATION_ICONS_DESCRIPTOR 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/descriptor.h> +#include <libucsi/endianops.h> +#include <libucsi/types.h> + +/** + * Possible values for the icon_flags field. + */ +enum { + AIT_APPLICATION_ICON_FLAG_32_32 = 0x001, + AIT_APPLICATION_ICON_FLAG_32_32_43 = 0x002, + AIT_APPLICATION_ICON_FLAG_24_32_169 = 0x004, + + AIT_APPLICATION_ICON_FLAG_64_64 = 0x008, + AIT_APPLICATION_ICON_FLAG_64_64_43 = 0x010, + AIT_APPLICATION_ICON_FLAG_48_64_169 = 0x020, + + AIT_APPLICATION_ICON_FLAG_128_128 = 0x040, + AIT_APPLICATION_ICON_FLAG_128_128_43 = 0x080, + AIT_APPLICATION_ICON_FLAG_96_128_169 = 0x100 +}; + +/** + * dvb_ait_application_icons_descriptor structure. + */ +struct dvb_ait_application_icons_descriptor { + struct descriptor d; + + uint8_t icon_locator_length; + /* uint8_t icon_locator[] */ + /* struct dvb_ait_application_icons_descriptor_part2 */ +} __ucsi_packed; + +/** + * Second part of a dvb_ait_application_icons_descriptor. + */ +struct dvb_ait_application_icons_descriptor_part2 { + uint16_t icon_flags; + /* uint8_t reserved[] */ +} __ucsi_packed; + +/** + * Process a dvb_ait_application_icons_descriptor. + * + * @param d Generic descriptor pointer. + * @return dvb_ait_application_icons_descriptor pointer, or NULL on error. + */ +static inline struct dvb_ait_application_icons_descriptor* + dvb_ait_application_icons_descriptor_codec(struct descriptor* d) +{ + uint8_t* buf = (uint8_t*) d; + uint32_t pos = 0; + uint32_t len = d->len + 2; + struct dvb_ait_application_icons_descriptor *ret = + (struct dvb_ait_application_icons_descriptor *) d; + + if (len < sizeof(struct dvb_ait_application_icons_descriptor)) + return NULL; + if (len < (sizeof(struct dvb_ait_application_icons_descriptor) + ret->icon_locator_length)) + return NULL; + + pos += sizeof(struct dvb_ait_application_icons_descriptor) + ret->icon_locator_length; + + if ((len - pos) < sizeof(struct dvb_ait_application_icons_descriptor_part2)) + return NULL; + bswap16(buf + pos); + + return ret; +} +/** + * Accessor for the icon_locator field of a dvb_ait_application_icons_descriptor. + * + * @param e dvb_ait_application_icons_descriptor pointer. + * @return Pointer to the field. + */ +static inline uint8_t * + dvb_ait_application_icons_descriptor_icon_locator(struct dvb_ait_application_icons_descriptor *e) +{ + return (uint8_t *) e + sizeof(struct dvb_ait_application_icons_descriptor); +} + +/** + * Accessor for the part2 field of a dvb_ait_application_icons_descriptor. + * + * @param e dvb_ait_application_icons_descriptor Pointer. + * @return dvb_ait_application_icons_descriptor_part2 pointer. + */ +static inline struct dvb_ait_application_icons_descriptor_part2 * + dvb_ait_application_icons_descriptor_part2(struct dvb_ait_application_icons_descriptor *e) +{ + return (struct dvb_ait_application_icons_descriptor_part2 *) + ((uint8_t *) e + sizeof(struct dvb_ait_application_icons_descriptor) + + e->icon_locator_length); +} + +/** + * Accessor for the reserved field of a dvb_ait_application_icons_descriptor_part2. + * + * @param e dvb_ait_application_icons_part2 pointer. + * @return Pointer to the field. + */ +static inline uint8_t * + dvb_ait_application_icons_descriptor_part2_reserved(struct dvb_ait_application_icons_descriptor_part2 *e) +{ + return (uint8_t *) e + sizeof(struct dvb_ait_application_icons_descriptor_part2); +} + +/** + * Calculate the number of bytes in the reserved field of a dvb_ait_application_icons_descriptor_part2. + * + * @param d dvb_ait_application_icons_descriptorpointer. + * @param part2 dvb_ait_application_icons_descriptor_part2 pointer. + * @return Number of bytes. + */ +static inline int + dvb_ait_application_icons_descriptor_part2_reserved_length(struct dvb_ait_application_icons_descriptor *d, + struct dvb_ait_application_icons_descriptor_part2* part2) +{ + uint8_t *ptr = (uint8_t*) part2 + sizeof(struct dvb_ait_application_icons_descriptor_part2); + uint8_t *end = (uint8_t*) d + d->d.len + 2; + + return (int) (end - ptr); +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/ait_application_name_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/ait_application_name_descriptor.h new file mode 100644 index 0000000..a4b719e --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/ait_application_name_descriptor.h @@ -0,0 +1,145 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_DVB_AIT_APPLICATION_NAME_DESCRIPTOR +#define _UCSI_DVB_AIT_APPLICATION_NAME_DESCRIPTOR 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/descriptor.h> +#include <libucsi/endianops.h> +#include <libucsi/types.h> + +/** + * dvb_ait_application_name_descriptor structure. + */ +struct dvb_ait_application_name_descriptor { + struct descriptor d; + + /* struct dvb_ait_application_name names[] */ +} __ucsi_packed; + +/** + * An entry in the names field of a dvb_ait_application_name_descriptor. + */ +struct dvb_ait_application_name { + iso639lang_t language_code; + uint8_t application_name_length; + /* uint8_t name[] */ +} __ucsi_packed; + +/** + * Process a dvb_ait_application_name_descriptor. + * + * @param d Generic descriptor pointer. + * @return dvb_ait_application_name_descriptor pointer, or NULL on error. + */ +static inline struct dvb_ait_application_name_descriptor* + dvb_ait_application_name_descriptor_codec(struct descriptor* d) +{ + uint8_t* buf = (uint8_t*) d + 2; + uint32_t pos = 0; + uint32_t len = d->len; + + while(pos < len) { + struct dvb_ait_application_name *e = + (struct dvb_ait_application_name*) (buf + pos); + + pos += sizeof(struct dvb_ait_application_name); + + if (pos > len) + return NULL; + + pos += e->application_name_length; + + if (pos > len) + return NULL; + } + + return (struct dvb_ait_application_name_descriptor*) d; +} + +/** + * Iterator for entries in the names field of a dvb_ait_application_name_descriptor. + * + * @param d dvb_ait_application_name_descriptor pointer. + * @param pos Variable containing a pointer to the current dvb_ait_application_name. + */ +#define dvb_ait_application_name_descriptor_names_for_each(d, pos) \ + for ((pos) = dvb_ait_application_name_descriptor_names_first(d); \ + (pos); \ + (pos) = dvb_ait_application_name_descriptor_names_next(d, pos)) + +/** + * Accessor for the name field of a dvb_ait_application_name. + * + * @param e dvb_ait_application_name pointer. + * @return Pointer to the name field. + */ +static inline uint8_t * + dvb_ait_application_name_name(struct dvb_ait_application_name *e) +{ + return (uint8_t *) e + sizeof(struct dvb_ait_application_name); +} + + + + + + + + + + +/******************************** PRIVATE CODE ********************************/ +static inline struct dvb_ait_application_name* + dvb_ait_application_name_descriptor_names_first(struct dvb_ait_application_name_descriptor *d) +{ + if (d->d.len == 0) + return NULL; + + return (struct dvb_ait_application_name *) + ((uint8_t*) d + sizeof(struct dvb_ait_application_name_descriptor)); +} + +static inline struct dvb_ait_application_name* + dvb_ait_application_name_descriptor_names_next(struct dvb_ait_application_name_descriptor *d, + struct dvb_ait_application_name *pos) +{ + uint8_t *end = (uint8_t*) d + 2 + d->d.len; + uint8_t *next = (uint8_t *) pos + + sizeof(struct dvb_ait_application_name) + + pos->application_name_length; + + if (next >= end) + return NULL; + + return (struct dvb_ait_application_name *) next; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/ait_external_application_authorisation_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/ait_external_application_authorisation_descriptor.h new file mode 100644 index 0000000..34f584a --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/ait_external_application_authorisation_descriptor.h @@ -0,0 +1,125 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_DVB_AIT_EXTERNAL_APPLICATION_AUTHORISATION_DESCRIPTOR +#define _UCSI_DVB_AIT_EXTERNAL_APPLICATION_AUTHORISATION_DESCRIPTOR 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/descriptor.h> +#include <libucsi/endianops.h> +#include <libucsi/types.h> + +/** + * dvb_ait_external_application_authorisation_descriptor structure. + */ +struct dvb_ait_external_application_authorisation_descriptor { + struct descriptor d; + + /* struct dvb_ait_external_application_authorisation auths[] */ +} __ucsi_packed; + +/** + * An entry in the auths field of a dvb_ait_external_application_authorisation_descriptor. + */ +struct dvb_ait_external_application_authorisation { + uint32_t organization_id; + uint16_t application_id; + uint8_t application_priority; +} __ucsi_packed; + +/** + * Process a dvb_ait_external_application_authorisation_descriptor. + * + * @param d Generic descriptor pointer. + * @return dvb_ait_external_application_authorisation_descriptor pointer, or NULL on error. + */ +static inline struct dvb_ait_external_application_authorisation_descriptor* + dvb_ait_external_application_authorisation_descriptor_codec(struct descriptor* d) +{ + uint8_t* buf = (uint8_t*) d + 2; + uint32_t pos = 0; + uint32_t len = d->len; + + if (len % sizeof(struct dvb_ait_external_application_authorisation)) + return NULL; + + while(pos < len) { + bswap32(buf + pos); + bswap32(buf + pos + 4); + pos += sizeof(struct dvb_ait_external_application_authorisation); + } + + return (struct dvb_ait_external_application_authorisation_descriptor*) d; +} + +/** + * Iterator for entries in the auths field of a dvb_ait_external_application_authorisation_descriptor. + * + * @param d dvb_ait_external_application_authorisation_descriptor pointer. + * @param pos Variable containing a pointer to the current dvb_ait_external_application_authorisation. + */ +#define dvb_ait_external_application_authorisation_descriptor_auths_for_each(d, pos) \ + for ((pos) = dvb_ait_external_application_authorisation_descriptor_auths_first(d); \ + (pos); \ + (pos) = dvb_ait_external_application_authorisation_descriptor_auths_next(d, pos)) + + + + + + + + + +/******************************** PRIVATE CODE ********************************/ +static inline struct dvb_ait_external_application_authorisation* + dvb_ait_external_application_authorisation_descriptor_auths_first(struct dvb_ait_external_application_authorisation_descriptor *d) +{ + if (d->d.len == 0) + return NULL; + + return (struct dvb_ait_external_application_authorisation *) + ((uint8_t*) d + sizeof(struct dvb_ait_external_application_authorisation_descriptor)); +} + +static inline struct dvb_ait_external_application_authorisation* + dvb_ait_external_application_authorisation_descriptor_auths_next(struct dvb_ait_external_application_authorisation_descriptor *d, + struct dvb_ait_external_application_authorisation *pos) +{ + uint8_t *end = (uint8_t*) d + 2 + d->d.len; + uint8_t *next = (uint8_t *) pos + + sizeof(struct dvb_ait_external_application_authorisation); + + if (next >= end) + return NULL; + + return (struct dvb_ait_external_application_authorisation *) next; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/ancillary_data_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/ancillary_data_descriptor.h new file mode 100644 index 0000000..7a0280d --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/ancillary_data_descriptor.h @@ -0,0 +1,67 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_DVB_ANCILLARY_DATA_DESCRIPTOR +#define _UCSI_DVB_ANCILLARY_DATA_DESCRIPTOR 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/descriptor.h> +#include <libucsi/endianops.h> + +/** + * dvb_ancillary_data_descriptor structure. + */ +struct dvb_ancillary_data_descriptor { + struct descriptor d; + EBIT8(uint8_t reserved : 1; , + uint8_t rds_via_udcp : 1; , + uint8_t mpeg4_ancillary_data : 1; , + uint8_t scale_factor_error_check : 1; , + uint8_t dab_ancillary_data : 1; , + uint8_t announcement_switching_data : 1; , + uint8_t extended_ancillary_data : 1; , + uint8_t dvd_video_ancillary_data : 1; ) +} __ucsi_packed; + +/** + * Process a dvb_ancillary_data_descriptor. + * + * @param d Generic descriptor pointer. + * @return dvb_ancillary_data_descriptor pointer, or NULL on error. + */ +static inline struct dvb_ancillary_data_descriptor* + dvb_ancillary_data_descriptor_codec(struct descriptor* d) +{ + if (d->len != (sizeof(struct dvb_ancillary_data_descriptor) - 2)) + return NULL; + + return (struct dvb_ancillary_data_descriptor*) d; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/announcement_support_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/announcement_support_descriptor.h new file mode 100644 index 0000000..55a570b --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/announcement_support_descriptor.h @@ -0,0 +1,219 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_DVB_ANNOUNCEMENT_SUPPORT_DESCRIPTOR +#define _UCSI_DVB_ANNOUNCEMENT_SUPPORT_DESCRIPTOR 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/descriptor.h> +#include <libucsi/endianops.h> + +/** + * Possible values for announcement_support_indicator. + */ +enum { + DVB_ANNOUNCEMENT_SUPPORT_EMERGENCY = 0x01, + DVB_ANNOUNCEMENT_SUPPORT_ROAD_TRAFFIC_FLASH = 0x02, + DVB_ANNOUNCEMENT_SUPPORT_PUBLIC_TRANSPORT_FLASH = 0x04, + DVB_ANNOUNCEMENT_SUPPORT_WARNING_MESSAGE = 0x08, + DVB_ANNOUNCEMENT_SUPPORT_NEWS_FLASH = 0x10, + DVB_ANNOUNCEMENT_SUPPORT_WEATHER_FLASH = 0x20, + DVB_ANNOUNCEMENT_SUPPORT_EVENT_ANNOUNCEMENT = 0x40, + DVB_ANNOUNCEMENT_SUPPORT_PERSONAL_CALL = 0x80 +}; + +/** + * Possible values for announcement_type. + */ +enum { + DVB_ANNOUNCEMENT_TYPE_EMERGENCY = 0x00, + DVB_ANNOUNCEMENT_TYPE_ROAD_TRAFFIC_FLASH = 0x01, + DVB_ANNOUNCEMENT_TYPE_PUBLIC_TRANSPORT_FLASH = 0x02, + DVB_ANNOUNCEMENT_TYPE_WARNING_MESSAGE = 0x03, + DVB_ANNOUNCEMENT_TYPE_NEWS_FLASH = 0x04, + DVB_ANNOUNCEMENT_TYPE_WEATHER_FLASH = 0x05, + DVB_ANNOUNCEMENT_TYPE_EVENT_ANNOUNCEMENT = 0x06, + DVB_ANNOUNCEMENT_TYPE_PERSONAL_CALL = 0x07 +}; + +/** + * Possible values for reference_type. + */ +enum { + DVB_REFERENCE_TYPE_AUDIO = 0x00, + DVB_REFERENCE_TYPE_OTHER_AUDIO = 0x01, + DVB_REFERENCE_TYPE_OTHER_SERVICE = 0x02, + DVB_REFERENCE_TYPE_OTHER_TS = 0x03 +}; + +/** + * dvb_announcement_support_descriptor structure. + */ +struct dvb_announcement_support_descriptor { + struct descriptor d; + uint16_t announcement_support_indicator; + /* struct dvb_announcement_support_entry entries[] */ +} __ucsi_packed; + +/** + * An entry in the entries field of a dvb_announcement_support_descriptor. + */ +struct dvb_announcement_support_entry { + EBIT3(uint8_t announcement_type : 4; , + uint8_t reserved : 1; , + uint8_t reference_type : 3; ) + /* Only if reference_type == 1, 2 or 3: + * struct dvb_announcement_support_reference reference */ +} __ucsi_packed; + +/** + * The optional reference field only present in a dvb_announcement_support_descriptor if + * its reference_type field is 1,2 or 3. + */ +struct dvb_announcement_support_reference { + uint16_t original_network_id; + uint16_t transport_stream_id; + uint16_t service_id; + uint8_t component_tag; +} __ucsi_packed; + +/** + * Process a dvb_announcement_support_descriptor. + * + * @param d Generic descriptor pointer. + * @return dvb_announcement_support_descriptor pointer, or NULL on error. + */ +static inline struct dvb_announcement_support_descriptor* + dvb_announcement_support_descriptor_codec(struct descriptor* d) +{ + uint32_t pos = 0; + uint8_t* buf = (uint8_t*) d + 2; + uint32_t len = d->len; + + if (len < (sizeof(struct dvb_announcement_support_descriptor) - 2)) + return NULL; + + bswap16(buf+pos); + + pos += 2; + + while(pos < len) { + struct dvb_announcement_support_entry *e = + (struct dvb_announcement_support_entry*) (buf+pos); + + pos += sizeof(struct dvb_announcement_support_entry); + + if (pos > len) + return NULL; + + if ((e->reference_type == 1) || + (e->reference_type == 2) || + (e->reference_type == 3)) { + if ((pos + sizeof(struct dvb_announcement_support_reference)) > len) + return NULL; + + bswap16(buf+pos); + bswap16(buf+pos+2); + bswap16(buf+pos+4); + + pos += sizeof(struct dvb_announcement_support_reference); + } + } + + return (struct dvb_announcement_support_descriptor*) d; +} + +/** + * Iterator for the entries field of a dvb_announcement_support_descriptor. + * + * @param d dvb_announcement_support_descriptor pointer. + * @param pod Variable holding a pointer to the current dvb_announcement_support_entry. + */ +#define dvb_announcement_support_descriptor_entries_for_each(d, pos) \ + for ((pos) = dvb_announcement_support_descriptor_entries_first(d); \ + (pos); \ + (pos) = dvb_announcement_support_descriptor_entries_next(d, pos)) + +/** + * Accessor for the reference field of a dvb_announcement_support_entry if present. + * + * @param entry dvb_announcement_support_entry pointer. + * @return dvb_announcement_support_reference pointer, or NULL on error. + */ +static inline struct dvb_announcement_support_reference* + dvb_announcement_support_entry_reference(struct dvb_announcement_support_entry* entry) +{ + if ((entry->reference_type != 0x01) && + (entry->reference_type != 0x02) && + (entry->reference_type != 0x03)) + return NULL; + + return (struct dvb_announcement_support_reference*) + ((uint8_t*) entry + sizeof(struct dvb_announcement_support_entry)); +} + + + + + + + + + + +/******************************** PRIVATE CODE ********************************/ +static inline struct dvb_announcement_support_entry* + dvb_announcement_support_descriptor_entries_first(struct dvb_announcement_support_descriptor *d) +{ + if (d->d.len == 2) + return NULL; + + return (struct dvb_announcement_support_entry *) + ((uint8_t*) d + sizeof(struct dvb_announcement_support_descriptor)); +} + +static inline struct dvb_announcement_support_entry* + dvb_announcement_support_descriptor_entries_next(struct dvb_announcement_support_descriptor *d, + struct dvb_announcement_support_entry *pos) +{ + uint8_t *end = (uint8_t*) d + 2 + d->d.len; + uint8_t* next = (uint8_t*) pos + sizeof(struct dvb_announcement_support_entry); + struct dvb_announcement_support_reference* reference = + dvb_announcement_support_entry_reference(pos); + + if (reference) + next += sizeof(struct dvb_announcement_support_reference); + + if (next >= end) + return NULL; + + return (struct dvb_announcement_support_entry *) next; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/application_signalling_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/application_signalling_descriptor.h new file mode 100644 index 0000000..c1d50ff --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/application_signalling_descriptor.h @@ -0,0 +1,124 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_DVB_APPLICATION_SIGNALLING_DESCRIPTOR +#define _UCSI_DVB_APPLICATION_SIGNALLING_DESCRIPTOR 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/descriptor.h> +#include <libucsi/endianops.h> + +/** + * dvb_application_signalling_descriptor structure. + */ +struct dvb_application_signalling_descriptor { + struct descriptor d; + + /* struct dvb_application_signalling_entry entries[] */ +} __ucsi_packed; + +/** + * An entry in the entries field of a dvb_application_signalling_descriptor. + */ +struct dvb_application_signalling_entry { + uint16_t application_type; + EBIT2(uint8_t reserved : 3; , + uint8_t AIT_version_number : 5; ) +} __ucsi_packed; + +/** + * Process a dvb_application_signalling_descriptor. + * + * @param d Generic descriptor pointer. + * @return dvb_application_signalling_descriptor pointer, or NULL on error. + */ +static inline struct dvb_application_signalling_descriptor* + dvb_application_signalling_descriptor_codec(struct descriptor* d) +{ + uint32_t pos = 0; + uint32_t len = d->len; + uint8_t* buf = (uint8_t*) d + 2; + + pos += sizeof(struct dvb_application_signalling_descriptor) - 2; + if (len % sizeof(struct dvb_application_signalling_entry)) + return NULL; + + while(pos < len) { + bswap16(buf+pos); + pos+=3; + } + + return (struct dvb_application_signalling_descriptor*) d; +} + +/** + * Iterator for the entries field of a dvb_application_signalling_descriptor. + * + * @param d dvb_application_signalling_descriptor pointer. + * @param pos Variable containing a pointer to the current dvb_application_signalling_entry. + */ +#define dvb_application_signalling_descriptor_entries_for_each(d, pos) \ + for ((pos) = dvb_application_signalling_descriptor_entries_first(d); \ + (pos); \ + (pos) = dvb_application_signalling_descriptor_entries_next(d, pos)) + + + + + + + + + + +/******************************** PRIVATE CODE ********************************/ +static inline struct dvb_application_signalling_entry* + dvb_application_signalling_descriptor_entries_first(struct dvb_application_signalling_descriptor *d) +{ + if (d->d.len == 0) + return NULL; + + return (struct dvb_application_signalling_entry *) + ((uint8_t*) d + sizeof(struct dvb_application_signalling_descriptor)); +} + +static inline struct dvb_application_signalling_entry* + dvb_application_signalling_descriptor_countries_next(struct dvb_application_signalling_descriptor *d, + struct dvb_application_signalling_entry *pos) +{ + uint8_t *end = (uint8_t*) d + 2 + d->d.len; + uint8_t *next = (uint8_t *) pos + sizeof(struct dvb_application_signalling_entry); + + if (next >= end) + return NULL; + + return (struct dvb_application_signalling_entry *) next; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/bat_section.c b/kaffeine/src/input/dvb/lib/libucsi/dvb/bat_section.c new file mode 100644 index 0000000..afbeb0f --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/bat_section.c @@ -0,0 +1,77 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include <libucsi/dvb/bat_section.h> + +struct dvb_bat_section * dvb_bat_section_codec(struct section_ext * ext) +{ + uint8_t * buf = (uint8_t *) ext; + unsigned int pos = sizeof(struct section_ext); + unsigned int len = section_ext_length(ext); + struct dvb_bat_section * ret = (struct dvb_bat_section *) ext; + + if (len < sizeof(struct dvb_bat_section)) + return NULL; + + bswap16(buf + pos); + pos += 2; + + if ((pos + ret->bouquet_descriptors_length) > len) + return NULL; + + if (verify_descriptors(buf + pos, ret->bouquet_descriptors_length)) + return NULL; + pos += ret->bouquet_descriptors_length; + + if ((pos + sizeof(struct dvb_bat_section_part2)) > len) + return NULL; + + bswap16(buf + pos); + pos += sizeof(struct dvb_bat_section_part2); + + while (pos < len) { + struct dvb_bat_transport * transport = + (struct dvb_bat_transport *) (buf + pos); + + if ((pos + sizeof(struct dvb_bat_transport)) > len) + return NULL; + + bswap16(buf + pos); + bswap16(buf + pos + 2); + bswap16(buf + pos + 4); + + pos += sizeof(struct dvb_bat_transport); + + if ((pos + transport->transport_descriptors_length) > len) + return NULL; + + if (verify_descriptors(buf + pos, + transport->transport_descriptors_length)) + return NULL; + + pos += transport->transport_descriptors_length; + } + + if (pos != len) + return NULL; + + return ret; +} diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/bat_section.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/bat_section.h new file mode 100644 index 0000000..277d5ab --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/bat_section.h @@ -0,0 +1,211 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_DVB_BAT_SECTION_H +#define _UCSI_DVB_BAT_SECTION_H 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/section.h> + +/** + * dvb_bat_section structure. + */ +struct dvb_bat_section { + struct section_ext head; + + EBIT2(uint16_t reserved_1 : 4; , + uint16_t bouquet_descriptors_length :12; ); + /* struct descriptor descriptors[] */ + /* struct dvb_bat_section_part2 part2 */ +}; + +/** + * Second part of a dvb_bat_section, following the variable length descriptors field. + */ +struct dvb_bat_section_part2 { + EBIT2(uint16_t reserved_2 : 4; , + uint16_t transport_stream_loop_length :12; ); + /* struct dvb_bat_transport transports[] */ +} __ucsi_packed; + +/** + * An entry in the transports field of a dvb_bat_section_part2. + */ +struct dvb_bat_transport { + uint16_t transport_stream_id; + uint16_t original_network_id; + EBIT2(uint16_t reserved : 4; , + uint16_t transport_descriptors_length :12; ); + /* struct descriptor descriptors[] */ +}; + +/** + * Process a dvb_bat_section. + * + * @param section Generic section pointer. + * @return dvb_bat_section pointer, or NULL on error. + */ +struct dvb_bat_section *dvb_bat_section_codec(struct section_ext *section); + +/** + * Accessor for the bouquet_id field of a BAT. + * + * @param bat BAT pointer. + * @return The bouquet_id. + */ +static inline uint16_t dvb_bat_section_bouquet_id(struct dvb_bat_section *bat) +{ + return bat->head.table_id_ext; +} + +/** + * Iterator for the descriptors field in a dvb_bat_section. + * + * @param bat dvb_bat_section pointer. + * @param pos Variable containing a pointer to the current descriptor. + */ +#define dvb_bat_section_descriptors_for_each(bat, pos) \ + for ((pos) = dvb_bat_section_descriptors_first(bat); \ + (pos); \ + (pos) = dvb_bat_section_descriptors_next(bat, pos)) + +/** + * Accessor for the second part of a dvb_bat_section. + * + * @param bat dvb_bat_section pointer. + * @return dvb_bat_section_part2 pointer. + */ +static inline struct dvb_bat_section_part2 * + dvb_bat_section_part2(struct dvb_bat_section *bat) +{ + return (struct dvb_bat_section_part2 *) + ((uint8_t*) bat + + sizeof(struct dvb_bat_section) + + bat->bouquet_descriptors_length); + +} + +/** + * Iterator for the transports field of a dvb_bat_section_part2. + * + * @param part2 dvb_bat_section_part2 pointer. + * @param pos Variable containing a pointer to the current dvb_bat_transport. + */ +#define dvb_bat_section_transports_for_each(part2, pos) \ + for ((pos) = dvb_bat_section_transports_first(part2); \ + (pos); \ + (pos) = dvb_bat_section_transports_next(part2, pos)) + +/** + * Iterator for the descriptors field of a dvb_bat_transport. + * + * @param transport dvb_bat_transport pointer. + * @param pos Variable containing a pointer to the current descriptor. + */ +#define dvb_bat_transport_descriptors_for_each(transport, pos) \ + for ((pos) = dvb_bat_transport_descriptors_first(transport); \ + (pos); \ + (pos) = dvb_bat_transport_descriptors_next(transport, pos)) + + + + + + + + + + + + +/******************************** PRIVATE CODE ********************************/ +static inline struct descriptor * + dvb_bat_section_descriptors_first(struct dvb_bat_section *bat) +{ + if (bat->bouquet_descriptors_length == 0) + return NULL; + + return (struct descriptor *) + ((uint8_t *) bat + sizeof(struct dvb_bat_section)); +} + +static inline struct descriptor * + dvb_bat_section_descriptors_next(struct dvb_bat_section *bat, + struct descriptor* pos) +{ + return next_descriptor((uint8_t*) bat + sizeof(struct dvb_bat_section), + bat->bouquet_descriptors_length, + pos); +} + +static inline struct dvb_bat_transport * + dvb_bat_section_transports_first(struct dvb_bat_section_part2 *part2) +{ + if (part2->transport_stream_loop_length == 0) + return NULL; + + return (struct dvb_bat_transport *) + ((uint8_t *) part2 + sizeof(struct dvb_bat_section_part2)); +} + +static inline struct dvb_bat_transport * + dvb_bat_section_transports_next(struct dvb_bat_section_part2 *part2, + struct dvb_bat_transport *pos) +{ + uint8_t *end = (uint8_t*) part2 + sizeof(struct dvb_bat_section_part2) + + part2->transport_stream_loop_length; + uint8_t *next = (uint8_t*) pos + sizeof(struct dvb_bat_transport) + + pos->transport_descriptors_length; + + if (next >= end) + return NULL; + + return (struct dvb_bat_transport *) next; +} + +static inline struct descriptor * + dvb_bat_transport_descriptors_first(struct dvb_bat_transport *t) +{ + if (t->transport_descriptors_length == 0) + return NULL; + + return (struct descriptor *) + ((uint8_t*)t + sizeof(struct dvb_bat_transport)); +} + +static inline struct descriptor * + dvb_bat_transport_descriptors_next(struct dvb_bat_transport *t, + struct descriptor* pos) +{ + return next_descriptor((uint8_t*) t + sizeof(struct dvb_bat_transport), + t->transport_descriptors_length, + pos); +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/bouquet_name_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/bouquet_name_descriptor.h new file mode 100644 index 0000000..a298849 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/bouquet_name_descriptor.h @@ -0,0 +1,82 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_DVB_BOUQUET_NAME_DESCRIPTOR +#define _UCSI_DVB_BOUQUET_NAME_DESCRIPTOR 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/descriptor.h> +#include <libucsi/endianops.h> + +/** + * dvb_bouquet_name_descriptor structure. + */ +struct dvb_bouquet_name_descriptor { + struct descriptor d; + + /* uint8_t name[] */ +} __ucsi_packed; + +/** + * Process a dvb_bouquet_name_descriptor. + * + * @param d Generic descriptor pointer. + * @return dvb_bouquet_name_descriptor pointer, or NULL on error. + */ +static inline struct dvb_bouquet_name_descriptor* + dvb_bouquet_name_descriptor_codec(struct descriptor* d) +{ + return (struct dvb_bouquet_name_descriptor*) d; +} + +/** + * Accessor for the name field of a dvb_bouquet_name_descriptor. + * + * @param d dvb_bouquet_name_descriptor pointer. + * @return Pointer to the field. + */ +static inline uint8_t * + dvb_bouquet_name_descriptor_name(struct dvb_bouquet_name_descriptor *d) +{ + return (uint8_t *) d + sizeof(struct dvb_bouquet_name_descriptor); +} + +/** + * Determine the length of the name field of a dvb_bouquet_name_descriptor in bytes. + * + * @param d dvb_bouquet_name_descriptor pointer. + * @return Length of the field in bytes. + */ +static inline int + dvb_bouquet_name_descriptor_name_length(struct dvb_bouquet_name_descriptor *d) +{ + return d->d.len; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/ca_identifier_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/ca_identifier_descriptor.h new file mode 100644 index 0000000..ac670a9 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/ca_identifier_descriptor.h @@ -0,0 +1,94 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_DVB_CA_IDENTIFIER_DESCRIPTOR +#define _UCSI_DVB_CA_IDENTIFIER_DESCRIPTOR 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/descriptor.h> +#include <libucsi/endianops.h> + +/** + * dvb_ca_identifier_descriptor structure. + */ +struct dvb_ca_identifier_descriptor { + struct descriptor d; + + /* uint16_t ca_system_ids[] */ +} __ucsi_packed; + +/** + * Process a dvb_ca_identifier_descriptor. + * + * @param d Generic descriptor pointer. + * @return dvb_ca_identifier_descriptor pointer, or NULL on error. + */ +static inline struct dvb_ca_identifier_descriptor* + dvb_ca_identifier_descriptor_codec(struct descriptor* d) +{ + uint32_t len = d->len; + uint8_t *buf = (uint8_t*) d + 2; + uint32_t pos = 0; + + if (len % 2) + return NULL; + + while(pos < len) { + bswap16(buf+pos); + pos+=2; + } + + return (struct dvb_ca_identifier_descriptor*) d; +} + +/** + * Accessor for the ca_system_ids field of a dvb_ca_identifier_descriptor. + * + * @param d Generic descriptor pointer. + * @return Pointer to the field. + */ +static inline uint16_t * + dvb_ca_identifier_descriptor_ca_system_ids(struct dvb_ca_identifier_descriptor *d) +{ + return (uint16_t *) ((uint8_t *) d + sizeof(struct dvb_ca_identifier_descriptor)); +} + +/** + * Calculate the number of entries in the ca_system_ids field of a dvb_ca_identifier_descriptor. + * + * @param d dvb_ca_identifier_descriptor pointer. + * @return Number of entries. + */ +static inline int + dvb_ca_identifier_descriptor_ca_system_ids_count(struct dvb_ca_identifier_descriptor *d) +{ + return d->d.len >> 1; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/cable_delivery_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/cable_delivery_descriptor.h new file mode 100644 index 0000000..70b0c98 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/cable_delivery_descriptor.h @@ -0,0 +1,70 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_DVB_CABLE_DELIVERY_DESCRIPTOR +#define _UCSI_DVB_CABLE_DELIVERY_DESCRIPTOR 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/descriptor.h> +#include <libucsi/endianops.h> + +/** + * dvb_cable_delivery_descriptor structure. + */ +struct dvb_cable_delivery_descriptor { + struct descriptor d; + + uint32_t frequency; // BCD, units 100Hz + EBIT2(uint16_t reserved : 12; , + uint16_t fec_outer : 4; ) + uint8_t modulation; + EBIT2(uint32_t symbol_rate : 28; , // BCD, units 100Hz + uint32_t fec_inner : 4; ) +} __ucsi_packed; + +/** + * Process a dvb_cable_delivery_descriptor. + * + * @param d Generic descriptor pointer. + * @return dvb_cable_delivery_descriptor pointer, or NULL on error. + */ +static inline struct dvb_cable_delivery_descriptor* + dvb_cable_delivery_descriptor_codec(struct descriptor* d) +{ + if (d->len != (sizeof(struct dvb_cable_delivery_descriptor) - 2)) + return NULL; + + bswap32((uint8_t*) d + 2); + bswap16((uint8_t*) d + 6); + bswap32((uint8_t*) d + 9); + + return (struct dvb_cable_delivery_descriptor*) d; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/cell_frequency_link_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/cell_frequency_link_descriptor.h new file mode 100644 index 0000000..b6285bd --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/cell_frequency_link_descriptor.h @@ -0,0 +1,190 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_DVB_CELL_FREQUENCY_LINK_DESCRIPTOR +#define _UCSI_DVB_CELL_FREQUENCY_LINK_DESCRIPTOR 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/descriptor.h> +#include <libucsi/endianops.h> + +/** + * dvb_cell_frequency_link_descriptor structure. + */ +struct dvb_cell_frequency_link_descriptor { + struct descriptor d; + + /* struct dvb_cell_frequency_link_cell cells[] */ +} __ucsi_packed; + +/** + * An entry in the cells field of a dvb_cell_frequency_link_descriptor. + */ +struct dvb_cell_frequency_link_cell { + uint16_t cell_id; + uint32_t frequency; + uint8_t subcell_loop_info_length; + /* struct dvb_cell_frequency_link_subcell subcells[] */ +} __ucsi_packed; + +/** + * An entry in the subcells field of a dvb_cell_frequency_link_cell. + */ +struct dvb_cell_frequency_link_cell_subcell { + uint8_t cell_id_extension; + uint32_t transposer_frequency; +} __ucsi_packed; + +/** + * Process a dvb_cell_frequency_link_descriptor. + * + * @param d Generic descriptor pointer. + * @return dvb_cell_frequency_link_descriptor pointer, or NULL on error. + */ +static inline struct dvb_cell_frequency_link_descriptor* + dvb_cell_frequency_link_descriptor_codec(struct descriptor* d) +{ + uint32_t pos = 0; + uint32_t pos2 = 0; + uint8_t* buf = (uint8_t*) d + 2; + uint32_t len = d->len; + + while(pos < len) { + struct dvb_cell_frequency_link_cell *e = + (struct dvb_cell_frequency_link_cell*) (buf+pos); + + if ((pos + sizeof(struct dvb_cell_frequency_link_cell)) > len) + return NULL; + + bswap16(buf+pos); + bswap32(buf+pos+2); + + pos += sizeof(struct dvb_cell_frequency_link_cell); + + if ((pos + e->subcell_loop_info_length) > len) + return NULL; + + if (e->subcell_loop_info_length % sizeof(struct dvb_cell_frequency_link_cell_subcell)) + return NULL; + + pos2 = 0; + while(pos2 < e->subcell_loop_info_length) { + bswap32(buf+pos+pos2+1); + + pos2 += sizeof(struct dvb_cell_frequency_link_cell_subcell); + } + + pos += e->subcell_loop_info_length; + } + + return (struct dvb_cell_frequency_link_descriptor*) d; +} + +/** + * Iterator for the cells field of a dvb_cell_frequency_link_descriptor. + * + * @param d dvb_cell_frequency_link_descriptor pointer. + * @param pos Variable holding a pointer to the current dvb_cell_frequency_link_cell. + */ +#define dvb_cell_frequency_link_descriptor_cells_for_each(d, pos) \ + for ((pos) = dvb_cell_frequency_link_descriptor_cells_first(d); \ + (pos); \ + (pos) = dvb_cell_frequency_link_descriptor_cells_next(d, pos)) + +/** + * Iterator for the subcells field of a dvb_cell_frequency_link_cell. + * + * @param cell dvb_cell_frequency_link_cell pointer. + * @param pos Variable holding a pointer to the current dvb_cell_frequency_link_cell_subcell. + */ +#define dvb_cell_frequency_link_cell_subcells_for_each(cell, pos) \ + for ((pos) = dvb_cell_frequency_link_cell_subcells_first(cell); \ + (pos); \ + (pos) = dvb_cell_frequency_link_cell_subcells_next(cell, pos)) + + + + + + + + + + +/******************************** PRIVATE CODE ********************************/ +static inline struct dvb_cell_frequency_link_cell* + dvb_cell_frequency_link_descriptor_cells_first(struct dvb_cell_frequency_link_descriptor *d) +{ + if (d->d.len == 0) + return NULL; + + return (struct dvb_cell_frequency_link_cell *) + ((uint8_t*) d + sizeof(struct dvb_cell_frequency_link_descriptor)); +} + +static inline struct dvb_cell_frequency_link_cell* + dvb_cell_frequency_link_descriptor_cells_next(struct dvb_cell_frequency_link_descriptor *d, + struct dvb_cell_frequency_link_cell *pos) +{ + uint8_t *end = (uint8_t*) d + 2 + d->d.len; + uint8_t *next = (uint8_t *) pos + + sizeof(struct dvb_cell_frequency_link_cell) + + pos->subcell_loop_info_length; + + if (next >= end) + return NULL; + + return (struct dvb_cell_frequency_link_cell *) next; +} + +static inline struct dvb_cell_frequency_link_cell_subcell* + dvb_cell_frequency_cell_subcells_first(struct dvb_cell_frequency_link_cell *d) +{ + if (d->subcell_loop_info_length == 0) + return NULL; + + return (struct dvb_cell_frequency_link_cell_subcell*) + ((uint8_t*) d + sizeof(struct dvb_cell_frequency_link_cell)); +} + +static inline struct dvb_cell_frequency_link_cell_subcell* + dvb_cell_frequency_cell_subcells_next(struct dvb_cell_frequency_link_cell *cell, + struct dvb_cell_frequency_link_cell_subcell *pos) +{ + uint8_t *end = (uint8_t*) cell + cell->subcell_loop_info_length; + uint8_t *next = (uint8_t*) pos + + sizeof(struct dvb_cell_frequency_link_cell_subcell); + + if (next >= end) + return NULL; + + return (struct dvb_cell_frequency_link_cell_subcell *) next; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/cell_list_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/cell_list_descriptor.h new file mode 100644 index 0000000..6a42ce4 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/cell_list_descriptor.h @@ -0,0 +1,201 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_DVB_CELL_LIST_DESCRIPTOR +#define _UCSI_DVB_CELL_LIST_DESCRIPTOR 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/descriptor.h> +#include <libucsi/endianops.h> + +/** + * dvb_cell_list_descriptor structure. + */ +struct dvb_cell_list_descriptor { + struct descriptor d; + + /* struct dvb_cell_list_entry cells[] */ +} __ucsi_packed; + +/** + * An entry in the cells field of a dvb_cell_list_descriptor. + */ +struct dvb_cell_list_entry { + uint16_t cell_id; + uint16_t cell_latitude; + uint16_t cell_longitude; + EBIT3(uint32_t cell_extend_of_latitude :12; , + uint32_t cell_extend_of_longitude :12; , + uint32_t subcell_info_loop_length : 8; ) + /* struct dvb_subcell_list_entry subcells[] */ +} __ucsi_packed; + +/** + * An entry in the subcells field of a dvb_cell_list_entry. + */ +struct dvb_subcell_list_entry { + uint8_t cell_id_extension; + uint16_t subcell_latitude; + uint16_t subcell_longitude; + EBIT2(uint32_t subcell_extend_of_latitude :12; , + uint32_t subcell_extend_of_longitude :12; ) +} __ucsi_packed; + +/** + * Process a dvb_cell_list_descriptor. + * + * @param d Generic descriptor pointer. + * @return dvb_cell_list_descriptor pointer, or NULL on error. + */ +static inline struct dvb_cell_list_descriptor* + dvb_cell_list_descriptor_codec(struct descriptor* d) +{ + uint32_t pos = 0; + uint32_t pos2 = 0; + uint8_t* buf = (uint8_t*) d + 2; + uint32_t len = d->len; + + while(pos < len) { + struct dvb_cell_list_entry *e = + (struct dvb_cell_list_entry*) (buf+pos); + + if ((pos + sizeof(struct dvb_cell_list_entry)) > len) + return NULL; + + bswap16(buf+pos); + bswap16(buf+pos+2); + bswap16(buf+pos+4); + bswap32(buf+pos+6); + + pos += sizeof(struct dvb_cell_list_entry); + + if ((pos + e->subcell_info_loop_length) > len) + return NULL; + + if (e->subcell_info_loop_length % sizeof(struct dvb_subcell_list_entry)) + return NULL; + + pos2 = 0; + while(pos2 < e->subcell_info_loop_length) { + bswap16(buf+pos+pos2+1); + bswap16(buf+pos+pos2+3); + bswap24(buf+pos+pos2+5); + + pos2 += sizeof(struct dvb_subcell_list_entry); + } + + pos += e->subcell_info_loop_length; + } + + return (struct dvb_cell_list_descriptor*) d; +} + +/** + * Iterator for the cells field of a dvb_cell_list_descriptor. + * + * @param d dvb_cell_list_descriptor pointer. + * @param pos Variable holding a pointer to the current dvb_cell_list_entry. + */ +#define dvb_cell_list_descriptor_cells_for_each(d, pos) \ + for ((pos) = dvb_cell_list_descriptor_cells_first(d); \ + (pos); \ + (pos) = dvb_cell_list_descriptor_cells_next(d, pos)) + +/** + * Iterator for the subcells field of a dvb_cell_list_entry. + * + * @param cell dvb_cell_list_entry pointer. + * @param pos Variable holding a pointer to the current dvb_subcell_list_entry. + */ +#define dvb_cell_list_entry_subcells_for_each(cell, pos) \ + for ((pos) = dvb_cell_list_entry_subcells_first(cell); \ + (pos); \ + (pos) = dvb_cell_list_entry_subcells_next(cell, pos)) + + + + + + + + + + +/******************************** PRIVATE CODE ********************************/ +static inline struct dvb_cell_list_entry* + dvb_cell_list_descriptor_cells_first(struct dvb_cell_list_descriptor *d) +{ + if (d->d.len == 0) + return NULL; + + return (struct dvb_cell_list_entry *) + ((uint8_t*) d + sizeof(struct dvb_cell_list_descriptor)); +} + +static inline struct dvb_cell_list_entry* + dvb_cell_list_descriptor_cells_next(struct dvb_cell_list_descriptor *d, + struct dvb_cell_list_entry *pos) +{ + uint8_t *end = (uint8_t*) d + 2 + d->d.len; + uint8_t *next = (uint8_t *) pos + + sizeof(struct dvb_cell_list_entry) + + pos->subcell_info_loop_length; + + if (next >= end) + return NULL; + + return (struct dvb_cell_list_entry *) next; +} + +static inline struct dvb_subcell_list_entry* + dvb_cell_list_entry_subcells_first(struct dvb_cell_list_entry *d) +{ + if (d->subcell_info_loop_length == 0) + return NULL; + + return (struct dvb_subcell_list_entry*) + ((uint8_t*) d + sizeof(struct dvb_cell_list_entry)); +} + +static inline struct dvb_subcell_list_entry* + dvb_cell_list_entry_subcells_next(struct dvb_cell_list_entry *d, + struct dvb_subcell_list_entry *pos) +{ + uint8_t *next = (uint8_t*) pos + sizeof(struct dvb_subcell_list_entry); + uint8_t *end = (uint8_t*) d + + sizeof(struct dvb_cell_list_entry) + + d->subcell_info_loop_length; + + if (next >= end) + return NULL; + + return (struct dvb_subcell_list_entry *) next; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/component_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/component_descriptor.h new file mode 100644 index 0000000..154e235 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/component_descriptor.h @@ -0,0 +1,147 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_DVB_COMPONENT_DESCRIPTOR +#define _UCSI_DVB_COMPONENT_DESCRIPTOR 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/descriptor.h> +#include <libucsi/endianops.h> +#include <libucsi/types.h> + +/** + * Possible values for stream_content. + */ +enum { + DVB_STREAM_CONTENT_VIDEO = 0x01, + DVB_STREAM_CONTENT_AUDIO = 0x02, + DVB_STREAM_CONTENT_SUBTITLE = 0x03, + DVB_STREAM_CONTENT_AC3 = 0x04 +}; + +/** + * Possible values for component_type. + */ +enum { + DVB_COMPONENT_TYPE_VIDEO_43_25Hz = 0x01, + DVB_COMPONENT_TYPE_VIDEO_169_PAN_25Hz = 0x02, + DVB_COMPONENT_TYPE_VIDEO_169_NOPAN_25Hz = 0x03, + DVB_COMPONENT_TYPE_VIDEO_GT169_25Hz = 0x04, + + DVB_COMPONENT_TYPE_VIDEO_43_30Hz = 0x05, + DVB_COMPONENT_TYPE_VIDEO_169_PAN_30Hz = 0x06, + DVB_COMPONENT_TYPE_VIDEO_169_NOPAN_30Hz = 0x07, + DVB_COMPONENT_TYPE_VIDEO_GT169_30Hz = 0x08, + + DVB_COMPONENT_TYPE_HDVIDEO_43_25Hz = 0x09, + DVB_COMPONENT_TYPE_HDVIDEO_169_PAN_25Hz = 0x0a, + DVB_COMPONENT_TYPE_HDVIDEO_169_NOPAN_25Hz = 0x0b, + DVB_COMPONENT_TYPE_HDVIDEO_GT169_25Hz = 0x0c, + + DVB_COMPONENT_TYPE_HDVIDEO_43_30Hz = 0x0d, + DVB_COMPONENT_TYPE_HDVIDEO_169_PAN_30Hz = 0x0e, + DVB_COMPONENT_TYPE_HDVIDEO_169_NOPAN_30Hz = 0x0f, + DVB_COMPONENT_TYPE_HDVIDEO_GT169_30Hz = 0x10, + + DVB_COMPONENT_TYPE_AUDIO_SINGLE_MONO = 0x01, + DVB_COMPONENT_TYPE_AUDIO_DUAL_MONO = 0x02, + DVB_COMPONENT_TYPE_AUDIO_STEREO = 0x03, + DVB_COMPONENT_TYPE_AUDIO_MULTI_LINGUAL_MULTI_CHAN= 0x04, + DVB_COMPONENT_TYPE_AUDIO_SURROUND = 0x05, + DVB_COMPONENT_TYPE_AUDIO_VISUAL_IMPAIRED = 0x40, + DVB_COMPONENT_TYPE_AUDIO_HARDHEAR = 0x41, + DVB_COMPONENT_TYPE_AUDIO_SUPPLEMENTARY = 0x42, + + DVB_COMPONENT_TYPE_SUBTITLE_TELETEXT = 0x01, + DVB_COMPONENT_TYPE_SUBTITLE_ASSOC_TELETEXT = 0x02, + DVB_COMPONENT_TYPE_SUBTITLE_VBI = 0x03, + DVB_COMPONENT_TYPE_SUBTITLE_DVB = 0x10, + DVB_COMPONENT_TYPE_SUBTITLE_DVB_43 = 0x11, + DVB_COMPONENT_TYPE_SUBTITLE_DVB_169 = 0x12, + DVB_COMPONENT_TYPE_SUBTITLE_DVB_2211 = 0x13, + DVB_COMPONENT_TYPE_SUBTITLE_DVB_HARDHEAR = 0x20, + DVB_COMPONENT_TYPE_SUBTITLE_DVB_HARDHEAR_43 = 0x21, + DVB_COMPONENT_TYPE_SUBTITLE_DVB_HARDHEAR_169 = 0x22, + DVB_COMPONENT_TYPE_SUBTITLE_DVB_HARDHEAR_2211 = 0x23 +}; + +/** + * dvb_component_descriptor structure. + */ +struct dvb_component_descriptor { + struct descriptor d; + + EBIT2(uint8_t reserved : 4; , + uint8_t stream_content : 4; ) + uint8_t component_type; + uint8_t component_tag; + iso639lang_t language_code; + /* uint8_t text[] */ +} __ucsi_packed; + +/** + * Process a dvb_component_descriptor. + * + * @param d Pointer to a generic descriptor. + * @return dvb_component_descriptor pointer, or NULL on error. + */ +static inline struct dvb_component_descriptor* + dvb_component_descriptor_codec(struct descriptor* d) +{ + if (d->len < (sizeof(struct dvb_component_descriptor) - 2)) + return NULL; + + return (struct dvb_component_descriptor*) d; +} + +/** + * Accessor for the text field of a dvb_component_descriptor. + * + * @param d dvb_component_descriptor pointer. + * @return Pointer to the field. + */ +static inline uint8_t * + dvb_component_descriptor_text(struct dvb_component_descriptor *d) +{ + return (uint8_t *) d + sizeof(struct dvb_component_descriptor); +} + +/** + * Determine the length of the text field of a dvb_component_descriptor. + * + * @param d dvb_component_descriptor pointer. + * @return Length of the field in bytes. + */ +static inline int + dvb_component_descriptor_text_length(struct dvb_component_descriptor *d) +{ + return d->d.len - 6; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/content_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/content_descriptor.h new file mode 100644 index 0000000..5cc16dc --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/content_descriptor.h @@ -0,0 +1,116 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_DVB_CONTENT_DESCRIPTOR +#define _UCSI_DVB_CONTENT_DESCRIPTOR 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/descriptor.h> +#include <libucsi/endianops.h> + +// FIXME: the nibbles + +/** + * dvb_content_descriptor structure. + */ +struct dvb_content_descriptor { + struct descriptor d; + + /* struct dvb_content_nibble nibbles[] */ +} __ucsi_packed; + +/** + * An entry in the nibbles field of a dvb_content_descriptor. + */ +struct dvb_content_nibble { + EBIT2(uint8_t content_nibble_level_1 : 4; , + uint8_t content_nibble_level_2 : 4; ) + EBIT2(uint8_t user_nibble_1 : 4; , + uint8_t user_nibble_2 : 4; ) +} __ucsi_packed; + +/** + * Process a dvb_content_descriptor. + * + * @param d Generic descriptor pointer. + * @return dvb_content_descriptor pointer, or NULL on error. + */ +static inline struct dvb_content_descriptor* + dvb_content_descriptor_codec(struct descriptor* d) +{ + if (d->len % sizeof(struct dvb_content_nibble)) + return NULL; + + return (struct dvb_content_descriptor*) d; +} + +/** + * Iterator for the nibbles field of a dvb_content_descriptor. + * + * @param d dvb_content_descriptor pointer. + * @param pos Variable containing a pointer to the current dvb_content_nibble. + */ +#define dvb_content_descriptor_nibbles_for_each(d, pos) \ + for ((pos) = dvb_content_descriptor_nibbles_first(d); \ + (pos); \ + (pos) = dvb_content_descriptor_nibbles_next(d, pos)) + + + + + + + + + +/******************************** PRIVATE CODE ********************************/ +static inline struct dvb_content_nibble* + dvb_content_descriptor_nibbles_first(struct dvb_content_descriptor *d) +{ + if (d->d.len == 0) + return NULL; + + return (struct dvb_content_nibble *) + ((uint8_t*) d + sizeof(struct dvb_content_descriptor)); +} + +static inline struct dvb_content_nibble* + dvb_content_descriptor_nibbles_next(struct dvb_content_descriptor *d, + struct dvb_content_nibble *pos) +{ + uint8_t *end = (uint8_t*) d + 2 + d->d.len; + uint8_t *next = (uint8_t *) pos + sizeof(struct dvb_content_nibble); + + if (next >= end) + return NULL; + + return (struct dvb_content_nibble *) next; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/content_identifier_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/content_identifier_descriptor.h new file mode 100644 index 0000000..63d24a1 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/content_identifier_descriptor.h @@ -0,0 +1,222 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_DVB_CONTENT_IDENTIFIER_DESCRIPTOR +#define _UCSI_DVB_CONTENT_IDENTIFIER_DESCRIPTOR 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/descriptor.h> +#include <libucsi/endianops.h> +#include <libucsi/types.h> + + +/** + * Possible values for the crid_type. + */ +enum { + DVB_CRID_TYPE_NONE = 0x00, + DVB_CRID_TYPE_ITEM = 0x01, + DVB_CRID_TYPE_SERIES = 0x02, + DVB_CRID_TYPE_RECOMMENDATION = 0x03 +}; + +/** + * Possible values for the crid_location. + */ +enum { + DVB_CRID_LOCATION_THIS_DESCRIPTOR = 0x00, + DVB_CRID_LOCATION_CIT = 0x01 +}; + +/** + * dvb_content_identifier_descriptor structure. + */ +struct dvb_content_identifier_descriptor { + struct descriptor d; + + /* struct dvb_content_identifier_entry entries[] */ +} __ucsi_packed; + +/** + * An entry in the entries field of a dvb_content_identifier_descriptor. + */ +struct dvb_content_identifier_entry { + EBIT2(uint8_t crid_type : 6; , + uint8_t crid_location : 2; ) + /* struct dvb_content_identifier_data_00 data0 */ + /* struct dvb_content_identifier_data_01 data1 */ +} __ucsi_packed; + +/** + * The data if crid_location == 0 + */ +struct dvb_content_identifier_entry_data_0 { + uint8_t crid_length; + /* uint8_t data[] */ +} __ucsi_packed; + +/** + * The data if crid_location == 1 + */ +struct dvb_content_identifier_entry_data_1 { + uint16_t crid_ref; +} __ucsi_packed; + + +/** + * Process a dvb_content_identifier_descriptor. + * + * @param d Generic descriptor. + * @return dvb_content_identifier_descriptor pointer, or NULL on error. + */ +static inline struct dvb_content_identifier_descriptor* + dvb_content_identifier_descriptor_codec(struct descriptor* d) +{ + uint32_t len = d->len + 2; + uint32_t pos = 2; + uint8_t *buf = (uint8_t*) d; + + while(pos < len) { + struct dvb_content_identifier_entry *e = + (struct dvb_content_identifier_entry*) (buf + pos); + + if (len < (pos+1)) + return NULL; + pos++; + + switch(e->crid_location) { + case 0: + if (len < (pos + 1)) + return NULL; + if (len < (pos + 1 + buf[pos])) + return NULL; + pos += 1 + buf[pos]; + break; + + case 1: + if (len < (pos+2)) + return NULL; + bswap16(buf+pos); + break; + } + } + + if (pos != len) + return NULL; + + return (struct dvb_content_identifier_descriptor*) d; +} + +/** + * Iterator for entries field of a dvb_content_identifier_descriptor. + * + * @param d dvb_content_identifier_descriptor pointer. + * @param pos Variable holding a pointer to the current dvb_content_identifier_entry. + */ +#define dvb_content_identifier_descriptor_entries_for_each(d, pos) \ + for ((pos) = dvb_content_identifier_descriptor_entries_first(d); \ + (pos); \ + (pos) = dvb_content_identifier_descriptor_entries_next(d, pos)) + +/** + * Accessor for the data0 field of a dvb_content_identifier_entry. + * + * @param d dvb_content_identifier_entry pointer. + * @return Pointer, or NULL on error. + */ +static inline struct dvb_content_identifier_entry_data_0* + dvb_content_identifier_entry_data_0(struct dvb_content_identifier_entry *d) +{ + if (d->crid_location != 0) + return NULL; + return (struct dvb_content_identifier_entry_data_0*) + ((uint8_t*) d + sizeof(struct dvb_content_identifier_entry)); +} + +/** + * Accessor for the data1 field of a dvb_content_identifier_entry. + * + * @param d dvb_content_identifier_entry pointer. + * @return Pointer, or NULL on error. + */ +static inline struct dvb_content_identifier_entry_data_1* + dvb_content_identifier_entry_data_1(struct dvb_content_identifier_entry *d) +{ + if (d->crid_location != 1) + return NULL; + return (struct dvb_content_identifier_entry_data_1*) + ((uint8_t*) d + sizeof(struct dvb_content_identifier_entry)); +} + + + + + + + + +/******************************** PRIVATE CODE ********************************/ +static inline struct dvb_content_identifier_entry* + dvb_content_identifier_descriptor_entries_first(struct dvb_content_identifier_descriptor *d) +{ + if (d->d.len == 0) + return NULL; + + return (struct dvb_content_identifier_entry *) + ((uint8_t*) d + sizeof(struct dvb_content_identifier_descriptor)); +} + +static inline struct dvb_content_identifier_entry* + dvb_content_identifier_descriptor_entries_next(struct dvb_content_identifier_descriptor *d, + struct dvb_content_identifier_entry *pos) +{ + uint8_t *end = (uint8_t*) d + 2 + d->d.len; + uint8_t *next = (uint8_t *) pos + sizeof(struct dvb_content_identifier_entry); + + if (next >= end) + return NULL; + + switch(pos->crid_location) { + case 0: + if ((next+2) >= end) + return NULL; + if ((next+2+next[1]) >= end) + return NULL; + break; + + case 1: + if ((next+3) >= end) + return NULL; + break; + } + + return (struct dvb_content_identifier_entry*) next; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/country_availability_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/country_availability_descriptor.h new file mode 100644 index 0000000..29a6b9a --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/country_availability_descriptor.h @@ -0,0 +1,120 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_DVB_COUNTRY_AVAILABILITY_DESCRIPTOR +#define _UCSI_DVB_COUNTRY_AVAILABILITY_DESCRIPTOR 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/descriptor.h> +#include <libucsi/endianops.h> +#include <libucsi/types.h> + +/** + * dvb_country_availability_descriptor structure. + */ +struct dvb_country_availability_descriptor { + struct descriptor d; + + EBIT2(uint8_t country_availability_flag : 1; , + uint8_t reserved : 7; ) + /* struct dvb_country_availability_entry countries[] */ +} __ucsi_packed; + +/** + * An entry in the countries field of a dvb_country_availability_descriptor. + */ +struct dvb_country_availability_entry { + iso639country_t country_code; +} __ucsi_packed; + +/** + * Process a dvb_country_availability_descriptor. + * + * @param d Generic descriptor pointer. + * @return dvb_country_availability_descriptor pointer, or NULL on error. + */ +static inline struct dvb_country_availability_descriptor* + dvb_country_availability_descriptor_codec(struct descriptor* d) +{ + uint32_t len = d->len; + + if (len < (sizeof(struct dvb_country_availability_descriptor) - 2)) + return NULL; + + if ((len - 1) % sizeof(struct dvb_country_availability_entry)) + return NULL; + + return (struct dvb_country_availability_descriptor*) d; +} + +/** + * Iterator for the countries field of a dvb_country_availability_descriptor. + * + * @param d dvb_country_availability_descriptor pointer. + * @param pos Variable containing a pointer to the current dvb_country_availability_entry. + */ +#define dvb_country_availability_descriptor_countries_for_each(d, pos) \ + for ((pos) = dvb_country_availability_descriptor_countries_first(d); \ + (pos); \ + (pos) = dvb_country_availability_descriptor_countries_next(d, pos)) + + + + + + + + + + +/******************************** PRIVATE CODE ********************************/ +static inline struct dvb_country_availability_entry* + dvb_country_availability_descriptor_countries_first(struct dvb_country_availability_descriptor *d) +{ + if (d->d.len == 1) + return NULL; + + return (struct dvb_country_availability_entry *) + ((uint8_t*) d + sizeof(struct dvb_country_availability_descriptor)); +} + +static inline struct dvb_country_availability_entry* + dvb_country_availability_descriptor_countries_next(struct dvb_country_availability_descriptor *d, + struct dvb_country_availability_entry *pos) +{ + uint8_t *end = (uint8_t*) d + 2 + d->d.len; + uint8_t *next = (uint8_t *) pos + sizeof(struct dvb_country_availability_entry); + + if (next >= end) + return NULL; + + return (struct dvb_country_availability_entry *) next; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/data_broadcast_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/data_broadcast_descriptor.h new file mode 100644 index 0000000..069e1db --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/data_broadcast_descriptor.h @@ -0,0 +1,139 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_DVB_DATA_BROADCAST_DESCRIPTOR +#define _UCSI_DVB_DATA_BROADCAST_DESCRIPTOR 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/descriptor.h> +#include <libucsi/endianops.h> +#include <libucsi/types.h> + +/** + * dvb_data_broadcast_descriptor structure. + */ +struct dvb_data_broadcast_descriptor { + struct descriptor d; + + uint16_t data_broadcast_id; + uint8_t component_tag; + uint8_t selector_length; + /* uint8_t selector[] */ + /* struct dvb_data_broadcast_descriptor_part2 part2 */ +} __ucsi_packed; + +/** + * Second part of a dvb_data_broadcast_descriptor following the variable length selector field. + */ +struct dvb_data_broadcast_descriptor_part2 { + iso639lang_t language_code; + uint8_t text_length; + /* uint8_t text[] */ +} __ucsi_packed; + +/** + * Process a dvb_data_broadcast_descriptor. + * + * @param d Generic descriptor pointer. + * @return dvb_data_broadcast_descriptor pointer, or NULL on error. + */ +static inline struct dvb_data_broadcast_descriptor* + dvb_data_broadcast_descriptor_codec(struct descriptor* d) +{ + struct dvb_data_broadcast_descriptor *p = + (struct dvb_data_broadcast_descriptor *) d; + struct dvb_data_broadcast_descriptor_part2 *p2; + uint8_t* buf = (uint8_t*) d + 2; + uint32_t pos = sizeof(struct dvb_data_broadcast_descriptor) - 2; + uint32_t len = d->len; + + if (pos > len) + return NULL; + + bswap16(buf + 2); + + pos += p->selector_length; + + if (pos > len) + return NULL; + + p2 = (struct dvb_data_broadcast_descriptor_part2*) (buf + 2 + pos); + + pos += sizeof(struct dvb_data_broadcast_descriptor_part2); + + if (pos > len) + return NULL; + + pos += p2->text_length; + + if (pos != len) + return NULL; + + return p; +} + +/** + * Accessor for the selector field of a dvb_data_broadcast_descriptor. + * + * @param d dvb_data_broadcast_descriptor pointer. + * @return pointer to the field. + */ +static inline uint8_t * + dvb_data_broadcast_descriptor_selector(struct dvb_data_broadcast_descriptor *d) +{ + return (uint8_t *) d + sizeof(struct dvb_data_broadcast_descriptor); +} + +/** + * Accessor for the second part of a dvb_data_broadcast_descriptor. + * + * @param d dvb_data_broadcast_descriptor pointer. + * @return dvb_data_broadcast_descriptor_part2 pointer. + */ +static inline struct dvb_data_broadcast_descriptor_part2 * + dvb_data_broadcast_descriptor_part2(struct dvb_data_broadcast_descriptor *d) +{ + return (struct dvb_data_broadcast_descriptor_part2*) + ((uint8_t*) d + sizeof(struct dvb_data_broadcast_descriptor) + + d->selector_length); +} + +/** + * Accessor for the text field in a dvb_data_broadcast_descriptor_part2. + * + * @param d dvb_data_broadcast_descriptor_part2 pointer. + * @return pointer to the field. + */ +static inline uint8_t * + dvb_data_broadcast_descriptor_part2_text(struct dvb_data_broadcast_descriptor_part2 *d) +{ + return (uint8_t *) d + sizeof(struct dvb_data_broadcast_descriptor_part2); +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/data_broadcast_id_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/data_broadcast_id_descriptor.h new file mode 100644 index 0000000..8547d8f --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/data_broadcast_id_descriptor.h @@ -0,0 +1,90 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_DVB_DATA_BROADCAST_ID_DESCRIPTOR +#define _UCSI_DVB_DATA_BROADCAST_ID_DESCRIPTOR 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/descriptor.h> +#include <libucsi/endianops.h> + +/** + * dvb_data_broadcast_id_descriptor structure. + */ +struct dvb_data_broadcast_id_descriptor { + struct descriptor d; + + uint16_t data_broadcast_id; + /* uint8_t id_selector_byte[] */ +} __ucsi_packed; + +/** + * Process a dvb_data_broadcast_id_descriptor. + * + * @param d Generic descriptor structure. + * @return dvb_data_broadcast_id_descriptor pointer, or NULL on error. + */ +static inline struct dvb_data_broadcast_id_descriptor* + dvb_data_broadcast_id_descriptor_codec(struct descriptor* d) +{ + if (d->len < (sizeof(struct dvb_data_broadcast_id_descriptor) - 2)) + return NULL; + + bswap16((uint8_t*) d + 2); + + return (struct dvb_data_broadcast_id_descriptor*) d; +} + +/** + * Accessor for the selector_byte field of a dvb_data_broadcast_id_descriptor. + * + * @param d dvb_data_broadcast_id_descriptor pointer. + * @return Pointer to the field. + */ +static inline uint8_t * + dvb_data_broadcast_id_descriptor_id_selector_byte(struct dvb_data_broadcast_id_descriptor *d) +{ + return (uint8_t *) d + sizeof(struct dvb_data_broadcast_id_descriptor); +} + +/** + * Determine the length of the selector_byte field of a dvb_data_broadcast_id_descriptor. + * + * @param d dvb_data_broadcast_id_descriptor pointer. + * @return Length of the field in bytes. + */ +static inline int + dvb_data_broadcast_id_descriptor_id_selector_byte_length(struct dvb_data_broadcast_id_descriptor *d) +{ + return d->d.len - 2; +} + +#ifdef __cplusplus +} +#endif + +#endif + +#include <libucsi/dvb/mhp_data_broadcast_id_descriptor.h> diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/default_authority_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/default_authority_descriptor.h new file mode 100644 index 0000000..0b0ba73 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/default_authority_descriptor.h @@ -0,0 +1,82 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_DVB_DEFAULT_AUTHORITY_DESCRIPTOR +#define _UCSI_DVB_DEFAULT_AUTHORITY_DESCRIPTOR 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/descriptor.h> +#include <libucsi/endianops.h> + +/** + * dvb_default_authority_descriptor structure. + */ +struct dvb_default_authority_descriptor { + struct descriptor d; + + /* char name[] */ +} __ucsi_packed; + +/** + * Process a dvb_default_authority_descriptor. + * + * @param d Generic descriptor pointer. + * @return dvb_default_authority_descriptor pointer, or NULL on error. + */ +static inline struct dvb_default_authority_descriptor* + dvb_default_authority_descriptor_codec(struct descriptor* d) +{ + return (struct dvb_default_authority_descriptor*) d; +} + +/** + * Accessor for the name field in a dvb_default_authority_descriptor. + * + * @param d dvb_default_authority_descriptor pointer. + * @return Pointer to the field. + */ +static inline uint8_t * + dvb_default_authority_descriptor_name(struct dvb_default_authority_descriptor *d) +{ + return (uint8_t *) d + sizeof(struct dvb_default_authority_descriptor); +} + +/** + * Calculate the length of the name field in a dvb_default_authority_descriptor. + * + * @param d dvb_default_authority_descriptor pointer. + * @return Length of the field in bytes. + */ +static inline int + dvb_default_authority_descriptor_name_length(struct dvb_default_authority_descriptor *d) +{ + return d->d.len; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/descriptor.h new file mode 100644 index 0000000..0772601 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/descriptor.h @@ -0,0 +1,198 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_DVB_DESCRIPTOR_H +#define _UCSI_DVB_DESCRIPTOR_H 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/dvb/ac3_descriptor.h> +#include <libucsi/dvb/adaptation_field_data_descriptor.h> +#include <libucsi/dvb/ancillary_data_descriptor.h> +#include <libucsi/dvb/announcement_support_descriptor.h> +#include <libucsi/dvb/application_signalling_descriptor.h> +#include <libucsi/dvb/bouquet_name_descriptor.h> +#include <libucsi/dvb/ca_identifier_descriptor.h> +#include <libucsi/dvb/cable_delivery_descriptor.h> +#include <libucsi/dvb/cell_frequency_link_descriptor.h> +#include <libucsi/dvb/cell_list_descriptor.h> +#include <libucsi/dvb/component_descriptor.h> +#include <libucsi/dvb/content_descriptor.h> +#include <libucsi/dvb/content_identifier_descriptor.h> +#include <libucsi/dvb/country_availability_descriptor.h> +#include <libucsi/dvb/data_broadcast_descriptor.h> +#include <libucsi/dvb/data_broadcast_id_descriptor.h> +#include <libucsi/dvb/default_authority_descriptor.h> +#include <libucsi/dvb/dsng_descriptor.h> +#include <libucsi/dvb/extended_event_descriptor.h> +#include <libucsi/dvb/frequency_list_descriptor.h> +#include <libucsi/dvb/linkage_descriptor.h> +#include <libucsi/dvb/local_time_offset_descriptor.h> +#include <libucsi/dvb/mosaic_descriptor.h> +#include <libucsi/dvb/multilingual_bouquet_name_descriptor.h> +#include <libucsi/dvb/multilingual_component_descriptor.h> +#include <libucsi/dvb/multilingual_network_name_descriptor.h> +#include <libucsi/dvb/multilingual_service_name_descriptor.h> +#include <libucsi/dvb/network_name_descriptor.h> +#include <libucsi/dvb/nvod_reference_descriptor.h> +#include <libucsi/dvb/parental_rating_descriptor.h> +#include <libucsi/dvb/partial_transport_stream_descriptor.h> +#include <libucsi/dvb/pdc_descriptor.h> +#include <libucsi/dvb/private_data_specifier_descriptor.h> +#include <libucsi/dvb/related_content_descriptor.h> +#include <libucsi/dvb/satellite_delivery_descriptor.h> +#include <libucsi/dvb/s2_satellite_delivery_descriptor.h> +#include <libucsi/dvb/scrambling_descriptor.h> +#include <libucsi/dvb/service_availability_descriptor.h> +#include <libucsi/dvb/service_descriptor.h> +#include <libucsi/dvb/service_identifier_descriptor.h> +#include <libucsi/dvb/service_list_descriptor.h> +#include <libucsi/dvb/service_move_descriptor.h> +#include <libucsi/dvb/short_event_descriptor.h> +#include <libucsi/dvb/short_smoothing_buffer_descriptor.h> +#include <libucsi/dvb/stream_identifier_descriptor.h> +#include <libucsi/dvb/stuffing_descriptor.h> +#include <libucsi/dvb/subtitling_descriptor.h> +#include <libucsi/dvb/telephone_descriptor.h> +#include <libucsi/dvb/teletext_descriptor.h> +#include <libucsi/dvb/terrestrial_delivery_descriptor.h> +#include <libucsi/dvb/time_shifted_event_descriptor.h> +#include <libucsi/dvb/time_shifted_service_descriptor.h> +#include <libucsi/dvb/transport_stream_descriptor.h> +#include <libucsi/dvb/tva_id_descriptor.h> +#include <libucsi/dvb/vbi_data_descriptor.h> +#include <libucsi/dvb/vbi_teletext_descriptor.h> +#include <libucsi/dvb/rnt_rar_over_dvb_stream_descriptor.h> +#include <libucsi/dvb/rnt_rar_over_ip_descriptor.h> +#include <libucsi/dvb/rnt_rnt_scan_descriptor.h> +#include <libucsi/dvb/ait_application_descriptor.h> +#include <libucsi/dvb/ait_application_name_descriptor.h> +#include <libucsi/dvb/ait_external_application_authorisation_descriptor.h> +#include <libucsi/dvb/ait_application_icons_descriptor.h> +#include <libucsi/endianops.h> + +/** + * The following are not implemented just now + */ +/* +#include <libucsi/dvb/ait_transport_protocol_descriptor.h> +#include <libucsi/dvb/ait_dvb_j_application_descriptor.h> +#include <libucsi/dvb/ait_dvb_j_application_location_descriptor.h> +#include <libucsi/dvb/ait_dvb_html_application_descriptor.h> +#include <libucsi/dvb/ait_dvb_html_application_location_descriptor.h> +#include <libucsi/dvb/ait_dvb_html_application_boundary_descriptor.h> +#include <libucsi/dvb/ait_prefetch_descriptor.h> +#include <libucsi/dvb/ait_dii_location_descriptor.h> +#include <libucsi/dvb/ait_ip_signalling_descriptor.h> +*/ + +/** + * Enumeration of DVB descriptor tags. + */ +enum dvb_descriptor_tag { + dtag_dvb_network_name = 0x40, + dtag_dvb_service_list = 0x41, + dtag_dvb_stuffing = 0x42, + dtag_dvb_satellite_delivery_system = 0x43, + dtag_dvb_cable_delivery_system = 0x44, + dtag_dvb_vbi_data = 0x45, + dtag_dvb_vbi_teletext = 0x46, + dtag_dvb_bouquet_name = 0x47, + dtag_dvb_service = 0x48, + dtag_dvb_country_availability = 0x49, + dtag_dvb_linkage = 0x4a, + dtag_dvb_nvod_reference = 0x4b, + dtag_dvb_time_shifted_service = 0x4c, + dtag_dvb_short_event = 0x4d, + dtag_dvb_extended_event = 0x4e, + dtag_dvb_time_shifted_event = 0x4f, + dtag_dvb_component = 0x50, + dtag_dvb_mosaic = 0x51, + dtag_dvb_stream_identifier = 0x52, + dtag_dvb_ca_identifier = 0x53, + dtag_dvb_content = 0x54, + dtag_dvb_parental_rating = 0x55, + dtag_dvb_teletext = 0x56, + dtag_dvb_telephone = 0x57, + dtag_dvb_local_time_offset = 0x58, + dtag_dvb_subtitling = 0x59, + dtag_dvb_terrestial_delivery_system = 0x5a, + dtag_dvb_multilingual_network_name = 0x5b, + dtag_dvb_multilingual_bouquet_name = 0x5c, + dtag_dvb_multilingual_service_name = 0x5d, + dtag_dvb_multilingual_component = 0x5e, + dtag_dvb_private_data_specifier = 0x5f, + dtag_dvb_service_move = 0x60, + dtag_dvb_short_smoothing_buffer = 0x61, + dtag_dvb_frequency_list = 0x62, + dtag_dvb_partial_transport_stream = 0x63, + dtag_dvb_data_broadcast = 0x64, + dtag_dvb_scrambling = 0x65, + dtag_dvb_data_broadcast_id = 0x66, + dtag_dvb_transport_stream = 0x67, + dtag_dvb_dsng = 0x68, + dtag_dvb_pdc = 0x69, + dtag_dvb_ac3 = 0x6a, + dtag_dvb_ancillary_data = 0x6b, + dtag_dvb_cell_list = 0x6c, + dtag_dvb_cell_frequency_link = 0x6d, + dtag_dvb_announcement_support = 0x6e, + dtag_dvb_application_signalling = 0x6f, + dtag_dvb_adaptation_field_data = 0x70, + dtag_dvb_service_identifier = 0x71, + dtag_dvb_service_availability = 0x72, + dtag_dvb_default_authority = 0x73, + dtag_dvb_related_content = 0x74, + dtag_dvb_tva_id = 0x75, + dtag_dvb_content_identifier = 0x76, + dtag_dvb_time_slice_fec_identifier = 0x77, + dtag_dvb_ecm_repetition_rate = 0x78, + dtag_dvb_s2_satellite_delivery_descriptor= 0x79, + + /* descriptors which may only appear in an RNT */ + dtag_dvb_rnt_rar_over_dvb_stream = 0x40, + dtag_dvb_rnt_rar_over_ip = 0x41, + dtag_dvb_rnt_rnt_scan = 0x42, + + /* descriptors which may only appear in an AIT */ + dtag_dvb_ait_application = 0x00, + dtag_dvb_ait_application_name = 0x01, + dtag_dvb_ait_transport_protocol = 0x02, + dtag_dvb_ait_dvb_j_application = 0x03, + dtag_dvb_ait_dvb_j_application_location = 0x04, + dtag_dvb_ait_external_application_authorisation = 0x05, + dtag_dvb_ait_dvb_html_application = 0x08, + dtag_dvb_ait_dvb_html_application_location = 0x09, + dtab_dvb_ait_dvb_html_application_boundary = 0x0a, + dtag_dvb_ait_application_icons = 0x0b, + dtag_dvb_ait_prefetch = 0x0c, + dtag_dvb_ait_dii_location = 0x0d, + dtag_dvb_ait_ip_signalling = 0x11 +};/*__ucsi_packed;*/ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/dit_section.c b/kaffeine/src/input/dvb/lib/libucsi/dvb/dit_section.c new file mode 100644 index 0000000..4f69d4e --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/dit_section.c @@ -0,0 +1,32 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include <libucsi/dvb/dit_section.h> + +struct dvb_dit_section * dvb_dit_section_codec(struct section * section) +{ + struct dvb_dit_section * ret = (struct dvb_dit_section *)section; + + if (section->length < 1) + return NULL; + + return ret; +} diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/dit_section.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/dit_section.h new file mode 100644 index 0000000..69fce4f --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/dit_section.h @@ -0,0 +1,54 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_DVB_DIT_SECTION_H +#define _UCSI_DVB_DIT_SECTION_H 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/section.h> + +/** + * dvb_dit_section structure. + */ +struct dvb_dit_section { + struct section head; + + EBIT2(uint8_t transition_flag : 1; , + uint8_t reserved : 7; ); +}; + +/** + * Process a dvb_dit_section. + * + * @param section Pointer to a generic section header. + * @return Pointer to a dvb_dit_section, or NULL on error. + */ +struct dvb_dit_section * dvb_dit_section_codec(struct section *section); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/dsng_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/dsng_descriptor.h new file mode 100644 index 0000000..6fd369b --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/dsng_descriptor.h @@ -0,0 +1,80 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_DVB_DSNG_DESCRIPTOR +#define _UCSI_DVB_DSNG_DESCRIPTOR 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/descriptor.h> +#include <libucsi/endianops.h> + +/** + * dvb_dsng_descriptor structure. + */ +struct dvb_dsng_descriptor { + struct descriptor d; + + /* uint8_t data[] */ +} __ucsi_packed; + +/** + * Process a dvb_dsng_descriptor. + * + * @param d Generic descriptor structure. + * @return Pointer to a dvb_dsng_descriptor, or NULL on error. + */ +static inline struct dvb_dsng_descriptor* + dvb_dsng_descriptor_codec(struct descriptor* d) +{ + return (struct dvb_dsng_descriptor*) d; +} + +/** + * Accessor for the data field in a dvb_dsng_descriptor. + * + * @param d dvb_dsng_descriptor pointer. + * @return Pointer to the field. + */ +static inline uint8_t *dvb_dsng_descriptor_data(struct dvb_dsng_descriptor *d) +{ + return (uint8_t *) d + sizeof(struct dvb_dsng_descriptor); +} + +/** + * Determine the length of the data field in a dvb_dsng_descriptor. + * + * @param d dvb_dsng_descriptor pointer. + * @return Length of the field in bytes. + */ +static inline int dvb_dsng_descriptor_data_length(struct dvb_dsng_descriptor *d) +{ + return d->d.len; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/eit_section.c b/kaffeine/src/input/dvb/lib/libucsi/dvb/eit_section.c new file mode 100644 index 0000000..ce22a58 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/eit_section.c @@ -0,0 +1,63 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include <libucsi/dvb/eit_section.h> + +struct dvb_eit_section *dvb_eit_section_codec(struct section_ext * ext) +{ + uint8_t * buf = (uint8_t *) ext; + unsigned int pos = sizeof(struct section_ext); + unsigned int len = section_ext_length(ext); + + if (len < sizeof(struct dvb_eit_section)) + return NULL; + + bswap16(buf + pos); + pos += 2; + bswap16(buf + pos); + pos += 4; + + while (pos < len) { + struct dvb_eit_event * event = + (struct dvb_eit_event *) (buf + pos); + + if ((pos + sizeof(struct dvb_eit_event)) > len) + return NULL; + + bswap16(buf + pos); + bswap16(buf + pos + 10); + + pos += sizeof(struct dvb_eit_event); + + if ((pos + event->descriptors_loop_length) > len) + return NULL; + + if (verify_descriptors(buf + pos, event->descriptors_loop_length)) + return NULL; + + pos += event->descriptors_loop_length; + } + + if (pos != len) + return NULL; + + return (struct dvb_eit_section *) ext; +} diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/eit_section.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/eit_section.h new file mode 100644 index 0000000..9064224 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/eit_section.h @@ -0,0 +1,160 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_DVB_EIT_SECTION_H +#define _UCSI_DVB_EIT_SECTION_H 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/section.h> +#include <libucsi/dvb/types.h> + + +/** + * dvb_eit_section structure. + */ +struct dvb_eit_section { + struct section_ext head; + + uint16_t transport_stream_id; + uint16_t original_network_id; + uint8_t segment_last_section_number; + uint8_t last_table_id; + /* struct eit_event events[] */ +} __ucsi_packed; + +/** + * An entry in the events field of a dvb_eit_section. + */ +struct dvb_eit_event { + uint16_t event_id; + dvbdate_t start_time; + dvbduration_t duration; + EBIT3(uint16_t running_status : 3; , + uint16_t free_ca_mode : 1; , + uint16_t descriptors_loop_length:12; ); + /* struct descriptor descriptors[] */ +} __ucsi_packed; + +/** + * Process a dvb_eit_section. + * + * @param section Pointer to a generic section_ext structure. + * @return Pointer to a dvb_eit_section, or NULL on error. + */ +struct dvb_eit_section *dvb_eit_section_codec(struct section_ext *section); + +/** + * Accessor for the service_id field of an EIT. + * + * @param eit EIT pointer. + * @return The service_id. + */ +static inline uint16_t dvb_eit_section_service_id(struct dvb_eit_section *eit) +{ + return eit->head.table_id_ext; +} + +/** + * Iterator for the events field of a dvb_eit_section. + * + * @param eit dvb_eit_section pointer. + * @param pos Variable containing a pointer to the current dvb_eit_event. + */ +#define dvb_eit_section_events_for_each(eit, pos) \ + for ((pos) = dvb_eit_section_events_first(eit); \ + (pos); \ + (pos) = dvb_eit_section_events_next(eit, pos)) + +/** + * Iterator for the descriptors field of a dvb_eit_event. + * + * @param eit dvb_eit_event pointer. + * @param pos Variable containing a pointer to the current descriptor. + */ +#define dvb_eit_event_descriptors_for_each(event, pos) \ + for ((pos) = dvb_eit_event_descriptors_first(event); \ + (pos); \ + (pos) = dvb_eit_event_descriptors_next(event, pos)) + + + + + + + + + + +/******************************** PRIVATE CODE ********************************/ +static inline struct dvb_eit_event * + dvb_eit_section_events_first(struct dvb_eit_section *eit) +{ + int pos = sizeof(struct dvb_eit_section); + + if (pos >= section_ext_length(&eit->head)) + return NULL; + + return (struct dvb_eit_event*) ((uint8_t *) eit + pos); +} + +static inline struct dvb_eit_event * + dvb_eit_section_events_next(struct dvb_eit_section *eit, + struct dvb_eit_event *pos) +{ + uint8_t *end = (uint8_t*) eit + section_ext_length(&eit->head); + uint8_t *next = (uint8_t *) pos + + sizeof(struct dvb_eit_event) + + pos->descriptors_loop_length; + + if (next >= end) + return NULL; + + return (struct dvb_eit_event *) next; +} + +static inline struct descriptor * + dvb_eit_event_descriptors_first(struct dvb_eit_event * t) +{ + if (t->descriptors_loop_length == 0) + return NULL; + + return (struct descriptor *) + ((uint8_t *) t + sizeof(struct dvb_eit_event)); +} + +static inline struct descriptor * + dvb_eit_event_descriptors_next(struct dvb_eit_event * t, + struct descriptor* pos) +{ + return next_descriptor((uint8_t*) t + sizeof(struct dvb_eit_event), + t->descriptors_loop_length, + pos); +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/extended_event_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/extended_event_descriptor.h new file mode 100644 index 0000000..82d580b --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/extended_event_descriptor.h @@ -0,0 +1,232 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_DVB_EXTENDED_EVENT_DESCRIPTOR +#define _UCSI_DVB_EXTENDED_EVENT_DESCRIPTOR 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/descriptor.h> +#include <libucsi/endianops.h> +#include <libucsi/types.h> + +/** + * dvb_extended_event_descriptor structure. + */ +struct dvb_extended_event_descriptor { + struct descriptor d; + + EBIT2(uint8_t descriptor_number : 4; , + uint8_t last_descriptor_number : 4; ) + iso639lang_t language_code; + uint8_t length_of_items; + /* struct dvb_extended_event_item items[] */ + /* struct dvb_extended_event_descriptor_part2 part2 */ +} __ucsi_packed; + +/** + * An entry in the items field of a dvb_extended_event_descriptor. + */ +struct dvb_extended_event_item { + uint8_t item_description_length; + /* uint8_t item_description[] */ + /* struct dvb_extended_event_item_part2 part2 */ +} __ucsi_packed; + +/** + * The second part of a dvb_extended_event_item, following the variable length + * description field. + */ +struct dvb_extended_event_item_part2 { + uint8_t item_length; + /* uint8_t item[] */ +} __ucsi_packed; + +/** + * The second part of a dvb_extended_event_descriptor, following the variable + * length items field. + */ +struct dvb_extended_event_descriptor_part2 { + uint8_t text_length; + /* uint8_t text[] */ +} __ucsi_packed; + +/** + * Process a dvb_extended_event_descriptor. + * + * @param d Generic descriptor structure. + * @return dvb_extended_event_descriptor pointer, or NULL on error. + */ +static inline struct dvb_extended_event_descriptor* + dvb_extended_event_descriptor_codec(struct descriptor* d) +{ + uint8_t* buf = (uint8_t*) d + 2; + uint32_t pos = 0; + uint32_t len = d->len; + struct dvb_extended_event_descriptor * p = + (struct dvb_extended_event_descriptor *) d; + struct dvb_extended_event_descriptor_part2 *p2; + + pos += sizeof(struct dvb_extended_event_descriptor) - 2; + + if (pos > len) + return NULL; + + pos += p->length_of_items; + + if (pos > len) + return NULL; + + p2 = (struct dvb_extended_event_descriptor_part2*) (buf+pos); + + pos += sizeof(struct dvb_extended_event_descriptor_part2); + + if (pos > len) + return NULL; + + pos += p2->text_length; + + if (pos != len) + return NULL; + + return p; +} + +/** + * Iterator for the items field of a dvb_extended_event_descriptor. + * + * @param d dvb_extended_event_descriptor pointer. + * @param pos Variable containing a pointer to the current dvb_extended_event_item. + */ +#define dvb_extended_event_descriptor_items_for_each(d, pos) \ + for ((pos) = dvb_extended_event_descriptor_items_first(d); \ + (pos); \ + (pos) = dvb_extended_event_descriptor_items_next(d, pos)) + +/** + * Accessor for the description field of a dvb_extended_event_item. + * + * @param d dvb_extended_event_item pointer. + * @return Pointer to the field. + */ +static inline uint8_t* + dvb_extended_event_item_description(struct dvb_extended_event_item *d) +{ + return (uint8_t*) d + sizeof(struct dvb_extended_event_item); +} + +/** + * Accessor for the second part of a dvb_extended_event_item. + * + * @param dvb_extended_event_item pointer. + * @return dvb_extended_event_item_part2 pointer. + */ +static inline struct dvb_extended_event_item_part2* + dvb_extended_event_item_part2(struct dvb_extended_event_item *d) +{ + return (struct dvb_extended_event_item_part2*) + ((uint8_t*) d + sizeof(struct dvb_extended_event_item) + + d->item_description_length); +} + +/** + * Accessor for the item field of a dvb_extended_event_item_part2. + * + * @param d dvb_extended_event_item_part2 pointer. + * @return Pointer to the item field. + */ +static inline uint8_t* + dvb_extended_event_item_part2_item(struct dvb_extended_event_item_part2 *d) +{ + return (uint8_t*) d + sizeof(struct dvb_extended_event_item_part2); +} + +/** + * Accessor for the second part of a dvb_extended_event_descriptor. + * + * @param d dvb_extended_event_descriptor pointer. + * @return dvb_extended_event_descriptor_part2 pointer. + */ +static inline struct dvb_extended_event_descriptor_part2* + dvb_extended_event_descriptor_part2(struct dvb_extended_event_descriptor *d) +{ + return (struct dvb_extended_event_descriptor_part2*) + ((uint8_t*) d + sizeof(struct dvb_extended_event_descriptor) + + d->length_of_items); +} + +/** + * Accessor for the text field of an dvb_extended_event_descriptor_part2. + * + * @param d dvb_extended_event_descriptor_part2 pointer. + * @return Pointer to the text field. + */ +static inline uint8_t* + dvb_extended_event_descriptor_part2_text(struct dvb_extended_event_descriptor_part2 *d) +{ + return (uint8_t*) + ((uint8_t*) d + sizeof(struct dvb_extended_event_descriptor_part2)); +} + + + + + + + + + +/******************************** PRIVATE CODE ********************************/ +static inline struct dvb_extended_event_item* + dvb_extended_event_descriptor_items_first(struct dvb_extended_event_descriptor *d) +{ + if (d->length_of_items == 0) + return NULL; + + return (struct dvb_extended_event_item *) + ((uint8_t*) d + sizeof(struct dvb_extended_event_descriptor)); +} + +static inline struct dvb_extended_event_item* + dvb_extended_event_descriptor_items_next(struct dvb_extended_event_descriptor *d, + struct dvb_extended_event_item *pos) +{ + struct dvb_extended_event_item_part2* part2 = + dvb_extended_event_item_part2(pos); + uint8_t *end = (uint8_t*) d + sizeof(struct dvb_extended_event_descriptor) + d->length_of_items; + uint8_t *next = (uint8_t *) part2 + + sizeof(struct dvb_extended_event_item_part2) + + part2->item_length; + + if (next >= end) + return NULL; + + return (struct dvb_extended_event_item *) next; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/frequency_list_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/frequency_list_descriptor.h new file mode 100644 index 0000000..4fca751 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/frequency_list_descriptor.h @@ -0,0 +1,107 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_DVB_FREQUENCY_LIST_DESCRIPTOR +#define _UCSI_DVB_FREQUENCY_LIST_DESCRIPTOR 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/descriptor.h> +#include <libucsi/endianops.h> + +/** + * Possible values for coding_type. + */ +enum { + DVB_CODING_TYPE_SATELLITE = 0x01, + DVB_CODING_TYPE_CABLE = 0x02, + DVB_CODING_TYPE_TERRESTRIAL = 0x03 +}; + +/** + * dvb_frequency_list_descriptor structure. + */ +struct dvb_frequency_list_descriptor { + struct descriptor d; + + EBIT2(uint8_t reserved : 6; , + uint8_t coding_type : 2; ) + /* uint32_t centre_frequencies [] */ +} __ucsi_packed; + +/** + * Process a dvb_frequency_list_descriptor. + * + * @param d Pointer to a generic descriptor structure. + * @return dvb_frequency_list_descriptor pointer, or NULL on error. + */ +static inline struct dvb_frequency_list_descriptor* + dvb_frequency_list_descriptor_codec(struct descriptor* d) +{ + uint32_t pos = 0; + uint8_t* buf = (uint8_t*) d + 2; + uint32_t len = d->len; + + pos += sizeof(struct dvb_frequency_list_descriptor) - 2; + + if ((len - pos) % 4) + return NULL; + + while(pos < len) { + bswap32(buf+pos); + pos += 4; + } + + return (struct dvb_frequency_list_descriptor*) d; +} + +/** + * Accessor for the centre_frequencies field of a dvb_frequency_list_descriptor. + * + * @param d dvb_frequency_list_descriptor pointer. + * @return Pointer to the field. + */ +static inline uint32_t * + dvb_frequency_list_descriptor_centre_frequencies(struct dvb_frequency_list_descriptor *d) +{ + return (uint32_t *) ((uint8_t *) d + sizeof(struct dvb_frequency_list_descriptor)); +} + +/** + * Determine the number of entries in the centre_frequencies field of a dvb_frequency_list_descriptor. + * + * @param d dvb_frequency_list_descriptor pointer. + * @return The number of entries. + */ +static inline int + dvb_frequency_list_descriptor_centre_frequencies_count(struct dvb_frequency_list_descriptor *d) +{ + return (d->d.len - 1) >> 2; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/int_section.c b/kaffeine/src/input/dvb/lib/libucsi/dvb/int_section.c new file mode 100644 index 0000000..a6ddd6e --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/int_section.c @@ -0,0 +1,80 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * Copyright (C) 2005 Patrick Boettcher (pb@linuxtv.org) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include <libucsi/dvb/int_section.h> + +struct dvb_int_section * dvb_int_section_codec(struct section_ext *ext) +{ + uint8_t *buf = (uint8_t *) ext; + struct dvb_int_section *in = (struct dvb_int_section *) ext; + + unsigned int pos = sizeof(struct section_ext); + unsigned int len = section_ext_length(ext); + + if (len < sizeof(struct dvb_int_section)) + return NULL; + + bswap32(buf+8); + bswap16(buf+12); + pos += 9; + + if (len - pos < in->platform_descriptors_length) + return NULL; + + if (verify_descriptors(buf + pos, in->platform_descriptors_length)) + return NULL; + + pos += in->platform_descriptors_length; + + while (pos < len) { + struct dvb_int_target *s2 = (struct dvb_int_target *) (buf + pos); + struct dvb_int_operational_loop *s3; + + bswap16(buf + pos); /* target_descriptor_loop_length swap */ + + if (len - pos < s2->target_descriptors_length) + return NULL; + + pos += sizeof(struct dvb_int_target); + + if (verify_descriptors(buf + pos, s2->target_descriptors_length)) + return NULL; + + pos += s2->target_descriptors_length; + + s3 = (struct dvb_int_operational_loop *) (buf + pos); + + bswap16(buf + pos); /* operational_descriptor_loop_length swap */ + + if (len - pos < s3->operational_descriptors_length) + return NULL; + + pos += sizeof(struct dvb_int_operational_loop); + + if (verify_descriptors(buf + pos, s3->operational_descriptors_length)) + return NULL; + + pos += s3->operational_descriptors_length; + } + + return (struct dvb_int_section *) ext; +} diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/int_section.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/int_section.h new file mode 100644 index 0000000..71ba1e8 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/int_section.h @@ -0,0 +1,245 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * Copyright (C) 2005 Patrick Boettcher (pb@linuxtv.org) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ +#ifndef _UCSI_DVB_INT_SECTION_H +#define _UCSI_DVB_INT_SECTION_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/section.h> + +/** + * dvb_int_section structure - IP/MAC notification section. + */ +struct dvb_int_section { + struct section_ext head; + + EBIT2(uint32_t platform_id :24; , + uint32_t processing_order : 8; ); + EBIT2(uint16_t reserved2 : 4; , + uint16_t platform_descriptors_length :12; ); + /* struct descriptor platform_descriptors[] */ + /* struct dvb_int_target target_loop[] */ +} __ucsi_packed; + +/** + * An entry in the target_loop field of a dvb_int_section. + */ +struct dvb_int_target { + EBIT2(uint16_t reserved3 : 4; , + uint16_t target_descriptors_length :12; ); + /* struct descriptor target_descriptors[] */ + /* struct dvb_int_operational_loop operational_loop */ +} __ucsi_packed; + +/** + * The operational_loop field in a dvb_int_target. + */ +struct dvb_int_operational_loop { + EBIT2(uint16_t reserved4 : 4; , + uint16_t operational_descriptors_length :12; ); + /* struct descriptor operational_descriptors[] */ +} __ucsi_packed; + +/** + * Process a dvb_int_section. + * + * @param section Generic section_ext pointer. + * @return dvb_int_section pointer, or NULL on error. + */ +extern struct dvb_int_section * dvb_int_section_codec(struct section_ext *section); + +/** + * Accessor for the action_type field of an INT. + * + * @param intp INT pointer. + * @return The action_type. + */ +static inline uint8_t dvb_int_section_action_type(struct dvb_int_section *intp) +{ + return intp->head.table_id_ext >> 8; +} + +/** + * Accessor for the platform_id_hash field of an INT. + * + * @param intp INT pointer. + * @return The platform_id_hash. + */ +static inline uint8_t dvb_int_section_platform_id_hash(struct dvb_int_section *intp) +{ + return intp->head.table_id_ext & 0xff; +} + +/** + * Iterator for platform_descriptors field in a dvb_int_section. + * + * @param intp dvb_int_section pointer. + * @param pos Variable holding a pointer to the current descriptor. + */ +#define dvb_int_section_platform_descriptors_for_each(intp, pos) \ + for ((pos) = dvb_int_section_platform_descriptors_first(intp); \ + (pos); \ + (pos) = dvb_int_section_platform_descriptors_next(intp, pos)) + +/** + * Iterator for the target_loop field in a dvb_int_section. + * + * @param intp dvb_int_section pointer. + * @param pos Variable holding a pointer to the current dvb_int_target. + */ +#define dvb_int_section_target_loop_for_each(intp,pos) \ + for ((pos) = dvb_int_section_target_loop_first(intp); \ + (pos); \ + (pos) = dvb_int_section_target_loop_next(intp, pos)) + +/** + * Iterator for the target_descriptors field in a dvb_int_target. + * + * @param target dvb_int_target pointer. + * @param pos Variable holding a pointer to the current descriptor. + */ +#define dvb_int_target_target_descriptors_for_each(target, pos) \ + for ((pos) = dvb_int_target_target_descriptors_first(target); \ + (pos); \ + (pos) = dvb_int_target_target_descriptors_next(target, pos)) + +/** + * Accessor for the operational_loop field of a dvb_int_target. + * + * @param target dvb_int_target pointer. + * @return Pointer to a dvb_int_operational_loop. + */ +static inline struct dvb_int_operational_loop * + dvb_int_target_operational_loop(struct dvb_int_target *target) +{ + return (struct dvb_int_operational_loop *) + ((uint8_t *) target + sizeof(struct dvb_int_target) + target->target_descriptors_length); +} + +/** + * Iterator for the operational_descriptors field in a dvb_int_operational_loop. + * + * @param oploop dvb_int_operational_loop pointer. + * @param pos Variable holding a pointer to the current descriptor. + */ +#define dvb_int_operational_loop_operational_descriptors_for_each(oploop, pos) \ + for ((pos) = dvb_int_operational_loop_operational_descriptors_first(oploop); \ + (pos); \ + (pos) = dvb_int_operational_loop_operational_descriptors_next(oploop, pos)) + + + + + +/******************************** PRIVATE CODE ********************************/ +static inline struct descriptor * + dvb_int_section_platform_descriptors_first(struct dvb_int_section *in) +{ + if (in->platform_descriptors_length == 0) + return NULL; + + return (struct descriptor *) + ((uint8_t *) in + sizeof(struct dvb_int_section)); +} + +static inline struct descriptor * + dvb_int_section_platform_descriptors_next(struct dvb_int_section *in, + struct descriptor* pos) +{ + return next_descriptor((uint8_t*) in + sizeof(struct dvb_int_section), + in->platform_descriptors_length, + pos); +} + +static inline struct dvb_int_target * + dvb_int_section_target_loop_first(struct dvb_int_section *in) +{ + if (sizeof(struct dvb_int_section) + in->platform_descriptors_length >= (uint32_t) section_ext_length((struct section_ext *) in)) + return NULL; + + return (struct dvb_int_target *) + ((uint8_t *) in + sizeof(struct dvb_int_section) + in->platform_descriptors_length); +} + +static inline struct dvb_int_target * + dvb_int_section_target_loop_next(struct dvb_int_section *in, + struct dvb_int_target *pos) +{ + struct dvb_int_operational_loop *ol = dvb_int_target_operational_loop(pos); + struct dvb_int_target *next = + (struct dvb_int_target *) ( (uint8_t *) pos + + sizeof(struct dvb_int_target) + pos->target_descriptors_length + + sizeof(struct dvb_int_operational_loop) + ol->operational_descriptors_length); + struct dvb_int_target *end = + (struct dvb_int_target *) ((uint8_t *) in + section_ext_length((struct section_ext *) in) ); + + if (next >= end) + return 0; + return next; +} + +static inline struct descriptor * + dvb_int_target_target_descriptors_first(struct dvb_int_target *tl) +{ + if (tl->target_descriptors_length == 0) + return NULL; + + return (struct descriptor *) + ((uint8_t *) tl + sizeof(struct dvb_int_target)); +} + +static inline struct descriptor * + dvb_int_target_target_descriptors_next(struct dvb_int_target *tl, + struct descriptor* pos) +{ + return next_descriptor((uint8_t*) tl + sizeof(struct dvb_int_target), + tl->target_descriptors_length, + pos); +} + +static inline struct descriptor * + dvb_int_operational_loop_operational_descriptors_first(struct dvb_int_operational_loop *ol) +{ + if (ol->operational_descriptors_length == 0) + return NULL; + + return (struct descriptor *) + ((uint8_t *) ol + sizeof(struct dvb_int_operational_loop)); +} + +static inline struct descriptor * + dvb_int_operational_loop_operational_descriptors_next(struct dvb_int_operational_loop *ol, + struct descriptor* pos) +{ + return next_descriptor((uint8_t*) ol + sizeof(struct dvb_int_operational_loop), + ol->operational_descriptors_length, + pos); +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/linkage_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/linkage_descriptor.h new file mode 100644 index 0000000..f3370c8 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/linkage_descriptor.h @@ -0,0 +1,478 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_DVB_LINKAGE_DESCRIPTOR +#define _UCSI_DVB_LINKAGE_DESCRIPTOR 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/descriptor.h> +#include <libucsi/endianops.h> +#include <libucsi/types.h> + +/** + * Possible values for linkage_type. + */ +enum { + DVB_LINKAGE_TYPE_INFORMATION = 0x01, + DVB_LINKAGE_TYPE_EPG = 0x02, + DVB_LINKAGE_TYPE_CA_REPLACEMENT = 0x03, + DVB_LINKAGE_TYPE_TS_WITH_BAT_NIT = 0x04, + DVB_LINKAGE_TYPE_SERVICE_REPLACMENT = 0x05, + DVB_LINKAGE_TYPE_DATA_BCAST = 0x06, + DVB_LINKAGE_TYPE_RCS_MAP = 0x07, + DVB_LINKAGE_TYPE_MOBILE_HANDOVER = 0x08, + DVB_LINKAGE_TYPE_SOFTWARE_UPDATE = 0x09, + DVB_LINKAGE_TYPE_TS_WITH_SSU_BAT_NIT = 0x0a, + DVB_LINKAGE_TYPE_IP_MAC_NOTIFICATION = 0x0b, + DVB_LINKAGE_TYPE_TS_WITH_INT_BAT_NIT = 0x0c +}; + +/** + * Possible values for hand_over_type. + */ +enum { + DVB_HAND_OVER_TYPE_IDENTICAL_NEIGHBOURING_COUNTRY = 0x01, + DVB_HAND_OVER_TYPE_LOCAL_VARIATION = 0x02, + DVB_HAND_OVER_TYPE_ASSOCIATED_SERVICE = 0x03 +}; + +/** + * Possible values for origin_type. + */ +enum { + DVB_ORIGIN_TYPE_NIT = 0x00, + DVB_ORIGIN_TYPE_SDT = 0x01 +}; + +/** + * dvb_linkage_descriptor structure. + */ +struct dvb_linkage_descriptor { + struct descriptor d; + + uint16_t transport_stream_id; + uint16_t original_network_id; + uint16_t service_id; + uint8_t linkage_type; + /* uint8_t data[] */ +} __ucsi_packed; + +/** + * Data for a linkage_type of 0x08. + */ +struct dvb_linkage_data_08 { + EBIT3(uint8_t hand_over_type : 4; , + uint8_t reserved : 3; , + uint8_t origin_type : 1; ) + /* uint16_t network_id if hand_over_type == 1,2,3 */ + /* uint16_t initial_service_id if origin_type = 0 */ + /* uint8_t data[] */ +} __ucsi_packed; + +/** + * Data for an linkage_type of 0x0b (IP/MAC Notification Table). + */ +struct dvb_linkage_data_0b { + uint8_t platform_id_data_length; + /* struct platform_id ids[] */ +} __ucsi_packed; + +/** + * Entries in the ids field of a dvb_linkage_data_0b. + */ +struct dvb_platform_id { + EBIT2(uint32_t platform_id : 24; , + uint32_t platform_name_loop_length : 8; ) + /* struct platform_name names[] */ +} __ucsi_packed; + +/** + * Entries in the names field of a dvb_platform_id. + */ +struct dvb_platform_name { + iso639lang_t language_code; + uint8_t platform_name_length; + /* uint8_t text[] */ +} __ucsi_packed; + +/** + * Data for a linkage_type of 0x0c (IP/MAC Notification Table). + */ +struct dvb_linkage_data_0c { + uint8_t table_type; + /* uint16_t bouquet_id if table_type == 0x02 */ +} __ucsi_packed; + + +/** + * Process a dvb_linkage_descriptor. + * + * @param d Generic descriptor pointer. + * @return dvb_linkage_descriptor pointer, or NULL on error. + */ +static inline struct dvb_linkage_descriptor* + dvb_linkage_descriptor_codec(struct descriptor* d) +{ + uint32_t pos = 0; + uint8_t* buf = (uint8_t*) d + 2; + uint32_t len = d->len; + struct dvb_linkage_descriptor *p = + (struct dvb_linkage_descriptor*) d; + + if (len < (sizeof(struct dvb_linkage_descriptor) - 2)) + return NULL; + + bswap16(buf); + bswap16(buf+2); + bswap16(buf+4); + + pos += sizeof(struct dvb_linkage_descriptor) - 2; + + if (p->linkage_type == 0x08) { + struct dvb_linkage_data_08 *d08; + + if ((len - pos) < sizeof(struct dvb_linkage_data_08)) + return NULL; + d08 = (struct dvb_linkage_data_08 *) (buf+pos); + pos += sizeof(struct dvb_linkage_data_08); + + switch(d08->hand_over_type) { + case 1: + case 2: + case 3: + if ((len - pos) < 2) + return NULL; + bswap16(buf+pos); + pos += 2; + break; + } + if (d08->origin_type == 0) { + if ((len - pos) < 2) + return NULL; + bswap16(buf+pos); + pos+=2; + } + + } else if (p->linkage_type == 0x0b) { + uint32_t pos2=0; + struct dvb_linkage_data_0b *l_0b = (struct dvb_linkage_data_0b *) (buf + pos); + + if ((len - pos) < sizeof(struct dvb_linkage_data_0b)) + return NULL; + + pos += sizeof(struct dvb_linkage_data_0b); + if ((len - pos) < l_0b->platform_id_data_length) + return NULL; + + while (pos2 < l_0b->platform_id_data_length) { + struct dvb_platform_id *p_id = (struct dvb_platform_id *) (buf + pos + pos2); + if ((len - pos - pos2) < p_id->platform_name_loop_length) + return NULL; + + pos2 += sizeof(struct dvb_platform_id) + p_id->platform_name_loop_length; + } + + pos += pos2; + } else if (p->linkage_type == 0x0c) { + struct dvb_linkage_data_0c *l_0c = (struct dvb_linkage_data_0c *) (buf + pos); + + if ((len - pos) < sizeof(struct dvb_linkage_data_0c)) + return NULL; + pos += sizeof(struct dvb_linkage_data_0c); + + if (l_0c->table_type == 0x02) { + if ((len - pos) < 2) + return NULL; + bswap16(buf+pos); + } + } + + return (struct dvb_linkage_descriptor*) d; +} + +/** + * Accessor for the data field of a dvb_linkage_descriptor. + * + * @param d dvb_linkage_descriptor pointer. + * @return Pointer to the data field. + */ +static inline uint8_t * + dvb_linkage_descriptor_data(struct dvb_linkage_descriptor *d) +{ + return (uint8_t *) d + sizeof(struct dvb_linkage_descriptor); +} + +/** + * Determine the length of the data field of a dvb_linkage_descriptor. + * + * @param d dvb_linkage_descriptor pointer. + * @return Length of the field in bytes. + */ +static inline int + dvb_linkage_descriptor_data_length(struct dvb_linkage_descriptor *d) +{ + return d->d.len - 7; +} + +/** + * Accessor for a dvb_linkage_data_08 pointer. + * + * @param d dvb_linkage_descriptor pointer. + * @return Pointer to the data field. + */ +static inline struct dvb_linkage_data_08 * + dvb_linkage_data_08(struct dvb_linkage_descriptor *d) +{ + if (d->linkage_type != 0x08) + return NULL; + return (struct dvb_linkage_data_08 *) dvb_linkage_descriptor_data(d); +} + +/** + * Accessor for the network_id field of a dvb_linkage_data_08. + * + * @param d dvb_linkage_descriptor pointer + * @param d08 dvb_linkage_data_08 pointer. + * @return network_id, or -1 if not present + */ +static inline int + dvb_linkage_data_08_network_id(struct dvb_linkage_descriptor *d, struct dvb_linkage_data_08 *d08) +{ + if (d->linkage_type != 0x08) + return -1; + + switch(d08->hand_over_type) { + case 1: + case 2: + case 3: + return *((uint16_t*) ((uint8_t*) d08 + sizeof(struct dvb_linkage_data_08))); + } + + return -1; +} + +/** + * Accessor for the initial_service_id field of a dvb_linkage_data_08. + * + * @param d dvb_linkage_descriptor pointer + * @param d08 dvb_linkage_data_08 pointer. + * @return initial_service_id, or -1 if not present + */ +static inline int + dvb_linkage_data_08_initial_service_id(struct dvb_linkage_descriptor *d, struct dvb_linkage_data_08 *d08) +{ + uint8_t *pos; + + if (d->linkage_type != 0x08) + return -1; + if (d08->origin_type != 0) + return -1; + + pos = ((uint8_t*) d08) + sizeof(struct dvb_linkage_data_08); + switch(d08->hand_over_type) { + case 1: + case 2: + case 3: + pos +=2; + break; + } + + return *((uint16_t*) pos); +} + +/** + * Accessor for the data field of a dvb_linkage_data_08. + * + * @param d dvb_linkage_descriptor pointer + * @param d08 dvb_linkage_data_08 pointer. + * @param length Pointer to int destination for data length. + * @return Pointer to the data field, or NULL if invalid + */ +static inline uint8_t * + dvb_linkage_data_08_data(struct dvb_linkage_descriptor *d, struct dvb_linkage_data_08 *d08, int *length) +{ + uint8_t *pos; + int used = 0; + + if (d->linkage_type != 0x08) { + *length = 0; + return NULL; + } + + pos = ((uint8_t*) d08) + sizeof(struct dvb_linkage_data_08); + switch(d08->hand_over_type) { + case 1: + case 2: + case 3: + pos += 2; + used += 2; + break; + } + if (d08->origin_type == 0) { + pos+=2; + used+=2; + } + + *length = dvb_linkage_descriptor_data_length(d) - (sizeof(struct dvb_linkage_data_08) + used); + return pos; +} + +/** + * Accessor for a dvb_linkage_data_0b pointer. + * + * @param d dvb_linkage_descriptor pointer. + * @return Pointer to the data field. + */ +static inline struct dvb_linkage_data_0b * + dvb_linkage_data_0b(struct dvb_linkage_descriptor *d) +{ + if (d->linkage_type != 0x0b) + return NULL; + return (struct dvb_linkage_data_0b *) dvb_linkage_descriptor_data(d); +} + +/** + * Iterator for the platform_id field of a dvb_linkage_data_0b. + * + * @param linkage dvb_linkage_data_0b pointer. + * @param pos Variable containing a pointer to the current dvb_platform_id. + */ +#define dvb_dvb_linkage_data_0b_platform_id_for_each(linkage, pos) \ + for ((pos) = dvb_platform_id_first(linkage); \ + (pos); \ + (pos) = dvb_platform_id_next(linkage, pos)) + +/** + * Iterator for the platform_name field of a dvb_platform_id. + * + * @param platid dvb_platform_id pointer. + * @param pos Variable containing a pointer to the current dvb_platform_name. + */ +#define dvb_platform_id_platform_name_for_each(platid, pos) \ + for ((pos) = dvb_platform_name_first(platid); \ + (pos); \ + (pos) = dvb_platform_name_next(platid, pos)) + +/** + * Accessor for the text field of a dvb_platform_name. + * + * @param p dvb_platform_name pointer. + * @return Pointer to the field. + */ +static inline uint8_t * + dvb_platform_name_text(struct dvb_platform_name *p) +{ + return (uint8_t *) p + sizeof(struct dvb_platform_name); +} + +/** + * Accessor for a dvb_linkage_data_0c pointer. + * + * @param d dvb_linkage_descriptor pointer. + * @return Pointer to the data field. + */ +static inline struct dvb_linkage_data_0c * + dvb_linkage_data_0c(struct dvb_linkage_descriptor *d) +{ + if (d->linkage_type != 0x0c) + return NULL; + return (struct dvb_linkage_data_0c *) dvb_linkage_descriptor_data(d); +} + +/** + * Accessor for the bouquet_id field of a dvb_linkage_data_0c if table_id == 0x02. + * + * @param l_0c dvb_linkage_data_0c pointer. + * @return The bouquet field, or -1 on error. + */ +static inline int + dvb_linkage_data_0c_bouquet_id(struct dvb_linkage_data_0c *l_0c) +{ + if (l_0c->table_type != 0x02) + return -1; + + return *((uint16_t *) ((uint8_t*) l_0c + 1)); +} + + + + + + + +/******************************** PRIVATE CODE ********************************/ +static inline struct dvb_platform_id * + dvb_platform_id_first(struct dvb_linkage_data_0b *d) +{ + if (d->platform_id_data_length == 0) + return NULL; + + return (struct dvb_platform_id *) ((uint8_t *) d + sizeof(struct dvb_linkage_data_0b)); +} + +static inline struct dvb_platform_id * + dvb_platform_id_next(struct dvb_linkage_data_0b *d, + struct dvb_platform_id *pos) +{ + uint8_t *end = (uint8_t *) d + d->platform_id_data_length; + uint8_t *next = (uint8_t *) pos + + sizeof(struct dvb_platform_id) + + pos->platform_name_loop_length; + + if (next >= end) + return NULL; + + return (struct dvb_platform_id *) next; +} + +static inline struct dvb_platform_name * + dvb_platform_name_first(struct dvb_platform_id *p) +{ + if (p->platform_name_loop_length == 0) + return NULL; + + return (struct dvb_platform_name *) ((uint8_t *) p + sizeof(struct dvb_platform_id)); +} + +static inline struct dvb_platform_name * + dvb_platform_name_next(struct dvb_platform_id *p, + struct dvb_platform_name *pos) +{ + uint8_t *end = (uint8_t *) p + p->platform_name_loop_length; + uint8_t *next = (uint8_t *) pos + + sizeof(struct dvb_platform_name) + + pos->platform_name_length; + + if (next >= end) + return NULL; + + return (struct dvb_platform_name *) next; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/local_time_offset_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/local_time_offset_descriptor.h new file mode 100644 index 0000000..94932ff --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/local_time_offset_descriptor.h @@ -0,0 +1,127 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_DVB_LOCAL_TIME_OFFSET_DESCRIPTOR +#define _UCSI_DVB_LOCAL_TIME_OFFSET_DESCRIPTOR 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/descriptor.h> +#include <libucsi/endianops.h> +#include <libucsi/types.h> +#include <libucsi/dvb/types.h> + +/** + * dvb_local_time_offset_descriptor parameter. + */ +struct dvb_local_time_offset_descriptor { + struct descriptor d; + + /* struct dvb_local_time_offset offsets[] */ +} __ucsi_packed; + +/** + * Entry in the offsets field of dvb_local_time_offset_descriptor. + */ +struct dvb_local_time_offset { + iso639country_t country_code; + EBIT3(uint8_t country_region_id : 6; , + uint8_t reserved : 1; , + uint8_t local_time_offset_polarity : 1; ) + dvbhhmm_t local_time_offset; + dvbdate_t time_of_change; + dvbhhmm_t next_time_offset; +} __ucsi_packed; + +/** + * Process a dvb_local_time_offset_descriptor. + * + * @param d Generic descriptor pointer. + * @return dvb_local_time_offset_descriptor pointer, or NULL on error. + */ +static inline struct dvb_local_time_offset_descriptor* + dvb_local_time_offset_descriptor_codec(struct descriptor* d) +{ + uint32_t len = d->len; + uint32_t pos = 0; + + if (len % sizeof(struct dvb_local_time_offset)) + return NULL; + + while(pos < len) { + pos += sizeof(struct dvb_local_time_offset); + } + + return (struct dvb_local_time_offset_descriptor*) d; +} + +/** + * Iterator for the offsets field of a dvb_local_time_offset_descriptor. + * + * @param d dvb_local_time_offset_descriptor pointer. + * @param pos Variable containing a pointer to the current dvb_local_time_offset. + */ +#define dvb_local_time_offset_descriptor_offsets_for_each(d, pos) \ + for ((pos) = dvb_local_time_offset_descriptor_offsets_first(d); \ + (pos); \ + (pos) = dvb_local_time_offset_descriptor_offsets_next(d, pos)) + + + + + + + + + + +/******************************** PRIVATE CODE ********************************/ +static inline struct dvb_local_time_offset* + dvb_local_time_offset_descriptor_offsets_first(struct dvb_local_time_offset_descriptor *d) +{ + if (d->d.len == 0) + return NULL; + + return (struct dvb_local_time_offset *) + ((uint8_t*) d + sizeof(struct dvb_local_time_offset_descriptor)); +} + +static inline struct dvb_local_time_offset* + dvb_local_time_offset_descriptor_offsets_next(struct dvb_local_time_offset_descriptor *d, + struct dvb_local_time_offset *pos) +{ + uint8_t *end = (uint8_t*) d + 2 + d->d.len; + uint8_t *next = (uint8_t *) pos + sizeof(struct dvb_local_time_offset); + + if (next >= end) + return NULL; + + return (struct dvb_local_time_offset *) next; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/mhp_data_broadcast_id_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/mhp_data_broadcast_id_descriptor.h new file mode 100644 index 0000000..d5cf435 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/mhp_data_broadcast_id_descriptor.h @@ -0,0 +1,110 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_DVB_MHP_DATA_BROADCAST_ID_DESCRIPTOR +#define _UCSI_DVB_MHP_DATA_BROADCAST_ID_DESCRIPTOR 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#ifndef _UCSI_DVB_DATA_BROADCAST_ID_DESCRIPTOR +#error Must include dvb/data_broadcast_id_descriptor.h first +#endif + +/** + * Broadcast IDs for MHP. + */ +enum { + DVB_BROADCAST_ID_MHP_OBJECT_CAROUSEL = 0x00f0, + DVB_BROADCAST_ID_MHP_MPE = 0x00f1 +}; + +/** + * dvb_mhp_data_broadcast_id_descriptor structure. + */ +struct dvb_mhp_data_broadcast_id_descriptor { + struct dvb_data_broadcast_id_descriptor d; + /* uint16_t application_type[] */ +} __ucsi_packed; + +/** + * Process a dvb_mhp_data_broadcast_id_descriptor. + * + * @param d Generic descriptor structure. + * @return dvb_mhp_data_broadcast_id_descriptor pointer, or NULL on error. + */ +static inline struct dvb_mhp_data_broadcast_id_descriptor* + dvb_mhp_data_broadcast_id_descriptor_codec(struct dvb_data_broadcast_id_descriptor* d) +{ + uint8_t * buf; + int len; + int pos = 0; + struct dvb_mhp_data_broadcast_id_descriptor *res = + (struct dvb_mhp_data_broadcast_id_descriptor *) d; + + if ((res->d.data_broadcast_id < 0xf0) || (res->d.data_broadcast_id > 0xfe)) + return NULL; + + buf = dvb_data_broadcast_id_descriptor_id_selector_byte(d); + len = dvb_data_broadcast_id_descriptor_id_selector_byte_length(d); + + if (len % 2) + return NULL; + + while(pos < len) { + bswap16(buf+pos); + pos+=2; + } + + return res; +} + +/** + * Accessor for the application_type field of a dvb_mhp_data_broadcast_id_descriptor. + * + * @param d dvb_mhp_data_broadcast_id_descriptor pointer. + * @return Pointer to the field. + */ +static inline uint16_t * + dvb_mhp_data_broadcast_id_descriptor_id_application_type(struct dvb_mhp_data_broadcast_id_descriptor *d) +{ + return (uint16_t *) dvb_data_broadcast_id_descriptor_id_selector_byte((struct dvb_data_broadcast_id_descriptor*) d); +} + +/** + * Determine the number of entries in the application_type field of a dvb_mhp_data_broadcast_id_descriptor. + * + * @param d dvb_data_broadcast_id_descriptor pointer. + * @return Length of the field in bytes. + */ +static inline int + dvb_mhp_data_broadcast_id_descriptor_id_application_type_count(struct dvb_mhp_data_broadcast_id_descriptor *d) +{ + return dvb_data_broadcast_id_descriptor_id_selector_byte_length((struct dvb_data_broadcast_id_descriptor*) d) >> 1; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/mosaic_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/mosaic_descriptor.h new file mode 100644 index 0000000..28838de --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/mosaic_descriptor.h @@ -0,0 +1,324 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_DVB_MOSAIC_DESCRIPTOR +#define _UCSI_DVB_MOSAIC_DESCRIPTOR 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/descriptor.h> +#include <libucsi/endianops.h> + +/** + * dvb_mosaic_descriptor structure. + */ +struct dvb_mosaic_descriptor { + struct descriptor d; + + EBIT4(uint8_t mosaic_entry_point : 1; , + uint8_t number_of_horiz_elementary_cells: 3; , + uint8_t reserved : 1; , + uint8_t number_of_vert_elementary_cells : 3; ) + /* struct dvb_mosaic_info infos[] */ +} __ucsi_packed; + +/** + * An entry in the infos field of a dvb_mosaic_descriptor. + */ +struct dvb_mosaic_info { + EBIT3(uint16_t logical_cell_id : 6; , + uint16_t reserved : 7; , + uint16_t logical_cell_presentation_info : 3; ) + uint8_t elementary_cell_field_length; + /* struct dvb_mosaic_elementary_cell_field fields[] */ + /* struct dvb_mosaic_info_part2 part2 */ + /* struct dvb_mosaic_linkage linkage */ +} __ucsi_packed; + +/** + * An entry in the fields field of a dvb_mosaic_info. + */ +struct dvb_mosaic_elementary_cell_field { + EBIT2(uint8_t reserved : 2; , + uint8_t elementary_cell_id : 6; ) +} __ucsi_packed; + +/** + * Part2 of dvb_mosaic_info, following the variable length fields field. + */ +struct dvb_mosaic_info_part2 { + uint8_t cell_linkage_info; +} __ucsi_packed; + +struct dvb_mosaic_linkage_01 { + uint16_t bouquet_id; +} __ucsi_packed; + +struct dvb_mosaic_linkage_02 { + uint16_t original_network_id; + uint16_t transport_stream_id; + uint16_t service_id; +} __ucsi_packed; + +struct dvb_mosaic_linkage_03 { + uint16_t original_network_id; + uint16_t transport_stream_id; + uint16_t service_id; +} __ucsi_packed; + +struct dvb_mosaic_linkage_04 { + uint16_t original_network_id; + uint16_t transport_stream_id; + uint16_t service_id; + uint16_t event_id; +} __ucsi_packed; + +/** + * Structure describing the linkage field of a dvb_mosaic_info + */ +struct dvb_mosaic_linkage { + union { + struct dvb_mosaic_linkage_01 linkage_01; + struct dvb_mosaic_linkage_02 linkage_02; + struct dvb_mosaic_linkage_03 linkage_03; + struct dvb_mosaic_linkage_04 linkage_04; + } u; +} __ucsi_packed; + +/** + * Process a dvb_mosaic_descriptor. + * + * @param d Pointer to a generic descriptor structure. + */ +static inline struct dvb_mosaic_descriptor* + dvb_mosaic_descriptor_codec(struct descriptor* d) +{ + uint8_t* buf = (uint8_t*) d + 2; + uint32_t pos = 0; + uint32_t len = d->len; + struct dvb_mosaic_descriptor * p = + (struct dvb_mosaic_descriptor *) d; + + pos += (sizeof(struct dvb_mosaic_descriptor) - 2); + + if (pos > len) + return NULL; + + while(pos < len) { + struct dvb_mosaic_info *e = + (struct dvb_mosaic_info*) (buf+pos); + struct dvb_mosaic_info_part2 *e2; + struct dvb_mosaic_linkage *linkage; + + if ((pos + sizeof(struct dvb_mosaic_info)) > len) + return NULL; + + bswap16(buf + pos); + + pos += sizeof(struct dvb_mosaic_info) + + e->elementary_cell_field_length; + + if (pos > len) + return NULL; + + e2 = (struct dvb_mosaic_info_part2*) (buf+pos); + + pos += sizeof(struct dvb_mosaic_info_part2); + + if (pos > len) + return NULL; + + linkage = (struct dvb_mosaic_linkage*) (buf+pos); + + switch(e2->cell_linkage_info) { + case 0x01: + if ((pos + sizeof(struct dvb_mosaic_linkage_01)) > len) + return NULL; + bswap16(buf+pos); + pos += sizeof(struct dvb_mosaic_linkage_01); + break; + + case 0x02: + if ((pos + sizeof(struct dvb_mosaic_linkage_02)) > len) + return NULL; + bswap16(buf+pos); + bswap16(buf+pos+2); + bswap16(buf+pos+4); + pos += sizeof(struct dvb_mosaic_linkage_02); + break; + + case 0x03: + if ((pos + sizeof(struct dvb_mosaic_linkage_03)) > len) + return NULL; + bswap16(buf+pos); + bswap16(buf+pos+2); + bswap16(buf+pos+4); + pos += sizeof(struct dvb_mosaic_linkage_03); + break; + + case 0x04: + if ((pos + sizeof(struct dvb_mosaic_linkage_04)) > len) + return NULL; + bswap16(buf+pos); + bswap16(buf+pos+2); + bswap16(buf+pos+4); + bswap16(buf+pos+6); + pos += sizeof(struct dvb_mosaic_linkage_04); + break; + } + } + + return p; +} + +/** + * Iterator over the infos field of a dvb_mosaic_descriptor. + * + * @param d dvb_mosaic_descriptor pointer. + * @param pos Variable containing a pointer to the current dvb_mosaic_info. + */ +#define dvb_mosaic_descriptor_infos_for_each(d, pos) \ + for ((pos) = dvb_mosaic_descriptor_infos_first(d); \ + (pos); \ + (pos) = dvb_mosaic_descriptor_infos_next(d, pos)) + +/** + * Iterator over the fields field of a dvb_mosaic_info. + * + * @param info dvb_mosaic_info pointer. + * @param pos Variable containing a pointer to the current dvb_mosaic_elementary_cell_field. + */ +#define dvb_mosaic_info_fields_for_each(info, pos) \ + for ((pos) = dvb_mosaic_info_fields_first(info); \ + (pos); \ + (pos) = dvb_mosaic_info_fields_next(info, pos)) + +/** + * Accessor for the second part of the dvb_mosaic_info structure. + * + * @param entry dvb_mosaic_info pointer. + * @return dvb_mosaic_info_part2 pointer. + */ +static inline struct dvb_mosaic_info_part2* + dvb_mosaic_info_part2(struct dvb_mosaic_info* entry) +{ + return (struct dvb_mosaic_info_part2*) + ((uint8_t*) entry + sizeof(struct dvb_mosaic_info) + + entry->elementary_cell_field_length); +} + +/** + * Accessor for the linkage field a dvb_mosaic_info structure. + * + * @param entry dvb_mosaic_info_part2 pointer. + * @return dvb_mosaic_linkage pointer, or NULL on error. + */ +static inline struct dvb_mosaic_linkage* + dvb_mosaic_linkage(struct dvb_mosaic_info_part2* entry) +{ + if ((entry->cell_linkage_info != 0x01) && + (entry->cell_linkage_info != 0x02) && + (entry->cell_linkage_info != 0x03) && + (entry->cell_linkage_info != 0x04)) + return NULL; + + return (struct dvb_mosaic_linkage*) + ((uint8_t*) entry + sizeof(struct dvb_mosaic_info_part2)); +} + + + + + + + + + + +/******************************** PRIVATE CODE ********************************/ +static inline struct dvb_mosaic_info* + dvb_mosaic_descriptor_infos_first(struct dvb_mosaic_descriptor *d) +{ + if (d->d.len == 1) + return NULL; + + return (struct dvb_mosaic_info *) + ((uint8_t*) d + sizeof(struct dvb_mosaic_descriptor)); +} + +static inline struct dvb_mosaic_info* + dvb_mosaic_descriptor_infos_next(struct dvb_mosaic_descriptor *d, + struct dvb_mosaic_info *pos) +{ + struct dvb_mosaic_info_part2* part2 = dvb_mosaic_info_part2(pos); + uint8_t *end = (uint8_t*) d + 2 + d->d.len; + uint8_t *next = (uint8_t *) pos + sizeof(struct dvb_mosaic_info) + + pos->elementary_cell_field_length + + sizeof(struct dvb_mosaic_info_part2); + + if (part2->cell_linkage_info == 0x01) + next += sizeof(struct dvb_mosaic_linkage_01); + else if (part2->cell_linkage_info == 0x02) + next += sizeof(struct dvb_mosaic_linkage_02); + else if (part2->cell_linkage_info == 0x03) + next += sizeof(struct dvb_mosaic_linkage_03); + else if (part2->cell_linkage_info == 0x04) + next += sizeof(struct dvb_mosaic_linkage_04); + + if (next >= end) + return NULL; + + return (struct dvb_mosaic_info *) next; +} + +static inline struct dvb_mosaic_elementary_cell_field* + dvb_mosaic_info_fields_first(struct dvb_mosaic_info *d) +{ + if (d->elementary_cell_field_length == 0) + return NULL; + + return (struct dvb_mosaic_elementary_cell_field*) + ((uint8_t*) d + sizeof(struct dvb_mosaic_info)); +} + +static inline struct dvb_mosaic_elementary_cell_field* + dvb_mosaic_info_fields_next(struct dvb_mosaic_info *d, + struct dvb_mosaic_elementary_cell_field* pos) +{ + uint8_t *end = (uint8_t*) d + sizeof(struct dvb_mosaic_info) + + d->elementary_cell_field_length; + uint8_t *next = (uint8_t *) pos + + sizeof(struct dvb_mosaic_elementary_cell_field); + + if (next >= end) + return NULL; + + return (struct dvb_mosaic_elementary_cell_field *) next; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/multilingual_bouquet_name_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/multilingual_bouquet_name_descriptor.h new file mode 100644 index 0000000..0d8deb1 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/multilingual_bouquet_name_descriptor.h @@ -0,0 +1,145 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_DVB_MULTILINGUAL_BOUQUET_NAME_DESCRIPTOR +#define _UCSI_DVB_MULTILINGUAL_BOUQUET_NAME_DESCRIPTOR 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/descriptor.h> +#include <libucsi/endianops.h> +#include <libucsi/types.h> + +/** + * dvb_multilingual_bouquet_name_descriptor structure. + */ +struct dvb_multilingual_bouquet_name_descriptor { + struct descriptor d; + + /* struct dvb_multilingual_bouquet_name names[]*/ +} __ucsi_packed; + +/** + * An entry in the names field of a dvb_multilingual_bouquet_name_descriptor. + */ +struct dvb_multilingual_bouquet_name { + iso639lang_t language_code; + uint8_t bouquet_name_length; + /* uint8_t name[] */ +} __ucsi_packed; + +/** + * Process a dvb_multilingual_bouquet_name_descriptor. + * + * @param d Generic descriptor pointer. + * @return dvb_multilingual_bouquet_name_descriptor pointer, or NULL on error. + */ +static inline struct dvb_multilingual_bouquet_name_descriptor* + dvb_multilingual_bouquet_name_descriptor_codec(struct descriptor* d) +{ + uint8_t* buf = (uint8_t*) d + 2; + uint32_t pos = 0; + uint32_t len = d->len; + + while(pos < len) { + struct dvb_multilingual_bouquet_name *e = + (struct dvb_multilingual_bouquet_name*) (buf+pos); + + pos += sizeof(struct dvb_multilingual_bouquet_name); + + if (pos > len) + return NULL; + + pos += e->bouquet_name_length; + + if (pos > len) + return NULL; + } + + return (struct dvb_multilingual_bouquet_name_descriptor*) d; +} + +/** + * Iterator for entries in the names field of a dvb_multilingual_bouquet_name_descriptor. + * + * @param d dvb_multilingual_bouquet_name_descriptor pointer. + * @param pos Variable containing a pointer to the current dvb_multilingual_bouquet_name. + */ +#define dvb_multilingual_bouquet_name_descriptor_names_for_each(d, pos) \ + for ((pos) = dvb_multilingual_bouquet_name_descriptor_names_first(d); \ + (pos); \ + (pos) = dvb_multilingual_bouquet_name_descriptor_names_next(d, pos)) + +/** + * Accessor for the name field of a dvb_multilingual_bouquet_name. + * + * @param e dvb_multilingual_bouquet_name pointer. + * @return Pointer to the field. + */ +static inline uint8_t * + dvb_multilingual_bouquet_name_name(struct dvb_multilingual_bouquet_name *e) +{ + return (uint8_t *) e + sizeof(struct dvb_multilingual_bouquet_name); +} + + + + + + + + + + +/******************************** PRIVATE CODE ********************************/ +static inline struct dvb_multilingual_bouquet_name* + dvb_multilingual_bouquet_name_descriptor_names_first(struct dvb_multilingual_bouquet_name_descriptor *d) +{ + if (d->d.len == 0) + return NULL; + + return (struct dvb_multilingual_bouquet_name *) + ((uint8_t*) d + sizeof(struct dvb_multilingual_bouquet_name_descriptor)); +} + +static inline struct dvb_multilingual_bouquet_name* + dvb_multilingual_bouquet_name_descriptor_names_next(struct dvb_multilingual_bouquet_name_descriptor *d, + struct dvb_multilingual_bouquet_name *pos) +{ + uint8_t *end = (uint8_t*) d + 2 + d->d.len; + uint8_t *next = (uint8_t *) pos + + sizeof(struct dvb_multilingual_bouquet_name) + + pos->bouquet_name_length; + + if (next >= end) + return NULL; + + return (struct dvb_multilingual_bouquet_name *) next; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/multilingual_component_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/multilingual_component_descriptor.h new file mode 100644 index 0000000..ab156af --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/multilingual_component_descriptor.h @@ -0,0 +1,149 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_DVB_MULTILINGUAL_COMPONENT_DESCRIPTOR +#define _UCSI_DVB_MULTILINGUAL_COMPONENT_DESCRIPTOR 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/descriptor.h> +#include <libucsi/endianops.h> +#include <libucsi/types.h> + +/** + * dvb_multilingual_component_descriptor structure. + */ +struct dvb_multilingual_component_descriptor { + struct descriptor d; + + uint8_t component_tag; + /* struct dvb_multilingual_component components[] */ +} __ucsi_packed; + +/** + * An entry in the components field of a dvb_multilingual_component_descriptor. + */ +struct dvb_multilingual_component { + iso639lang_t language_code; + uint8_t text_description_length; + /* uint8_t text_char[] */ +} __ucsi_packed; + +/** + * Process a dvb_multilingual_component_descriptor. + * + * @param d Generic descriptor pointer. + * @return dvb_multilingual_component_descriptor pointer, or NULL on error. + */ +static inline struct dvb_multilingual_component_descriptor* + dvb_multilingual_component_descriptor_codec(struct descriptor* d) +{ + uint8_t* buf = (uint8_t*) d + 2; + uint32_t pos = sizeof(struct dvb_multilingual_component_descriptor) - 2; + uint32_t len = d->len; + + if (pos > len) + return NULL; + + while(pos < len) { + struct dvb_multilingual_component *e = + (struct dvb_multilingual_component*) (buf+pos); + + pos += sizeof(struct dvb_multilingual_component); + + if (pos > len) + return NULL; + + pos += e->text_description_length; + + if (pos > len) + return NULL; + } + + return (struct dvb_multilingual_component_descriptor*) d; +} + +/** + * Iterator for entries in the components field of a dvb_multilingual_component_descriptor. + * + * @param d Generic descriptor pointer. + * @param pos Variable containing a pointer to the current dvb_multilingual_component. + */ +#define dvb_multilingual_component_descriptor_components_for_each(d, pos) \ + for ((pos) = dvb_multilingual_component_descriptor_components_first(d); \ + (pos); \ + (pos) = dvb_multilingual_component_descriptor_components_next(d, pos)) + +/** + * Accessor for the text_char field in a dvb_multilingual_component. + * + * @param e dvb_multilingual_component pointer. + * @return Pointer to the field. + */ +static inline uint8_t * + dvb_multilingual_component_text_char(struct dvb_multilingual_component *e) +{ + return (uint8_t *) e + sizeof(struct dvb_multilingual_component); +} + + + + + + + + + + +/******************************** PRIVATE CODE ********************************/ +static inline struct dvb_multilingual_component* + dvb_multilingual_component_descriptor_components_first(struct dvb_multilingual_component_descriptor *d) +{ + if (d->d.len == 1) + return NULL; + + return (struct dvb_multilingual_component *) + ((uint8_t*) d + sizeof(struct dvb_multilingual_component_descriptor)); +} + +static inline struct dvb_multilingual_component* + dvb_multilingual_component_descriptor_components_next(struct dvb_multilingual_component_descriptor *d, + struct dvb_multilingual_component *pos) +{ + uint8_t *end = (uint8_t*) d + 2 + d->d.len; + uint8_t *next = (uint8_t *) pos + + sizeof(struct dvb_multilingual_component) + + pos->text_description_length; + + if (next >= end) + return NULL; + + return (struct dvb_multilingual_component *) next; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/multilingual_network_name_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/multilingual_network_name_descriptor.h new file mode 100644 index 0000000..1a7b8c4 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/multilingual_network_name_descriptor.h @@ -0,0 +1,145 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_DVB_MULTILINGUAL_NETWORK_NAME_DESCRIPTOR +#define _UCSI_DVB_MULTILINGUAL_NETWORK_NAME_DESCRIPTOR 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/descriptor.h> +#include <libucsi/endianops.h> +#include <libucsi/types.h> + +/** + * dvb_multilingual_network_name_descriptor structure. + */ +struct dvb_multilingual_network_name_descriptor { + struct descriptor d; + + /* struct dvb_multilingual_network_name names[] */ +} __ucsi_packed; + +/** + * An entry in the names field of a dvb_multilingual_network_name_descriptor. + */ +struct dvb_multilingual_network_name { + iso639lang_t language_code; + uint8_t network_name_length; + /* uint8_t name[] */ +} __ucsi_packed; + +/** + * Process a dvb_multilingual_network_name_descriptor. + * + * @param d Generic descriptor pointer. + * @return dvb_multilingual_network_name_descriptor pointer, or NULL on error. + */ +static inline struct dvb_multilingual_network_name_descriptor* + dvb_multilingual_network_name_descriptor_codec(struct descriptor* d) +{ + uint8_t* buf = (uint8_t*) d + 2; + uint32_t pos = 0; + uint32_t len = d->len; + + while(pos < len) { + struct dvb_multilingual_network_name *e = + (struct dvb_multilingual_network_name*) (buf + pos); + + pos += sizeof(struct dvb_multilingual_network_name); + + if (pos > len) + return NULL; + + pos += e->network_name_length; + + if (pos > len) + return NULL; + } + + return (struct dvb_multilingual_network_name_descriptor*) d; +} + +/** + * Iterator for entries in the names field of a dvb_multilingual_network_name_descriptor. + * + * @param d dvb_multilingual_network_name_descriptor pointer. + * @param pos Variable containing a pointer to the current dvb_multilingual_network_name. + */ +#define dvb_multilingual_network_name_descriptor_names_for_each(d, pos) \ + for ((pos) = dvb_multilingual_network_name_descriptor_names_first(d); \ + (pos); \ + (pos) = dvb_multilingual_network_name_descriptor_names_next(d, pos)) + +/** + * Accessor for the name field of a dvb_multilingual_network_name. + * + * @param e dvb_multilingual_network_name pointer. + * @return Pointer to the name field. + */ +static inline uint8_t * + dvb_multilingual_network_name_name(struct dvb_multilingual_network_name *e) +{ + return (uint8_t *) e + sizeof(struct dvb_multilingual_network_name); +} + + + + + + + + + + +/******************************** PRIVATE CODE ********************************/ +static inline struct dvb_multilingual_network_name* + dvb_multilingual_network_name_descriptor_names_first(struct dvb_multilingual_network_name_descriptor *d) +{ + if (d->d.len == 0) + return NULL; + + return (struct dvb_multilingual_network_name *) + ((uint8_t*) d + sizeof(struct dvb_multilingual_network_name_descriptor)); +} + +static inline struct dvb_multilingual_network_name* + dvb_multilingual_network_name_descriptor_names_next(struct dvb_multilingual_network_name_descriptor *d, + struct dvb_multilingual_network_name *pos) +{ + uint8_t *end = (uint8_t*) d + 2 + d->d.len; + uint8_t *next = (uint8_t *) pos + + sizeof(struct dvb_multilingual_network_name) + + pos->network_name_length; + + if (next >= end) + return NULL; + + return (struct dvb_multilingual_network_name *) next; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/multilingual_service_name_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/multilingual_service_name_descriptor.h new file mode 100644 index 0000000..31bb9c3 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/multilingual_service_name_descriptor.h @@ -0,0 +1,197 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_DVB_MULTILINGUAL_SERVICE_NAME_DESCRIPTOR +#define _UCSI_DVB_MULTILINGUAL_SERVICE_NAME_DESCRIPTOR 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/descriptor.h> +#include <libucsi/endianops.h> +#include <libucsi/types.h> + +/** + * dvb_multilingual_service_name_descriptor structure. + */ +struct dvb_multilingual_service_name_descriptor { + struct descriptor d; + + /* struct dvb_multilingual_service_name names[] */ +} __ucsi_packed; + +/** + * An entry in the service_names field of a dvb_multilingual_service_name_descriptor. + */ +struct dvb_multilingual_service_name { + iso639lang_t language_code; + uint8_t service_provider_name_length; + /* uint8_t service_provider_name[] */ + /* struct dvb_multilingual_service_name_part2 part2 */ +} __ucsi_packed; + +/** + * Second part of a dvb_multilingual_service_name following the variable length + * service_provider_name. + */ +struct dvb_multilingual_service_name_part2 { + uint8_t service_name_length; + /* uint8_t service_name[] */ +} __ucsi_packed; + +/** + * Process a dvb_multilingual_service_name_descriptor. + * + * @param d Generic descriptor pointer. + * @return dvb_multilingual_service_name_descriptor pointer, or NULL on error. + */ +static inline struct dvb_multilingual_service_name_descriptor* + dvb_multilingual_service_name_descriptor_codec(struct descriptor* d) +{ + uint8_t* buf = (uint8_t*) d + 2; + uint32_t pos = 0; + uint32_t len = d->len; + + while(pos < len) { + struct dvb_multilingual_service_name *e = + (struct dvb_multilingual_service_name*) (buf+pos); + struct dvb_multilingual_service_name_part2 *e2; + + pos += sizeof(struct dvb_multilingual_service_name); + + if (pos > len) + return NULL; + + pos += e->service_provider_name_length; + + if (pos > len) + return NULL; + + e2 = (struct dvb_multilingual_service_name_part2*) (buf+pos); + + pos += sizeof(struct dvb_multilingual_service_name_part2); + + if (pos > len) + return NULL; + + pos += e2->service_name_length; + + if (pos > len) + return NULL; + } + + return (struct dvb_multilingual_service_name_descriptor*) d; +} + +/** + * Iterator for entries in the service_name field of a dvb_multilingual_service_name_descriptor. + * + * @param d dvb_multilingual_service_name_descriptor pointer, + * @param pos Variable containing pointer to the current dvb_multilingual_service_name. + */ +#define dvb_multilingual_service_name_descriptor_names_for_each(d, pos) \ + for ((pos) = dvb_multilingual_service_name_descriptor_names_first(d); \ + (pos); \ + (pos) = dvb_multilingual_service_name_descriptor_names_next(d, pos)) + +/** + * Accessor for the service_provider_name field of a dvb_multilingual_service_name. + * + * @param e dvb_multilingual_service_name pointer. + * @return Pointer to the field. + */ +static inline uint8_t * + dvb_multilingual_service_name_service_provider_name(struct dvb_multilingual_service_name *e) +{ + return (uint8_t *) e + sizeof(struct dvb_multilingual_service_name); +} + +/** + * Accessor for the dvb_multilingual_service_name_part2 - second part of a + * dvb_multilingual_service_name following the service_name field. + * + * @param e dvb_multilingual_service_name Pointer. + * @return dvb_multilingual_service_name_part2 pointer. + */ +static inline struct dvb_multilingual_service_name_part2 * + dvb_multilingual_service_name_part2(struct dvb_multilingual_service_name *e) +{ + return (struct dvb_multilingual_service_name_part2 *) + ((uint8_t *) e + sizeof(struct dvb_multilingual_service_name) + + e->service_provider_name_length); +} + +/** + * Accessor for the service_name field of a dvb_multilingual_service_name_part2. + * + * @param e dvb_multilingual_service_name_part2 pointer. + * @return Pointer to the field. + */ +static inline uint8_t * + dvb_multilingual_service_name_service_name(struct dvb_multilingual_service_name_part2 *e) +{ + return (uint8_t *) e + sizeof(struct dvb_multilingual_service_name_part2); +} + + + + + + + + + + +/******************************** PRIVATE CODE ********************************/ +static inline struct dvb_multilingual_service_name* + dvb_multilingual_service_name_descriptor_names_first(struct dvb_multilingual_service_name_descriptor *d) +{ + if (d->d.len == 0) + return NULL; + + return (struct dvb_multilingual_service_name *) + ((uint8_t*) d + sizeof(struct dvb_multilingual_service_name_descriptor)); +} + +static inline struct dvb_multilingual_service_name* + dvb_multilingual_service_name_descriptor_names_next(struct dvb_multilingual_service_name_descriptor *d, + struct dvb_multilingual_service_name *pos) +{ + struct dvb_multilingual_service_name_part2 * part2 = + dvb_multilingual_service_name_part2(pos); + uint8_t *end = (uint8_t*) d + 2 + d->d.len; + uint8_t *next = (uint8_t *) part2+ + sizeof(struct dvb_multilingual_service_name_part2) + + part2->service_name_length; + + if (next >= end) + return NULL; + + return (struct dvb_multilingual_service_name *) next; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/network_name_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/network_name_descriptor.h new file mode 100644 index 0000000..0754597 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/network_name_descriptor.h @@ -0,0 +1,82 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_DVB_NETWORK_NAME_DESCRIPTOR +#define _UCSI_DVB_NETWORK_NAME_DESCRIPTOR 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/descriptor.h> +#include <libucsi/endianops.h> + +/** + * dvb_network_name_descriptor structure. + */ +struct dvb_network_name_descriptor { + struct descriptor d; + + /* char name[] */ +} __ucsi_packed; + +/** + * Process a dvb_network_name_descriptor. + * + * @param d Generic descriptor pointer. + * @return dvb_network_name_descriptor pointer, or NULL on error. + */ +static inline struct dvb_network_name_descriptor* + dvb_network_name_descriptor_codec(struct descriptor* d) +{ + return (struct dvb_network_name_descriptor*) d; +} + +/** + * Accessor for the name field in a dvb_network_name_descriptor. + * + * @param d dvb_network_name_descriptor pointer. + * @return Pointer to the field. + */ +static inline uint8_t * + dvb_network_name_descriptor_name(struct dvb_network_name_descriptor *d) +{ + return (uint8_t *) d + sizeof(struct dvb_network_name_descriptor); +} + +/** + * Calculate the length of the name field in a dvb_network_name_descriptor. + * + * @param d dvb_network_name_descriptor pointer. + * @return Length of the field in bytes. + */ +static inline int + dvb_network_name_descriptor_name_length(struct dvb_network_name_descriptor *d) +{ + return d->d.len; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/nit_section.c b/kaffeine/src/input/dvb/lib/libucsi/dvb/nit_section.c new file mode 100644 index 0000000..d931926 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/nit_section.c @@ -0,0 +1,79 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include <libucsi/dvb/nit_section.h> + +struct dvb_nit_section *dvb_nit_section_codec(struct section_ext * ext) +{ + uint8_t * buf = (uint8_t *) ext; + struct dvb_nit_section * ret = (struct dvb_nit_section *) ext; + unsigned int pos = sizeof(struct section_ext); + unsigned int len = section_ext_length(ext); + + if (len < sizeof(struct dvb_nit_section)) + return NULL; + + bswap16(buf + pos); + pos += 2; + + if ((pos + ret->network_descriptors_length) > len) + return NULL; + + if (verify_descriptors(buf + pos, ret->network_descriptors_length)) + return NULL; + + pos += ret->network_descriptors_length; + + if ((pos + sizeof(struct dvb_nit_section_part2)) > len) + return NULL; + + bswap16(buf + pos); + pos += 2; + + while (pos < len) { + struct dvb_nit_transport *transport = + (struct dvb_nit_transport *)(buf + pos); + + if ((pos + sizeof(struct dvb_nit_transport)) > len) + return NULL; + + bswap16(buf + pos); + bswap16(buf + pos + 2); + bswap16(buf + pos + 4); + + pos += sizeof(struct dvb_nit_transport); + + if ((pos + transport->transport_descriptors_length) > len) + return NULL; + + if (verify_descriptors(buf + pos, + transport->transport_descriptors_length)) + return NULL; + + pos += transport->transport_descriptors_length; + } + + if (pos != len) + return NULL; + + return ret; +} + diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/nit_section.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/nit_section.h new file mode 100644 index 0000000..77ab1a0 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/nit_section.h @@ -0,0 +1,207 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_DVB_NIT_SECTION_H +#define _UCSI_DVB_NIT_SECTION_H 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/section.h> + +/** + * dvb_nit_section structure. + */ +struct dvb_nit_section { + struct section_ext head; + + EBIT2(uint16_t reserved_1 : 4; , + uint16_t network_descriptors_length :12; ); + /* struct descriptor descriptors[] */ + /* struct dvb_nit_section_part2 part2 */ +}; + +/** + * Second part of a dvb_nit_section, following the variable length descriptors field. + */ +struct dvb_nit_section_part2 { + EBIT2(uint16_t reserved_2 : 4; , + uint16_t transport_stream_loop_length :12; ); + /* struct dvb_nit_transport transports[] */ +} __ucsi_packed; + +/** + * An entry in the transports field of a dvb_nit_section_part2 + */ +struct dvb_nit_transport { + uint16_t transport_stream_id; + uint16_t original_network_id; + EBIT2(uint16_t reserved : 4; , + uint16_t transport_descriptors_length :12; ); + /* struct descriptor descriptors[] */ +} __ucsi_packed; + +/** + * Process a dvb_nit_section. + * + * @param section Generic section_ext pointer. + * @return dvb_nit_section pointer, or NULL on error. + */ +struct dvb_nit_section * dvb_nit_section_codec(struct section_ext *section); + +/** + * Accessor for the network_id field of a NIT. + * + * @param nit NIT pointer. + * @return The network_id. + */ +static inline uint16_t dvb_nit_section_network_id(struct dvb_nit_section *nit) +{ + return nit->head.table_id_ext; +} + +/** + * Iterator over the descriptors field in a dvb_nit_section. + * + * @param nit dvb_nit_section pointer. + * @param pos Variable containing a pointer to the current descriptor. + */ +#define dvb_nit_section_descriptors_for_each(nit, pos) \ + for ((pos) = dvb_nit_section_descriptors_first(nit); \ + (pos); \ + (pos) = dvb_nit_section_descriptors_next(nit, pos)) + +/** + * Accessor for a pointer to the dvb_nit_section_part2 structure. + * + * @param nit dvb_nit_section pointer. + * @return dvb_nit_section_part2 pointer. + */ +static inline struct dvb_nit_section_part2 *dvb_nit_section_part2(struct dvb_nit_section * nit) +{ + return (struct dvb_nit_section_part2 *) + ((uint8_t*) nit + sizeof(struct dvb_nit_section) + + nit->network_descriptors_length); +} + +/** + * Iterator over the transports field in a dvb_nit_section_part2. + * + * @param nit dvb_nit_section pointer. + * @param part2 dvb_nit_section_part2 pointer. + * @param pos Pointer to the current dvb_nit_transport. + */ +#define dvb_nit_section_transports_for_each(nit, part2, pos) \ + for ((pos) = dvb_nit_section_transports_first(part2); \ + (pos); \ + (pos) = dvb_nit_section_transports_next(part2, pos)) + +/** + * Iterator over the descriptors field in a dvb_nit_transport. + * + * @param transport dvb_nit_transport pointer. + * @param pos Pointer to the current descriptor. + */ +#define dvb_nit_transport_descriptors_for_each(transport, pos) \ + for ((pos) = dvb_nit_transport_descriptors_first(transport); \ + (pos); \ + (pos) = dvb_nit_transport_descriptors_next(transport, pos)) + + + + + + + + + + +/******************************** PRIVATE CODE ********************************/ +static inline struct descriptor * + dvb_nit_section_descriptors_first(struct dvb_nit_section * nit) +{ + if (nit->network_descriptors_length == 0) + return NULL; + + return (struct descriptor *) + ((uint8_t *) nit + sizeof(struct dvb_nit_section)); +} + +static inline struct descriptor * + dvb_nit_section_descriptors_next(struct dvb_nit_section * nit, + struct descriptor* pos) +{ + return next_descriptor((uint8_t*) nit + sizeof(struct dvb_nit_section), + nit->network_descriptors_length, + pos); +} + +static inline struct dvb_nit_transport * + dvb_nit_section_transports_first(struct dvb_nit_section_part2 *part2) +{ + if (part2->transport_stream_loop_length == 0) + return NULL; + + return (struct dvb_nit_transport *) + ((uint8_t *)part2 + sizeof(struct dvb_nit_section_part2)); +} + +static inline struct dvb_nit_transport * + dvb_nit_section_transports_next(struct dvb_nit_section_part2 *part2, + struct dvb_nit_transport *pos) +{ + uint8_t *end = (uint8_t*) part2 + sizeof(struct dvb_nit_section_part2) + + part2->transport_stream_loop_length; + uint8_t *next = (uint8_t*) pos + sizeof(struct dvb_nit_transport) + + pos->transport_descriptors_length; + + if (next >= end) + return NULL; + + return (struct dvb_nit_transport *) next; +} + +static inline struct descriptor * + dvb_nit_transport_descriptors_first(struct dvb_nit_transport *t) +{ + if (t->transport_descriptors_length == 0) + return NULL; + + return (struct descriptor *) + ((uint8_t*) t + sizeof(struct dvb_nit_transport)); +} + +static inline struct descriptor * + dvb_nit_transport_descriptors_next(struct dvb_nit_transport *t, + struct descriptor* pos) +{ + return next_descriptor((uint8_t*) t + sizeof(struct dvb_nit_transport), + t->transport_descriptors_length, + pos); +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/nvod_reference_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/nvod_reference_descriptor.h new file mode 100644 index 0000000..6180514 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/nvod_reference_descriptor.h @@ -0,0 +1,125 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_DVB_NVOD_REFERENCE_DESCRIPTOR +#define _UCSI_DVB_NVOD_REFERENCE_DESCRIPTOR 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/descriptor.h> +#include <libucsi/endianops.h> + +/** + * dvb_nvod_reference_descriptor structure. + */ +struct dvb_nvod_reference_descriptor { + struct descriptor d; + + /* struct dvb_nvod_reference references[] */ +} __ucsi_packed; + +/** + * An entry in the references field of a dvb_nvod_reference_descriptor. + */ +struct dvb_nvod_reference { + uint16_t transport_stream_id; + uint16_t original_network_id; + uint16_t service_id; +} __ucsi_packed; + +/** + * Process a dvb_nvod_reference_descriptor. + * + * @param d Pointer to a generic descriptor structure pointer. + * @return dvb_nvod_reference_descriptor pointer, or NULL on error. + */ +static inline struct dvb_nvod_reference_descriptor* + dvb_nvod_reference_descriptor_codec(struct descriptor* d) +{ + uint32_t pos = 0; + uint8_t* buf = (uint8_t*) d + 2; + uint32_t len = d->len; + + if (len % sizeof(struct dvb_nvod_reference)) + return NULL; + + while(pos < len) { + bswap16(buf+pos); + bswap16(buf+pos+2); + bswap16(buf+pos+4); + pos += sizeof(struct dvb_nvod_reference); + } + + return (struct dvb_nvod_reference_descriptor*) d; +} + +/** + * Iterator over the references field in a dvb_nvod_reference_descriptor. + * + * @param d dvb_nvod_reference_descriptor pointer. + * @param pos Variable containing a pointer to the current dvb_nvod_reference. + */ +#define dvb_nvod_reference_descriptor_references_for_each(d, pos) \ + for ((pos) = dvb_nvod_reference_descriptor_references_first(d); \ + (pos); \ + (pos) = dvb_nvod_reference_descriptor_references_next(d, pos)) + + + + + + + + + + +/******************************** PRIVATE CODE ********************************/ +static inline struct dvb_nvod_reference* + dvb_nvod_reference_descriptor_references_first(struct dvb_nvod_reference_descriptor *d) +{ + if (d->d.len == 0) + return NULL; + + return (struct dvb_nvod_reference *) + ((uint8_t*) d + sizeof(struct dvb_nvod_reference_descriptor)); +} + +static inline struct dvb_nvod_reference* + dvb_nvod_reference_descriptor_references_next(struct dvb_nvod_reference_descriptor *d, + struct dvb_nvod_reference *pos) +{ + uint8_t *end = (uint8_t*) d + 2 + d->d.len; + uint8_t *next = (uint8_t *) pos + sizeof(struct dvb_nvod_reference); + + if (next >= end) + return NULL; + + return (struct dvb_nvod_reference *) next; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/parental_rating_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/parental_rating_descriptor.h new file mode 100644 index 0000000..9acbcb0 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/parental_rating_descriptor.h @@ -0,0 +1,135 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_DVB_PARENTAL_RATING_DESCRIPTOR +#define _UCSI_DVB_PARENTAL_RATING_DESCRIPTOR 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/descriptor.h> +#include <libucsi/endianops.h> +#include <libucsi/types.h> + +/** + * Defined values for the rating field. + */ +enum { + DVB_PARENTAL_RATING_MIN_3YEARS = 0x01, + DVB_PARENTAL_RATING_MIN_4YEARS = 0x02, + DVB_PARENTAL_RATING_MIN_5YEARS = 0x03, + DVB_PARENTAL_RATING_MIN_6YEARS = 0x04, + DVB_PARENTAL_RATING_MIN_7YEARS = 0x05, + DVB_PARENTAL_RATING_MIN_8YEARS = 0x06, + DVB_PARENTAL_RATING_MIN_9YEARS = 0x07, + DVB_PARENTAL_RATING_MIN_10YEARS = 0x08, + DVB_PARENTAL_RATING_MIN_11YEARS = 0x09, + DVB_PARENTAL_RATING_MIN_12YEARS = 0x0a, + DVB_PARENTAL_RATING_MIN_13YEARS = 0x0b, + DVB_PARENTAL_RATING_MIN_14YEARS = 0x0c, + DVB_PARENTAL_RATING_MIN_15YEARS = 0x0d, + DVB_PARENTAL_RATING_MIN_16YEARS = 0x0e, + DVB_PARENTAL_RATING_MIN_17YEARS = 0x0f +}; + +/** + * dvb_parental_rating_descriptor structure. + */ +struct dvb_parental_rating_descriptor { + struct descriptor d; + + /* struct dvb_parental_rating ratings[] */ +} __ucsi_packed; + +/** + * An entry in the ratings field of a dvb_parental_rating_descriptor. + */ +struct dvb_parental_rating { + iso639country_t country_code; + uint8_t rating; +} __ucsi_packed; + +/** + * Process a dvb_parental_rating_descriptor. + * + * @param d Generic descriptor structure pointer. + * @return dvb_parental_rating_descriptor pointer, or NULL on error. + */ +static inline struct dvb_parental_rating_descriptor* + dvb_parental_rating_descriptor_codec(struct descriptor* d) +{ + if (d->len % sizeof(struct dvb_parental_rating)) + return NULL; + + return (struct dvb_parental_rating_descriptor*) d; +} + +/** + * Iterator for entries in the ratings field of a dvb_parental_rating_descriptor. + * + * @param d dvb_parental_rating_descriptor pointer. + * @param pos Variable containing a pointer to the current dvb_parental_rating. + */ +#define dvb_parental_rating_descriptor_ratings_for_each(d, pos) \ + for ((pos) = dvb_parental_rating_descriptor_ratings_first(d); \ + (pos); \ + (pos) = dvb_parental_rating_descriptor_ratings_next(d, pos)) + + + + + + + + + + +/******************************** PRIVATE CODE ********************************/ +static inline struct dvb_parental_rating* + dvb_parental_rating_descriptor_ratings_first(struct dvb_parental_rating_descriptor *d) +{ + if (d->d.len == 0) + return NULL; + + return (struct dvb_parental_rating *) + ((uint8_t*) d + sizeof(struct dvb_parental_rating_descriptor)); +} + +static inline struct dvb_parental_rating* + dvb_parental_rating_descriptor_ratings_next(struct dvb_parental_rating_descriptor *d, + struct dvb_parental_rating *pos) +{ + uint8_t *end = (uint8_t*) d + 2 + d->d.len; + uint8_t *next = (uint8_t *) pos + sizeof(struct dvb_parental_rating); + + if (next >= end) + return NULL; + + return (struct dvb_parental_rating *) next; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/partial_transport_stream_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/partial_transport_stream_descriptor.h new file mode 100644 index 0000000..c8ba441 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/partial_transport_stream_descriptor.h @@ -0,0 +1,68 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_DVB_PARTIAL_TRANSPORT_STREAM_DESCRIPTOR +#define _UCSI_DVB_PARTIAL_TRANSPORT_STREAM_DESCRIPTOR 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/descriptor.h> +#include <libucsi/endianops.h> + +/** + * dvb_partial_transport_stream_descriptor structure. + */ +struct dvb_partial_transport_stream_descriptor { + struct descriptor d; + + EBIT6(uint64_t reserved : 2; , + uint64_t peak_rate :22; , + uint64_t reserved_2 : 2; , + uint64_t minimum_overall_smoothing_rate :22; , + uint64_t reserved_3 : 2; , + uint64_t maximum_overall_smoothing_rate :14; ) +} __ucsi_packed; + +/** + * Process a dvb_partial_transport_stream_descriptor. + * + * @param d Generic descriptor pointer. + * @return dvb_partial_transport_stream_descriptor pointer, or NULL on error. + */ +static inline struct dvb_partial_transport_stream_descriptor* + dvb_partial_transport_stream_descriptor_codec(struct descriptor* d) +{ + if (d->len != (sizeof(struct dvb_partial_transport_stream_descriptor) - 2)) + return NULL; + + bswap64((uint8_t*) d + 2); + + return (struct dvb_partial_transport_stream_descriptor*) d; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/pdc_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/pdc_descriptor.h new file mode 100644 index 0000000..49cc187 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/pdc_descriptor.h @@ -0,0 +1,64 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_DVB_PDC_DESCRIPTOR +#define _UCSI_DVB_PDC_DESCRIPTOR 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/descriptor.h> +#include <libucsi/endianops.h> + +/** + * dvb_pdc_descriptor structure. + */ +struct dvb_pdc_descriptor { + struct descriptor d; + + EBIT2(uint32_t reserved : 4; , + uint32_t programme_id_label :20; ) +} __ucsi_packed; + +/** + * Process a dvb_pdc_descriptor. + * + * @param d Pointer to a generic descriptor structure. + * @return dvb_pdc_descriptor pointer, or NULL on error. + */ +static inline struct dvb_pdc_descriptor* + dvb_pdc_descriptor_codec(struct descriptor* d) +{ + if (d->len != (sizeof(struct dvb_pdc_descriptor) - 2)) + return NULL; + + bswap24((uint8_t*) d + 2); + + return (struct dvb_pdc_descriptor*) d; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/private_data_specifier_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/private_data_specifier_descriptor.h new file mode 100644 index 0000000..f4cc03c --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/private_data_specifier_descriptor.h @@ -0,0 +1,63 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_DVB_PRIVATE_DATA_SPECIFIER_DESCRIPTOR +#define _UCSI_DVB_PRIVATE_DATA_SPECIFIER_DESCRIPTOR 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/descriptor.h> +#include <libucsi/endianops.h> + +/** + * dvb_private_data_specifier_descriptor structure. + */ +struct dvb_private_data_specifier_descriptor { + struct descriptor d; + + uint32_t private_data_specifier; +} __ucsi_packed; + +/** + * Process a dvb_private_data_specifier_descriptor. + * + * @param d Generic descriptor structure. + * @return dvb_private_data_specifier_descriptor pointer, or NULL on error. + */ +static inline struct dvb_private_data_specifier_descriptor* + dvb_private_data_specifier_descriptor_codec(struct descriptor* d) +{ + if (d->len != (sizeof(struct dvb_private_data_specifier_descriptor) - 2)) + return NULL; + + bswap32((uint8_t*) d + 2); + + return (struct dvb_private_data_specifier_descriptor*) d; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/related_content_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/related_content_descriptor.h new file mode 100644 index 0000000..fd6a358 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/related_content_descriptor.h @@ -0,0 +1,56 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_DVB_RELATED_CONTENT_DESCRIPTOR +#define _UCSI_DVB_RELATED_CONTENT_DESCRIPTOR 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/descriptor.h> +#include <libucsi/endianops.h> + +/** + * dvb_related_content_descriptor structure. + */ +struct dvb_related_content_descriptor { + struct descriptor d; +} __ucsi_packed; + +/** + * Process a dvb_related_content_descriptor. + * + * @param d Generic descriptor pointer. + * @return dvb_related_content_descriptor pointer, or NULL on error. + */ +static inline struct dvb_related_content_descriptor* + dvb_related_content_descriptor_codec(struct descriptor* d) +{ + return (struct dvb_related_content_descriptor*) d; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/rnt_rar_over_dvb_stream_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/rnt_rar_over_dvb_stream_descriptor.h new file mode 100644 index 0000000..b67b0d9 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/rnt_rar_over_dvb_stream_descriptor.h @@ -0,0 +1,110 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_DVB_RNT_RAR_OVER_DVB_STREAM_DESCRIPTOR +#define _UCSI_DVB_RNT_RAR_OVER_DVB_STREAM_DESCRIPTOR 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/descriptor.h> +#include <libucsi/endianops.h> + +/** + * dvb_rnt_rar_over_dvb_stream_descriptor structure. + */ +struct dvb_rnt_rar_over_dvb_stream_descriptor { + struct descriptor d; + + dvbdate_t first_valid_date; + dvbdate_t last_valid_date; + EBIT3(uint8_t weighting : 6; , + uint8_t complete_flag : 1; , + uint8_t scheduled_flag : 1; ) + uint16_t transport_stream_id; + uint16_t original_network_id; + uint16_t service_id; + uint8_t component_tag; + /* struct dvb_rnt_rar_over_dvb_stream_descriptor_scheduled_info scheduled_info */ +} __ucsi_packed; + +/** + * The scheduled_info field of a dvb_rnt_rar_over_dvb_stream_descriptor (only appears + * if scheduled_flag = 1). + */ +struct dvb_rnt_rar_over_dvb_stream_descriptor_scheduled_info { + dvbdate_t download_start_time; + uint8_t download_period_duration; + uint8_t download_cycle_time; +} __ucsi_packed; + +/** + * Process a dvb_rnt_rar_over_dvb_stream_descriptor. + * + * @param d Generic descriptor pointer. + * @return dvb_rnt_rar_over_dvb_stream_descriptor pointer, or NULL on error. + */ +static inline struct dvb_rnt_rar_over_dvb_stream_descriptor* + dvb_rnt_rar_over_dvb_stream_descriptor_codec(struct descriptor* d) +{ + uint8_t *buf = (uint8_t*) d; + uint32_t len = d->len + 2; + struct dvb_rnt_rar_over_dvb_stream_descriptor *ret = + (struct dvb_rnt_rar_over_dvb_stream_descriptor *) buf; + + if (len < sizeof(struct dvb_rnt_rar_over_dvb_stream_descriptor)) + return NULL; + + bswap16(buf + 13); + bswap16(buf + 15); + bswap16(buf + 17); + + if (ret->scheduled_flag == 1) { + if (len < (sizeof(struct dvb_rnt_rar_over_dvb_stream_descriptor)+ + sizeof(struct dvb_rnt_rar_over_dvb_stream_descriptor_scheduled_info))) + return NULL; + } + + return ret; +} + +/** + * Accessor for the scheduled_info field of a dvb_rnt_rar_over_dvb_stream_descriptor. + * + * @param d dvb_rnt_rar_over_dvb_stream_descriptor pointer. + * @return Pointer, or NULL on error. + */ +static inline struct dvb_rnt_rar_over_dvb_stream_descriptor_scheduled_info* + dvb_rnt_rar_over_dvb_stream_descriptor_scheduled_info(struct dvb_rnt_rar_over_dvb_stream_descriptor *d) +{ + if (d->scheduled_flag != 1) + return NULL; + return (struct dvb_rnt_rar_over_dvb_stream_descriptor_scheduled_info*) + ((uint8_t*) d + sizeof(struct dvb_rnt_rar_over_dvb_stream_descriptor)); +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/rnt_rar_over_ip_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/rnt_rar_over_ip_descriptor.h new file mode 100644 index 0000000..cc0ed58 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/rnt_rar_over_ip_descriptor.h @@ -0,0 +1,87 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_DVB_RNT_RAR_OVER_IP_DESCRIPTOR +#define _UCSI_DVB_RNT_RAR_OVER_IP_DESCRIPTOR 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/descriptor.h> +#include <libucsi/endianops.h> + +/** + * dvb_rnt_rar_over_ip_descriptor structure. + */ +struct dvb_rnt_rar_over_ip_descriptor { + struct descriptor d; + + dvbdate_t first_valid_date; + dvbdate_t last_valid_date; + EBIT3(uint8_t weighting : 6; , + uint8_t complete_flag : 1; , + uint8_t reserved : 1; ) + uint8_t url_length; + /* uint8_t url[] */ +} __ucsi_packed; + +/** + * Process a dvb_rnt_rar_over_ip_descriptor. + * + * @param d Generic descriptor pointer. + * @return dvb_rnt_rar_over_ip_descriptor pointer, or NULL on error. + */ +static inline struct dvb_rnt_rar_over_ip_descriptor* + dvb_rnt_rar_over_ip_descriptor_codec(struct descriptor* d) +{ + uint8_t *buf = (uint8_t*) d; + uint32_t len = d->len + 2; + struct dvb_rnt_rar_over_ip_descriptor *ret = + (struct dvb_rnt_rar_over_ip_descriptor *) buf; + + if (len < sizeof(struct dvb_rnt_rar_over_ip_descriptor)) + return NULL; + if (len < (sizeof(struct dvb_rnt_rar_over_ip_descriptor) + buf[13])) + return NULL; + + return ret; +} + +/** + * Accessor for the url field of a dvb_rnt_rar_over_ip_descriptor. + * + * @param d dvb_rnt_rar_over_ip_descriptor pointer. + * @return Pointer. + */ +static inline uint8_t* + dvb_rnt_rar_over_ip_descriptor_url(struct dvb_rnt_rar_over_ip_descriptor *d) +{ + return (uint8_t*) + ((uint8_t*) d + sizeof(struct dvb_rnt_rar_over_ip_descriptor)); +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/rnt_rnt_scan_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/rnt_rnt_scan_descriptor.h new file mode 100644 index 0000000..cb74f75 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/rnt_rnt_scan_descriptor.h @@ -0,0 +1,125 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_DVB_RNT_RNT_SCAN_DESCRIPTOR +#define _UCSI_DVB_RNT_RNT_SCAN_DESCRIPTOR 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/descriptor.h> +#include <libucsi/endianops.h> +#include <libucsi/types.h> + +/** + * dvb_rnt_rnt_scan_descriptor structure. + */ +struct dvb_rnt_rnt_scan_descriptor { + struct descriptor d; + + /* struct dvb_rnt_rnt_scan_entry entries[] */ +} __ucsi_packed; + +/** + * An entry in the entries field of a dvb_rnt_rnt_scan_descriptor. + */ +struct dvb_rnt_rnt_scan_entry { + uint16_t transport_stream_id; + uint16_t original_network_id; + uint8_t scan_weighting; +} __ucsi_packed; + +/** + * Process a dvb_rnt_rnt_scan_descriptor. + * + * @param d Generic descriptor. + * @return dvb_rnt_rnt_scan_descriptor pointer, or NULL on error. + */ +static inline struct dvb_rnt_rnt_scan_descriptor* + dvb_rnt_rnt_scan_descriptor_codec(struct descriptor* d) +{ + uint8_t *buf = (uint8_t*) d; + uint32_t len = d->len +2; + uint32_t pos = 2; + + if ((len-2) % sizeof(struct dvb_rnt_rnt_scan_entry)) + return NULL; + + while(pos < len) { + bswap16(buf+pos); + bswap16(buf+pos+2); + pos += sizeof(struct dvb_rnt_rnt_scan_entry); + } + + return (struct dvb_rnt_rnt_scan_descriptor*) d; +} + +/** + * Iterator for entries field of a dvb_rnt_rnt_scan_descriptor. + * + * @param d dvb_rnt_rnt_scan_descriptor pointer. + * @param pos Variable holding a pointer to the current dvb_rnt_rnt_scan_entry. + */ +#define dvb_rnt_rnt_scan_descriptor_entries_for_each(d, pos) \ + for ((pos) = dvb_rnt_rnt_scan_descriptor_entries_first(d); \ + (pos); \ + (pos) = dvb_rnt_rnt_scan_descriptor_entries_next(d, pos)) + + + + + + + + + + +/******************************** PRIVATE CODE ********************************/ +static inline struct dvb_rnt_rnt_scan_entry* + dvb_rnt_rnt_scan_descriptor_entries_first(struct dvb_rnt_rnt_scan_descriptor *d) +{ + if (d->d.len == 0) + return NULL; + + return (struct dvb_rnt_rnt_scan_entry *) + ((uint8_t*) d + sizeof(struct dvb_rnt_rnt_scan_descriptor)); +} + +static inline struct dvb_rnt_rnt_scan_entry* + dvb_rnt_rnt_scan_descriptor_entries_next(struct dvb_rnt_rnt_scan_descriptor *d, + struct dvb_rnt_rnt_scan_entry *pos) +{ + uint8_t *end = (uint8_t*) d + 2 + d->d.len; + uint8_t *next = (uint8_t *) pos + sizeof(struct dvb_rnt_rnt_scan_entry); + + if (next >= end) + return NULL; + + return (struct dvb_rnt_rnt_scan_entry *) next; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/rst_section.c b/kaffeine/src/input/dvb/lib/libucsi/dvb/rst_section.c new file mode 100644 index 0000000..67fa0d3 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/rst_section.c @@ -0,0 +1,47 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include <libucsi/dvb/rst_section.h> + +struct dvb_rst_section * dvb_rst_section_codec(struct section *section) +{ + uint8_t * buf = (uint8_t *) section; + int pos = sizeof(struct section); + int len = section_length(section); + struct dvb_rst_section * ret = (struct dvb_rst_section *) section; + + while (pos < len) { + if ((pos + sizeof(struct dvb_rst_status)) > len) + return NULL; + + bswap16(buf + pos); + bswap16(buf + pos + 2); + bswap16(buf + pos + 4); + bswap16(buf + pos + 6); + + pos += sizeof(struct dvb_rst_status); + } + + if (pos != len) + return NULL; + + return ret; +} diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/rst_section.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/rst_section.h new file mode 100644 index 0000000..b4269b8 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/rst_section.h @@ -0,0 +1,111 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_DVB_RST_SECTION_H +#define _UCSI_DVB_RST_SECTION_H 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/section.h> + +/** + * dvb_rst_section structure. + */ +struct dvb_rst_section { + struct section head; + + /* struct dvb_rst_status statuses[] */ +}; + +/** + * An entry in the statuses field of a dvb_rst_section structure. + */ +struct dvb_rst_status { + uint16_t transport_stream_id; + uint16_t original_network_id; + uint16_t service_id; + uint16_t event_id; + EBIT2(uint8_t reserved : 5; , + uint8_t running_status : 3; ); +}; + +/** + * Process a dvb_rst_section. + * + * @param section Pointer to a generic section strcuture. + * @return dvb_rst_section pointer, or NULL on error. + */ +struct dvb_rst_section *dvb_rst_section_codec(struct section *section); + +/** + * Iterator for entries in the statuses field of a dvb_rst_section. + * + * @param rst dvb_rst_section pointer. + * @param pos Variable containing a pointer to the current dvb_rst_status. + */ +#define dvb_rst_section_statuses_for_each(rst, pos) \ + for ((pos) = dvb_rst_section_statuses_first(rst); \ + (pos); \ + (pos) = dvb_rst_section_statuses_next(rst, pos)) + + + + + + + + + + +/******************************** PRIVATE CODE ********************************/ +static inline struct dvb_rst_status * + dvb_rst_section_statuses_first(struct dvb_rst_section *rst) +{ + int pos = sizeof(struct dvb_rst_section); + + if (pos >= section_length(&rst->head)) + return NULL; + + return (struct dvb_rst_status*) ((uint8_t *) rst + pos); +} + +static inline struct dvb_rst_status * + dvb_rst_section_statuses_next(struct dvb_rst_section * rst, + struct dvb_rst_status * pos) +{ + uint8_t *end = (uint8_t*) rst + section_length(&rst->head); + uint8_t *next = (uint8_t *) pos + sizeof(struct dvb_rst_status); + + if (next >= end) + return NULL; + + return (struct dvb_rst_status *) next; +} + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/s2_satellite_delivery_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/s2_satellite_delivery_descriptor.h new file mode 100644 index 0000000..66c9288 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/s2_satellite_delivery_descriptor.h @@ -0,0 +1,116 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_DVB_S2_SATELLITE_DELIVERY_DESCRIPTOR +#define _UCSI_DVB_S2_SATELLITE_DELIVERY_DESCRIPTOR 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/descriptor.h> +#include <libucsi/endianops.h> + +/** + * dvb_s2_satellite_delivery_descriptor structure. + */ +struct dvb_s2_satellite_delivery_descriptor { + struct descriptor d; + + EBIT4(uint8_t scrambling_sequence_selector : 1; , + uint8_t multiple_input_stream : 1; , + uint8_t backwards_compatability : 1; , + uint8_t reserved : 5; ) + /* uint32_t scrambling_sequence_index if scrambling_sequence_selector = 1 */ + /* uint8_t input_stream_id if multiple_input_stream = 1 */ +} __ucsi_packed; + +/** + * Process a dvb_s2_satellite_delivery_descriptor. + * + * @param d Pointer to a generic descriptor structure. + * @return dvb_s2_satellite_delivery_descriptor pointer, or NULL on error. + */ +static inline struct dvb_s2_satellite_delivery_descriptor* + dvb_s2_satellite_delivery_descriptor_codec(struct descriptor* d) +{ + struct dvb_s2_satellite_delivery_descriptor *s2 = + (struct dvb_s2_satellite_delivery_descriptor*) d; + + if (d->len < (sizeof(struct dvb_s2_satellite_delivery_descriptor) - 2)) + return NULL; + + int len = sizeof(struct dvb_s2_satellite_delivery_descriptor); + if (s2->scrambling_sequence_selector) { + len += 3; + } + if (s2->multiple_input_stream) { + len += 1; + } + + if (d->len < len) + return NULL; + + return s2; +} + +/** + * Accessor for the scrambling_sequence_index field of a dvb_s2_satellite_delivery_descriptor. + * + * @param s2 dvb_s2_satellite_delivery_descriptor pointer. + * @return The scrambling_sequence_index. + */ +static inline uint32_t dvb_s2_satellite_delivery_descriptor_scrambling_sequence_index(struct dvb_s2_satellite_delivery_descriptor *s2) +{ + uint8_t *tmp = (uint8_t*) s2; + + if (s2->scrambling_sequence_selector) { + return ((tmp[4] & 0x03) << 16) | (tmp[5] << 8) | tmp[6]; + } + return 0; +} + +/** + * Accessor for the input_stream_id field of a dvb_s2_satellite_delivery_descriptor. + * + * @param s2 dvb_s2_satellite_delivery_descriptor pointer. + * @return The input_stream_id. + */ +static inline uint8_t dvb_s2_satellite_delivery_descriptor_input_stream_id(struct dvb_s2_satellite_delivery_descriptor *s2) +{ + uint8_t *tmp = (uint8_t*) s2; + + if (!s2->multiple_input_stream) + return 0; + + int off = 3; + if (s2->scrambling_sequence_selector) { + off += 3; + } + return tmp[off]; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/satellite_delivery_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/satellite_delivery_descriptor.h new file mode 100644 index 0000000..23be76e --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/satellite_delivery_descriptor.h @@ -0,0 +1,73 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_DVB_SATELLITE_DELIVERY_DESCRIPTOR +#define _UCSI_DVB_SATELLITE_DELIVERY_DESCRIPTOR 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/descriptor.h> +#include <libucsi/endianops.h> + +/** + * dvb_satellite_delivery_descriptor structure. + */ +struct dvb_satellite_delivery_descriptor { + struct descriptor d; + + uint32_t frequency; // BCD, units 10kHz + uint16_t orbital_position; + EBIT5(uint8_t west_east_flag : 1; , + uint8_t polarization : 2; , + uint8_t roll_off : 2; , + uint8_t modulation_system : 1; , + uint8_t modulation_type : 2; ) + EBIT2(uint32_t symbol_rate : 28; , // BCD, units 100Hz + uint32_t fec_inner : 4; ) +} __ucsi_packed; + +/** + * Process a dvb_satellite_delivery_descriptor. + * + * @param d Pointer to a generic descriptor structure. + * @return dvb_satellite_delivery_descriptor pointer, or NULL on error. + */ +static inline struct dvb_satellite_delivery_descriptor* + dvb_satellite_delivery_descriptor_codec(struct descriptor* d) +{ + if (d->len < (sizeof(struct dvb_satellite_delivery_descriptor) - 2)) + return NULL; + + bswap32((uint8_t*) d + 2); + bswap16((uint8_t*) d + 6); + bswap32((uint8_t*) d + 9); + + return (struct dvb_satellite_delivery_descriptor*) d; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/scrambling_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/scrambling_descriptor.h new file mode 100644 index 0000000..4669bc8 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/scrambling_descriptor.h @@ -0,0 +1,61 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_DVB_SCRAMBLING_DESCRIPTOR +#define _UCSI_DVB_SCRAMBLING_DESCRIPTOR 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/descriptor.h> +#include <libucsi/endianops.h> + +/** + * dvb_scrambling_descriptor structure. + */ +struct dvb_scrambling_descriptor { + struct descriptor d; + + uint8_t scrambling_mode; +} __ucsi_packed; + +/** + * Process a dvb_scrambling_descriptor. + * + * @param d Generic descriptor structure. + * @return Pointer to dvb_scrambling_descriptor, or NULL on error. + */ +static inline struct dvb_scrambling_descriptor* + dvb_scrambling_descriptor_codec(struct descriptor* d) +{ + if (d->len != (sizeof(struct dvb_scrambling_descriptor) - 2)) + return NULL; + + return (struct dvb_scrambling_descriptor*) d; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/sdt_section.c b/kaffeine/src/input/dvb/lib/libucsi/dvb/sdt_section.c new file mode 100644 index 0000000..bdc8ce1 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/sdt_section.c @@ -0,0 +1,60 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include <libucsi/dvb/sdt_section.h> + +struct dvb_sdt_section * dvb_sdt_section_codec(struct section_ext * ext) +{ + uint8_t * buf = (uint8_t *) ext; + unsigned int pos = sizeof(struct section_ext); + unsigned int len = section_ext_length(ext); + + if (len < sizeof(struct dvb_sdt_section)) + return NULL; + + bswap16(buf + pos); + pos += 3; + + while (pos < len) { + struct dvb_sdt_service * service = + (struct dvb_sdt_service *)(buf + pos); + + if ((pos + sizeof(struct dvb_sdt_service)) > len) + return NULL; + + bswap16(buf + pos); + bswap16(buf + pos + 3); + pos += sizeof(struct dvb_sdt_service); + + if ((pos + service->descriptors_loop_length) > len) + return NULL; + + if (verify_descriptors(buf + pos, service->descriptors_loop_length)) + return NULL; + + pos += service->descriptors_loop_length; + } + + if (pos != len) + return NULL; + + return (struct dvb_sdt_section *) ext; +} diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/sdt_section.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/sdt_section.h new file mode 100644 index 0000000..0130fe7 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/sdt_section.h @@ -0,0 +1,157 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_DVB_SDT_SECTION_H +#define _UCSI_DVB_SDT_SECTION_H 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/section.h> + +/** + * dvb_sdt_section structure. + */ +struct dvb_sdt_section { + struct section_ext head; + + uint16_t original_network_id; + uint8_t reserved; + /* struct dvb_sdt_service services[] */ +} __ucsi_packed; + +/** + * An entry in the services field of a dvb_sdt_section. + */ +struct dvb_sdt_service { + uint16_t service_id; + EBIT3(uint8_t reserved : 6; , + uint8_t eit_schedule_flag : 1; , + uint8_t eit_present_following_flag : 1; ); + EBIT3(uint16_t running_status : 3; , + uint16_t free_ca_mode : 1; , + uint16_t descriptors_loop_length :12; ); + /* struct descriptor descriptors[] */ +} __ucsi_packed; + +/** + * Process a dvb_sdt_section. + * + * @param section Pointer to a generic section_ext structure. + * @return dvb_sdt_section pointer, or NULL on error. + */ +struct dvb_sdt_section * dvb_sdt_section_codec(struct section_ext *section); + +/** + * Accessor for the transport_stream_id field of an SDT. + * + * @param sdt SDT pointer. + * @return The transport_stream_id. + */ +static inline uint16_t dvb_sdt_section_transport_stream_id(struct dvb_sdt_section *sdt) +{ + return sdt->head.table_id_ext; +} + +/** + * Iterator for the services field in a dvb_sdt_section. + * + * @param sdt dvb_sdt_section pointer. + * @param pos Variable containing a pointer to the current dvb_sdt_service. + */ +#define dvb_sdt_section_services_for_each(sdt, pos) \ + for ((pos) = dvb_sdt_section_services_first(sdt); \ + (pos); \ + (pos) = dvb_sdt_section_services_next(sdt, pos)) + +/** + * Iterator for the descriptors field in a dvb_sdt_service. + * + * @param service dvb_sdt_service pointer. + * @param pos Variable containing a pointer to the current descriptor. + */ +#define dvb_sdt_service_descriptors_for_each(service, pos) \ + for ((pos) = dvb_sdt_service_descriptors_first(service); \ + (pos); \ + (pos) = dvb_sdt_service_descriptors_next(service, pos)) + + + + + + + + + + + +/******************************** PRIVATE CODE ********************************/ +static inline struct dvb_sdt_service * + dvb_sdt_section_services_first(struct dvb_sdt_section * sdt) +{ + int pos = sizeof(struct dvb_sdt_section); + + if (pos >= section_ext_length(&sdt->head)) + return NULL; + + return (struct dvb_sdt_service*) ((uint8_t *) sdt + pos); +} + +static inline struct dvb_sdt_service * + dvb_sdt_section_services_next(struct dvb_sdt_section * sdt, + struct dvb_sdt_service * pos) +{ + uint8_t *end = (uint8_t*) sdt + section_ext_length(&sdt->head); + uint8_t *next = (uint8_t*) pos + sizeof(struct dvb_sdt_service) + + pos->descriptors_loop_length; + + if (next >= end) + return NULL; + + return (struct dvb_sdt_service *) next; +} + +static inline struct descriptor * + dvb_sdt_service_descriptors_first(struct dvb_sdt_service *svc) +{ + if (svc->descriptors_loop_length == 0) + return NULL; + + return (struct descriptor *) + ((uint8_t*) svc + sizeof(struct dvb_sdt_service)); +} + +static inline struct descriptor * + dvb_sdt_service_descriptors_next(struct dvb_sdt_service *svc, + struct descriptor* pos) +{ + return next_descriptor((uint8_t*) svc + sizeof(struct dvb_sdt_service), + svc->descriptors_loop_length, + pos); +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/section.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/section.h new file mode 100644 index 0000000..8488d71 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/section.h @@ -0,0 +1,107 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_DVB_SECTION_H +#define _UCSI_DVB_SECTION_H 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/dvb/bat_section.h> +#include <libucsi/dvb/dit_section.h> +#include <libucsi/dvb/eit_section.h> +#include <libucsi/dvb/nit_section.h> +#include <libucsi/dvb/rst_section.h> +#include <libucsi/dvb/sdt_section.h> +#include <libucsi/dvb/sit_section.h> +#include <libucsi/dvb/st_section.h> +#include <libucsi/dvb/tdt_section.h> +#include <libucsi/dvb/tot_section.h> +#include <libucsi/dvb/tva_container_section.h> +#include <libucsi/dvb/int_section.h> + +/** + * The following are not implemented just now. + */ +/* +#include <libucsi/dvb/tva_related_content_section.h> +#include <libucsi/dvb/tva_content_identifier_section.h> +#include <libucsi/dvb/tva_resolution_provider_notification_section.h> +#include <libucsi/dvb/ait_section.h> +#include <libucsi/dvb/cit_section.h> +#include <libucsi/dvb/rct_section.h> +#include <libucsi/dvb/rnt_section.h> +*/ + +#define TRANSPORT_NIT_PID 0x10 +#define TRANSPORT_SDT_PID 0x11 +#define TRANSPORT_BAT_PID 0x11 +#define TRANSPORT_EIT_PID 0x12 +#define TRANSPORT_CIT_PID 0x12 +#define TRANSPORT_RST_PID 0x13 +#define TRANSPORT_TDT_PID 0x14 +#define TRANSPORT_TOT_PID 0x14 +#define TRANSPORT_RNT_PID 0x16 +#define TRANSPORT_DIT_PID 0x1e +#define TRANSPORT_SIT_PID 0x1f + +/** + * Enumeration of DVB section tags. + */ +enum dvb_section_tag { + stag_dvb_network_information_actual = 0x40, + stag_dvb_network_information_other = 0x41, + + stag_dvb_service_description_actual = 0x42, + stag_dvb_service_description_other = 0x46, + + stag_dvb_bouquet_association = 0x4a, + stag_dvb_update_notification = 0x4b, /* same syntax as IP_MAC */ + stag_dvb_ip_mac_notification = 0x4c, + + stag_dvb_event_information_nownext_actual = 0x4e, + stag_dvb_event_information_nownext_other = 0x4f, + stag_dvb_event_information_schedule_actual = 0x50, /* 0x50->0x5f */ + stag_dvb_event_information_schedule_other = 0x60, /* 0x60->0x6f */ + + stag_dvb_time_date = 0x70, + stag_dvb_running_status = 0x71, + stag_dvb_stuffing = 0x72, + stag_dvb_time_offset = 0x73, + stag_dvb_application_information = 0x74, + stag_dvb_tva_container = 0x75, + stag_dvb_tva_related_content = 0x76, + stag_dvb_tva_content_identifier = 0x77, + stag_dvb_mpe_fec = 0x78, + stag_dvb_tva_resolution_provider_notification = 0x79, + + stag_dvb_discontinuity_information = 0x7e, + stag_dvb_selection_information = 0x7f, + +}; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/service_availability_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/service_availability_descriptor.h new file mode 100644 index 0000000..f16781b --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/service_availability_descriptor.h @@ -0,0 +1,98 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_DVB_SERVICE_AVAILABILITY_DESCRIPTOR +#define _UCSI_DVB_SERVICE_AVAILABILITY_DESCRIPTOR 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/descriptor.h> +#include <libucsi/endianops.h> + +/** + * dvb_service_availability_descriptor structure. + */ +struct dvb_service_availability_descriptor { + struct descriptor d; + + EBIT2(uint8_t availability_flag : 1; , + uint8_t reserved : 7; ) + /* uint16_t cell_ids[] */ +} __ucsi_packed; + +/** + * Process a dvb_service_availability_descriptor. + * + * @param d Pointer to a generic descriptor structure. + * @return dvb_service_availability_descriptor pointer, or NULL on error. + */ +static inline struct dvb_service_availability_descriptor* + dvb_service_availability_descriptor_codec(struct descriptor* d) +{ + uint32_t pos = 0; + uint8_t* buf = (uint8_t*) d + 2; + uint32_t len = d->len; + + pos += sizeof(struct dvb_service_availability_descriptor) - 2; + + if ((len - pos) % 2) + return NULL; + + while(pos < len) { + bswap16(buf+pos); + pos += 2; + } + + return (struct dvb_service_availability_descriptor*) d; +} + +/** + * Accessor for the cell_ids field of a dvb_service_availability_descriptor. + * + * @param d dvb_service_availability_descriptor pointer. + * @return Pointer to the field. + */ +static inline uint32_t * + dvb_service_availability_descriptor_cell_ids(struct dvb_service_availability_descriptor *d) +{ + return (uint32_t *) ((uint8_t *) d + sizeof(struct dvb_service_availability_descriptor)); +} + +/** + * Determine the number of entries in the cell_ids field of a dvb_service_availability_descriptor. + * + * @param d dvb_service_availability_descriptor pointer. + * @return The number of entries. + */ +static inline int + dvb_service_availability_descriptor_cell_ids_count(struct dvb_service_availability_descriptor *d) +{ + return (d->d.len - 1) >> 1; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/service_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/service_descriptor.h new file mode 100644 index 0000000..e116ffc --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/service_descriptor.h @@ -0,0 +1,156 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_DVB_SERVICE_DESCRIPTOR +#define _UCSI_DVB_SERVICE_DESCRIPTOR 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/descriptor.h> +#include <libucsi/endianops.h> + +/** + * Possible values for service_type. + */ +enum { + DVB_SERVICE_TYPE_DIGITAL_TV = 0x01, + DVB_SERVICE_TYPE_DIGITAL_RADIO = 0x02, + DVB_SERVICE_TYPE_TELETEXT = 0x03, + DVB_SERVICE_TYPE_NVOD_REF = 0x04, + DVB_SERVICE_TYPE_NVOD_TIMESHIFT = 0x05, + DVB_SERVICE_TYPE_MOSAIC = 0x06, + DVB_SERVICE_TYPE_PAL = 0x07, + DVB_SERVICE_TYPE_SECAM = 0x08, + DVB_SERVICE_TYPE_D_D2_MAC = 0x09, + DVB_SERVICE_TYPE_FM_RADIO = 0x0a, + DVB_SERVICE_TYPE_NTSC = 0x0b, + DVB_SERVICE_TYPE_DATA_BCAST = 0x0c, + DVB_SERVICE_TYPE_EN50221 = 0x0d, + DVB_SERVICE_TYPE_RCS_MAP = 0x0e, + DVB_SERVICE_TYPE_RCS_FLS = 0x0f, + DVB_SERVICE_TYPE_MHP = 0x10 +}; + +/** + * dvb_service_descriptor structure. + */ +struct dvb_service_descriptor { + struct descriptor d; + + uint8_t service_type; + uint8_t service_provider_name_length; + /* uint8_t service_provider_name[] */ + /* struct dvb_service_descriptor_part2 part2 */ +} __ucsi_packed; + +/** + * Second part of a dvb_service_descriptor following the variable length + * service_provider_name field. + */ +struct dvb_service_descriptor_part2 { + uint8_t service_name_length; + /* uint8_t service_name[] */ +} __ucsi_packed; + +/** + * Process a dvb_service_descriptor. + * + * @param d Generic descriptor pointer. + * @return dvb_service_descriptor pointer, or NULL on error. + */ +static inline struct dvb_service_descriptor* + dvb_service_descriptor_codec(struct descriptor* d) +{ + struct dvb_service_descriptor *p = + (struct dvb_service_descriptor *) d; + struct dvb_service_descriptor_part2 *p2; + uint32_t pos = sizeof(struct dvb_service_descriptor) - 2; + uint32_t len = d->len; + + if (pos > len) + return NULL; + + pos += p->service_provider_name_length; + + if (pos > len) + return NULL; + + p2 = (struct dvb_service_descriptor_part2*) ((uint8_t*) d + 2 + pos); + + pos += sizeof(struct dvb_service_descriptor_part2); + + if (pos > len) + return NULL; + + pos += p2->service_name_length; + + if (pos != len) + return NULL; + + return p; +} + +/** + * Accessor for the service_provider_name field of a dvb_service_descriptor. + * + * @param d dvb_service_descriptor pointer. + * @return Pointer to the service_provider_name field. + */ +static inline uint8_t * + dvb_service_descriptor_service_provider_name(struct dvb_service_descriptor *d) +{ + return (uint8_t *) d + sizeof(struct dvb_service_descriptor); +} + +/** + * Accessor for the second part of a dvb_service_descriptor. + * + * @param d dvb_service_descriptor pointer. + * @return dvb_service_descriptor_part2 pointer. + */ +static inline struct dvb_service_descriptor_part2 * + dvb_service_descriptor_part2(struct dvb_service_descriptor *d) +{ + return (struct dvb_service_descriptor_part2 *) + ((uint8_t*) d + sizeof(struct dvb_service_descriptor) + + d->service_provider_name_length); +} + +/** + * Accessor for the service_name field of a dvb_service_descriptor_part2. + * + * @param d dvb_service_descriptor_part2 pointer. + * @return Pointer to the service_name field. + */ +static inline uint8_t * + dvb_service_descriptor_service_name(struct dvb_service_descriptor_part2 *d) +{ + return (uint8_t *) d + sizeof(struct dvb_service_descriptor_part2); +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/service_identifier_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/service_identifier_descriptor.h new file mode 100644 index 0000000..2037a05 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/service_identifier_descriptor.h @@ -0,0 +1,82 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_DVB_SERVICE_IDENTIFIER_DESCRIPTOR +#define _UCSI_DVB_SERVICE_IDENTIFIER_DESCRIPTOR 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/descriptor.h> +#include <libucsi/endianops.h> + +/** + * dvb_service_identifier_descriptor. + */ +struct dvb_service_identifier_descriptor { + struct descriptor d; + + /* uint8_t identifier[] */ +} __ucsi_packed; + +/** + * Process a dvb_service_identifier_descriptor. + * + * @param d Generic descriptor structure. + * @return dvb_service_identifier_descriptor pointer, or NULL on error. + */ +static inline struct dvb_service_identifier_descriptor* + dvb_service_identifier_descriptor_codec(struct descriptor* d) +{ + return (struct dvb_service_identifier_descriptor*) d; +} + +/** + * Retrieve a pointer to the identifier field of a dvb_service_identifier_descriptor. + * + * @param d dvb_service_identifier_descriptor pointer. + * @return Pointer to the field. + */ +static inline uint8_t * + dvb_service_identifier_descriptor_identifier(struct dvb_service_identifier_descriptor *d) +{ + return (uint8_t *) d + sizeof(struct dvb_service_identifier_descriptor); +} + +/** + * Calculate length of the identifier field of a dvb_service_identifier_descriptor. + * + * @param d dvb_service_identifier_descriptor pointer. + * @return The length in bytes. + */ +static inline int + dvb_service_identifier_descriptor_identifier_length(struct dvb_service_identifier_descriptor *d) +{ + return d->d.len; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/service_list_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/service_list_descriptor.h new file mode 100644 index 0000000..0086b25 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/service_list_descriptor.h @@ -0,0 +1,122 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_DVB_SERVICE_LIST_DESCRIPTOR +#define _UCSI_DVB_SERVICE_LIST_DESCRIPTOR 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/descriptor.h> +#include <libucsi/endianops.h> + +/** + * dvb_service_list_descriptor structure. + */ +struct dvb_service_list_descriptor { + struct descriptor d; + + /* struct dvb_service_list_service services[] */ +} __ucsi_packed; + +/** + * An entry in the services field of a dvb_service_list_descriptor. + */ +struct dvb_service_list_service { + uint16_t service_id; + uint8_t service_type; +} __ucsi_packed; + +/** + * Process a dvb_service_list_descriptor. + * + * @param d Generic descriptor structure. + * @return dvb_service_list_descriptor pointer, or NULL on error. + */ +static inline struct dvb_service_list_descriptor* + dvb_service_list_descriptor_codec(struct descriptor* d) +{ + uint32_t pos = 0; + uint32_t len = d->len; + uint8_t *p = (uint8_t*) d + 2; + + if (len % sizeof(struct dvb_service_list_service)) + return NULL; + + while(pos < len) { + bswap16(p+pos); + pos += sizeof(struct dvb_service_list_service); + } + + return (struct dvb_service_list_descriptor*) d; +} + +/** + * Iterator for services field in a dvb_service_list_descriptor. + * + * @param d dvb_service_list_descriptor pointer. + * @param pos Variable containing a pointer to the current dvb_service_list_service. + */ +#define dvb_service_list_descriptor_services_for_each(d, pos) \ + for ((pos) = dvb_service_list_descriptor_services_first(d); \ + (pos); \ + (pos) = dvb_service_list_descriptor_services_next(d, pos)) + + + + + + + + + + +/******************************** PRIVATE CODE ********************************/ +static inline struct dvb_service_list_service* + dvb_service_list_descriptor_services_first(struct dvb_service_list_descriptor *d) +{ + if (d->d.len == 0) + return NULL; + + return (struct dvb_service_list_service *) + ((uint8_t*) d + sizeof(struct dvb_service_list_descriptor)); +} + +static inline struct dvb_service_list_service* + dvb_service_list_descriptor_services_next(struct dvb_service_list_descriptor *d, + struct dvb_service_list_service *pos) +{ + uint8_t *end = (uint8_t*) d + 2 + d->d.len; + uint8_t *next = (uint8_t *) pos + sizeof(struct dvb_service_list_service); + + if (next >= end) + return NULL; + + return (struct dvb_service_list_service *) next; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/service_move_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/service_move_descriptor.h new file mode 100644 index 0000000..7685e65 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/service_move_descriptor.h @@ -0,0 +1,67 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_DVB_SERVICE_MOVE_DESCRIPTOR +#define _UCSI_DVB_SERVICE_MOVE_DESCRIPTOR 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/descriptor.h> +#include <libucsi/endianops.h> + +/** + * dvb_service_move_descriptor structure. + */ +struct dvb_service_move_descriptor { + struct descriptor d; + + uint16_t new_original_network_id; + uint16_t new_transport_stream_id; + uint16_t new_service_id; +} __ucsi_packed; + +/** + * Process a dvb_service_move_descriptor. + * + * @param d Generic descriptor structure. + * @return Pointer to dvb_service_move_descriptor, or NULL on error. + */ +static inline struct dvb_service_move_descriptor* + dvb_service_move_descriptor_codec(struct descriptor* d) +{ + if (d->len != (sizeof(struct dvb_service_move_descriptor) - 2)) + return NULL; + + bswap16((uint8_t*) d + 2); + bswap16((uint8_t*) d + 4); + bswap16((uint8_t*) d + 6); + + return (struct dvb_service_move_descriptor*) d; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/short_event_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/short_event_descriptor.h new file mode 100644 index 0000000..449c6f0 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/short_event_descriptor.h @@ -0,0 +1,135 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_DVB_SHORT_EVENT_DESCRIPTOR +#define _UCSI_DVB_SHORT_EVENT_DESCRIPTOR 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/descriptor.h> +#include <libucsi/endianops.h> +#include <libucsi/types.h> + +/** + * dvb_short_event_descriptor structure. + */ +struct dvb_short_event_descriptor { + struct descriptor d; + + iso639lang_t language_code; + uint8_t event_name_length; + /* uint8_t event_name[] */ + /* struct dvb_short_event_descriptor_part2 part2 */ +} __ucsi_packed; + +/** + * Second part of a dvb_short_event_descriptor, following the variable length + * name field. + */ +struct dvb_short_event_descriptor_part2 { + uint8_t text_length; + /* uint8_t text[] */ +} __ucsi_packed; + +/** + * Process a dvb_short_event_descriptor. + * + * @param d Generic descriptor pointer. + * @return dvb_short_event_descriptor pointer, or NULL on error. + */ +static inline struct dvb_short_event_descriptor* + dvb_short_event_descriptor_codec(struct descriptor* d) +{ + struct dvb_short_event_descriptor *p = + (struct dvb_short_event_descriptor*) d; + struct dvb_short_event_descriptor_part2 *p2; + uint32_t pos = sizeof(struct dvb_short_event_descriptor) - 2; + uint32_t len = d->len; + + if (pos > len) + return NULL; + + pos += p->event_name_length; + + if (pos > len) + return NULL; + + p2 = (struct dvb_short_event_descriptor_part2*) ((uint8_t*) d + 2 + pos); + + pos += sizeof(struct dvb_short_event_descriptor_part2); + + if (pos > len) + return NULL; + + pos += p2->text_length; + + if (pos != len) + return NULL; + + return p; +} + +/** + * Accessor for name field in a dvb_short_event_descriptor. + * + * @param d dvb_short_event_descriptor pointer. + * @return Pointer to name field. + */ +static inline uint8_t * + dvb_short_event_descriptor_event_name(struct dvb_short_event_descriptor *d) +{ + return (uint8_t *) d + sizeof(struct dvb_short_event_descriptor); +} + +/** + * Accessor for second part of a dvb_short_event_descriptor. + * + * @param d dvb_short_event_descriptor pointer. + * @return dvb_short_event_descriptor_part2 pointer. + */ +static inline struct dvb_short_event_descriptor_part2 * + dvb_short_event_descriptor_part2(struct dvb_short_event_descriptor *d) +{ + return (struct dvb_short_event_descriptor_part2 *) + ((uint8_t*) d + sizeof(struct dvb_short_event_descriptor) + + d->event_name_length); +} + +/** + * Accessor for text field in a dvb_short_event_descriptor_part2. + * + * @param d dvb_short_event_descriptor_part2 pointer. + * @return Pointer to text field. + */ +static inline uint8_t * + dvb_short_event_descriptor_text(struct dvb_short_event_descriptor_part2 *d) +{ + return (uint8_t *) d + sizeof(struct dvb_short_event_descriptor_part2); +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/short_smoothing_buffer_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/short_smoothing_buffer_descriptor.h new file mode 100644 index 0000000..7deab9b --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/short_smoothing_buffer_descriptor.h @@ -0,0 +1,87 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_DVB_SHORT_SMOOTHING_BUFFER_DESCRIPTOR +#define _UCSI_DVB_SHORT_SMOOTHING_BUFFER_DESCRIPTOR 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/descriptor.h> +#include <libucsi/endianops.h> + +/** + * dvb_short_smoothing_buffer_descriptor structure. + */ +struct dvb_short_smoothing_buffer_descriptor { + struct descriptor d; + + EBIT2(uint8_t sb_size : 2; , + uint8_t sb_leak_rate : 6; ) + /* uint8_t reserved [] */ +} __ucsi_packed; + +/** + * Process a dvb_short_smoothing_buffer_descriptor. + * + * @param d Generic descriptor structure. + * @return dvb_short_smoothing_buffer_descriptor pointer, or NULL on error. + */ +static inline struct dvb_short_smoothing_buffer_descriptor* + dvb_short_smoothing_buffer_descriptor_codec(struct descriptor* d) +{ + if (d->len < (sizeof(struct dvb_short_smoothing_buffer_descriptor) - 2)) + return NULL; + + return (struct dvb_short_smoothing_buffer_descriptor*) d; +} + +/** + * Accessor for reserved field in a dvb_short_smoothing_buffer_descriptor. + * + * @param d dvb_short_smoothing_buffer_descriptor pointer. + * @return Pointer to reserved field. + */ +static inline uint8_t * + dvb_short_smoothing_buffer_descriptor_reserved(struct dvb_short_smoothing_buffer_descriptor *d) +{ + return (uint8_t*) d + sizeof(struct dvb_short_smoothing_buffer_descriptor); +} + +/** + * Calculate length of reserved field in a dvb_short_smoothing_buffer_descriptor. + * + * @param d dvb_short_smoothing_buffer_descriptor pointer. + * @return Length of the field in bytes. + */ +static inline int + dvb_short_smoothing_buffer_descriptor_reserved_length(struct dvb_short_smoothing_buffer_descriptor *d) +{ + return d->d.len - 1; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/sit_section.c b/kaffeine/src/input/dvb/lib/libucsi/dvb/sit_section.c new file mode 100644 index 0000000..61134d0 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/sit_section.c @@ -0,0 +1,70 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include <libucsi/dvb/sit_section.h> + +struct dvb_sit_section * dvb_sit_section_codec(struct section_ext * ext) +{ + uint8_t * buf = (uint8_t *) ext; + struct dvb_sit_section * ret = (struct dvb_sit_section *) ext; + unsigned int pos = sizeof(struct section_ext); + unsigned int len = section_ext_length(ext); + + if (len < sizeof(struct dvb_sit_section)) + return NULL; + + bswap16(buf + pos); + pos += 2; + + if ((pos + ret->transmission_info_loop_length) > len) + return NULL; + + if (verify_descriptors(buf + pos, ret->transmission_info_loop_length)) + return NULL; + + pos += ret->transmission_info_loop_length; + + while (pos < len) { + struct dvb_sit_service * service = (void*)(buf + pos); + + if ((pos + sizeof(struct dvb_sit_service)) > len) + return NULL; + + bswap16(buf + pos); + bswap16(buf + pos + 2); + bswap16(buf + pos + 4); + pos += sizeof(struct dvb_sit_service); + + if ((pos + service->service_loop_length) > len) + return NULL; + + if (verify_descriptors(buf + pos, service->service_loop_length)) + return NULL; + + pos += service->service_loop_length; + } + + if (pos != len) + return NULL; + + return ret; +} + diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/sit_section.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/sit_section.h new file mode 100644 index 0000000..d05989f --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/sit_section.h @@ -0,0 +1,173 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_DVB_SIT_SECTION_H +#define _UCSI_DVB_SIT_SECTION_H 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/section.h> + +/** + * dvb_sit_section structure. + */ +struct dvb_sit_section { + struct section_ext head; + + EBIT2(uint16_t reserved : 4; , + uint16_t transmission_info_loop_length :12; ); + /* struct descriptor descriptors[] */ + /* struct dvb_sit_service services[] */ +}; + +/** + * An entry in the services field of a dvb_sit_section. + */ +struct dvb_sit_service { + uint16_t service_id; + EBIT3(uint16_t reserved : 1; , + uint16_t running_status : 3; , + uint16_t service_loop_length :12; ); + /* struct descriptor descriptors[] */ +}; + +/** + * Process a dvb_sit_section. + * + * @param section Generic section_ext structure. + * @return dvb_sit_section pointer, or NULL on error. + */ +struct dvb_sit_section * dvb_sit_section_codec(struct section_ext *section); + +/** + * Iterator for descriptors field in a dvb_sit_section. + * + * @param sit dvb_sit_section Pointer. + * @param pos Variable holding pointer to current descriptor. + */ +#define dvb_sit_section_descriptors_for_each(sit, pos) \ + for ((pos) = dvb_sit_section_descriptors_first(sit); \ + (pos); \ + (pos) = dvb_sit_section_descriptors_first(sit)) + +/** + * Iterator for services field in a dvb_sit_section. + * + * @param sit dvb_sit_section Pointer. + * @param pos Variable holding pointer to current dvb_sit_service. + */ +#define dvb_sit_section_services_for_each(sit, pos) \ + for ((pos) = dvb_sit_section_services_first(sit); \ + (pos); \ + (pos) = dvb_sit_section_services_next(sit, pos)) + +/** + * Iterator for descriptors field in a dvb_sit_service. + * + * @param service dvb_sit_service Pointer. + * @param pos Variable holding pointer to current descriptor. + */ +#define dvb_sit_service_descriptors_for_each(service, pos) \ + for ((pos) = dvb_sit_service_descriptors_first(service); \ + (pos); \ + (pos) = dvb_sit_service_descriptors_next(service, pos)) + + + + + + + + + + +/******************************** PRIVATE CODE ********************************/ +static inline struct descriptor * + dvb_sit_section_descriptors_first(struct dvb_sit_section *sit) +{ + if (sit->transmission_info_loop_length == 0) + return NULL; + + return (struct descriptor *) + ((uint8_t *) sit + sizeof(struct dvb_sit_section)); +} + +static inline struct descriptor * + dvb_sit_section_descriptors_next(struct dvb_sit_section *sit, + struct descriptor* pos) +{ + return next_descriptor((uint8_t*) sit + sizeof(struct dvb_sit_section), + sit->transmission_info_loop_length, + pos); +} + +static inline struct dvb_sit_service * + dvb_sit_section_services_first(struct dvb_sit_section *sit) +{ + int pos = sizeof(struct dvb_sit_section) + sit->transmission_info_loop_length; + + if (pos >= section_ext_length(&sit->head)) + return NULL; + + return (struct dvb_sit_service*) ((uint8_t *) sit + pos); +} + +static inline struct dvb_sit_service * + dvb_sit_section_services_next(struct dvb_sit_section *sit, + struct dvb_sit_service *pos) +{ + uint8_t *end = (uint8_t*) sit + section_ext_length(&sit->head); + uint8_t *next = (uint8_t *) pos + sizeof(struct dvb_sit_service) + + pos->service_loop_length; + + if (next >= end) + return NULL; + + return (struct dvb_sit_service *) next; +} + +static inline struct descriptor * + dvb_sit_service_descriptors_first(struct dvb_sit_service * t) +{ + if (t->service_loop_length == 0) + return NULL; + + return (struct descriptor *) + ((uint8_t *) t + sizeof(struct dvb_sit_service)); +} + +static inline struct descriptor * + dvb_sit_service_descriptors_next(struct dvb_sit_service *t, + struct descriptor* pos) +{ + return next_descriptor((uint8_t*) t + sizeof(struct dvb_sit_service), + t->service_loop_length, + pos); +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/st_section.c b/kaffeine/src/input/dvb/lib/libucsi/dvb/st_section.c new file mode 100644 index 0000000..0e60aa1 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/st_section.c @@ -0,0 +1,29 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include <libucsi/dvb/st_section.h> + +struct dvb_st_section * dvb_st_section_codec(struct section * section) +{ + struct dvb_st_section * ret = (struct dvb_st_section *)section; + + return ret; +} diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/st_section.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/st_section.h new file mode 100644 index 0000000..52ba888 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/st_section.h @@ -0,0 +1,77 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_DVB_ST_SECTION_H +#define _UCSI_DVB_ST_SECTION_H 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/section.h> + +/** + * dvb_st_section structure. + */ +struct dvb_st_section { + struct section head; + + /* uint8_t data[] */ +}; + +/** + * Process a dvb_st_section. + * + * @param section Generic section header. + * @return dvb_st_section pointer, or NULL on error. + */ +struct dvb_st_section *dvb_st_section_codec(struct section *section); + +/** + * Accessor for data field of dvb_st_section. + * + * @param st dvb_st_section Pointer. + * @return Pointer to field. + */ +static inline uint8_t* + dvb_st_section_data(struct dvb_st_section* st) +{ + return (uint8_t*) st + sizeof(struct dvb_st_section); +} + +/** + * Calculate length of data field of dvb_st_section. + * + * @param st dvb_st_section Pointer. + * @return Length in bytes. + */ +static inline int + dvb_st_section_data_length(struct dvb_st_section* st) +{ + return st->head.length; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/stream_identifier_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/stream_identifier_descriptor.h new file mode 100644 index 0000000..262c7e2 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/stream_identifier_descriptor.h @@ -0,0 +1,61 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_DVB_STREAM_IDENTIFIER_DESCRIPTOR +#define _UCSI_DVB_STREAM_IDENTIFIER_DESCRIPTOR 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/descriptor.h> +#include <libucsi/endianops.h> + +/** + * dvb_stream_identifier_descriptor structure. + */ +struct dvb_stream_identifier_descriptor { + struct descriptor d; + + uint8_t component_tag; +} __ucsi_packed; + +/** + * Process a dvb_stream_identifier_descriptor. + * + * @param d Pointer to generic descriptor structure. + * @return dvb_stream_identifier_descriptor pointer, or NULL on error. + */ +static inline struct dvb_stream_identifier_descriptor* + dvb_stream_identifier_descriptor_codec(struct descriptor* d) +{ + if (d->len != (sizeof(struct dvb_stream_identifier_descriptor) - 2)) + return NULL; + + return (struct dvb_stream_identifier_descriptor*) d; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/stuffing_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/stuffing_descriptor.h new file mode 100644 index 0000000..48e415d --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/stuffing_descriptor.h @@ -0,0 +1,82 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_DVB_STUFFING_DESCRIPTOR +#define _UCSI_DVB_STUFFING_DESCRIPTOR 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/descriptor.h> +#include <libucsi/endianops.h> + +/** + * dvb_stuffing_descriptor. + */ +struct dvb_stuffing_descriptor { + struct descriptor d; + + /* uint8_t data[] */ +} __ucsi_packed; + +/** + * Process a dvb_stuffing_descriptor. + * + * @param d Generic descriptor structure. + * @return dvb_stuffing_descriptor pointer, or NULL on error. + */ +static inline struct dvb_stuffing_descriptor* + dvb_stuffing_descriptor_codec(struct descriptor* d) +{ + return (struct dvb_stuffing_descriptor*) d; +} + +/** + * Retrieve a pointer to the data field of a dvb_stuffing_descriptor. + * + * @param d dvb_stuffing_descriptor pointer. + * @return Pointer to the field. + */ +static inline uint8_t * + dvb_stuffing_descriptor_data(struct dvb_stuffing_descriptor *d) +{ + return (uint8_t *) d + sizeof(struct dvb_stuffing_descriptor); +} + +/** + * Calculate length of the data field of a dvb_stuffing_descriptor. + * + * @param d dvb_stuffing_descriptor pointer. + * @return The length in bytes. + */ +static inline int + dvb_stuffing_descriptor_data_length(struct dvb_stuffing_descriptor *d) +{ + return d->d.len; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/subtitling_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/subtitling_descriptor.h new file mode 100644 index 0000000..74fc25a --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/subtitling_descriptor.h @@ -0,0 +1,126 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_DVB_SUBTITLING_DESCRIPTOR +#define _UCSI_DVB_SUBTITLING_DESCRIPTOR 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/descriptor.h> +#include <libucsi/endianops.h> +#include <libucsi/types.h> + +/** + * dvb_subtitling_descriptor structure. + */ +struct dvb_subtitling_descriptor { + struct descriptor d; + + /* struct dvb_subtitling_entry subtitles[] */ +} __ucsi_packed; + +/** + * An entry in the subtitles field of the a dvb_subtitling_descriptor. + */ +struct dvb_subtitling_entry { + iso639lang_t language_code; + uint8_t subtitling_type; + uint16_t composition_page_id; + uint16_t ancillary_page_id; +} __ucsi_packed; + +/** + * Process a dvb_subtitling_descriptor. + * + * @param d Generic descriptor. + * @return dvb_subtitling_descriptor pointer, or NULL on error. + */ +static inline struct dvb_subtitling_descriptor* + dvb_subtitling_descriptor_codec(struct descriptor* d) +{ + uint32_t pos = 0; + uint8_t* ptr = (uint8_t*) d + 2; + uint32_t len = d->len; + + if (len % sizeof(struct dvb_subtitling_entry)) + return NULL; + + while(pos < len) { + bswap16(ptr+pos+4); + bswap16(ptr+pos+6); + pos += sizeof(struct dvb_subtitling_entry); + } + + return (struct dvb_subtitling_descriptor*) d; +} + +/** + * Iterator for subtitles field in dvb_subtitling_descriptor. + * + * @param d dvb_subtitling_descriptor pointer. + * @param pos Variable containing a pointer to current dvb_subtitling_entry. + */ +#define dvb_subtitling_descriptor_subtitles_for_each(d, pos) \ + for ((pos) = dvb_subtitling_descriptor_subtitles_first(d); \ + (pos); \ + (pos) = dvb_subtitling_descriptor_subtitles_next(d, pos)) + + + + + + + + + + +/******************************** PRIVATE CODE ********************************/ +static inline struct dvb_subtitling_entry* + dvb_subtitling_descriptor_subtitles_first(struct dvb_subtitling_descriptor *d) +{ + if (d->d.len == 0) + return NULL; + + return (struct dvb_subtitling_entry *) + ((uint8_t*) d + sizeof(struct dvb_subtitling_descriptor)); +} + +static inline struct dvb_subtitling_entry* + dvb_subtitling_descriptor_subtitles_next(struct dvb_subtitling_descriptor *d, + struct dvb_subtitling_entry *pos) +{ + uint8_t *end = (uint8_t*) d + 2 + d->d.len; + uint8_t *next = (uint8_t *) pos + sizeof(struct dvb_subtitling_entry); + + if (next >= end) + return NULL; + + return (struct dvb_subtitling_entry *) next; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/tdt_section.c b/kaffeine/src/input/dvb/lib/libucsi/dvb/tdt_section.c new file mode 100644 index 0000000..30a23cf --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/tdt_section.c @@ -0,0 +1,33 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include <libucsi/dvb/tdt_section.h> + +struct dvb_tdt_section * dvb_tdt_section_codec(struct section * section) +{ + int len = section->length + sizeof(struct section); + struct dvb_tdt_section * ret = (struct dvb_tdt_section *) section; + + if (len != sizeof(struct dvb_tdt_section)) + return NULL; + + return ret; +} diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/tdt_section.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/tdt_section.h new file mode 100644 index 0000000..fc2bcb8 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/tdt_section.h @@ -0,0 +1,54 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_DVB_TDT_SECTION_H +#define _UCSI_DVB_TDT_SECTION_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/section.h> +#include <libucsi/dvb/types.h> + +/** + * dvb_tdt_section structure. + */ +struct dvb_tdt_section { + struct section head; + + dvbdate_t utc_time; +} __ucsi_packed; + +/** + * Process a dvb_tdt_section. + * + * @param section Generic section header. + * @return dvb_tdt_section pointer, or NULL on error. + */ +struct dvb_tdt_section *dvb_tdt_section_codec(struct section *section); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/telephone_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/telephone_descriptor.h new file mode 100644 index 0000000..46b39e4 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/telephone_descriptor.h @@ -0,0 +1,150 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_DVB_TELEPHONE_DESCRIPTOR +#define _UCSI_DVB_TELEPHONE_DESCRIPTOR 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/descriptor.h> +#include <libucsi/endianops.h> + +/** + * dvb_telephone_descriptor stucture. + */ +struct dvb_telephone_descriptor { + struct descriptor d; + + EBIT3(uint8_t reserved_1 : 2; , + uint8_t foreign_availability : 1; , + uint8_t connection_type : 5; ) + EBIT4(uint8_t reserved_2 : 1; , + uint8_t country_prefix_length : 2; , + uint8_t international_area_code_length : 3; , + uint8_t operator_code_length : 2; ) + EBIT3(uint8_t reserved_3 : 1; , + uint8_t national_area_code_length : 3; , + uint8_t core_number_length : 4; ) + /* uint8_t country_prefix[] */ + /* uint8_t international_area_code[] */ + /* uint8_t operator_code[] */ + /* uint8_t national_area_code[] */ + /* uint8_t core_number[] */ +} __ucsi_packed; + + +/** + * Process a dvb_telephone_descriptor. + * + * @param d Generic descriptor. + * @return dvb_telephone_descriptor pointer, or NULL on error. + */ +static inline struct dvb_telephone_descriptor* + dvb_telephone_descriptor_codec(struct descriptor* d) +{ + struct dvb_telephone_descriptor* p = + (struct dvb_telephone_descriptor*) d; + uint32_t pos = sizeof(struct dvb_telephone_descriptor) - 2; + uint32_t len = d->len; + + if (pos > len) + return NULL; + + pos += p->country_prefix_length + + p->international_area_code_length + + p->operator_code_length + + p->national_area_code_length + + p->core_number_length; + + if (pos != len) + return NULL; + + return p; +} + +/** + * Retrieve pointer to country_prefix field of a dvb_telephone_descriptor. + * + * @param d dvb_telephone_descriptor pointer. + * @return Pointer to the field. + */ +static inline uint8_t* + dvb_telephone_descriptor_country_prefix(struct dvb_telephone_descriptor* d) +{ + return (uint8_t*) d + sizeof(struct dvb_telephone_descriptor); +} + +/** + * Retrieve pointer to international_area_code field of a dvb_telephone_descriptor. + * + * @param d dvb_telephone_descriptor pointer. + * @return Pointer to the field. + */ +static inline uint8_t* + dvb_telephone_descriptor_international_area_code(struct dvb_telephone_descriptor* d) +{ + return dvb_telephone_descriptor_country_prefix(d) + d->country_prefix_length; +} + +/** + * Retrieve pointer to operator_code field of a dvb_telephone_descriptor. + * + * @param d dvb_telephone_descriptor pointer. + * @return Pointer to the field. + */ +static inline uint8_t* + dvb_telephone_descriptor_operator_code(struct dvb_telephone_descriptor* d) +{ + return dvb_telephone_descriptor_international_area_code(d) + d->international_area_code_length; +} + +/** + * Retrieve pointer to national_area_code field of a dvb_telephone_descriptor. + * + * @param d dvb_telephone_descriptor pointer. + * @return Pointer to the field. + */ +static inline uint8_t* + dvb_telephone_descriptor_national_area_code(struct dvb_telephone_descriptor* d) +{ + return dvb_telephone_descriptor_operator_code(d) + d->operator_code_length; +} + +/** + * Retrieve pointer to core_number field of a dvb_telephone_descriptor. + * + * @param d dvb_telephone_descriptor pointer. + * @return Pointer to the field. + */ +static inline uint8_t* + dvb_telephone_descriptor_core_number(struct dvb_telephone_descriptor* d) +{ + return dvb_telephone_descriptor_national_area_code(d) + d->national_area_code_length; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/teletext_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/teletext_descriptor.h new file mode 100644 index 0000000..280b6eb --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/teletext_descriptor.h @@ -0,0 +1,127 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_DVB_TELETEXT_DESCRIPTOR +#define _UCSI_DVB_TELETEXT_DESCRIPTOR 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/descriptor.h> +#include <libucsi/endianops.h> +#include <libucsi/types.h> + +/** + * Possible values for the type field. + */ +enum { + DVB_TELETEXT_TYPE_INITIAL = 0x01, + DVB_TELETEXT_TYPE_SUBTITLE = 0x02, + DVB_TELETEXT_TYPE_ADDITIONAL = 0x03, + DVB_TELETEXT_TYPE_SCHEDULE = 0x04, + DVB_TELETEXT_TYPE_SUBTITLE_HEARING_IMPAIRED= 0x05 +}; + +/** + * dvb_teletext_descriptor structure. + */ +struct dvb_teletext_descriptor { + struct descriptor d; + + /* struct dvb_teletext_entry entries[] */ +} __ucsi_packed; + +/** + * An entry in the entries field of a dvb_teletext_descriptor. + */ +struct dvb_teletext_entry { + iso639lang_t language_code; + EBIT2(uint8_t type : 5; , + uint8_t magazine_number: 3; ) + uint8_t page_number; +} __ucsi_packed; + +/** + * Process a dvb_teletext_descriptor. + * + * @param d Generic descriptor. + * @return dvb_teletext_descriptor pointer, or NULL on error. + */ +static inline struct dvb_teletext_descriptor* + dvb_teletext_descriptor_codec(struct descriptor* d) +{ + if (d->len % sizeof(struct dvb_teletext_entry)) + return NULL; + + return (struct dvb_teletext_descriptor*) d; +} + +/** + * Iterator for entries field of a dvb_teletext_descriptor. + * + * @param d dvb_teletext_descriptor pointer. + * @param pos Variable holding a pointer to the current dvb_teletext_entry. + */ +#define dvb_teletext_descriptor_entries_for_each(d, pos) \ + for ((pos) = dvb_teletext_descriptor_entries_first(d); \ + (pos); \ + (pos) = dvb_teletext_descriptor_entries_next(d, pos)) + + + + + + + + + + +/******************************** PRIVATE CODE ********************************/ +static inline struct dvb_teletext_entry* + dvb_teletext_descriptor_entries_first(struct dvb_teletext_descriptor *d) +{ + if (d->d.len == 0) + return NULL; + + return (struct dvb_teletext_entry *) + ((uint8_t*) d + sizeof(struct dvb_teletext_descriptor)); +} + +static inline struct dvb_teletext_entry* + dvb_teletext_descriptor_entries_next(struct dvb_teletext_descriptor *d, + struct dvb_teletext_entry *pos) +{ + uint8_t *end = (uint8_t*) d + 2 + d->d.len; + uint8_t *next = (uint8_t *) pos + sizeof(struct dvb_teletext_entry); + + if (next >= end) + return NULL; + + return (struct dvb_teletext_entry *) next; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/terrestrial_delivery_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/terrestrial_delivery_descriptor.h new file mode 100644 index 0000000..b890178 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/terrestrial_delivery_descriptor.h @@ -0,0 +1,77 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_DVB_TERRESTRIAL_DELIVERY_DESCRIPTOR +#define _UCSI_DVB_TERRESTRIAL_DELIVERY_DESCRIPTOR 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/descriptor.h> +#include <libucsi/endianops.h> + +/** + * dvb_terrestrial_delivery_descriptor structure. + */ +struct dvb_terrestrial_delivery_descriptor { + struct descriptor d; + + uint32_t centre_frequency; // Normal integer, units 10Hz + EBIT5(uint8_t bandwidth : 3; , + uint8_t priority : 1; , + uint8_t time_slicing_indicator : 1; , + uint8_t mpe_fec_indicator : 1; , + uint8_t reserved_1 : 2; ) + EBIT3(uint8_t constellation : 2; , + uint8_t hierarchy_information : 3; , + uint8_t code_rate_hp_stream : 3; ) + EBIT4(uint8_t code_rate_lp_stream : 3; , + uint8_t guard_interval : 2; , + uint8_t transmission_mode : 2; , + uint8_t other_frequency_flag : 1; ) + uint32_t reserved_2; +} __ucsi_packed; + +/** + * Process a dvb_terrestrial_delivery_descriptor. + * + * @param d Generic descriptor structure. + * @return dvb_terrestrial_delivery_descriptor pointer, or NULL on error. + */ +static inline struct dvb_terrestrial_delivery_descriptor* + dvb_terrestrial_delivery_descriptor_codec(struct descriptor* d) +{ + if (d->len != (sizeof(struct dvb_terrestrial_delivery_descriptor) - 2)) + return NULL; + + bswap32((uint8_t*) d + 2); + bswap32((uint8_t*) d + 9); + + return (struct dvb_terrestrial_delivery_descriptor*) d; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/time_shifted_event_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/time_shifted_event_descriptor.h new file mode 100644 index 0000000..6b4a9f6 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/time_shifted_event_descriptor.h @@ -0,0 +1,65 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_DVB_TIME_SHIFTED_EVENT_DESCRIPTOR +#define _UCSI_DVB_TIME_SHIFTED_EVENT_DESCRIPTOR 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/descriptor.h> +#include <libucsi/endianops.h> + +/** + * dvb_time_shifted_event_descriptor structure. + */ +struct dvb_time_shifted_event_descriptor { + struct descriptor d; + + uint16_t reference_service_id; + uint16_t reference_event_id; +} __ucsi_packed; + +/** + * Process a dvb_time_shifted_event_descriptor. + * + * @param d Generic descriptor. + * @return dvb_time_shifted_event_descriptor pointer, or NULL on error. + */ +static inline struct dvb_time_shifted_event_descriptor* + dvb_time_shifted_event_descriptor_codec(struct descriptor* d) +{ + if (d->len != (sizeof(struct dvb_time_shifted_event_descriptor) - 2)) + return NULL; + + bswap16((uint8_t*) d + 2); + bswap16((uint8_t*) d + 4); + + return (struct dvb_time_shifted_event_descriptor*) d; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/time_shifted_service_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/time_shifted_service_descriptor.h new file mode 100644 index 0000000..c8dcc0e --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/time_shifted_service_descriptor.h @@ -0,0 +1,63 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_DVB_TIME_SHIFTED_SERVICE_DESCRIPTOR +#define _UCSI_DVB_TIME_SHIFTED_SERVICE_DESCRIPTOR 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/descriptor.h> +#include <libucsi/endianops.h> + +/** + * dvb_time_shifted_service_descriptor structure. + */ +struct dvb_time_shifted_service_descriptor { + struct descriptor d; + + uint16_t reference_service_id; +} __ucsi_packed; + +/** + * Process a dvb_time_shifted_service_descriptor. + * + * @param d Generic descriptor. + * @return Pointer to dvb_time_shifted_service_descriptor, or NULL on error. + */ +static inline struct dvb_time_shifted_service_descriptor* + dvb_time_shifted_service_descriptor_codec(struct descriptor* d) +{ + if (d->len != (sizeof(struct dvb_time_shifted_service_descriptor) - 2)) + return NULL; + + bswap16((uint8_t*) d + 2); + + return (struct dvb_time_shifted_service_descriptor*) d; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/tot_section.c b/kaffeine/src/input/dvb/lib/libucsi/dvb/tot_section.c new file mode 100644 index 0000000..3ce2c6d --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/tot_section.c @@ -0,0 +1,50 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include <libucsi/dvb/tot_section.h> + +struct dvb_tot_section *dvb_tot_section_codec(struct section *section) +{ + uint8_t * buf = (uint8_t *)section; + int pos = sizeof(struct section); + int len = section->length + sizeof(struct section) - CRC_SIZE; + struct dvb_tot_section * ret = (struct dvb_tot_section *)section; + + if (len < sizeof(struct dvb_tot_section)) + return NULL; + + pos += 5; + bswap16(buf + pos); + pos += 2; + + if ((pos + ret->descriptors_loop_length) > len) + return NULL; + + if (verify_descriptors(buf + pos, ret->descriptors_loop_length)) + return NULL; + + pos += ret->descriptors_loop_length; + + if (pos != len) + return NULL; + + return ret; +} diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/tot_section.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/tot_section.h new file mode 100644 index 0000000..3474da1 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/tot_section.h @@ -0,0 +1,97 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_DVB_TOT_SECTION_H +#define _UCSI_DVB_TOT_SECTION_H 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/section.h> +#include <libucsi/dvb/types.h> + +/** + * dvb_tot_section structure. + */ +struct dvb_tot_section { + struct section head; + + dvbdate_t utc_time; + EBIT2(uint16_t reserved : 4; , + uint16_t descriptors_loop_length:12; ); + /* struct descriptor descriptors[] */ +} __ucsi_packed; + +/** + * Process a dvb_tot_section. + * + * @param section Pointer to generic section structure. + * @return dvb_tot_section pointer, or NULL on error. + */ +struct dvb_tot_section * dvb_tot_section_codec(struct section *section); + +/** + * Iterator for descriptors field of dvb_tot_section. + * + * @param tot dvb_tot_section pointer. + * @param pos Variable holding a pointer to the current descriptor. + */ +#define dvb_tot_section_descriptors_for_each(tot, pos) \ + for ((pos) = dvb_tot_section_descriptors_first(tot); \ + (pos); \ + (pos) = dvb_tot_section_descriptors_next(tot, pos)) + + + + + + + + + + +/******************************** PRIVATE CODE ********************************/ +static inline struct descriptor * + dvb_tot_section_descriptors_first(struct dvb_tot_section * tot) +{ + if (tot->descriptors_loop_length == 0) + return NULL; + + return (struct descriptor *) + ((uint8_t *) tot + sizeof(struct dvb_tot_section)); +} + +static inline struct descriptor * + dvb_tot_section_descriptors_next(struct dvb_tot_section *tot, + struct descriptor* pos) +{ + return next_descriptor((uint8_t *) tot + sizeof(struct dvb_tot_section), + tot->descriptors_loop_length, + pos); +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/transport_stream_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/transport_stream_descriptor.h new file mode 100644 index 0000000..1797ec5 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/transport_stream_descriptor.h @@ -0,0 +1,82 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_DVB_TRANSPORT_STREAM_DESCRIPTOR +#define _UCSI_DVB_TRANSPORT_STREAM_DESCRIPTOR 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/descriptor.h> +#include <libucsi/endianops.h> + +/** + * dvb_transport_stream_descriptor structure. + */ +struct dvb_transport_stream_descriptor { + struct descriptor d; + + /* uint8_t data[] */ +} __ucsi_packed; + +/** + * Process dvb_transport_stream_descriptor structure. + * + * @param d Pointer to generic descriptor. + * @return dvb_transport_stream_descriptor structure or NULL on error. + */ +static inline struct dvb_transport_stream_descriptor* + dvb_transport_stream_descriptor_codec(struct descriptor* d) +{ + return (struct dvb_transport_stream_descriptor*) d; +} + +/** + * Retrieve a pointer to the data field of a dvb_transport_stream_descriptor. + * + * @param d dvb_transport_stream_descriptor structure. + * @return Pointer to data field. + */ +static inline uint8_t * + dvb_transport_stream_descriptor_data(struct dvb_transport_stream_descriptor *d) +{ + return (uint8_t *) d + sizeof(struct dvb_transport_stream_descriptor); +} + +/** + * Calculate the length of the data field of a dvb_transport_stream_descriptor. + * + * @param d dvb_transport_stream_descriptor structure. + * @return length of data field in bytes. + */ +static inline int + dvb_transport_stream_descriptor_data_length(struct dvb_transport_stream_descriptor *d) +{ + return d->d.len; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/tva_container_section.c b/kaffeine/src/input/dvb/lib/libucsi/dvb/tva_container_section.c new file mode 100644 index 0000000..32a5795 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/tva_container_section.c @@ -0,0 +1,33 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include <libucsi/dvb/tva_container_section.h> + +struct dvb_tva_container_section *dvb_tva_container_section_codec(struct section_ext *ext) +{ + int len = section_ext_length(ext); + struct dvb_tva_container_section* ret = (struct dvb_tva_container_section*) ext; + + if (len < sizeof(struct dvb_tva_container_section)) + return NULL; + + return ret; +} diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/tva_container_section.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/tva_container_section.h new file mode 100644 index 0000000..6519ded --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/tva_container_section.h @@ -0,0 +1,90 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_DVB_TVA_CONTAINER_SECTION_H +#define _UCSI_DVB_TVA_CONTAINER_SECTION_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/section.h> +#include <libucsi/dvb/types.h> + +/** + * dvb_tva_container_section structure. + */ +struct dvb_tva_container_section { + struct section_ext head; + + /* uint8_t data[] */ +} __ucsi_packed; + +/** + * Process a dvb_tva_container_section. + * + * @param section Generic section header. + * @return dvb_tdt_section pointer, or NULL on error. + */ +struct dvb_tva_container_section *dvb_tva_container_section_codec(struct section_ext *ext); + +/** + * Accessor for the container_id field of a tva container section. + * + * @param container dvb_tva_container_section pointer. + * @return The container_id. + */ +static inline uint16_t dvb_tva_container_section_container_id(struct dvb_tva_container_section *container) +{ + return container->head.table_id_ext; +} + +/** + * Accessor for the selector_byte field of a dvb_data_broadcast_id_descriptor. + * + * @param d dvb_data_broadcast_id_descriptor pointer. + * @return Pointer to the field. + */ +static inline uint8_t * +dvb_tva_container_section_data(struct dvb_tva_container_section *s) +{ + return (uint8_t *) s + sizeof(struct dvb_tva_container_section); +} + +/** + * Determine the number of bytes in the data field of a dvb_tva_container_section. + * + * @param d dvb_tva_container_section pointer. + * @return Length of the field in bytes. + */ +static inline int +dvb_tva_container_section_data_length(struct dvb_tva_container_section *s) +{ + return section_ext_length(&s->head) - sizeof(struct dvb_tva_container_section); +} + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/tva_id_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/tva_id_descriptor.h new file mode 100644 index 0000000..c830259 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/tva_id_descriptor.h @@ -0,0 +1,124 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_DVB_TVA_ID_DESCRIPTOR +#define _UCSI_DVB_TVA_ID_DESCRIPTOR 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/descriptor.h> +#include <libucsi/endianops.h> + +/** + * dvb_tva_id_descriptor structure. + */ +struct dvb_tva_id_descriptor { + struct descriptor d; + + /* struct dvb_tva_id_entry entries[] */ +} __ucsi_packed; + +/** + * An entry in the entries field of a dvb_tva_id_descriptor. + */ +struct dvb_tva_id_entry { + uint16_t tva_id; + EBIT2(uint8_t reserved : 5; , + uint8_t running_status : 3; ) +} __ucsi_packed; + +/** + * Process a dvb_tva_id_descriptor. + * + * @param d Generic descriptor pointer. + * @return dvb_tva_id_descriptor pointer, or NULL on error. + */ +static inline struct dvb_tva_id_descriptor* + dvb_tva_id_descriptor_codec(struct descriptor* d) +{ + uint32_t pos = 0; + uint32_t len = d->len; + uint8_t* buf = (uint8_t*) d + 2; + + pos += sizeof(struct dvb_tva_id_descriptor) - 2; + if (len % sizeof(struct dvb_tva_id_entry)) + return NULL; + + while(pos < len) { + bswap16(buf+pos); + pos+=3; + } + + return (struct dvb_tva_id_descriptor*) d; +} + +/** + * Iterator for the entries field of a dvb_tva_id_descriptor. + * + * @param d dvb_tva_id_descriptor pointer. + * @param pos Variable containing a pointer to the current dvb_tva_id_entry. + */ +#define dvb_tva_id_descriptor_entries_for_each(d, pos) \ + for ((pos) = dvb_tva_id_descriptor_entries_first(d); \ + (pos); \ + (pos) = dvb_tva_id_descriptor_entries_next(d, pos)) + + + + + + + + + + +/******************************** PRIVATE CODE ********************************/ +static inline struct dvb_tva_id_entry* + dvb_tva_id_descriptor_entries_first(struct dvb_tva_id_descriptor *d) +{ + if (d->d.len == 0) + return NULL; + + return (struct dvb_tva_id_entry *) + ((uint8_t*) d + sizeof(struct dvb_tva_id_descriptor)); +} + +static inline struct dvb_tva_id_entry* + dvb_tva_id_descriptor_countries_next(struct dvb_tva_id_descriptor *d, + struct dvb_tva_id_entry *pos) +{ + uint8_t *end = (uint8_t*) d + 2 + d->d.len; + uint8_t *next = (uint8_t *) pos + sizeof(struct dvb_tva_id_entry); + + if (next >= end) + return NULL; + + return (struct dvb_tva_id_entry *) next; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/types.c b/kaffeine/src/input/dvb/lib/libucsi/dvb/types.c new file mode 100644 index 0000000..c1cf583 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/types.c @@ -0,0 +1,270 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include <string.h> +#include "types.h" + +time_t dvbdate_to_unixtime(dvbdate_t dvbdate) +{ + int k = 0; + struct tm tm; + double mjd; + + /* check for the undefined value */ + if ((dvbdate[0] == 0xff) && + (dvbdate[1] == 0xff) && + (dvbdate[2] == 0xff) && + (dvbdate[3] == 0xff) && + (dvbdate[4] == 0xff)) { + return -1; + } + + memset(&tm, 0, sizeof(tm)); + mjd = (dvbdate[0] << 8) | dvbdate[1]; + + tm.tm_year = (int) ((mjd - 15078.2) / 365.25); + tm.tm_mon = (int) (((mjd - 14956.1) - (int) (tm.tm_year * 365.25)) / 30.6001); + tm.tm_mday = (int) mjd - 14956 - (int) (tm.tm_year * 365.25) - (int) (tm.tm_mon * 30.6001); + if ((tm.tm_mon == 14) || (tm.tm_mon == 15)) k = 1; + tm.tm_year += k; + tm.tm_mon = tm.tm_mon - 2 - k * 12; + tm.tm_sec = bcd_to_integer(dvbdate[4]); + tm.tm_min = bcd_to_integer(dvbdate[3]); + tm.tm_hour = bcd_to_integer(dvbdate[2]); + + return mktime(&tm); +} + +void unixtime_to_dvbdate(time_t unixtime, dvbdate_t dvbdate) +{ + struct tm tm; + double l = 0; + int mjd; + + /* the undefined value */ + if (unixtime == -1) { + memset(dvbdate, 0xff, 5); + return; + } + + gmtime_r(&unixtime, &tm); + tm.tm_mon++; + if ((tm.tm_mon == 1) || (tm.tm_mon == 2)) l = 1; + mjd = 14956 + tm.tm_mday + (int) ((tm.tm_year - l) * 365.25) + (int) ((tm.tm_mon + 1 + l * 12) * 30.6001); + + dvbdate[0] = (mjd & 0xff00) >> 8; + dvbdate[1] = mjd & 0xff; + dvbdate[2] = integer_to_bcd(tm.tm_hour); + dvbdate[3] = integer_to_bcd(tm.tm_min); + dvbdate[4] = integer_to_bcd(tm.tm_sec); +} + +int dvbduration_to_seconds(dvbduration_t dvbduration) +{ + int seconds = 0; + + seconds += (bcd_to_integer(dvbduration[0]) * 60 * 60); + seconds += (bcd_to_integer(dvbduration[1]) * 60); + seconds += bcd_to_integer(dvbduration[2]); + + return seconds; +} + +void seconds_to_dvbduration(int seconds, dvbduration_t dvbduration) +{ + int hours, mins; + + hours = seconds / (60*60); + seconds -= (hours * 60 * 60); + mins = seconds / 60; + seconds -= (mins * 60); + + dvbduration[0] = integer_to_bcd(hours); + dvbduration[1] = integer_to_bcd(mins); + dvbduration[2] = integer_to_bcd(seconds); +} + +int dvbhhmm_to_seconds(dvbhhmm_t dvbhhmm) +{ + int seconds = 0; + + seconds += (bcd_to_integer(dvbhhmm[0]) * 60 * 60); + seconds += (bcd_to_integer(dvbhhmm[1]) * 60); + + return seconds; +} + +void seconds_to_dvbhhmm(int seconds, dvbhhmm_t dvbhhmm) +{ + int hours, mins; + + hours = seconds / (60*60); + seconds -= (hours * 60 * 60); + mins = seconds / 60; + + dvbhhmm[0] = integer_to_bcd(hours); + dvbhhmm[1] = integer_to_bcd(mins); +} + +uint32_t integer_to_bcd(uint32_t intval) +{ + uint32_t val = 0; + + int i; + for(i=0; i<=28;i+=4) { + val |= ((intval % 10) << i); + intval /= 10; + } + + return val; +} + +uint32_t bcd_to_integer(uint32_t bcdval) +{ + uint32_t val = 0; + + int i; + for(i=28; i>=0;i-=4) { + val += ((bcdval >> i) & 0x0f); + if (i != 0) val *= 10; + } + + return val; +} + +const char *dvb_charset(char *dvb_text, int dvb_text_length, int *consumed) +{ + char *charset = "ISO6937"; + int used = 0; + + if (dvb_text_length == 0) + goto exit; + if (dvb_text[0] >= 32) + goto exit; + if (dvb_text[0] == 0x10) { + if (dvb_text_length < 3) + goto exit; + + used = 3; + uint16_t ext = (dvb_text[1] << 8) | dvb_text[2]; + switch(ext) { + case 0x01: + charset = "ISO8859-1"; + break; + case 0x02: + charset = "ISO8859-2"; + break; + case 0x03: + charset = "ISO8859-3"; + break; + case 0x04: + charset = "ISO8859-4"; + break; + case 0x05: + charset = "ISO8859-5"; + break; + case 0x06: + charset = "ISO8859-6"; + break; + case 0x07: + charset = "ISO8859-7"; + break; + case 0x08: + charset = "ISO8859-8"; + break; + case 0x09: + charset = "ISO8859-9"; + break; + case 0x0a: + charset = "ISO8859-10"; + break; + case 0x0b: + charset = "ISO8859-11"; + break; + case 0x0d: + charset = "ISO8859-13"; + break; + case 0x0e: + charset = "ISO8859-14"; + break; + case 0x0f: + charset = "ISO8859-15"; + break; + default: + used = 0; + break; + } + } else { + used = 1; + switch(dvb_text[0]) { + case 0x01: + charset = "ISO8859-5"; + break; + case 0x02: + charset = "ISO8859-6"; + break; + case 0x03: + charset = "ISO8859-7"; + break; + case 0x04: + charset = "ISO8859-8"; + break; + case 0x05: + charset = "ISO8859-9"; + break; + case 0x06: + charset = "ISO8859-10"; + break; + case 0x07: + charset = "ISO8859-11"; + break; + case 0x09: + charset = "ISO8859-13"; + break; + case 0x0a: + charset = "ISO8859-14"; + break; + case 0x0b: + charset = "ISO8859-15"; + break; + case 0x11: + charset = "UTF16"; + break; + case 0x12: + charset = "EUC-KR"; + break; + case 0x13: + charset = "GB2312"; + break; + case 0x14: + charset = "GBK"; + break; + case 0x15: + charset = "UTF8"; + break; + default: + used = 0; + break; + } + } +exit: + *consumed = used; + return charset; +} diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/types.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/types.h new file mode 100644 index 0000000..f26ea6b --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/types.h @@ -0,0 +1,127 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_DVB_TYPES_H +#define _UCSI_DVB_TYPES_H 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <stdint.h> +#include <time.h> + +typedef uint8_t dvbdate_t[5]; +typedef uint8_t dvbduration_t[3]; +typedef uint8_t dvbhhmm_t[2]; + +/** + * Running status values. + */ +enum { + DVB_RUNNING_STATUS_NOT_RUNNING = 0x01, + DVB_RUNNING_STATUS_FEW_SECONDS = 0x02, + DVB_RUNNING_STATUS_PAUSING = 0x03, + DVB_RUNNING_STATUS_RUNNING = 0x04 +}; + +/** + * Convert from a 5 byte DVB UTC date to unix time. + * Note: this functions expects the DVB date in network byte order. + * + * @param d Pointer to DVB date. + * @return The unix timestamp, or -1 if the dvbdate was set to the 'undefined' value + */ +extern time_t dvbdate_to_unixtime(dvbdate_t dvbdate); + +/** + * Convert from a unix timestemp to a 5 byte DVB UTC date. + * Note: this function will always output the DVB date in + * network byte order. + * + * @param unixtime The unix timestamp, or -1 for the 'undefined' value. + * @param utc Pointer to 5 byte DVB date. + */ +extern void unixtime_to_dvbdate(time_t unixtime, dvbdate_t dvbdate); + +/** + * Convert from a DVB BCD duration to a number of seconds. + * + * @param dvbduration Pointer to 3 byte DVB duration. + * @return Number of seconds. + */ +extern int dvbduration_to_seconds(dvbduration_t dvbduration); + +/** + * Convert from a number of seconds to a DVB 3 byte BCD duration. + * + * @param seconds The number of seconds. + * @param dvbduration Pointer to 3 byte DVB duration. + */ +extern void seconds_to_dvbduration(int seconds, dvbduration_t dvbduration); + +/** + * Convert from a DVB BCD HHMM to a number of seconds. + * + * @param dvbduration Pointer to 2 byte DVB HHMM. + * @return Number of seconds. + */ +extern int dvbhhmm_to_seconds(dvbhhmm_t dvbhhmm); + +/** + * Convert from a number of seconds to a DVB 2 byte BCD HHMM. + * + * @param seconds The number of seconds. + * @param dvbduration Pointer to 2 byte DVB HHMM. + */ +extern void seconds_to_dvbhhmm(int seconds, dvbhhmm_t dvbhhmm); + +/** + * Convert a __ucsi_packed BCD value into a normal integer. + * + * @param bcd The value to convert. + * @return The value. + */ +extern uint32_t bcd_to_integer(uint32_t bcd); + +/** + * Convert a normal integer into a __ucsi_packed BCD value. + * + * @param integer The value to convert. + * @return The value. + */ +extern uint32_t integer_to_bcd(uint32_t integer); + +/** + * Determine the (iconv compatable) character set of a dvb string. + * + * @param dvb_text DVB text concerned. + * @param dvb_text_length Length of text. + * @param consumed Out parameter of number of bytes used to encode the character set. + * @return Name of the character set. + */ +extern const char *dvb_charset(char *dvb_text, int dvb_text_length, int *consumed); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/vbi_data_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/vbi_data_descriptor.h new file mode 100644 index 0000000..9d41e0c --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/vbi_data_descriptor.h @@ -0,0 +1,186 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_DVB_VBI_DATA_DESCRIPTOR +#define _UCSI_DVB_VBI_DATA_DESCRIPTOR 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/descriptor.h> +#include <libucsi/endianops.h> + +/** + * Possible values for the data_service_id field. + */ +enum { + DVB_VBI_DATA_SERVICE_ID_EBU = 0x01, + DVB_VBI_DATA_SERVICE_ID_INVERTED = 0x02, + DVB_VBI_DATA_SERVICE_ID_VPS = 0x04, + DVB_VBI_DATA_SERVICE_ID_WSS = 0x05, + DVB_VBI_DATA_SERVICE_ID_CC = 0x06, + DVB_VBI_DATA_SERVICE_ID_MONO_422 = 0x07 +}; + +/** + * dvb_vbi_data_descriptor structure + */ +struct dvb_vbi_data_descriptor { + struct descriptor d; + + /* struct dvb_vbi_data_entry entries[] */ +} __ucsi_packed; + +/** + * An entry in the dvb_vbi_data_descriptor entries field. + */ +struct dvb_vbi_data_entry { + uint8_t data_service_id; + uint8_t data_length; + /* uint8_t data[] */ +} __ucsi_packed; + +/** + * Format of the dvb_vbi_data_entry data field, if data_service_id == 1,2,4,5,6,7. + */ +struct dvb_vbi_data_x { + EBIT3(uint8_t reserved : 2; , + uint8_t field_parity : 1; , + uint8_t line_offset : 5; ) +} __ucsi_packed; + +/** + * Process a dvb_vbi_data_descriptor. + * + * @param d Generic descriptor structure. + * @return dvb_vbi_data_descriptor pointer, or NULL on error. + */ +static inline struct dvb_vbi_data_descriptor* + dvb_vbi_data_descriptor_codec(struct descriptor* d) +{ + uint8_t* p = (uint8_t*) d + 2; + uint32_t pos = 0; + uint32_t len = d->len; + + while(pos < len) { + struct dvb_vbi_data_entry *e = + (struct dvb_vbi_data_entry*) (p+pos); + + pos += sizeof(struct dvb_vbi_data_entry); + + if (pos > len) + return NULL; + + pos += e->data_length; + + if (pos > len) + return NULL; + } + + return (struct dvb_vbi_data_descriptor*) d; +} + +/** + * Iterator for entries field in a dvb_vbi_data_descriptor structure. + * + * @param d Pointer to dvb_vbi_data_descriptor structure. + * @param pos Variable holding pointer to the current dvb_vbi_data_entry structure. + */ +#define dvb_vbi_data_descriptor_entries_for_each(d, pos) \ + for ((pos) = dvb_vbi_data_descriptor_entries_first(d); \ + (pos); \ + (pos) = dvb_vbi_data_descriptor_entries_next(d, pos)) + +/** + * Get a pointer to the data field of a dvb_vbi_data_entry. + * + * @param d dvb_vbi_data_entry structure. + * @return Pointer to the data field. + */ +static inline uint8_t * + dvb_vbi_data_entry_data(struct dvb_vbi_data_entry *d) +{ + return (uint8_t *) d + sizeof(struct dvb_vbi_data_entry); +} + +/** + * Get a pointer to the data field of a dvb_vbi_data_x for id 1,2,4,5,6,7. + * + * @param d dvb_vbi_data_entry structure. + * @return Pointer to the data field, or NULL if invalid + */ +static inline struct dvb_vbi_data_x* + dvb_vbi_data_entry_data_x(struct dvb_vbi_data_entry *d) +{ + switch(d->data_service_id) { + case 1: + case 2: + case 4: + case 5: + case 6: + case 7: + return (struct dvb_vbi_data_x*) ((uint8_t *) d + sizeof(struct dvb_vbi_data_entry)); + } + + return NULL; +} + + + + + + + + + + +/******************************** PRIVATE CODE ********************************/ +static inline struct dvb_vbi_data_entry* + dvb_vbi_data_descriptor_entries_first(struct dvb_vbi_data_descriptor *d) +{ + if (d->d.len == 0) + return NULL; + + return (struct dvb_vbi_data_entry *) + ((uint8_t*) d + sizeof(struct dvb_vbi_data_descriptor)); +} + +static inline struct dvb_vbi_data_entry* + dvb_vbi_data_descriptor_entries_next(struct dvb_vbi_data_descriptor *d, + struct dvb_vbi_data_entry *pos) +{ + uint8_t *end = (uint8_t*) d + 2 + d->d.len; + uint8_t *next = (uint8_t *) pos + sizeof(struct dvb_vbi_data_entry) + + pos->data_length; + + if (next >= end) + return NULL; + + return (struct dvb_vbi_data_entry *) next; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/vbi_teletext_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/vbi_teletext_descriptor.h new file mode 100644 index 0000000..6ae9791 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/vbi_teletext_descriptor.h @@ -0,0 +1,116 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_DVB_VBI_TELETEXT_DESCRIPTOR +#define _UCSI_DVB_VBI_TELETEXT_DESCRIPTOR 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/descriptor.h> +#include <libucsi/endianops.h> +#include <libucsi/types.h> + +/** + * dvb_vbi_teletext_descriptor structure + */ +struct dvb_vbi_teletext_descriptor { + struct descriptor d; + + /* struct dvb_vbi_teletext_entry entries[] */ +} __ucsi_packed; + +/** + * An entry in a dvb_vbi_teletext_descriptor structure. + */ +struct dvb_vbi_teletext_entry { + iso639lang_t language_code; + EBIT2(uint8_t type : 5; , + uint8_t magazine_number: 3; ) + uint8_t page_number; +} __ucsi_packed; + +/** + * Process an dvb_vbi_teletext_descriptor. + * + * @param d Generic descriptor. + * @return dvb_vbi_teletext_descriptor pointer, or NULL on error. + */ +static inline struct dvb_vbi_teletext_descriptor* + dvb_vbi_teletext_descriptor_codec(struct descriptor* d) +{ + if (d->len % sizeof(struct dvb_vbi_teletext_entry)) + return NULL; + + return (struct dvb_vbi_teletext_descriptor*) d; +} + +/** + * Iterator for entries field of a dvb_vbi_teletext_descriptor. + * + * @param d Pointer to dvb_vbi_teletext_descriptor. + * @param pos Variable holding a pointer to the current dvb_vbi_teletext_entry. + */ +#define dvb_vbi_teletext_descriptor_entries_for_each(d, pos) \ + for ((pos) = dvb_vbi_teletext_descriptor_entries_first(d); \ + (pos); \ + (pos) = dvb_vbi_teletext_descriptor_entries_next(d, pos)) + + + + + + + + + + +/******************************** PRIVATE CODE ********************************/ +static inline struct dvb_vbi_teletext_entry* + dvb_vbi_teletext_descriptor_entries_first(struct dvb_vbi_teletext_descriptor *d) +{ + if (d->d.len == 0) + return NULL; + + return (struct dvb_vbi_teletext_entry *) + ((uint8_t*) d + sizeof(struct dvb_vbi_teletext_descriptor)); +} + +static inline struct dvb_vbi_teletext_entry* + dvb_vbi_teletext_descriptor_entries_next(struct dvb_vbi_teletext_descriptor *d, + struct dvb_vbi_teletext_entry *pos) +{ + uint8_t *end = (uint8_t*) d + 2 + d->d.len; + uint8_t *next = (uint8_t *) pos + sizeof(struct dvb_vbi_teletext_entry); + + if (next >= end) + return NULL; + + return (struct dvb_vbi_teletext_entry *) next; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/endianops.h b/kaffeine/src/input/dvb/lib/libucsi/endianops.h new file mode 100644 index 0000000..23b418b --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/endianops.h @@ -0,0 +1,128 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_COMMON_H +#define _UCSI_COMMON_H 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <stdint.h> +#include <byteswap.h> +#include <endian.h> + +#define __ucsi_packed __attribute__((packed)) + + + + +#if __BYTE_ORDER == __BIG_ENDIAN +#define EBIT2(x1,x2) x1 x2 +#define EBIT3(x1,x2,x3) x1 x2 x3 +#define EBIT4(x1,x2,x3,x4) x1 x2 x3 x4 +#define EBIT5(x1,x2,x3,x4,x5) x1 x2 x3 x4 x5 +#define EBIT6(x1,x2,x3,x4,x5,x6) x1 x2 x3 x4 x5 x6 +#define EBIT7(x1,x2,x3,x4,x5,x6,x7) x1 x2 x3 x4 x5 x6 x7 +#define EBIT8(x1,x2,x3,x4,x5,x6,x7,x8) x1 x2 x3 x4 x5 x6 x7 x8 + +static inline void bswap16(uint8_t *buf) { + (void) buf; +} + +static inline void bswap32(uint8_t *buf) { + (void) buf; +} + +static inline void bswap64(uint8_t *buf) { + (void) buf; +} + +static inline void bswap24(uint8_t *buf) { + (void) buf; +} + +static inline void bswap40(uint8_t *buf) { + (void) buf; +} + +static inline void bswap48(uint8_t *buf) { + (void) buf; +} + +#else +#define EBIT2(x1,x2) x2 x1 +#define EBIT3(x1,x2,x3) x3 x2 x1 +#define EBIT4(x1,x2,x3,x4) x4 x3 x2 x1 +#define EBIT5(x1,x2,x3,x4,x5) x5 x4 x3 x2 x1 +#define EBIT6(x1,x2,x3,x4,x5,x6) x6 x5 x4 x3 x2 x1 +#define EBIT7(x1,x2,x3,x4,x5,x6,x7) x7 x6 x5 x4 x3 x2 x1 +#define EBIT8(x1,x2,x3,x4,x5,x6,x7,x8) x8 x7 x6 x5 x4 x3 x2 x1 + +static inline void bswap16(uint8_t * buf) { + *((uint16_t*)buf) = bswap_16((*(uint16_t*)buf)); +} + +static inline void bswap32(uint8_t * buf) { + *((uint32_t*)buf) = bswap_32((*(uint32_t*)buf)); +} + +static inline void bswap64(uint8_t * buf) { + *((uint64_t*)buf) = bswap_64((*(uint64_t*)buf)); +} + +static inline void bswap24(uint8_t * buf) { + uint8_t tmp0 = buf[0]; + + buf[0] = buf[2]; + buf[2] = tmp0; +} + +static inline void bswap40(uint8_t * buf) { + uint8_t tmp0 = buf[0]; + uint8_t tmp1 = buf[1]; + + buf[0] = buf[4]; + buf[1] = buf[3]; + buf[3] = tmp1; + buf[4] = tmp0; +} + +static inline void bswap48(uint8_t * buf) { + uint8_t tmp0 = buf[0]; + uint8_t tmp1 = buf[1]; + uint8_t tmp2 = buf[2]; + + buf[0] = buf[5]; + buf[1] = buf[4]; + buf[2] = buf[3]; + buf[3] = tmp2; + buf[4] = tmp1; + buf[5] = tmp0; +} + +#endif // __BYTE_ORDER + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/mpeg/Makefile.am b/kaffeine/src/input/dvb/lib/libucsi/mpeg/Makefile.am new file mode 100644 index 0000000..a8d0c32 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/mpeg/Makefile.am @@ -0,0 +1,12 @@ +noinst_LTLIBRARIES = libdvbmpeg.la + +INCLUDES = -I$(top_srcdir)/kaffeine/src/input/dvb/lib + +libdvbmpeg_la_SOURCES = cat_section.c \ + metadata_section.c \ + odsmt_section.c \ + pat_section.c \ + pmt_section.c \ + tsdt_section.c + +CFLAGS = -g -O2 -Wall -Wshadow -Wpointer-arith -Wstrict-prototypes -fPIC diff --git a/kaffeine/src/input/dvb/lib/libucsi/mpeg/audio_stream_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/mpeg/audio_stream_descriptor.h new file mode 100644 index 0000000..7e6ea07 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/mpeg/audio_stream_descriptor.h @@ -0,0 +1,65 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_MPEG_AUDIO_STREAM_DESCRIPTOR +#define _UCSI_MPEG_AUDIO_STREAM_DESCRIPTOR 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/descriptor.h> +#include <libucsi/endianops.h> + +/** + * mpeg_audio_stream_descriptor structure + */ +struct mpeg_audio_stream_descriptor { + struct descriptor d; + + EBIT5(uint8_t free_format_flag : 1; , + uint8_t id : 1; , + uint8_t layer : 2; , + uint8_t variable_rate_audio_indicator : 1; , + uint8_t reserved : 3; ); +} __ucsi_packed; + +/** + * Process an mpeg_audio_stream_descriptor. + * + * @param d Pointer to the generic descriptor structure. + * @return Pointer to the mpeg_audio_stream_descriptor structure, or NULL on error. + */ +static inline struct mpeg_audio_stream_descriptor* + mpeg_audio_stream_descriptor_codec(struct descriptor *d) +{ + if (d->len != (sizeof(struct mpeg_audio_stream_descriptor) - 2)) + return NULL; + + return (struct mpeg_audio_stream_descriptor*) d; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/mpeg/ca_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/mpeg/ca_descriptor.h new file mode 100644 index 0000000..88a65dd --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/mpeg/ca_descriptor.h @@ -0,0 +1,91 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_MPEG_CA_DESCRIPTOR +#define _UCSI_MPEG_CA_DESCRIPTOR 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/descriptor.h> +#include <libucsi/endianops.h> + +/** + * mpeg_ca_descriptor structure + */ +struct mpeg_ca_descriptor { + struct descriptor d; + + uint16_t ca_system_id; + EBIT2(uint16_t reserved : 3; , + uint16_t ca_pid : 13; ); + /* uint8_t data[] */ +} __ucsi_packed; + +/** + * Process an mpeg_ca_descriptor. + * + * @param d Generic descriptor. + * @return Pointer to an mpeg_ca_descriptor, or NULL on error. + */ +static inline struct mpeg_ca_descriptor* + mpeg_ca_descriptor_codec(struct descriptor* d) +{ + if (d->len < (sizeof(struct mpeg_ca_descriptor) - 2)) + return NULL; + + bswap16((uint8_t*) d + 2); + bswap16((uint8_t*) d + 4); + + return (struct mpeg_ca_descriptor*) d; +} + +/** + * Accessor for pointer to data field of an mpeg_ca_descriptor. + * + * @param d The mpeg_ca_descriptor structure. + * @return Pointer to the field. + */ +static inline uint8_t * + mpeg_ca_descriptor_data(struct mpeg_ca_descriptor *d) +{ + return (uint8_t *) d + sizeof(struct mpeg_ca_descriptor); +} + +/** + * Determine length of data field of an mpeg_ca_descriptor. + * + * @param d The mpeg_ca_descriptor structure. + * @return Length of the field in bytes. + */ +static inline int + mpeg_ca_descriptor_data_length(struct mpeg_ca_descriptor *d) +{ + return d->d.len - 4; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/mpeg/cat_section.c b/kaffeine/src/input/dvb/lib/libucsi/mpeg/cat_section.c new file mode 100644 index 0000000..c72973e --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/mpeg/cat_section.c @@ -0,0 +1,34 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include <libucsi/mpeg/cat_section.h> + +struct mpeg_cat_section * mpeg_cat_section_codec(struct section_ext * ext) +{ + uint8_t * buf = (uint8_t *)ext; + int pos = sizeof(struct section_ext); + + if (verify_descriptors(buf + pos, + section_ext_length(ext) - sizeof(struct mpeg_cat_section))) + return NULL; + + return (struct mpeg_cat_section *)ext; +} diff --git a/kaffeine/src/input/dvb/lib/libucsi/mpeg/cat_section.h b/kaffeine/src/input/dvb/lib/libucsi/mpeg/cat_section.h new file mode 100644 index 0000000..864b19e --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/mpeg/cat_section.h @@ -0,0 +1,94 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_MPEG_CAT_SECTION_H +#define _UCSI_MPEG_CAT_SECTION_H 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/section.h> + +/** + * mpeg_cat_section structure. + */ +struct mpeg_cat_section { + struct section_ext head; + + /* struct descriptor descriptors[] */ +} __ucsi_packed; + +/** + * Process an mpeg_cat_section. + * + * @param section The generic section_ext structure. + * @return Pointer to an mpeg_cat_section structure, or NULL on error. + */ +extern struct mpeg_cat_section *mpeg_cat_section_codec(struct section_ext *section); + +/** + * Convenience iterator for descriptors field of an mpeg_cat_section. + * + * @param cat The mpeg_cat_section pointer. + * @param pos Variable holding a pointer to the current descriptor. + */ +#define mpeg_cat_section_descriptors_for_each(cat, pos) \ + for ((pos) = mpeg_cat_section_descriptors_first(cat); \ + (pos); \ + (pos) = mpeg_cat_section_descriptors_next(cat, pos)) + + + + + + + + + +/******************************** PRIVATE CODE ********************************/ +static inline struct descriptor * + mpeg_cat_section_descriptors_first(struct mpeg_cat_section *cat) +{ + int pos = sizeof(struct mpeg_cat_section); + + if (pos >= section_ext_length(&cat->head)) + return NULL; + + return (struct descriptor*)((uint8_t *) cat + pos); +} + + +static inline struct descriptor * + mpeg_cat_section_descriptors_next(struct mpeg_cat_section *cat, + struct descriptor* pos) +{ + return next_descriptor((uint8_t *) cat + sizeof(struct mpeg_cat_section), + section_ext_length(&cat->head) - sizeof(struct mpeg_cat_section), + pos); +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/mpeg/content_labelling_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/mpeg/content_labelling_descriptor.h new file mode 100644 index 0000000..06738ab --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/mpeg/content_labelling_descriptor.h @@ -0,0 +1,356 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_MPEG_CONTENT_LABELLING_DESCRIPTOR +#define _UCSI_MPEG_CONTENT_LABELLING_DESCRIPTOR 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/descriptor.h> +#include <libucsi/endianops.h> + +/** + * Possible values for content_time_base_indicator. + */ +enum { + MPEG_CONTENT_TIME_BASE_STC = 0x01, + MPEG_CONTENT_TIME_BASE_NPT = 0x02, +}; + +/** + * mpeg_content_labelling_descriptor structure. + */ +struct mpeg_content_labelling_descriptor { + struct descriptor d; + + uint16_t metadata_application_format; + /* struct mpeg_content_labelling_descriptor_application_format_identifier id */ + /* struct mpeg_content_labelling_descriptor_flags flags */ + /* struct mpeg_content_labelling_descriptor_reference_id reference_id */ + /* struct mpeg_content_labelling_descriptor_time_base time_base */ + /* struct mpeg_content_labelling_descriptor_content_id content_id */ + /* struct mpeg_content_labelling_descriptor_time_base_association time_base_assoc */ + /* uint8_t private_data[] */ +} __ucsi_packed; + +/** + * id field of a content_labelling_descriptor. + */ +struct mpeg_content_labelling_descriptor_application_format_identifier { + uint32_t id; +} __ucsi_packed; + +/** + * Flags field of a content_labelling_descriptor + */ +struct mpeg_content_labelling_descriptor_flags { + EBIT3(uint8_t content_reference_id_record_flag : 1; , + uint8_t content_time_base_indicator : 4; , + uint8_t reserved : 3; ); +} __ucsi_packed; + +/** + * Reference_id field of a content_labelling_descriptor. + */ +struct mpeg_content_labelling_descriptor_reference_id { + uint8_t content_reference_id_record_length; + /* uint8_t data[] */ +} __ucsi_packed; + +/** + * time_base field of a content_labelling_descriptor. + */ +struct mpeg_content_labelling_descriptor_time_base { + EBIT2(uint64_t reserved_1 : 7; , + uint64_t content_time_base_value :33; ); + EBIT2(uint64_t reserved_2 : 7; , + uint64_t metadata_time_base_value :33; ); +} __ucsi_packed; + +/** + * content_id field of a content_labelling_descriptor. + */ +struct mpeg_content_labelling_descriptor_content_id { + EBIT2(uint8_t reserved : 1; , + uint8_t contentId : 7; ); +} __ucsi_packed; + +/** + * time_base_assoc field of a content_labelling_descriptor. + */ +struct mpeg_content_labelling_descriptor_time_base_association { + uint8_t time_base_association_data_length; + /* uint8_t data[] */ +} __ucsi_packed; + + + +/** + * Process an mpeg_content_labelling_descriptor. + * + * @param d Generic descriptor. + * @return Pointer to an mpeg_content_labelling_descriptor, or NULL on error. + */ +static inline struct mpeg_content_labelling_descriptor* + mpeg_content_labelling_descriptor_codec(struct descriptor* d) +{ + uint32_t pos = 2; + uint8_t *buf = (uint8_t*) d; + uint32_t len = d->len + 2; + struct mpeg_content_labelling_descriptor_flags *flags; + int id; + + if (len < sizeof(struct mpeg_content_labelling_descriptor)) + return NULL; + + bswap16(buf + pos); + id = *((uint16_t*) (buf+pos)); + pos += 2; + + if (id == 0xffff) { + if (len < (pos+4)) + return NULL; + bswap32(buf+pos); + pos += 4; + } + + if (len < (pos + sizeof(struct mpeg_content_labelling_descriptor_flags))) + return NULL; + flags = (struct mpeg_content_labelling_descriptor_flags*) (buf+pos); + pos += sizeof(struct mpeg_content_labelling_descriptor_flags); + + if (flags->content_reference_id_record_flag == 1) { + if (len < (pos+1)) + return NULL; + if (len < (pos+1+buf[pos])) + return NULL; + pos += 1 + buf[pos]; + } + + if ((flags->content_time_base_indicator == 1) || + (flags->content_time_base_indicator == 2)) { + if (len < (pos + sizeof(struct mpeg_content_labelling_descriptor_time_base))) + return NULL; + bswap40(buf+pos); + bswap40(buf+pos+5); + pos += sizeof(struct mpeg_content_labelling_descriptor_time_base); + } + + if (flags->content_time_base_indicator == 2) { + if (len < (pos + sizeof(struct mpeg_content_labelling_descriptor_content_id))) + return NULL; + pos += sizeof(struct mpeg_content_labelling_descriptor_content_id); + } + + if (flags->content_time_base_indicator > 2) { + if (len < (pos+1)) + return NULL; + if (len < (pos+1+buf[pos])) + return NULL; + pos += 1 + buf[pos]; + } + + if (len < pos) + return NULL; + + return (struct mpeg_content_labelling_descriptor*) d; +} + +/** + * Accessor for pointer to id field of an mpeg_content_labelling_descriptor. + * + * @param d The mpeg_content_labelling_descriptor structure. + * @return The pointer, or NULL on error. + */ +static inline struct mpeg_content_labelling_descriptor_application_format_identifier* + mpeg_content_labelling_descriptor_id(struct mpeg_content_labelling_descriptor *d) +{ + uint8_t *buf = (uint8_t*) d; + + if (d->metadata_application_format != 0xffff) + return NULL; + return (struct mpeg_content_labelling_descriptor_application_format_identifier*) + (buf + sizeof(struct mpeg_content_labelling_descriptor)); +} + +/** + * Accessor for pointer to flags field of an mpeg_content_labelling_descriptor. + * + * @param d The mpeg_content_labelling_descriptor structure. + * @return The pointer, or NULL on error. + */ +static inline struct mpeg_content_labelling_descriptor_flags* + mpeg_content_labelling_descriptor_flags(struct mpeg_content_labelling_descriptor *d) +{ + uint8_t *buf = (uint8_t*) d + sizeof(struct mpeg_content_labelling_descriptor); + + if (d->metadata_application_format != 0xffff) + buf += 4; + + return (struct mpeg_content_labelling_descriptor_flags *) buf; +} + +/** + * Accessor for reference_id field of an mpeg_content_labelling_descriptor. + * + * @param flags Pointer to the mpeg_content_labelling_descriptor_flags. + * @return Pointer to the field, or NULL on error. + */ +static inline struct mpeg_content_labelling_descriptor_reference_id* + mpeg_content_labelling_descriptor_reference_id(struct mpeg_content_labelling_descriptor_flags *flags) +{ + uint8_t *buf = (uint8_t*) flags + sizeof(struct mpeg_content_labelling_descriptor_flags); + + if (flags->content_reference_id_record_flag != 1) + return NULL; + + return (struct mpeg_content_labelling_descriptor_reference_id *) buf; +} + +/** + * Accessor for data field of an mpeg_content_reference_id. + * + * @param d The mpeg_content_reference_id structure. + * @return Pointer to the field. + */ +static inline uint8_t* + mpeg_content_reference_id_data(struct mpeg_content_labelling_descriptor_reference_id *d) +{ + return (uint8_t*) d + sizeof(struct mpeg_content_labelling_descriptor_reference_id); +} + +/** + * Accessor for time_base field of an mpeg_content_labelling_descriptor. + * + * @param flags Pointer to the mpeg_content_labelling_descriptor_flags. + * @return Pointer to the field, or NULL on error. + */ +static inline struct mpeg_content_labelling_descriptor_time_base* + mpeg_content_labelling_descriptor_time_base(struct mpeg_content_labelling_descriptor_flags *flags) +{ + uint8_t *buf = (uint8_t*) flags + sizeof(struct mpeg_content_labelling_descriptor_flags); + + if ((flags->content_time_base_indicator!=1) && (flags->content_time_base_indicator!=2)) + return NULL; + + if (flags->content_reference_id_record_flag == 1) + buf += 1 + buf[1]; + + return (struct mpeg_content_labelling_descriptor_time_base *) buf; +} + +/** + * Accessor for content_id field of an mpeg_content_labelling_descriptor. + * + * @param flags Pointer to the mpeg_content_labelling_descriptor_flags. + * @return Pointer to the field, or NULL on error. + */ +static inline struct mpeg_content_labelling_descriptor_content_id* + mpeg_content_labelling_descriptor_content_id(struct mpeg_content_labelling_descriptor_flags *flags) +{ + uint8_t *buf = (uint8_t*) flags + sizeof(struct mpeg_content_labelling_descriptor_flags); + + if (flags->content_time_base_indicator!=2) + return NULL; + + if (flags->content_reference_id_record_flag == 1) + buf += 1 + buf[1]; + if ((flags->content_time_base_indicator==1) || (flags->content_time_base_indicator==2)) + buf += sizeof(struct mpeg_content_labelling_descriptor_time_base); + + return (struct mpeg_content_labelling_descriptor_content_id *) buf; +} + +/** + * Accessor for time_base_association field of an mpeg_content_labelling_descriptor. + * + * @param flags Pointer to the mpeg_content_labelling_descriptor_flags. + * @return Pointer to the field, or NULL on error. + */ +static inline struct mpeg_content_labelling_descriptor_time_base_association* + mpeg_content_labelling_descriptor_time_base_assoc(struct mpeg_content_labelling_descriptor_flags *flags) +{ + uint8_t *buf = (uint8_t*) flags + sizeof(struct mpeg_content_labelling_descriptor_flags); + + if (flags->content_time_base_indicator<3) + return NULL; + + if (flags->content_reference_id_record_flag == 1) + buf += 1 + buf[1]; + if ((flags->content_time_base_indicator==1) || (flags->content_time_base_indicator==2)) + buf += sizeof(struct mpeg_content_labelling_descriptor_time_base); + if (flags->content_time_base_indicator==2) + buf += sizeof(struct mpeg_content_labelling_descriptor_content_id); + + return (struct mpeg_content_labelling_descriptor_time_base_association *) buf; +} + +/** + * Accessor for data field of an mpeg_time_base_association. + * + * @param d The mpeg_time_base_association structure. + * @return Pointer to the field. + */ +static inline uint8_t* + mpeg_time_base_association_data(struct mpeg_content_labelling_descriptor_time_base_association *d) +{ + return (uint8_t*) d + sizeof(struct mpeg_content_labelling_descriptor_time_base_association); +} + + +/** + * Accessor for private_data field of an mpeg_content_labelling_descriptor. + * + * @param d The mpeg_content_labelling_descriptor structure. + * @param flags Pointer to the mpeg_content_labelling_descriptor_flags. + * @param length Where the number of bytes in the field should be stored. + * @return Pointer to the field. + */ +static inline uint8_t* + mpeg_content_labelling_descriptor_data(struct mpeg_content_labelling_descriptor *d, + struct mpeg_content_labelling_descriptor_flags *flags, + int *length) +{ + uint8_t *buf = (uint8_t*) flags + sizeof(struct mpeg_content_labelling_descriptor_flags); + uint8_t *end = (uint8_t*) d + d->d.len + 2; + + if (flags->content_reference_id_record_flag == 1) + buf += 1 + buf[1]; + if ((flags->content_time_base_indicator==1) || (flags->content_time_base_indicator==2)) + buf += sizeof(struct mpeg_content_labelling_descriptor_time_base); + if (flags->content_time_base_indicator==2) + buf += sizeof(struct mpeg_content_labelling_descriptor_content_id); + if (flags->content_time_base_indicator<3) + buf += 1 + buf[1]; + + *length = end - buf; + + return buf; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/mpeg/copyright_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/mpeg/copyright_descriptor.h new file mode 100644 index 0000000..5991fe9 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/mpeg/copyright_descriptor.h @@ -0,0 +1,89 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_MPEG_COPYRIGHT_DESCRIPTOR +#define _UCSI_MPEG_COPYRIGHT_DESCRIPTOR 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/descriptor.h> +#include <libucsi/endianops.h> + +/** + * mpeg_copyright_descriptor structure. + */ +struct mpeg_copyright_descriptor { + struct descriptor d; + + uint32_t copyright_identifier; + /* uint8_t data[] */ +} __ucsi_packed; + +/** + * Process an mpeg_copyright_descriptor. + * + * @param d Generic descriptor. + * @return mpeg_copyright_descriptor pointer, or NULL on error. + */ +static inline struct mpeg_copyright_descriptor* + mpeg_copyright_descriptor_codec(struct descriptor* d) +{ + if (d->len < (sizeof(struct mpeg_copyright_descriptor) - 2)) + return NULL; + + bswap32((uint8_t*) d + 2); + + return (struct mpeg_copyright_descriptor*) d; +} + +/** + * Retrieve pointer to data field of an mpeg_copyright_descriptor. + * + * @param d mpeg_copyright_descriptor pointer. + * @return Pointer to the field. + */ +static inline uint8_t * + mpeg_copyright_descriptor_data(struct mpeg_copyright_descriptor *d) +{ + return (uint8_t *) d + sizeof(struct mpeg_copyright_descriptor); +} + + +/** + * Determine length of the data field of an mpeg_copyright_descriptor. + * + * @param d mpeg_copyright_descriptor pointer. + * @return Length of field in bytes. + */ +static inline int + mpeg_copyright_descriptor_data_length(struct mpeg_copyright_descriptor *d) +{ + return d->d.len - 4; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/mpeg/data_stream_alignment_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/mpeg/data_stream_alignment_descriptor.h new file mode 100644 index 0000000..887495f --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/mpeg/data_stream_alignment_descriptor.h @@ -0,0 +1,73 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_MPEG_DATA_STREAM_ALIGNMENT_DESCRIPTOR +#define _UCSI_MPEG_DATA_STREAM_ALIGNMENT_DESCRIPTOR 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/descriptor.h> +#include <libucsi/endianops.h> + +/** + * Possible values for alignment_type. + */ +enum { + MPEG_DATA_STREAM_ALIGNMENT_VIDEO_SLICE_OR_AU = 0x01, + MPEG_DATA_STREAM_ALIGNMENT_VIDEO_AU = 0x02, + MPEG_DATA_STREAM_ALIGNMENT_VIDEO_GOP_OR_SEQ = 0x03, + MPEG_DATA_STREAM_ALIGNMENT_VIDEO_SEQ = 0x04, + + MPEG_DATA_STREAM_ALIGNMENT_AUDIO_SYNC_WORD = 0x01, +}; + +/** + * mpeg_data_stream_alignment_descriptor structure. + */ +struct mpeg_data_stream_alignment_descriptor { + struct descriptor d; + + uint8_t alignment_type; +} __ucsi_packed; + +/** + * Process an mpeg_data_stream_alignment_descriptor. + * + * @param d Pointer to generic descriptor structure. + * @return Pointer to mpeg_data_stream_alignment_descriptor, or NULL on error. + */ +static inline struct mpeg_data_stream_alignment_descriptor* + mpeg_data_stream_alignment_descriptor_codec(struct descriptor* d) +{ + if (d->len != (sizeof(struct mpeg_data_stream_alignment_descriptor) - 2)) + return NULL; + + return (struct mpeg_data_stream_alignment_descriptor*) d; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/mpeg/descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/mpeg/descriptor.h new file mode 100644 index 0000000..c32775f --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/mpeg/descriptor.h @@ -0,0 +1,102 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_MPEG_DESCRIPTOR_H +#define _UCSI_MPEG_DESCRIPTOR_H 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/mpeg/mpeg4_audio_descriptor.h> +#include <libucsi/mpeg/mpeg4_video_descriptor.h> +#include <libucsi/mpeg/audio_stream_descriptor.h> +#include <libucsi/mpeg/ca_descriptor.h> +#include <libucsi/mpeg/content_labelling_descriptor.h> +#include <libucsi/mpeg/copyright_descriptor.h> +#include <libucsi/mpeg/data_stream_alignment_descriptor.h> +#include <libucsi/mpeg/external_es_id_descriptor.h> +#include <libucsi/mpeg/fmc_descriptor.h> +#include <libucsi/mpeg/fmxbuffer_size_descriptor.h> +#include <libucsi/mpeg/hierarchy_descriptor.h> +#include <libucsi/mpeg/ibp_descriptor.h> +#include <libucsi/mpeg/iod_descriptor.h> +#include <libucsi/mpeg/iso_639_language_descriptor.h> +#include <libucsi/mpeg/maximum_bitrate_descriptor.h> +#include <libucsi/mpeg/metadata_descriptor.h> +#include <libucsi/mpeg/metadata_pointer_descriptor.h> +#include <libucsi/mpeg/metadata_std_descriptor.h> +#include <libucsi/mpeg/multiplex_buffer_descriptor.h> +#include <libucsi/mpeg/multiplex_buffer_utilization_descriptor.h> +#include <libucsi/mpeg/muxcode_descriptor.h> +#include <libucsi/mpeg/private_data_indicator_descriptor.h> +#include <libucsi/mpeg/registration_descriptor.h> +#include <libucsi/mpeg/sl_descriptor.h> +#include <libucsi/mpeg/smoothing_buffer_descriptor.h> +#include <libucsi/mpeg/std_descriptor.h> +#include <libucsi/mpeg/system_clock_descriptor.h> +#include <libucsi/mpeg/target_background_grid_descriptor.h> +#include <libucsi/mpeg/video_stream_descriptor.h> +#include <libucsi/mpeg/video_window_descriptor.h> +#include <libucsi/endianops.h> + +/** + * Enumeration of MPEG descriptor tags. + */ +enum mpeg_descriptor_tag { + dtag_mpeg_video_stream = 0x02, + dtag_mpeg_audio_stream = 0x03, + dtag_mpeg_hierarchy = 0x04, + dtag_mpeg_registration = 0x05, + dtag_mpeg_data_stream_alignment = 0x06, + dtag_mpeg_target_background_grid = 0x07, + dtag_mpeg_video_window = 0x08, + dtag_mpeg_ca = 0x09, + dtag_mpeg_iso_639_language = 0x0a, + dtag_mpeg_system_clock = 0x0b, + dtag_mpeg_multiplex_buffer_utilization = 0x0c, + dtag_mpeg_copyright = 0x0d, + dtag_mpeg_maximum_bitrate = 0x0e, + dtag_mpeg_private_data_indicator = 0x0f, + dtag_mpeg_smoothing_buffer = 0x10, + dtag_mpeg_std = 0x11, + dtag_mpeg_ibp = 0x12, + dtag_mpeg_4_video = 0x1b, + dtag_mpeg_4_audio = 0x1c, + dtag_mpeg_iod = 0x1d, + dtag_mpeg_sl = 0x1e, + dtag_mpeg_fmc = 0x1f, + dtag_mpeg_external_es_id = 0x20, + dtag_mpeg_muxcode = 0x21, + dtag_mpeg_fmxbuffer_size = 0x22, + dtag_mpeg_multiplex_buffer = 0x23, + dtag_mpeg_content_labelling = 0x24, + dtag_mpeg_metadata_pointer = 0x25, + dtag_mpeg_metadata = 0x26, + dtag_mpeg_metadata_std = 0x27, +}; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/mpeg/external_es_id_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/mpeg/external_es_id_descriptor.h new file mode 100644 index 0000000..3aa3237 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/mpeg/external_es_id_descriptor.h @@ -0,0 +1,63 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_MPEG_EXTERNAL_ES_ID_DESCRIPTOR +#define _UCSI_MPEG_EXTERNAL_ES_ID_DESCRIPTOR 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/descriptor.h> +#include <libucsi/endianops.h> + +/** + * mpeg_external_es_id_descriptor structure. + */ +struct mpeg_external_es_id_descriptor { + struct descriptor d; + + uint16_t external_es_id; +} __ucsi_packed; + +/** + * Process an mpeg_external_es_id_descriptor structure. + * + * @param d Generic descriptor structure. + * @return mpeg_external_es_id_descriptor pointer, or NULL on error. + */ +static inline struct mpeg_external_es_id_descriptor* + mpeg_external_es_id_descriptor_codec(struct descriptor* d) +{ + if (d->len != (sizeof(struct mpeg_external_es_id_descriptor) - 2)) + return NULL; + + bswap16((uint8_t*) d + 2); + + return (struct mpeg_external_es_id_descriptor*) d; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/mpeg/fmc_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/mpeg/fmc_descriptor.h new file mode 100644 index 0000000..5a5bed2 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/mpeg/fmc_descriptor.h @@ -0,0 +1,122 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_MPEG_FMC_DESCRIPTOR +#define _UCSI_MPEG_FMC_DESCRIPTOR 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/descriptor.h> +#include <libucsi/endianops.h> + +/** + * mpeg_fmc_descriptor structure. + */ +struct mpeg_fmc_descriptor { + struct descriptor d; + + /* struct mpeg_flex_mux muxes[] */ +} __ucsi_packed; + +/** + * An entry in the muxes field of an mpeg_fmc_descriptor structure. + */ +struct mpeg_flex_mux { + uint16_t es_id; + uint8_t flex_mux_channel; +} __ucsi_packed; + +/** + * Process an mpeg_fmc_descriptor structure. + * + * @param d Generic descriptor structure. + * @return Pointer to an mpeg_fmc_descriptor structure, or NULL on error. + */ +static inline struct mpeg_fmc_descriptor* + mpeg_fmc_descriptor_codec(struct descriptor* d) +{ + uint8_t* buf = (uint8_t*) d + 2; + int pos = 0; + int len = d->len; + + if (len % sizeof(struct mpeg_flex_mux)) + return NULL; + + while(pos < len) { + bswap16(buf+pos); + pos += sizeof(struct mpeg_flex_mux); + } + + return (struct mpeg_fmc_descriptor*) d; +} + +/** + * Convenience iterator for the muxes field of an mpeg_fmc_descriptor structure. + * + * @param d Generic descriptor structure. + * @param pos Variable holding a pointer to the the current entry within the muxes field. + */ +#define mpeg_fmc_descriptor_muxes_for_each(d, pos) \ + for ((pos) = mpeg_fmc_descriptor_muxes_first(d); \ + (pos); \ + (pos) = mpeg_fmc_descriptor_muxes_next(d, pos)) + + + + + + + + + + +/******************************** PRIVATE CODE ********************************/ +static inline struct mpeg_flex_mux* + mpeg_fmc_descriptor_muxes_first(struct mpeg_fmc_descriptor *d) +{ + if (d->d.len < sizeof(struct mpeg_flex_mux)) + return NULL; + + return (struct mpeg_flex_mux *) + ((uint8_t*) d + sizeof(struct mpeg_fmc_descriptor)); +} + +static inline struct mpeg_flex_mux* + mpeg_fmc_descriptor_muxes_next(struct mpeg_fmc_descriptor *d, + struct mpeg_flex_mux *pos) +{ + uint8_t *end = (uint8_t*) d + 2 + d->d.len; + uint8_t *next = (uint8_t *) pos + sizeof(struct mpeg_flex_mux); + + if (next >= end) + return NULL; + + return (struct mpeg_flex_mux *) next; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/mpeg/fmxbuffer_size_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/mpeg/fmxbuffer_size_descriptor.h new file mode 100644 index 0000000..74f643c --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/mpeg/fmxbuffer_size_descriptor.h @@ -0,0 +1,83 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_MPEG_FMXBUFFER_SIZE_DESCRIPTOR +#define _UCSI_MPEG_FMXBUFFER_SIZE_DESCRIPTOR 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/descriptor.h> +#include <libucsi/endianops.h> + + +/** + * mpeg_fmxbuffer_size_descriptor structure. + */ +struct mpeg_fmxbuffer_size_descriptor { + struct descriptor d; + + /* uint8_t descriptors[] */ +} __ucsi_packed; + +/** + * Process an mpeg_fmxbuffer_size_descriptor structure. + * + * @param d Pointer to a generic descriptor structure. + * @return Pointer to an mpeg_fmxbuffer_size_descriptor structure, or NULL on error. + */ +static inline struct mpeg_fmxbuffer_size_descriptor* + mpeg_fmxbuffer_size_descriptor_codec(struct descriptor* d) +{ + return (struct mpeg_fmxbuffer_size_descriptor*) d; +} + +/** + * Retrieve pointer to descriptors field of mpeg_fmxbuffer_size_descriptor structure. + * + * @param d mpeg_fmxbuffer_size_descriptor structure pointer. + * @return Pointer to the descriptors. + */ +static inline uint8_t * + mpeg_fmxbuffer_size_descriptor_descriptors(struct mpeg_fmxbuffer_size_descriptor *d) +{ + return (uint8_t *) d + sizeof(struct mpeg_fmxbuffer_size_descriptor); +} + +/** + * Calculate the length of the descriptors field of an mpeg_fmxbuffer_size_descriptor structure. + * + * @param d mpeg_fmxbuffer_size_descriptor structure pointer. + * @return Length of descriptors in bytes. + */ +static inline int + mpeg_fmxbuffer_size_descriptor_descriptors_length(struct mpeg_fmxbuffer_size_descriptor *d) +{ + return d->d.len; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/mpeg/hierarchy_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/mpeg/hierarchy_descriptor.h new file mode 100644 index 0000000..a38539d --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/mpeg/hierarchy_descriptor.h @@ -0,0 +1,83 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_MPEG_HIERARCHY_DESCRIPTOR +#define _UCSI_MPEG_HIERARCHY_DESCRIPTOR 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/descriptor.h> +#include <libucsi/endianops.h> + +/** + * Hierarchy type values. + */ +enum { + MPEG_HIERARCHY_TYPE_ISO13818_2_SPATIAL_SCALABILITY = 0x01, + MPEG_HIERARCHY_TYPE_ISO13818_2_SNR_SCALABILITY = 0x02, + MPEG_HIERARCHY_TYPE_ISO13818_2_TEMPORAL_SCALABILITY = 0x03, + MPEG_HIERARCHY_TYPE_ISO13818_2_DATA_PARTITIONING = 0x04, + MPEG_HIERARCHY_TYPE_ISO13818_3_EXTENSION_BITSTREAM = 0x05, + MPEG_HIERARCHY_TYPE_ISO13818_1_PRIVATE_BITSTREAM = 0x06, + MPEG_HIERARCHY_TYPE_ISO13818_2_MULTI_VIEW_PROFILE = 0x07, + MPEG_HIERARCHY_TYPE_BASE_LAYER = 0x0f, +}; + + +/** + * mpeg_hierarchy_descriptor structure. + */ +struct mpeg_hierarchy_descriptor { + struct descriptor d; + + EBIT2(uint8_t reserved_1 : 4; , + uint8_t hierarchy_type : 4; ); + EBIT2(uint8_t reserved_2 : 2; , + uint8_t hierarchy_layer_index : 6; ); + EBIT2(uint8_t reserved_3 : 2; , + uint8_t hierarchy_embedded_layer_index : 6; ); + EBIT2(uint8_t reserved_4 : 2; , + uint8_t hierarchy_channel : 6; ); +} __ucsi_packed; + +/** + * Process an mpeg_hierarchy_descriptor. + * + * @param d Generic descriptor structure. + * @return Pointer to mpeg_hierarchy_descriptor structure, or NULL on error. + */ +static inline struct mpeg_hierarchy_descriptor* + mpeg_hierarchy_descriptor_codec(struct descriptor* d) +{ + if (d->len != (sizeof(struct mpeg_hierarchy_descriptor) - 2)) + return NULL; + + return (struct mpeg_hierarchy_descriptor*) d; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/mpeg/ibp_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/mpeg/ibp_descriptor.h new file mode 100644 index 0000000..e82780a --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/mpeg/ibp_descriptor.h @@ -0,0 +1,65 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_MPEG_IBP_DESCRIPTOR +#define _UCSI_MPEG_IBP_DESCRIPTOR 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/descriptor.h> +#include <libucsi/endianops.h> + +/** + * mpeg_ibp_descriptor structure. + */ +struct mpeg_ibp_descriptor { + struct descriptor d; + + EBIT3(uint16_t closed_gop_flag : 1; , + uint16_t identical_gop_flag : 1; , + uint16_t max_gop_length : 14; ); +} __ucsi_packed; + +/** + * Process an mpeg_ibp_descriptor structure. + * + * @param d Generic descriptor structure. + * @return Pointer to the mpeg_ibp_descriptor structure, or NULL on error. + */ +static inline struct mpeg_ibp_descriptor* + mpeg_ibp_descriptor_codec(struct descriptor* d) +{ + if (d->len != (sizeof(struct mpeg_ibp_descriptor) - 2)) + return NULL; + + bswap16((uint8_t*) d + 2); + + return (struct mpeg_ibp_descriptor*) d; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/mpeg/iod_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/mpeg/iod_descriptor.h new file mode 100644 index 0000000..61de153 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/mpeg/iod_descriptor.h @@ -0,0 +1,87 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_MPEG_IOD_DESCRIPTOR +#define _UCSI_MPEG_IOD_DESCRIPTOR 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/descriptor.h> +#include <libucsi/endianops.h> + +/** + * mpeg_iod_descriptor structure. + */ +struct mpeg_iod_descriptor { + struct descriptor d; + + uint8_t scope_of_iod_label; + uint8_t iod_label; + /* uint8_t iod[] */ +} __ucsi_packed; + +/** + * Process an mpeg_iod_descriptor. + * + * @param d Generic descriptor structure. + * @return Pointer to an mpeg_iod_descriptor structure, or NULL on error. + */ +static inline struct mpeg_iod_descriptor* + mpeg_iod_descriptor_codec(struct descriptor* d) +{ + if (d->len < (sizeof(struct mpeg_iod_descriptor) - 2)) + return NULL; + + return (struct mpeg_iod_descriptor*) d; +} + +/** + * Retrieve pointer to iod field of an mpeg_iod_descriptor structure. + * + * @param d Pointer to mpeg_iod_descriptor structure. + * @return Pointer to the iod field. + */ +static inline uint8_t * + mpeg_iod_descriptor_iod(struct mpeg_iod_descriptor *d) +{ + return (uint8_t *) d + sizeof(struct mpeg_iod_descriptor); +} + +/** + * Calculate the length of the iod field of an mpeg_iod_descriptor structure. + * + * @param d Pointer to mpeg_iod_descriptor structure. + * @return The number of bytes. + */ +static inline int + mpeg_iod_descriptor_iod_length(struct mpeg_iod_descriptor *d) +{ + return d->d.len - 2; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/mpeg/iso_639_language_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/mpeg/iso_639_language_descriptor.h new file mode 100644 index 0000000..5b5aac0 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/mpeg/iso_639_language_descriptor.h @@ -0,0 +1,124 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_MPEG_ISO_639_LANGUAGE_DESCRIPTOR +#define _UCSI_MPEG_ISO_639_LANGUAGE_DESCRIPTOR 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/descriptor.h> +#include <libucsi/endianops.h> +#include <libucsi/types.h> + +/** + * Possible values for audio_type. + */ +enum { + MPEG_AUDIO_TYPE_CLEAN_EFFECTS = 0x01, + MPEG_AUDIO_TYPE_HEARING_IMPAIRED = 0x02, + MPEG_AUDIO_TYPE_VISUAL_IMPAIRED_COMMENTARY = 0x03, +}; + +/** + * mpeg_iso_639_language_descriptor structure. + */ +struct mpeg_iso_639_language_descriptor { + struct descriptor d; + + /* struct mpeg_iso_639_language_code languages[] */ +} __ucsi_packed; + +/** + * An entry in the mpeg_iso_639_language_descriptor languages field. + */ +struct mpeg_iso_639_language_code { + iso639lang_t language_code; + uint8_t audio_type; +} __ucsi_packed; + +/** + * Process an mpeg_iso_639_language_descriptor. + * + * @param d Generic descriptor structure. + * @return Pointer to an mpeg_iso_639_language_descriptor structure, or NULL + * on error. + */ +static inline struct mpeg_iso_639_language_descriptor* + mpeg_iso_639_language_descriptor_codec(struct descriptor* d) +{ + if (d->len % sizeof(struct mpeg_iso_639_language_code)) + return NULL; + + return (struct mpeg_iso_639_language_descriptor*) d; +} + +/** + * Convenience iterator for the languages field of an mpeg_iso_639_language_descriptor + * + * @param d Pointer to the mpeg_iso_639_language_descriptor structure. + * @param pos Variable holding a pointer to the current entry. + */ +#define mpeg_iso_639_language_descriptor_languages_for_each(_d, _pos) \ + for ((_pos) = mpeg_iso_639_language_descriptor_languages_first(_d); \ + (_pos); \ + (_pos) = mpeg_iso_639_language_descriptor_languages_next(_d, _pos)) + + + + + + + + + + +/******************************** PRIVATE CODE ********************************/ +static inline struct mpeg_iso_639_language_code* + mpeg_iso_639_language_descriptor_languages_first(struct mpeg_iso_639_language_descriptor *d) +{ + if (d->d.len < sizeof(struct mpeg_iso_639_language_code)) + return NULL; + + return (struct mpeg_iso_639_language_code *) + ((uint8_t*) d + sizeof(struct mpeg_iso_639_language_descriptor)); +} + +static inline struct mpeg_iso_639_language_code* + mpeg_iso_639_language_descriptor_languages_next(struct mpeg_iso_639_language_descriptor *d, + struct mpeg_iso_639_language_code *pos) +{ + uint8_t *end = (uint8_t*) d + 2 + d->d.len; + uint8_t *next = (uint8_t *) pos + sizeof(struct mpeg_iso_639_language_code); + + if (next >= end) + return NULL; + + return (struct mpeg_iso_639_language_code *) next; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/mpeg/maximum_bitrate_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/mpeg/maximum_bitrate_descriptor.h new file mode 100644 index 0000000..e0bcddb --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/mpeg/maximum_bitrate_descriptor.h @@ -0,0 +1,64 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_MPEG_MAXIMUM_BITRATE_DESCRIPTOR +#define _UCSI_MPEG_MAXIMUM_BITRATE_DESCRIPTOR 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/descriptor.h> +#include <libucsi/endianops.h> + +/** + * mpeg_maximum_bitrate_descriptor structure. + */ +struct mpeg_maximum_bitrate_descriptor { + struct descriptor d; + + EBIT2(uint32_t reserved : 2; , + uint32_t maximum_bitrate : 22; ); +} __ucsi_packed; + +/** + * Process an mpeg_maximum_bitrate_descriptor. + * + * @param d Pointer to generic descriptor structure. + * @return Pointer to mpeg_maximum_bitrate_descriptor, or NULL on error. + */ +static inline struct mpeg_maximum_bitrate_descriptor* + mpeg_maximum_bitrate_descriptor_codec(struct descriptor* d) +{ + if (d->len != (sizeof(struct mpeg_maximum_bitrate_descriptor) - 2)) + return NULL; + + bswap24((uint8_t*) d + 2); + + return (struct mpeg_maximum_bitrate_descriptor*) d; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/mpeg/metadata_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/mpeg/metadata_descriptor.h new file mode 100644 index 0000000..5b91e05 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/mpeg/metadata_descriptor.h @@ -0,0 +1,472 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_MPEG_METADATA_DESCRIPTOR +#define _UCSI_MPEG_METADATA_DESCRIPTOR 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/descriptor.h> +#include <libucsi/endianops.h> + +/** + * Values for the decoder_config_flags field. + */ +enum { + MPEG_DECODER_CONFIG_NONE = 0x00, + MPEG_DECODER_CONFIG_IN_DECODER_CONFIG = 0x01, + MPEG_DECODER_CONFIG_SAME_METADATA_SERVICE = 0x02, + MPEG_DECODER_CONFIG_DSMCC = 0x03, + MPEG_DECODER_CONFIG_SAME_PROGRAM = 0x04, +}; + +/** + * mpeg_metadata_descriptor structure. + */ +struct mpeg_metadata_descriptor { + struct descriptor d; + + uint16_t metadata_application_format; + /* struct mpeg_metadata_descriptor_application_format_identifier appid */ + /* uint8_t metadata_format */ + /* struct mpeg_metadata_descriptor_format_identifier formid */ + /* struct mpeg_metadata_descriptor_flags flags */ + /* struct mpeg_metadata_descriptor_service_identifier service_identifier */ + /* struct mpeg_metadata_descriptor_decoder_config decoder_config */ + /* struct mpeg_metadata_descriptor_decoder_config_id_record decoder_config_id_record */ + /* struct mpeg_metadata_descriptor_decoder_config_service_id decoder_config_service_id */ + /* struct mpeg_metadata_descriptor_decoder_config_reserved decoder_config_reserved */ + /* uint8_t private_data[] */ +} __ucsi_packed; + +/** + * appid field of a metadata_descriptor. + */ +struct mpeg_metadata_descriptor_application_format_identifier { + uint32_t id; +} __ucsi_packed; + +/** + * formid field of a metadata_descriptor. + */ +struct mpeg_metadata_descriptor_format_identifier { + uint32_t id; +} __ucsi_packed; + +/** + * Flags field of a metadata_descriptor + */ +struct mpeg_metadata_descriptor_flags { + uint8_t metadata_service_id; + EBIT3(uint8_t decoder_config_flags : 3; , + uint8_t dsm_cc_flag : 1; , + uint8_t reserved : 4; ); +} __ucsi_packed; + +/** + * service_identifier field of a metadata_descriptor. + */ +struct mpeg_metadata_descriptor_service_identifier { + uint8_t service_identification_length; + /* uint8_t data[] */ +} __ucsi_packed; + +/** + * decoder_config field of a metadata_descriptor. + */ +struct mpeg_metadata_descriptor_decoder_config { + uint8_t decoder_config_length; + /* uint8_t data[] */ +} __ucsi_packed; + +/** + * decoder_config_id_record field of a metadata_descriptor. + */ +struct mpeg_metadata_descriptor_decoder_config_id_record { + uint8_t decoder_config_id_record_length; + /* uint8_t data[] */ +} __ucsi_packed; + +/** + * decoder_config_service_id field of a metadata_descriptor. + */ +struct mpeg_metadata_descriptor_decoder_config_service_id { + uint8_t decoder_config_metadata_service_id; +} __ucsi_packed; + +/** + * decoder_config_reserved field of a metadata_descriptor. + */ +struct mpeg_metadata_descriptor_decoder_config_reserved { + uint8_t reserved_data_length; + /* uint8_t data[] */ +} __ucsi_packed; + + + + +/** + * Process an mpeg_metadata_descriptor. + * + * @param d Generic descriptor. + * @return Pointer to an mpeg_metadata_descriptor, or NULL on error. + */ +static inline struct mpeg_metadata_descriptor* + mpeg_metadata_descriptor_codec(struct descriptor* d) +{ + uint32_t pos = 2; + uint8_t *buf = (uint8_t*) d; + uint32_t len = d->len + 2; + struct mpeg_metadata_descriptor_flags *flags; + int id; + + if (len < sizeof(struct mpeg_metadata_descriptor)) + return NULL; + + bswap16(buf + pos); + id = *((uint16_t*) (buf+pos)); + pos += 2; + + if (id == 0xffff) { + if (len < (pos+4)) + return NULL; + bswap32(buf+pos); + pos += 4; + } + + if (len < (pos+1)) + return NULL; + + id = buf[pos]; + pos++; + if (id == 0xff) { + if (len < (pos+4)) + return NULL; + bswap32(buf+pos); + pos += 4; + } + + if (len < (pos + sizeof(struct mpeg_metadata_descriptor_flags))) + return NULL; + flags = (struct mpeg_metadata_descriptor_flags*) (buf+pos); + pos += sizeof(struct mpeg_metadata_descriptor_flags); + + if (flags->dsm_cc_flag == 1) { + if (len < (pos+1)) + return NULL; + if (len < (pos+1+buf[pos])) + return NULL; + pos += 1 + buf[pos]; + } + + if (flags->decoder_config_flags == 1) { + if (len < (pos+1)) + return NULL; + if (len < (pos+1+buf[pos])) + return NULL; + pos += 1 + buf[pos]; + } + + if (flags->decoder_config_flags == 3) { + if (len < (pos+1)) + return NULL; + if (len < (pos+1+buf[pos])) + return NULL; + pos += 1 + buf[pos]; + } + + if (flags->decoder_config_flags == 4) { + if (len < (pos+1)) + return NULL; + pos++; + } + + if ((flags->decoder_config_flags == 5) || + (flags->decoder_config_flags == 6)) { + if (len < (pos+1)) + return NULL; + if (len < (pos+1+buf[pos])) + return NULL; + pos += 1 + buf[pos]; + } + + if (len < pos) + return NULL; + + return (struct mpeg_metadata_descriptor*) d; +} + +/** + * Accessor for pointer to appid field of an mpeg_metadata_descriptor. + * + * @param d The mpeg_metadata_descriptor structure. + * @return The pointer, or NULL on error. + */ +static inline struct mpeg_metadata_descriptor_application_format_identifier* + mpeg_metadata_descriptor_appid(struct mpeg_metadata_descriptor *d) +{ + uint8_t *buf = (uint8_t*) d + sizeof(struct mpeg_metadata_descriptor); + + if (d->metadata_application_format != 0xffff) + return NULL; + return (struct mpeg_metadata_descriptor_application_format_identifier*) buf; +} + +/** + * Accessor for metadata_format field of an mpeg_metadata_descriptor. + * + * @param d The mpeg_metadata_descriptor structure. + * @return The pointer, or NULL on error. + */ +static inline uint8_t + mpeg_metadata_descriptor_metadata_format(struct mpeg_metadata_descriptor *d) +{ + uint8_t *buf = (uint8_t*) d + sizeof(struct mpeg_metadata_descriptor); + + if (d->metadata_application_format == 0xffff) + buf+=4; + return *buf; +} + +/** + * Accessor for pointer to formid field of an mpeg_metadata_descriptor. + * + * @param d The mpeg_metadata_descriptor structure. + * @return The pointer, or NULL on error. + */ +static inline struct mpeg_metadata_descriptor_format_identifier* + mpeg_metadata_descriptor_formid(struct mpeg_metadata_descriptor *d) +{ + uint8_t *buf = (uint8_t*) d + sizeof(struct mpeg_metadata_descriptor); + + if (d->metadata_application_format == 0xffff) + buf+=4; + if (*buf != 0xff) + return NULL; + + return (struct mpeg_metadata_descriptor_format_identifier*) (buf+1); +} + +/** + * Accessor for flags field of an mpeg_metadata_descriptor. + * + * @param d The mpeg_metadata_descriptor structure. + * @return Pointer to the field, or NULL on error. + */ +static inline struct mpeg_metadata_descriptor_flags* + mpeg_metadata_descriptor_flags(struct mpeg_metadata_descriptor *d) +{ + uint8_t *buf = (uint8_t*) d + sizeof(struct mpeg_metadata_descriptor); + + if (d->metadata_application_format == 0xffff) + buf+=4; + if (*buf == 0xff) + buf+=4; + + return (struct mpeg_metadata_descriptor_flags*) buf; +} + + +/** + * Accessor for service_identifier field of an mpeg_metadata_descriptor. + * + * @param flags Pointer to the mpeg_metadata_descriptor_flags. + * @return Pointer to the field, or NULL on error. + */ +static inline struct mpeg_metadata_descriptor_service_identifier* + mpeg_metadata_descriptor_sevice_identifier(struct mpeg_metadata_descriptor_flags *flags) +{ + uint8_t *buf = (uint8_t*) flags + sizeof(struct mpeg_metadata_descriptor_flags); + + if (flags->dsm_cc_flag!=1) + return NULL; + + return (struct mpeg_metadata_descriptor_service_identifier *) buf; +} + +/** + * Accessor for data field of an mpeg_metadata_descriptor_service_identifier. + * + * @param d The mpeg_metadata_descriptor_service_identifier structure. + * @return Pointer to the field. + */ +static inline uint8_t* + mpeg_metadata_descriptor_service_identifier_data(struct mpeg_metadata_descriptor_service_identifier *d) +{ + return (uint8_t*) d + sizeof(struct mpeg_metadata_descriptor_service_identifier); +} + +/** + * Accessor for decoder_config field of an mpeg_metadata_descriptor. + * + * @param flags Pointer to the mpeg_metadata_descriptor_flags. + * @return Pointer to the field, or NULL on error. + */ +static inline struct mpeg_metadata_descriptor_decoder_config* + mpeg_metadata_descriptor_decoder_config(struct mpeg_metadata_descriptor_flags *flags) +{ + uint8_t *buf = (uint8_t*) flags + sizeof(struct mpeg_metadata_descriptor_flags); + + if (flags->decoder_config_flags != 1) + return NULL; + + if (flags->dsm_cc_flag==1) + buf += 1 + buf[1]; + + return (struct mpeg_metadata_descriptor_decoder_config*) buf; +} + +/** + * Accessor for data field of an mpeg_metadata_descriptor_service_identifier. + * + * @param d The mpeg_metadata_descriptor_service_identifier structure. + * @return Pointer to the field. + */ +static inline uint8_t* + mpeg_metadata_descriptor_decoder_config_data(struct mpeg_metadata_descriptor_decoder_config *d) +{ + return (uint8_t*) d + sizeof(struct mpeg_metadata_descriptor_decoder_config); +} + +/** + * Accessor for decoder_config_id_record field of an mpeg_metadata_descriptor. + * + * @param flags Pointer to the mpeg_metadata_descriptor_flags. + * @return Pointer to the field, or NULL on error. + */ +static inline struct mpeg_metadata_descriptor_decoder_config_id_record* + mpeg_metadata_descriptor_decoder_config_id_record(struct mpeg_metadata_descriptor_flags *flags) +{ + uint8_t *buf = (uint8_t*) flags + sizeof(struct mpeg_metadata_descriptor_flags); + + if (flags->decoder_config_flags != 3) + return NULL; + + if (flags->dsm_cc_flag==1) + buf += 1 + buf[1]; + + return (struct mpeg_metadata_descriptor_decoder_config_id_record *) buf; +} + +/** + * Accessor for data field of an mpeg_metadata_descriptor_decoder_config_id_record. + * + * @param d The mpeg_metadata_descriptor_decoder_config_id_record structure. + * @return Pointer to the field. + */ +static inline uint8_t* + mpeg_metadata_descriptor_decoder_config_id_record_data(struct mpeg_metadata_descriptor_decoder_config_id_record *d) +{ + return (uint8_t*) d + sizeof(struct mpeg_metadata_descriptor_decoder_config_id_record); +} + +/** + * Accessor for decoder_config_service_id field of an mpeg_metadata_descriptor. + * + * @param flags Pointer to the mpeg_metadata_descriptor_flags. + * @return Pointer to the field, or NULL on error. + */ +static inline struct mpeg_metadata_descriptor_decoder_config_service_id* + mpeg_metadata_descriptor_decoder_config_service_id(struct mpeg_metadata_descriptor_flags *flags) +{ + uint8_t *buf = (uint8_t*) flags + sizeof(struct mpeg_metadata_descriptor_flags); + + if (flags->decoder_config_flags != 4) + return NULL; + + if (flags->dsm_cc_flag==1) + buf += 1 + buf[1]; + + return (struct mpeg_metadata_descriptor_decoder_config_service_id *) buf; +} + +/** + * Accessor for decoder_config_reserved field of an mpeg_metadata_descriptor. + * + * @param flags Pointer to the mpeg_metadata_descriptor_flags. + * @return Pointer to the field, or NULL on error. + */ +static inline struct mpeg_metadata_descriptor_decoder_config_reserved* + mpeg_metadata_descriptor_decoder_config_reserved(struct mpeg_metadata_descriptor_flags *flags) +{ + uint8_t *buf = (uint8_t*) flags + sizeof(struct mpeg_metadata_descriptor_flags); + + if ((flags->decoder_config_flags != 5) && (flags->decoder_config_flags != 6)) + return NULL; + + if (flags->dsm_cc_flag==1) + buf += 1 + buf[1]; + + return (struct mpeg_metadata_descriptor_decoder_config_reserved *) buf; +} + +/** + * Accessor for data field of an mpeg_metadata_descriptor_decoder_config_reserved. + * + * @param d The mpeg_metadata_descriptor_decoder_config_reserved structure. + * @return Pointer to the field. + */ +static inline uint8_t* + mpeg_metadata_descriptor_decoder_config_reserved_data(struct mpeg_metadata_descriptor_decoder_config_reserved *d) +{ + return (uint8_t*) d + sizeof(struct mpeg_metadata_descriptor_decoder_config_reserved); +} + +/** + * Accessor for private_data field of an mpeg_metadata_descriptor. + * + * @param d The mpeg_metadata_descriptor structure. + * @param flags Pointer to the mpeg_metadata_descriptor_flags. + * @param length Where the number of bytes in the field should be stored. + * @return Pointer to the field. + */ +static inline uint8_t* + mpeg_metadata_descriptor_private_data(struct mpeg_metadata_descriptor *d, + struct mpeg_metadata_descriptor_flags *flags, + int *length) +{ + uint8_t *buf = (uint8_t*) flags + sizeof(struct mpeg_metadata_descriptor_flags); + uint8_t *end = (uint8_t*) d + d->d.len + 2; + + + if (flags->dsm_cc_flag==1) + buf += 1 + buf[1]; + if (flags->decoder_config_flags==1) + buf += 1 + buf[1]; + if (flags->decoder_config_flags==3) + buf += 1 + buf[1]; + if (flags->decoder_config_flags==4) + buf++; + if ((flags->decoder_config_flags==5)||(flags->decoder_config_flags==6)) + buf += 1 + buf[1]; + + *length = end - buf; + return buf; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/mpeg/metadata_pointer_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/mpeg/metadata_pointer_descriptor.h new file mode 100644 index 0000000..e4d7503 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/mpeg/metadata_pointer_descriptor.h @@ -0,0 +1,360 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_MPEG_METADATA_POINTER_DESCRIPTOR +#define _UCSI_MPEG_METADATA_POINTER_DESCRIPTOR 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/descriptor.h> +#include <libucsi/endianops.h> + +/** + * Possible values for the mpeg_carriage_flags field. + */ +enum { + MPEG_CARRIAGE_SAME_TS = 0x00, + MPEG_CARRIAGE_DIFFERENT_TS = 0x01, + MPEG_CARRIAGE_PS = 0x02, + MPEG_CARRIAGE_OTHER = 0x03, +}; + +/** + * mpeg_metadata_pointer_descriptor structure. + */ +struct mpeg_metadata_pointer_descriptor { + struct descriptor d; + + uint16_t metadata_application_format; + /* struct mpeg_metadata_pointer_descriptor_application_format_identifier appid */ + /* uint8_t metadata_format */ + /* struct mpeg_metadata_pointer_descriptor_format_identifier formid */ + /* struct mpeg_metadata_pointer_descriptor_flags flags */ + /* struct mpeg_metadata_pointer_descriptor_locator locator */ + /* struct mpeg_metadata_pointer_descriptor_program_number program_number */ + /* struct mpeg_metadata_pointer_descriptor_carriage carriage */ + /* uint8_t private_data[] */ +} __ucsi_packed; + +/** + * appid field of a metadata_pointer_descriptor. + */ +struct mpeg_metadata_pointer_descriptor_application_format_identifier { + uint32_t id; +} __ucsi_packed; + +/** + * formid field of a metadata_pointer_descriptor. + */ +struct mpeg_metadata_pointer_descriptor_format_identifier { + uint32_t id; +} __ucsi_packed; + +/** + * Flags field of a metadata_pointer_descriptor + */ +struct mpeg_metadata_pointer_descriptor_flags { + uint8_t metadata_service_id; + EBIT3(uint8_t metadata_locator_record_flag : 1; , + uint8_t mpeg_carriage_flags : 2; , + uint8_t reserved : 5; ); +} __ucsi_packed; + +/** + * Reference_id field of a metadata_pointer_descriptor. + */ +struct mpeg_metadata_pointer_descriptor_locator { + uint8_t metadata_locator_record_length; + /* uint8_t data[] */ +} __ucsi_packed; + +/** + * program_number field of a metadata_pointer_descriptor. + */ +struct mpeg_metadata_pointer_descriptor_program_number { + uint16_t number; +} __ucsi_packed; + +/** + * carriage field of a metadata_pointer_descriptor. + */ +struct mpeg_metadata_pointer_descriptor_carriage { + uint16_t transport_stream_location; + uint16_t transport_stream_id; +} __ucsi_packed; + + + + +/** + * Process an mpeg_metadata_pointer_descriptor. + * + * @param d Generic descriptor. + * @return Pointer to an mpeg_metadata_pointer_descriptor, or NULL on error. + */ +static inline struct mpeg_metadata_pointer_descriptor* + mpeg_metadata_pointer_descriptor_codec(struct descriptor* d) +{ + uint32_t pos = 2; + uint8_t *buf = (uint8_t*) d; + uint32_t len = d->len + 2; + struct mpeg_metadata_pointer_descriptor_flags *flags; + int id; + + if (len < sizeof(struct mpeg_metadata_pointer_descriptor)) + return NULL; + + bswap16(buf + pos); + id = *((uint16_t*) (buf+pos)); + pos += 2; + + if (id == 0xffff) { + if (len < (pos+4)) + return NULL; + bswap32(buf+pos); + pos += 4; + } + + if (len < (pos+1)) + return NULL; + + id = buf[pos]; + pos++; + if (id == 0xff) { + if (len < (pos+4)) + return NULL; + bswap32(buf+pos); + pos += 4; + } + + if (len < (pos + sizeof(struct mpeg_metadata_pointer_descriptor_flags))) + return NULL; + flags = (struct mpeg_metadata_pointer_descriptor_flags*) (buf+pos); + pos += sizeof(struct mpeg_metadata_pointer_descriptor_flags); + + if (flags->metadata_locator_record_flag == 1) { + if (len < (pos+1)) + return NULL; + if (len < (pos+1+buf[pos])) + return NULL; + pos += 1 + buf[pos]; + } + + if (flags->mpeg_carriage_flags < 3) { + if (len < (pos + 2)) + return NULL; + bswap16(buf+pos); + pos += 2; + } + + if (flags->mpeg_carriage_flags == 1) { + if (len < (pos + 4)) + return NULL; + bswap16(buf+pos); + bswap16(buf+pos+2); + pos += 4; + } + + if (len < pos) + return NULL; + + return (struct mpeg_metadata_pointer_descriptor*) d; +} + +/** + * Accessor for pointer to appid field of an mpeg_metadata_pointer_descriptor. + * + * @param d The mpeg_metadata_pointer_descriptor structure. + * @return The pointer, or NULL on error. + */ +static inline struct mpeg_metadata_pointer_descriptor_application_format_identifier* + mpeg_metadata_pointer_descriptor_appid(struct mpeg_metadata_pointer_descriptor *d) +{ + uint8_t *buf = (uint8_t*) d + sizeof(struct mpeg_metadata_pointer_descriptor); + + if (d->metadata_application_format != 0xffff) + return NULL; + return (struct mpeg_metadata_pointer_descriptor_application_format_identifier*) buf; +} + +/** + * Accessor for metadata_format field of an mpeg_metadata_pointer_descriptor. + * + * @param d The mpeg_metadata_pointer_descriptor structure. + * @return The pointer, or NULL on error. + */ +static inline uint8_t + mpeg_metadata_pointer_descriptor_metadata_format(struct mpeg_metadata_pointer_descriptor *d) +{ + uint8_t *buf = (uint8_t*) d + sizeof(struct mpeg_metadata_pointer_descriptor); + + if (d->metadata_application_format == 0xffff) + buf+=4; + return *buf; +} + +/** + * Accessor for pointer to formid field of an mpeg_metadata_pointer_descriptor. + * + * @param d The mpeg_metadata_pointer_descriptor structure. + * @return The pointer, or NULL on error. + */ +static inline struct mpeg_metadata_pointer_descriptor_format_identifier* + mpeg_metadata_pointer_descriptor_formid(struct mpeg_metadata_pointer_descriptor *d) +{ + uint8_t *buf = (uint8_t*) d + sizeof(struct mpeg_metadata_pointer_descriptor); + + if (d->metadata_application_format == 0xffff) + buf+=4; + if (*buf != 0xff) + return NULL; + + return (struct mpeg_metadata_pointer_descriptor_format_identifier*) (buf+1); +} + +/** + * Accessor for flags field of an mpeg_metadata_pointer_descriptor. + * + * @param d The mpeg_metadata_pointer_descriptor structure. + * @return Pointer to the field, or NULL on error. + */ +static inline struct mpeg_metadata_pointer_descriptor_flags* + mpeg_metadata_pointer_descriptor_flags(struct mpeg_metadata_pointer_descriptor *d) +{ + uint8_t *buf = (uint8_t*) d + sizeof(struct mpeg_metadata_pointer_descriptor); + + if (d->metadata_application_format == 0xffff) + buf+=4; + if (*buf == 0xff) + buf+=4; + + return (struct mpeg_metadata_pointer_descriptor_flags*) buf; +} + + +/** + * Accessor for locator field of an mpeg_metadata_pointer_descriptor. + * + * @param flags Pointer to the mpeg_metadata_pointer_descriptor_flags. + * @return Pointer to the field, or NULL on error. + */ +static inline struct mpeg_metadata_pointer_descriptor_locator* + mpeg_metadata_pointer_descriptor_locator(struct mpeg_metadata_pointer_descriptor_flags *flags) +{ + uint8_t *buf = (uint8_t*) flags + sizeof(struct mpeg_metadata_pointer_descriptor_flags); + + if (flags->metadata_locator_record_flag!=1) + return NULL; + + return (struct mpeg_metadata_pointer_descriptor_locator *) buf; +} + +/** + * Accessor for data field of an mpeg_metadata_pointer_descriptor_locator. + * + * @param d The mpeg_metadata_pointer_descriptor_locator structure. + * @return Pointer to the field. + */ +static inline uint8_t* + mpeg_metadata_pointer_descriptor_locator_data(struct mpeg_metadata_pointer_descriptor_locator *d) +{ + return (uint8_t*) d + sizeof(struct mpeg_metadata_pointer_descriptor_locator); +} + + +/** + * Accessor for program_number field of an mpeg_metadata_pointer_descriptor. + * + * @param flags Pointer to the mpeg_metadata_pointer_descriptor_flags. + * @return Pointer to the field, or NULL on error. + */ +static inline struct mpeg_metadata_pointer_descriptor_program_number* + mpeg_metadata_pointer_descriptor_program_number(struct mpeg_metadata_pointer_descriptor_flags *flags) +{ + uint8_t *buf = (uint8_t*) flags + sizeof(struct mpeg_metadata_pointer_descriptor_flags); + + if (flags->mpeg_carriage_flags < 3) + return NULL; + + if (flags->metadata_locator_record_flag==1) + buf += 1 + buf[1]; + + return (struct mpeg_metadata_pointer_descriptor_program_number*) buf; +} + +/** + * Accessor for carriage field of an mpeg_metadata_pointer_descriptor. + * + * @param flags Pointer to the mpeg_metadata_pointer_descriptor_flags. + * @return Pointer to the field, or NULL on error. + */ +static inline struct mpeg_metadata_pointer_descriptor_carriage* + mpeg_metadata_pointer_descriptor_carriage(struct mpeg_metadata_pointer_descriptor_flags *flags) +{ + uint8_t *buf = (uint8_t*) flags + sizeof(struct mpeg_metadata_pointer_descriptor_flags); + + if (flags->mpeg_carriage_flags != 1) + return NULL; + + if (flags->metadata_locator_record_flag==1) + buf += 1 + buf[1]; + if (flags->mpeg_carriage_flags < 3) + buf += sizeof(struct mpeg_metadata_pointer_descriptor_program_number); + + return (struct mpeg_metadata_pointer_descriptor_carriage *) buf; +} + +/** + * Accessor for private_data field of an mpeg_metadata_pointer_descriptor. + * + * @param d The mpeg_metadata_pointer_descriptor structure. + * @param flags Pointer to the mpeg_metadata_pointer_descriptor_flags. + * @param length Where the number of bytes in the field should be stored. + * @return Pointer to the field. + */ +static inline uint8_t* + mpeg_metadata_pointer_descriptor_private_data(struct mpeg_metadata_pointer_descriptor *d, + struct mpeg_metadata_pointer_descriptor_flags *flags, + int *length) +{ + uint8_t *buf = (uint8_t*) flags + sizeof(struct mpeg_metadata_pointer_descriptor_flags); + uint8_t *end = (uint8_t*) d + d->d.len + 2; + + + if (flags->metadata_locator_record_flag==1) + buf += 1 + buf[1]; + if (flags->mpeg_carriage_flags < 3) + buf += sizeof(struct mpeg_metadata_pointer_descriptor_program_number); + if (flags->mpeg_carriage_flags != 1) + buf += sizeof(struct mpeg_metadata_pointer_descriptor_carriage); + + *length = end - buf; + return buf; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/mpeg/metadata_section.c b/kaffeine/src/input/dvb/lib/libucsi/mpeg/metadata_section.c new file mode 100644 index 0000000..9af1d96 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/mpeg/metadata_section.c @@ -0,0 +1,28 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include <libucsi/mpeg/metadata_section.h> + +struct mpeg_metadata_section * mpeg_metadata_section_codec(struct section_ext * ext) +{ + return (struct mpeg_metadata_section *)ext; +} + diff --git a/kaffeine/src/input/dvb/lib/libucsi/mpeg/metadata_section.h b/kaffeine/src/input/dvb/lib/libucsi/mpeg/metadata_section.h new file mode 100644 index 0000000..62c4e03 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/mpeg/metadata_section.h @@ -0,0 +1,122 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_MPEG_METADATA_SECTION_H +#define _UCSI_MPEG_METADATA_SECTION_H 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/section.h> + +/** + * mpeg_metadata_section structure. + */ +struct mpeg_metadata_section { + struct section_ext head; + + /* uint8_t data[] */ +} __ucsi_packed; + +/** + * Process an mpeg_metadata_section structure. + * + * @param section Pointer to the section_ext structure. + * @return Pointer to the mpeg_metadata_section structure, or NULL on error. + */ +extern struct mpeg_metadata_section *mpeg_metadata_section_codec(struct section_ext *section); + +/** + * Accessor for the random_access_indicator field of a metadata section. + * + * @param metadata metadata section pointer. + * @return The random_access_indicator. + */ +static inline uint8_t mpeg_metadata_section_random_access_indicator(struct mpeg_metadata_section *metadata) +{ + return metadata->head.reserved >> 1; +} + +/** + * Accessor for the decoder_config_flag field of a metadata section. + * + * @param metadata metadata section pointer. + * @return The decoder_config_flag. + */ +static inline uint8_t mpeg_metadata_section_decoder_config_flag(struct mpeg_metadata_section *metadata) +{ + return metadata->head.reserved & 1; +} + +/** + * Accessor for the fragment_indicator field of a metadata section. + * + * @param metadata metadata section pointer. + * @return The fragment_indicator. + */ +static inline uint8_t mpeg_metadata_section_fragment_indicator(struct mpeg_metadata_section *metadata) +{ + return metadata->head.reserved1; +} + +/** + * Accessor for the service_id field of a metadata section. + * + * @param metadata metadata section pointer. + * @return The service_id. + */ +static inline uint16_t mpeg_metadata_section_service_id(struct mpeg_metadata_section *metadata) +{ + return metadata->head.table_id_ext >> 8; +} + +/** + * Retrieve pointer to data field of an mpeg_metadata_section. + * + * @param s mpeg_metadata_section pointer. + * @return Pointer to the field. + */ +static inline uint8_t * + mpeg_metadata_section_data(struct mpeg_metadata_section *s) +{ + return (uint8_t *) s + sizeof(struct mpeg_metadata_section); +} + + +/** + * Determine length of the data field of an mpeg_copyright_descriptor. + * + * @param s mpeg_metadata_section_data pointer. + * @return Length of field in bytes. + */ +static inline int + mpeg_metadata_section_data_length(struct mpeg_metadata_section *s) +{ + return section_ext_length(&s->head) - sizeof(struct mpeg_metadata_section); +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/mpeg/metadata_std_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/mpeg/metadata_std_descriptor.h new file mode 100644 index 0000000..fc83e6e --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/mpeg/metadata_std_descriptor.h @@ -0,0 +1,72 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_MPEG_METADATA_STD_DESCRIPTOR +#define _UCSI_MPEG_METADATA_STD_DESCRIPTOR 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/descriptor.h> +#include <libucsi/endianops.h> + +/** + * mpeg_metadata_std_descriptor structure. + */ +struct mpeg_metadata_std_descriptor { + struct descriptor d; + + EBIT2(uint32_t reserved_1 : 2; , + uint32_t metadata_input_leak_rate :22; ); + EBIT2(uint32_t reserved_2 : 2; , + uint32_t metadata_buffer_size :22; ); + EBIT2(uint32_t reserved_3 : 2; , + uint32_t metadata_output_leak_rate :22; ); +} __ucsi_packed; + +/** + * Process an mpeg_metadata_std_descriptor. + * + * @param d Pointer to the generic descriptor structure. + * @return Pointer to the mpeg_metadata_std_descriptor, or NULL on error. + */ +static inline struct mpeg_metadata_std_descriptor* + mpeg_metadata_std_descriptor_codec(struct descriptor* d) +{ + uint8_t *buf = (uint8_t*) d; + + if (d->len != (sizeof(struct mpeg_metadata_std_descriptor) - 2)) + return NULL; + + bswap24(buf + 2); + bswap24(buf + 5); + bswap24(buf + 8); + + return (struct mpeg_metadata_std_descriptor*) d; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/mpeg/mpeg4_audio_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/mpeg/mpeg4_audio_descriptor.h new file mode 100644 index 0000000..f876759 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/mpeg/mpeg4_audio_descriptor.h @@ -0,0 +1,61 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_MPEG4_AUDIO_DESCRIPTOR +#define _UCSI_MPEG4_AUDIO_DESCRIPTOR 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/descriptor.h> +#include <libucsi/endianops.h> + +/** + * mpeg4_audio_descriptor structure. + */ +struct mpeg4_audio_descriptor { + struct descriptor d; + + uint8_t mpeg4_audio_profile_and_level; +} __ucsi_packed; + +/** + * Process an mpeg4_audio_descriptor. + * + * @param d Generic descriptor structure. + * @return Pointer to an mpeg4_audio_descriptor structure, or NULL on error. + */ +static inline struct mpeg4_audio_descriptor* + mpeg4_audio_descriptor_codec(struct descriptor* d) +{ + if (d->len != (sizeof(struct mpeg4_audio_descriptor) - 2)) + return NULL; + + return (struct mpeg4_audio_descriptor*) d; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/mpeg/mpeg4_video_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/mpeg/mpeg4_video_descriptor.h new file mode 100644 index 0000000..b956b91 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/mpeg/mpeg4_video_descriptor.h @@ -0,0 +1,61 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_MPEG4_VIDEO_DESCRIPTOR +#define _UCSI_MPEG4_VIDEO_DESCRIPTOR 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/descriptor.h> +#include <libucsi/endianops.h> + +/** + * mpeg4_video_descriptor structure. + */ +struct mpeg4_video_descriptor { + struct descriptor d; + + uint8_t mpeg4_visual_profile_and_level; +} __ucsi_packed; + +/** + * Process an mpeg4_video_descriptor structure. + * + * @param d Pointer to generic descriptor structure. + * @return Pointer to mpeg4_video_descriptor structure, or NULL on error. + */ +static inline struct mpeg4_video_descriptor* + mpeg4_video_descriptor_codec(struct descriptor* d) +{ + if (d->len != (sizeof(struct mpeg4_video_descriptor) - 2)) + return NULL; + + return (struct mpeg4_video_descriptor*) d; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/mpeg/multiplex_buffer_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/mpeg/multiplex_buffer_descriptor.h new file mode 100644 index 0000000..d55ce3d --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/mpeg/multiplex_buffer_descriptor.h @@ -0,0 +1,65 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_MPEG_MULTIPLEX_BUFFER_DESCRIPTOR +#define _UCSI_MPEG_MULTIPLEX_BUFFER_DESCRIPTOR 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/descriptor.h> +#include <libucsi/endianops.h> + +/** + * mpeg_multiplex_buffer_descriptor descriptor. + */ +struct mpeg_multiplex_buffer_descriptor { + struct descriptor d; + + EBIT2(uint64_t mb_buffer_size : 24; , + uint64_t tb_leak_rate : 24; ); +} __ucsi_packed; + +/** + * Process an mpeg_multiplex_buffer_descriptor. + * + * @param d Pointer to generic descriptor structure. + * @return Pointer to an mpeg_multiplex_buffer_descriptor structure, or NULL on + * error. + */ +static inline struct mpeg_multiplex_buffer_descriptor* + mpeg_multiplex_buffer_descriptor_codec(struct descriptor* d) +{ + if (d->len != (sizeof(struct mpeg_multiplex_buffer_descriptor) - 2)) + return NULL; + + bswap48((uint8_t*) d + 2); + + return (struct mpeg_multiplex_buffer_descriptor*) d; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/mpeg/multiplex_buffer_utilization_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/mpeg/multiplex_buffer_utilization_descriptor.h new file mode 100644 index 0000000..16550ed --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/mpeg/multiplex_buffer_utilization_descriptor.h @@ -0,0 +1,67 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_MPEG_MULTIPLEX_BUFFER_UTILIZATION_DESCRIPTOR +#define _UCSI_MPEG_MULTIPLEX_BUFFER_UTILIZATION_DESCRIPTOR 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/descriptor.h> +#include <libucsi/endianops.h> + +/** + * mpeg_multiplex_buffer_utilization_descriptor structure. + */ +struct mpeg_multiplex_buffer_utilization_descriptor { + struct descriptor d; + + EBIT2(uint16_t bound_valid_flag : 1; , + uint16_t ltw_offset_lower_bound : 15; ); + EBIT2(uint16_t reserved : 1; , + uint16_t ltw_offset_upper_bound : 15; ); +} __ucsi_packed; + +/** + * Process a mpeg_multiplex_buffer_utilization_descriptor. + * + * @param d Generic descriptor pointer. + * @return mpeg_multiplex_buffer_utilization_descriptor pointer, or NULL on error. + */ +static inline struct mpeg_multiplex_buffer_utilization_descriptor* + mpeg_multiplex_buffer_utilization_descriptor_codec(struct descriptor* d) +{ + if (d->len != (sizeof(struct mpeg_multiplex_buffer_utilization_descriptor) - 2)) + return NULL; + + bswap16((uint8_t*) d + 2); + bswap16((uint8_t*) d + 4); + + return (struct mpeg_multiplex_buffer_utilization_descriptor*) d; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/mpeg/muxcode_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/mpeg/muxcode_descriptor.h new file mode 100644 index 0000000..6bed334 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/mpeg/muxcode_descriptor.h @@ -0,0 +1,82 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_MPEG_MUXCODE_DESCRIPTOR +#define _UCSI_MPEG_MUXCODE_DESCRIPTOR 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/descriptor.h> +#include <libucsi/endianops.h> + +/** + * mpeg_muxcode_descriptor structure + */ +struct mpeg_muxcode_descriptor { + struct descriptor d; + + /* uint8_t entries[] */ +} __ucsi_packed; + +/** + * Process an mpeg_muxcode_descriptor. + * + * @param d Pointer to a generic descriptor structure. + * @return Pointer to an mpeg_muxcode_descriptor structure, or NULL on error. + */ +static inline struct mpeg_muxcode_descriptor* + mpeg_muxcode_descriptor_codec(struct descriptor* d) +{ + return (struct mpeg_muxcode_descriptor*) d; +} + +/** + * Retrieve pointer to entries field of an mpeg_muxcode_descriptor structure. + * + * @param d Generic descriptor structure. + * @return Pointer to the entries field. + */ +static inline uint8_t * + mpeg_muxcode_descriptor_entries(struct mpeg_muxcode_descriptor *d) +{ + return (uint8_t *) d + sizeof(struct mpeg_muxcode_descriptor); +} + +/** + * Determine length of entries field of an mpeg_muxcode_descriptor structure. + * + * @param d Generic descriptor structure. + * @return Number of bytes in the entries field. + */ +static inline int + mpeg_muxcode_descriptor_entries_length(struct mpeg_muxcode_descriptor *d) +{ + return d->d.len; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/mpeg/odsmt_section.c b/kaffeine/src/input/dvb/lib/libucsi/mpeg/odsmt_section.c new file mode 100644 index 0000000..c56ccb1 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/mpeg/odsmt_section.c @@ -0,0 +1,80 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include <libucsi/mpeg/odsmt_section.h> + +struct mpeg_odsmt_section *mpeg_odsmt_section_codec(struct section_ext * ext) +{ + struct mpeg_odsmt_section * odsmt = (struct mpeg_odsmt_section *)ext; + uint8_t * buf = (uint8_t *)ext; + int pos = sizeof(struct section_ext); + int len = section_ext_length(ext); + int i; + + if (len < sizeof(struct mpeg_odsmt_section)) + return NULL; + + pos++; + + if (odsmt->stream_count == 0) { + struct mpeg_odsmt_stream * stream = + (struct mpeg_odsmt_stream *) (buf + pos); + + if ((pos + sizeof(struct mpeg_odsmt_stream_single)) > len) + return NULL; + + bswap16(buf+pos); + pos+=3; + + if ((pos + stream->u.single.es_info_length) >= len) + return NULL; + + if (verify_descriptors(buf + pos, stream->u.single.es_info_length)) + return NULL; + + pos += stream->u.single.es_info_length; + } else { + for (i=0; i< odsmt->stream_count; i++) { + struct mpeg_odsmt_stream * stream = + (struct mpeg_odsmt_stream *)(buf + pos); + + if ((pos + sizeof(struct mpeg_odsmt_stream_multi)) > len) + return NULL; + + bswap16(buf+pos); + pos += sizeof(struct mpeg_odsmt_stream_multi); + + if ((pos + stream->u.multi.es_info_length) > len) + return NULL; + + if (verify_descriptors(buf + pos, + stream->u.multi.es_info_length)) + return NULL; + + pos += stream->u.multi.es_info_length; + } + } + + if (pos != len) + return NULL; + + return (struct mpeg_odsmt_section *) ext; +} diff --git a/kaffeine/src/input/dvb/lib/libucsi/mpeg/odsmt_section.h b/kaffeine/src/input/dvb/lib/libucsi/mpeg/odsmt_section.h new file mode 100644 index 0000000..2e5302d --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/mpeg/odsmt_section.h @@ -0,0 +1,224 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_MPEG_ODSMT_SECTION_H +#define _UCSI_MPEG_ODSMT_SECTION_H 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/section.h> + +/** + * mpeg_odsmt_section structure. + */ +struct mpeg_odsmt_section { + struct section_ext head; + + uint8_t stream_count; + /* stream_count==0 => struct mpeg_odsmt_stream_single streams + stream_count>0 => struct mpeg_odsmt_stream_multi streams[] */ + /* uint8_t object_descriptors[] */ +} __ucsi_packed; + +struct mpeg_odsmt_stream_single +{ + uint16_t esid; + uint8_t es_info_length; + /* struct descriptor descriptors[] */ +} __ucsi_packed; + +struct mpeg_odsmt_stream_multi +{ + uint16_t esid; + uint8_t fmc; + uint8_t es_info_length; + /* struct descriptor descriptors[] */ +} __ucsi_packed; + +/** + * Structure describing the stream information held in an mpeg_odsmt_section. + */ +struct mpeg_odsmt_stream { + union { + struct mpeg_odsmt_stream_single single __ucsi_packed; + struct mpeg_odsmt_stream_multi multi __ucsi_packed; + } u __ucsi_packed; +} __ucsi_packed; + +/** + * Process an mpeg_odsmt_section. + * + * @param section Pointer to the generic section_ext structure. + * @return Pointer to a mpeg_odsmt_section structure, or NULL on error. + */ +extern struct mpeg_odsmt_section *mpeg_odsmt_section_codec(struct section_ext *section); + +/** + * Accessor for the PID field of an ODSMT. + * + * @param odsmt odsmt pointer. + * @return The pid. + */ +static inline uint16_t mpeg_odsmt_section_pid(struct mpeg_odsmt_section *odsmt) +{ + return odsmt->head.table_id_ext & 0x1fff; +} + +/** + * Convenience iterator for the streams field of an mpeg_odsmt_section. + * + * @param osdmt Pointer to the mpeg_odsmt_section structure. + * @param pos Variable holding pointer to the current mpeg_odsmt_stream structure. + * @param index Variable holding the stream index. + */ +#define mpeg_odsmt_section_streams_for_each(osdmt, pos, index) \ + for (index=0, (pos) = mpeg_odsmt_section_streams_first(odsmt); \ + (pos); \ + (pos) = mpeg_odsmt_section_streams_next(odsmt, pos, ++index)) + +/** + * Convenience iterator for the descriptors field of an mpeg_odsmt_stream. + * + * @param osdmt Pointer to the mpeg_odsmt_section structure. + * @param stream Pointer to the mpeg_odsmt_stream structure. + * @param pos Variable holding pointer to the current descriptor structure. + */ +#define mpeg_odsmt_stream_descriptors_for_each(osdmt, stream, pos) \ + for ((pos) = mpeg_odsmt_stream_descriptors_first(odsmt, stream); \ + (pos); \ + (pos) = mpeg_odsmt_stream_descriptors_next(odsmt, stream, pos)) + +/** + * Retrieve a pointer to the object_descriptors field of an mpeg_odsmt_section. + * + * @param osdmt Pointer to the mpeg_odsmt_section structure. + * @param len On return, will contain the number of bytes in the object descriptors field. + * @return Pointer to the object_descriptors field, or NULL on error. + */ +static inline uint8_t* + mpeg_odsmt_section_object_descriptors(struct mpeg_odsmt_section * odsmt, + uint32_t* len); + + + + + + + + + + +/******************************** PRIVATE CODE ********************************/ +static inline struct mpeg_odsmt_stream * + mpeg_odsmt_section_streams_first(struct mpeg_odsmt_section *odsmt) +{ + int pos = sizeof(struct mpeg_odsmt_section); + + if (pos >= section_ext_length(&odsmt->head)) + return NULL; + + return (struct mpeg_odsmt_stream *) ((uint8_t *) odsmt + pos); +} + +static inline struct mpeg_odsmt_stream * + mpeg_odsmt_section_streams_next(struct mpeg_odsmt_section *odsmt, + struct mpeg_odsmt_stream *pos, + int index) +{ + uint8_t *end = (uint8_t*) odsmt + section_ext_length(&odsmt->head); + uint8_t *next; + + if (index > odsmt->stream_count) + return NULL; + + next = (uint8_t *) pos + sizeof(struct mpeg_odsmt_stream_multi) + + pos->u.multi.es_info_length; + + if (next >= end) + return NULL; + + return (struct mpeg_odsmt_stream *) next; +} + +static inline struct descriptor * + mpeg_odsmt_stream_descriptors_first(struct mpeg_odsmt_section *odsmt, + struct mpeg_odsmt_stream *stream) +{ + if (odsmt->stream_count == 0) { + if (stream->u.single.es_info_length == 0) + return NULL; + + return (struct descriptor *) + ((uint8_t*) stream + sizeof(struct mpeg_odsmt_stream_single)); + } else { + if (stream->u.multi.es_info_length == 0) + return NULL; + + return (struct descriptor *) + ((uint8_t*) stream + sizeof(struct mpeg_odsmt_stream_multi)); + } +} + +static inline struct descriptor * + mpeg_odsmt_stream_descriptors_next(struct mpeg_odsmt_section *odsmt, + struct mpeg_odsmt_stream *stream, + struct descriptor* pos) +{ + if (odsmt->stream_count == 0) { + return next_descriptor((uint8_t *) stream + sizeof(struct mpeg_odsmt_stream_single), + stream->u.single.es_info_length, + pos); + } else { + return next_descriptor((uint8_t *) stream + sizeof(struct mpeg_odsmt_stream_multi), + stream->u.multi.es_info_length, + pos); + } +} + +static inline uint8_t* + mpeg_odsmt_section_object_descriptors(struct mpeg_odsmt_section * odsmt, + uint32_t* len) +{ + struct mpeg_odsmt_stream* pos; + int size = sizeof(struct mpeg_odsmt_section); + int index; + + mpeg_odsmt_section_streams_for_each(odsmt, pos, index) { + if (odsmt->stream_count == 0) + size += sizeof(struct mpeg_odsmt_stream_single) + + pos->u.single.es_info_length; + else + size += sizeof(struct mpeg_odsmt_stream_multi) + + pos->u.multi.es_info_length; + } + + *len = section_ext_length(&odsmt->head) - size; + return (uint8_t*) odsmt + size; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/mpeg/pat_section.c b/kaffeine/src/input/dvb/lib/libucsi/mpeg/pat_section.c new file mode 100644 index 0000000..80b28d5 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/mpeg/pat_section.c @@ -0,0 +1,46 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include <libucsi/mpeg/pat_section.h> + +struct mpeg_pat_section *mpeg_pat_section_codec(struct section_ext * ext) +{ + uint8_t *buf = (uint8_t *)ext; + int pos = sizeof(struct section_ext); + int len = section_ext_length(ext); + + if (len < sizeof(struct mpeg_pat_section)) + return NULL; + + while (pos < len) { + if ((pos + 4) > len) + return NULL; + + bswap16(buf + pos); + bswap16(buf + pos + 2); + pos += 4; + } + + if (pos != len) + return NULL; + + return (struct mpeg_pat_section *)ext; +} diff --git a/kaffeine/src/input/dvb/lib/libucsi/mpeg/pat_section.h b/kaffeine/src/input/dvb/lib/libucsi/mpeg/pat_section.h new file mode 100644 index 0000000..20b3f7a --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/mpeg/pat_section.h @@ -0,0 +1,118 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_MPEG_PAT_SECTION_H +#define _UCSI_MPEG_PAT_SECTION_H 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/section.h> + +/** + * mpeg_pat_section structure. + */ +struct mpeg_pat_section { + struct section_ext head; /* table_id_ext == transport_stream_id */ + + /* struct mpeg_pat_program programs[] */ +} __ucsi_packed; + +/** + * A program within an mpeg_pat_section. + */ +struct mpeg_pat_program { + uint16_t program_number; + EBIT2(uint16_t reserved : 3; , + uint16_t pid :13; ) +} __ucsi_packed; + +/** + * Process an mpeg_pat_section. + * + * @param section Pointer to the generic section_ext structure. + * @return Pointer to the mpeg_pat_section structure, or NULL on error. + */ +extern struct mpeg_pat_section *mpeg_pat_section_codec(struct section_ext *section); + +/** + * Accessor for the transport_stream_id field of a PAT. + * + * @param pat PAT pointer. + * @return The transport_stream_id. + */ +static inline uint16_t mpeg_pat_section_transport_stream_id(struct mpeg_pat_section *pat) +{ + return pat->head.table_id_ext; +} + +/** + * Conveience iterator for the programs field of an mpeg_pat_section. + * + * @param pat Pointer to the mpeg_pat_section structure. + * @param pos Variable holding a pointer to the current mpeg_pat_program structure. + */ +#define mpeg_pat_section_programs_for_each(pat, pos) \ + for ((pos) = mpeg_pat_section_programs_first(pat); \ + (pos); \ + (pos) = mpeg_pat_section_programs_next(pat, pos)) + + + + + + + + + + +/******************************** PRIVATE CODE ********************************/ +static inline struct mpeg_pat_program * + mpeg_pat_section_programs_first(struct mpeg_pat_section * pat) +{ + int pos = sizeof(struct mpeg_pat_section); + + if (pos >= section_ext_length(&pat->head)) + return NULL; + + return (struct mpeg_pat_program*)((uint8_t *) pat + pos); +} + +static inline + struct mpeg_pat_program *mpeg_pat_section_programs_next(struct mpeg_pat_section * pat, + struct mpeg_pat_program * pos) +{ + uint8_t *end = (uint8_t*) pat + section_ext_length(&pat->head); + uint8_t *next= (uint8_t *) pos + sizeof(struct mpeg_pat_program); + + if (next >= end) + return NULL; + + return (struct mpeg_pat_program *) next; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/mpeg/pmt_section.c b/kaffeine/src/input/dvb/lib/libucsi/mpeg/pmt_section.c new file mode 100644 index 0000000..6ff4fac --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/mpeg/pmt_section.c @@ -0,0 +1,71 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include <libucsi/mpeg/pmt_section.h> + +struct mpeg_pmt_section * mpeg_pmt_section_codec(struct section_ext * ext) +{ + uint8_t * buf = (uint8_t *) ext; + struct mpeg_pmt_section * pmt = (struct mpeg_pmt_section *) ext; + unsigned int pos = sizeof(struct section_ext); + unsigned int len = section_ext_length(ext); + + if (len < sizeof(struct mpeg_pmt_section)) + return NULL; + + bswap16(buf + pos); + pos += 2; + bswap16(buf + pos); + pos += 2; + + if ((pos + pmt->program_info_length) > len) + return NULL; + + if (verify_descriptors(buf + pos, pmt->program_info_length)) + return NULL; + + pos += pmt->program_info_length; + + while (pos < len) { + struct mpeg_pmt_stream * stream = + (struct mpeg_pmt_stream *) (buf + pos); + + if ((pos + sizeof(struct mpeg_pmt_stream)) > len) + return NULL; + + bswap16(buf + pos + 1); + bswap16(buf + pos + 3); + pos += sizeof(struct mpeg_pmt_stream); + + if ((pos + stream->es_info_length) > len) + return NULL; + + if (verify_descriptors(buf + pos, stream->es_info_length)) + return NULL; + + pos += stream->es_info_length; + } + + if (pos != len) + return NULL; + + return (struct mpeg_pmt_section *) ext; +} diff --git a/kaffeine/src/input/dvb/lib/libucsi/mpeg/pmt_section.h b/kaffeine/src/input/dvb/lib/libucsi/mpeg/pmt_section.h new file mode 100644 index 0000000..73bba1d --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/mpeg/pmt_section.h @@ -0,0 +1,188 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_MPEG_PMT_SECTION_H +#define _UCSI_MPEG_PMT_SECTION_H 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/section.h> + +/** + * mpeg_pmt_section structure. + */ +struct mpeg_pmt_section { + struct section_ext head; + + EBIT2(uint16_t reserved_1 : 3; , + uint16_t pcr_pid :13; ) + EBIT2(uint16_t reserved_2 : 4; , + uint16_t program_info_length :12; ) + /* struct descriptor descriptors[] */ + /* struct mpeg_pmt_stream streams[] */ +} __ucsi_packed; + +/** + * A stream within an mpeg_pmt_section. + */ +struct mpeg_pmt_stream { + uint8_t stream_type; + EBIT2(uint16_t reserved_1 : 3; , + uint16_t pid :13; ) + EBIT2(uint16_t reserved_2 : 4; , + uint16_t es_info_length :12; ) + + /* struct descriptor descriptors[] */ +} __ucsi_packed; + +/** + * Process an mpeg_pmt_section section. + * + * @param section Pointer to the generic section header. + * @return Pointer to the mpeg_pmt_section structure, or NULL on error. + */ +extern struct mpeg_pmt_section *mpeg_pmt_section_codec(struct section_ext *section); + +/** + * Accessor for program_number field of a PMT. + * + * @param pmt PMT pointer. + * @return The program_number. + */ +static inline uint16_t mpeg_pmt_section_program_number(struct mpeg_pmt_section *pmt) +{ + return pmt->head.table_id_ext; +} + +/** + * Convenience iterator for the descriptors field of the mpeg_pmt_section structure. + * + * @param pmt Pointer to the mpeg_pmt_section structure. + * @param pos Variable holding a pointer to the current descriptor. + */ +#define mpeg_pmt_section_descriptors_for_each(pmt, pos) \ + for ((pos) = mpeg_pmt_section_descriptors_first(pmt); \ + (pos); \ + (pos) = mpeg_pmt_section_descriptors_next(pmt, pos)) + +/** + * Convenience iterator for the streams field of the mpeg_pmt_section structure. + * + * @param pmt Pointer to the mpeg_pmt_section structure. + * @param pos Variable holding a pointer to the current mpeg_pmt_stream. + */ +#define mpeg_pmt_section_streams_for_each(pmt, pos) \ + for ((pos) = mpeg_pmt_section_streams_first(pmt); \ + (pos); \ + (pos) = mpeg_pmt_section_streams_next(pmt, pos)) + +/** + * Convenience iterator for the descriptors field of an mpeg_pmt_stream structure. + * + * @param stream Pointer to the mpeg_pmt_stream structure. + * @param pos Variable holding a pointer to the current descriptor. + */ +#define mpeg_pmt_stream_descriptors_for_each(stream, pos) \ + for ((pos) = mpeg_pmt_stream_descriptors_first(stream); \ + (pos); \ + (pos) = mpeg_pmt_stream_descriptors_next(stream, pos)) + + + + + + + + + + +/******************************** PRIVATE CODE ********************************/ +static inline struct descriptor * + mpeg_pmt_section_descriptors_first(struct mpeg_pmt_section * pmt) +{ + if (pmt->program_info_length == 0) + return NULL; + + return (struct descriptor *) + ((uint8_t *) pmt + sizeof(struct mpeg_pmt_section)); +} + +static inline struct descriptor * + mpeg_pmt_section_descriptors_next(struct mpeg_pmt_section *pmt, + struct descriptor* pos) +{ + return next_descriptor((uint8_t *) pmt + sizeof(struct mpeg_pmt_section), + pmt->program_info_length, + pos); +} + +static inline struct mpeg_pmt_stream * + mpeg_pmt_section_streams_first(struct mpeg_pmt_section * pmt) +{ + int pos = sizeof(struct mpeg_pmt_section) + pmt->program_info_length; + + if (pos >= section_ext_length(&pmt->head)) + return NULL; + + return (struct mpeg_pmt_stream *)((uint8_t *)pmt + pos); +} + +static inline struct mpeg_pmt_stream * + mpeg_pmt_section_streams_next(struct mpeg_pmt_section * pmt, + struct mpeg_pmt_stream * pos) +{ + uint8_t *end = (uint8_t*) pmt + section_ext_length(&pmt->head); + uint8_t *next = (uint8_t *) pos + sizeof(struct mpeg_pmt_stream) + + pos->es_info_length; + + if (next >= end) + return NULL; + + return (struct mpeg_pmt_stream *) next; +} + +static inline struct descriptor * + mpeg_pmt_stream_descriptors_first(struct mpeg_pmt_stream *stream) +{ + if (stream->es_info_length == 0) + return NULL; + + return (struct descriptor *) + ((uint8_t*) stream + sizeof(struct mpeg_pmt_stream)); +} + +static inline struct descriptor * + mpeg_pmt_stream_descriptors_next(struct mpeg_pmt_stream *stream, + struct descriptor* pos) +{ + return next_descriptor((uint8_t *) stream + sizeof(struct mpeg_pmt_stream), + stream->es_info_length, + pos); +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/mpeg/private_data_indicator_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/mpeg/private_data_indicator_descriptor.h new file mode 100644 index 0000000..80e8ef3 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/mpeg/private_data_indicator_descriptor.h @@ -0,0 +1,63 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_MPEG_PRIVATE_DATA_INDICATOR_DESCRIPTOR +#define _UCSI_MPEG_PRIVATE_DATA_INDICATOR_DESCRIPTOR 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/descriptor.h> +#include <libucsi/endianops.h> + +/** + * mpeg_private_data_indicator_descriptor structure + */ +struct mpeg_private_data_indicator_descriptor { + struct descriptor d; + + uint32_t private_data_indicator; +} __ucsi_packed; + +/** + * Process an mpeg_private_data_indicator_descriptor structure. + * + * @param d Pointer to the generic descriptor structure. + * @return Pointer to the mpeg_private_data_indicator_descriptor, or NULL on error. + */ +static inline struct mpeg_private_data_indicator_descriptor* + mpeg_private_data_indicator_descriptor_codec(struct descriptor* d) +{ + if (d->len != (sizeof(struct mpeg_private_data_indicator_descriptor) - 2)) + return NULL; + + bswap32((uint8_t*) d + 2); + + return (struct mpeg_private_data_indicator_descriptor*) d; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/mpeg/registration_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/mpeg/registration_descriptor.h new file mode 100644 index 0000000..df5c186 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/mpeg/registration_descriptor.h @@ -0,0 +1,91 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_MPEG_REGISTRATION_DESCRIPTOR +#define _UCSI_MPEG_REGISTRATION_DESCRIPTOR 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/descriptor.h> +#include <libucsi/endianops.h> + +/** + * mpeg_registration_descriptor structure. + */ +struct mpeg_registration_descriptor { + struct descriptor d; + + uint32_t format_identifier; + /* uint8_t additional_id_info[] */ +} __ucsi_packed; + +/** + * Process an mpeg_registration_descriptor. + * + * @param d Pointer to the generic descriptor structure. + * @return Pointer to the mpeg_registration_descriptor structure, or NULL on error. + */ +static inline struct mpeg_registration_descriptor* + mpeg_registration_descriptor_codec(struct descriptor* d) +{ + if (d->len < (sizeof(struct mpeg_registration_descriptor) - 2)) + return NULL; + + bswap32((uint8_t*) d + 2); + + return (struct mpeg_registration_descriptor*) d; +} + +/** + * Retrieve a pointer to the additional_id_info field of the + * mpeg_registration_descriptor structure. + * + * @param d Pointer to the mpeg_registration_descriptor structure. + * @return Pointer to the field. + */ +static inline uint8_t * + mpeg_registration_descriptor_additional_id_info(struct mpeg_registration_descriptor *d) +{ + return (uint8_t *) d + sizeof(struct mpeg_registration_descriptor); +} + +/** + * Determine number of bytes in the additional_id_info field of the + * mpeg_registration_descriptor structure. + * + * @param d Pointer to the mpeg_registration_descriptor structure. + * @return Number of bytes. + */ + +static inline int + mpeg_registration_descriptor_additional_id_info_length(struct mpeg_registration_descriptor *d) +{ + return d->d.len - 4; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/mpeg/section.h b/kaffeine/src/input/dvb/lib/libucsi/mpeg/section.h new file mode 100644 index 0000000..6215e95 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/mpeg/section.h @@ -0,0 +1,58 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_MPEG_SECTION_H +#define _UCSI_MPEG_SECTION_H 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/mpeg/cat_section.h> +#include <libucsi/mpeg/odsmt_section.h> +#include <libucsi/mpeg/pat_section.h> +#include <libucsi/mpeg/pmt_section.h> +#include <libucsi/mpeg/tsdt_section.h> +#include <libucsi/mpeg/metadata_section.h> + +#define TRANSPORT_PAT_PID 0x00 +#define TRANSPORT_CAT_PID 0x01 +#define TRANSPORT_TSDT_PID 0x02 + +/** + * Enumeration of MPEG section tags. + */ +enum mpeg_section_tag { + stag_mpeg_program_association = 0x00, + stag_mpeg_conditional_access = 0x01, + stag_mpeg_program_map = 0x02, + stag_mpeg_transport_stream_description = 0x03, + stag_mpeg_iso14496_scene_description = 0x04, + stag_mpeg_iso14496_object_description = 0x05, + stag_mpeg_metadata = 0x06 +}; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/mpeg/sl_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/mpeg/sl_descriptor.h new file mode 100644 index 0000000..ab086e3 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/mpeg/sl_descriptor.h @@ -0,0 +1,63 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_MPEG_SL_DESCRIPTOR +#define _UCSI_MPEG_SL_DESCRIPTOR 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/descriptor.h> +#include <libucsi/endianops.h> + +/** + * mpeg_sl_descriptor structure. + */ +struct mpeg_sl_descriptor { + struct descriptor d; + + uint16_t es_id; +} __ucsi_packed; + +/** + * Process an mpeg_sl_descriptor. + * + * @param d The generic descriptor structure. + * @return Pointer to an mpeg_sl_descriptor structure, or NULL on error. + */ +static inline struct mpeg_sl_descriptor* + mpeg_sl_descriptor_codec(struct descriptor* d) +{ + if (d->len != (sizeof(struct mpeg_sl_descriptor) - 2)) + return NULL; + + bswap16((uint8_t*) d + 2); + + return (struct mpeg_sl_descriptor*) d; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/mpeg/smoothing_buffer_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/mpeg/smoothing_buffer_descriptor.h new file mode 100644 index 0000000..5e6ad33 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/mpeg/smoothing_buffer_descriptor.h @@ -0,0 +1,66 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_MPEG_SMOOTHING_BUFFER_DESCRIPTOR +#define _UCSI_MPEG_SMOOTHING_BUFFER_DESCRIPTOR 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/descriptor.h> +#include <libucsi/endianops.h> + +/** + * mpeg_smoothing_buffer_descriptor structure. + */ +struct mpeg_smoothing_buffer_descriptor { + struct descriptor d; + + EBIT4(uint64_t reserved_1 : 2; , + uint64_t sb_leak_rate :22; , + uint64_t reserved_2 : 2; , + uint64_t sb_size :22; ); +} __ucsi_packed; + +/** + * Process an mpeg_smoothing_buffer_descriptor. + * + * @param d The generic descriptor structure. + * @return Pointer to mpeg_smoothing_buffer_descriptor, or NULL on error. + */ +static inline struct mpeg_smoothing_buffer_descriptor* + mpeg_smoothing_buffer_descriptor_codec(struct descriptor* d) +{ + if (d->len != (sizeof(struct mpeg_smoothing_buffer_descriptor) - 2)) + return NULL; + + bswap48((uint8_t*) d + 2); + + return (struct mpeg_smoothing_buffer_descriptor*) d; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/mpeg/std_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/mpeg/std_descriptor.h new file mode 100644 index 0000000..2625a41 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/mpeg/std_descriptor.h @@ -0,0 +1,62 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_MPEG_STD_DESCRIPTOR +#define _UCSI_MPEG_STD_DESCRIPTOR 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/descriptor.h> +#include <libucsi/endianops.h> + +/** + * mpeg_std_descriptor structure. + */ +struct mpeg_std_descriptor { + struct descriptor d; + + EBIT2(uint8_t reserved : 7; , + uint8_t leak_valid_flag : 1; ); +} __ucsi_packed; + +/** + * Process an mpeg_std_descriptor. + * + * @param d Pointer to the generic descriptor structure. + * @return Pointer to the mpeg_std_descriptor, or NULL on error. + */ +static inline struct mpeg_std_descriptor* + mpeg_std_descriptor_codec(struct descriptor* d) +{ + if (d->len != (sizeof(struct mpeg_std_descriptor) - 2)) + return NULL; + + return (struct mpeg_std_descriptor*) d; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/mpeg/system_clock_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/mpeg/system_clock_descriptor.h new file mode 100644 index 0000000..681641f --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/mpeg/system_clock_descriptor.h @@ -0,0 +1,65 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_MPEG_SYSTEM_CLOCK_DESCRIPTOR +#define _UCSI_MPEG_SYSTEM_CLOCK_DESCRIPTOR 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/descriptor.h> +#include <libucsi/endianops.h> + +/** + * mpeg_system_clock_descriptor structure. + */ +struct mpeg_system_clock_descriptor { + struct descriptor d; + + EBIT3(uint8_t external_clock_reference_indicator : 1; , + uint8_t reserved_1 : 1; , + uint8_t clock_accuracy_integer : 6; ); + EBIT2(uint8_t clock_accuracy_exponent : 3; , + uint8_t reserved_2 : 5; ); +} __ucsi_packed; + +/** + * Process an mpeg_system_clock_descriptor. + * + * @param d The generic descriptor structure. + * @return Pointer to a mpeg_system_clock_descriptor structure, or NULL on error. + */ +static inline struct mpeg_system_clock_descriptor* + mpeg_system_clock_descriptor_codec(struct descriptor* d) +{ + if (d->len != (sizeof(struct mpeg_system_clock_descriptor) - 2)) + return NULL; + + return (struct mpeg_system_clock_descriptor*) d; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/mpeg/target_background_grid_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/mpeg/target_background_grid_descriptor.h new file mode 100644 index 0000000..7394e82 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/mpeg/target_background_grid_descriptor.h @@ -0,0 +1,66 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_MPEG_TARGET_BACKGROUND_GRID_DESCRIPTOR +#define _UCSI_MPEG_TARGET_BACKGROUND_GRID_DESCRIPTOR 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/descriptor.h> +#include <libucsi/endianops.h> + +/** + * mpeg_target_background_grid_descriptor structure. + */ +struct mpeg_target_background_grid_descriptor { + struct descriptor d; + + EBIT3(uint32_t horizontal_size : 14; , + uint32_t vertical_size : 14; , + uint32_t aspect_ratio_information : 4; ); +} __ucsi_packed; + +/** + * Process an mpeg_target_background_grid_descriptor structure. + * + * @param d Pointer to the generic descriptor structure. + * @return Pointer to the mpeg_target_background_grid_descriptor structure, or + * NULL on error. + */ +static inline struct mpeg_target_background_grid_descriptor* + mpeg_target_background_grid_descriptor_codec(struct descriptor* d) +{ + if (d->len != (sizeof(struct mpeg_target_background_grid_descriptor) - 2)) + return NULL; + + bswap32((uint8_t*) d + 2); + + return (struct mpeg_target_background_grid_descriptor*) d; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/mpeg/tsdt_section.c b/kaffeine/src/input/dvb/lib/libucsi/mpeg/tsdt_section.c new file mode 100644 index 0000000..fbbbe3c --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/mpeg/tsdt_section.c @@ -0,0 +1,35 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include <libucsi/mpeg/tsdt_section.h> + +struct mpeg_tsdt_section * mpeg_tsdt_section_codec(struct section_ext * ext) +{ + uint8_t * buf = (uint8_t *)ext; + int pos = sizeof(struct section_ext); + + if (verify_descriptors(buf + pos, + section_ext_length(ext) - sizeof(struct mpeg_tsdt_section))) + return NULL; + + return (struct mpeg_tsdt_section *)ext; +} + diff --git a/kaffeine/src/input/dvb/lib/libucsi/mpeg/tsdt_section.h b/kaffeine/src/input/dvb/lib/libucsi/mpeg/tsdt_section.h new file mode 100644 index 0000000..9039278 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/mpeg/tsdt_section.h @@ -0,0 +1,94 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_MPEG_TSDT_SECTION_H +#define _UCSI_MPEG_TSDT_SECTION_H 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/section.h> + +/** + * mpeg_tsdt_section structure. + */ +struct mpeg_tsdt_section { + struct section_ext head; + + /* struct descriptor descriptors[] */ +} __ucsi_packed; + +/** + * Process an mpeg_tsdt_section structure. + * + * @param section Pointer to the section_ext structure. + * @return Pointer to the mpeg_tsdt_section structure, or NULL on error. + */ +extern struct mpeg_tsdt_section *mpeg_tsdt_section_codec(struct section_ext *section); + +/** + * Convenience iterator for descriptors field. + * + * @param tsdt Pointer to the mpeg_tsdt_section structure. + * @param pos Variable holding a pointer to the current descriptor. + */ +#define mpeg_tsdt_section_descriptors_for_each(tsdt, pos) \ + for ((pos) = mpeg_tsdt_section_descriptors_first(tsdt); \ + (pos); \ + (pos) = mpeg_tsdt_section_descriptors_next(tsdt, pos)) + + + + + + + + + + +/******************************** PRIVATE CODE ********************************/ +static inline struct descriptor * + mpeg_tsdt_section_descriptors_first(struct mpeg_tsdt_section * tsdt) +{ + int pos = sizeof(struct mpeg_tsdt_section); + + if (pos >= section_ext_length(&tsdt->head)) + return NULL; + + return (struct descriptor*)((uint8_t *) tsdt + pos); +} + +static inline struct descriptor * + mpeg_tsdt_section_descriptors_next(struct mpeg_tsdt_section *tsdt, + struct descriptor* pos) +{ + return next_descriptor((uint8_t *) tsdt + sizeof(struct mpeg_tsdt_section), + section_ext_length(&tsdt->head) - sizeof(struct mpeg_tsdt_section), + pos); +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/mpeg/types.h b/kaffeine/src/input/dvb/lib/libucsi/mpeg/types.h new file mode 100644 index 0000000..300cb23 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/mpeg/types.h @@ -0,0 +1,127 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_MPEG_TYPES_H +#define _UCSI_MPEG_TYPES_H 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +/** + * Known stream types. + */ +enum { + MPEG_STREAM_TYPE_ISO11172_VIDEO = 0x01, + MPEG_STREAM_TYPE_ISO13818_2_VIDEO = 0x02, + MPEG_STREAM_TYPE_ISO11172_AUDIO = 0x03, + MPEG_STREAM_TYPE_ISO13818_3_AUDIO = 0x04, + MPEG_STREAM_TYPE_ISO13818_1_PRIVATE_SECTIONS = 0x05, + MPEG_STREAM_TYPE_ISO13818_1_PRIVATE_PES = 0x06, + MPEG_STREAM_TYPE_ISO13522_MHEG = 0x07, + MPEG_STREAM_TYPE_ISO13818_DSMCC = 0x08, + MPEG_STREAM_TYPE_ITUH222_1 = 0x09, + MPEG_STREAM_TYPE_ISO13818_6_A = 0x0a, + MPEG_STREAM_TYPE_ISO13818_6_B = 0x0b, + MPEG_STREAM_TYPE_ISO13818_6_C = 0x0c, + MPEG_STREAM_TYPE_ISO13818_6_D = 0x0d, + MPEG_STREAM_TYPE_ISO13818_1_AUX = 0x0e, + MPEG_STREAM_TYPE_ISO13818_7_AUDIO_ADTS = 0x0f, + MPEG_STREAM_TYPE_ISO14496_2_VISUAL = 0x10, + MPEG_STREAM_TYPE_ISO14496_3_AUDIO_LATM = 0x11, + MPEG_STREAM_TYPE_ISO14496_1_PES = 0x12, + MPEG_STREAM_TYPE_ISO14496_1_SECTIONS = 0x13, + MPEG_STREAM_TYPE_ISO14496_6_SYNCDOWNLOAD = 0x14, + MPEG_STREAM_TYPE_METADATA_PES = 0x15, + MPEG_STREAM_TYPE_METADATA_SECTIONS = 0x16, + MPEG_STREAM_TYPE_METADATA_DSMCC_DATA = 0x17, + MPEG_STREAM_TYPE_METADATA_DSMCC_OBJECT = 0x18, + MPEG_STREAM_TYPE_METADATA_SYNCDOWNLOAD = 0x19, +}; + +/** + * Metadata formats + */ +enum { + MPEG_METADATA_FORMAT_ISO15938_1_TEM = 0x01, + MPEG_METADATA_FORMAT_ISO15938_1_BIM = 0x02, + MPEG_METADATA_FORMAT_METADATA_APPLICATION_FORMAT = 0x3F, + MPEG_METADATA_FORMAT_METADATA_APPLICATION_FORMAT_ID = 0xFF, +}; + +/** + * MPEG 4 audio profile and levels. + */ +enum { + MPEG4_AUDIO_PROFILE_MAIN_LEVEL_1 = 0x10, + MPEG4_AUDIO_PROFILE_MAIN_LEVEL_2 = 0x11, + MPEG4_AUDIO_PROFILE_MAIN_LEVEL_3 = 0x12, + MPEG4_AUDIO_PROFILE_MAIN_LEVEL_4 = 0x13, + + MPEG4_AUDIO_PROFILE_SCALABLE_LEVEL_1 = 0x18, + MPEG4_AUDIO_PROFILE_SCALABLE_LEVEL_2 = 0x19, + MPEG4_AUDIO_PROFILE_SCALABLE_LEVEL_3 = 0x1a, + MPEG4_AUDIO_PROFILE_SCALABLE_LEVEL_4 = 0x1b, + + MPEG4_AUDIO_PROFILE_SPEECH_LEVEL_1 = 0x20, + MPEG4_AUDIO_PROFILE_SPEECH_LEVEL_2 = 0x21, + + MPEG4_AUDIO_PROFILE_SYNTHESIS_LEVEL_1 = 0x28, + MPEG4_AUDIO_PROFILE_SYNTHESIS_LEVEL_2 = 0x29, + MPEG4_AUDIO_PROFILE_SYNTHESIS_LEVEL_3 = 0x2a, + + MPEG4_AUDIO_PROFILE_HQ_LEVEL_1 = 0x30, + MPEG4_AUDIO_PROFILE_HQ_LEVEL_2 = 0x31, + MPEG4_AUDIO_PROFILE_HQ_LEVEL_3 = 0x32, + MPEG4_AUDIO_PROFILE_HQ_LEVEL_4 = 0x33, + MPEG4_AUDIO_PROFILE_HQ_LEVEL_5 = 0x34, + MPEG4_AUDIO_PROFILE_HQ_LEVEL_6 = 0x35, + MPEG4_AUDIO_PROFILE_HQ_LEVEL_7 = 0x36, + MPEG4_AUDIO_PROFILE_HQ_LEVEL_8 = 0x37, + + MPEG4_AUDIO_PROFILE_LOW_DELAY_LEVEL_1 = 0x38, + MPEG4_AUDIO_PROFILE_LOW_DELAY_LEVEL_2 = 0x39, + MPEG4_AUDIO_PROFILE_LOW_DELAY_LEVEL_3 = 0x3a, + MPEG4_AUDIO_PROFILE_LOW_DELAY_LEVEL_4 = 0x3b, + MPEG4_AUDIO_PROFILE_LOW_DELAY_LEVEL_5 = 0x3c, + MPEG4_AUDIO_PROFILE_LOW_DELAY_LEVEL_6 = 0x3d, + MPEG4_AUDIO_PROFILE_LOW_DELAY_LEVEL_7 = 0x3e, + MPEG4_AUDIO_PROFILE_LOW_DELAY_LEVEL_8 = 0x3f, + + MPEG4_AUDIO_PROFILE_NATURAL_LEVEL_1 = 0x40, + MPEG4_AUDIO_PROFILE_NATURAL_LEVEL_2 = 0x41, + MPEG4_AUDIO_PROFILE_NATURAL_LEVEL_3 = 0x42, + MPEG4_AUDIO_PROFILE_NATURAL_LEVEL_4 = 0x43, + + MPEG4_AUDIO_PROFILE_MOBILE_LEVEL_1 = 0x48, + MPEG4_AUDIO_PROFILE_MOBILE_LEVEL_2 = 0x49, + MPEG4_AUDIO_PROFILE_MOBILE_LEVEL_3 = 0x4a, + MPEG4_AUDIO_PROFILE_MOBILE_LEVEL_4 = 0x4b, + MPEG4_AUDIO_PROFILE_MOBILE_LEVEL_5 = 0x4c, + MPEG4_AUDIO_PROFILE_MOBILE_LEVEL_6 = 0x4d, +}; + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/mpeg/video_stream_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/mpeg/video_stream_descriptor.h new file mode 100644 index 0000000..14e9196 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/mpeg/video_stream_descriptor.h @@ -0,0 +1,101 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_MPEG_VIDEO_STREAM_DESCRIPTOR +#define _UCSI_MPEG_VIDEO_STREAM_DESCRIPTOR 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/descriptor.h> +#include <libucsi/endianops.h> + +/** + * The mpeg_video_stream_descriptor structure + */ +struct mpeg_video_stream_descriptor { + struct descriptor d; + + EBIT5(uint8_t multiple_frame_rate_flag : 1; , + uint8_t frame_rate_code : 4; , + uint8_t mpeg_1_only_flag : 1; , + uint8_t constrained_parameter_flag : 1; , + uint8_t still_picture_flag : 1; ); + /* if (mpeg_1_only_flag == 0) struct mpeg_video_stream_extra extra */ +} __ucsi_packed; + +/** + * The mpeg_video_stream_extra - only present in non-MPEG1-only streams. + */ +struct mpeg_video_stream_extra { + uint8_t profile_and_level_indication; + EBIT3(uint8_t chroma_format : 2; , + uint8_t frame_rate_extension : 1; , + uint8_t reserved : 5; ); +} __ucsi_packed; + +/** + * Process an mpeg_video_stream_descriptor structure. + * + * @param d Pointer to the generic descriptor structure. + * @return Pointer to the mpeg_video_stream_descriptor, or NULL on error. + */ +static inline struct mpeg_video_stream_descriptor* + mpeg_video_stream_descriptor_codec(struct descriptor* d) +{ + struct mpeg_video_stream_descriptor* vsd = + (struct mpeg_video_stream_descriptor*) d; + + if (d->len < (sizeof(struct mpeg_video_stream_descriptor) - 2)) + return NULL; + + if (!vsd->mpeg_1_only_flag) { + if (d->len != (sizeof(struct mpeg_video_stream_descriptor) + + sizeof(struct mpeg_video_stream_extra) - 2)) + return NULL; + } + + return (struct mpeg_video_stream_descriptor*) d; +} + +/** + * Get a pointer to the mpeg_video_stream_extra structure. + * + * @param d Pointer to the mpeg_video_stream_descriptor structure. + * @return Pointer to the mpeg_video_stream_extra structure, or NULL on error. + */ +static inline struct mpeg_video_stream_extra* + mpeg_video_stream_descriptor_extra(struct mpeg_video_stream_descriptor* d) +{ + if (d->mpeg_1_only_flag != 0) + return NULL; + + return (struct mpeg_video_stream_extra*) + ((uint8_t*) d + sizeof(struct mpeg_video_stream_descriptor)); +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/mpeg/video_window_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/mpeg/video_window_descriptor.h new file mode 100644 index 0000000..a9a63c7 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/mpeg/video_window_descriptor.h @@ -0,0 +1,64 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_MPEG_VIDEO_WINDOW_DESCRIPTOR +#define _UCSI_MPEG_VIDEO_WINDOW_DESCRIPTOR 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/descriptor.h> + +/** + * mpeg_video_window_descriptor structure. + */ +struct mpeg_video_window_descriptor { + struct descriptor d; + + EBIT3(uint32_t horizontal_offset : 14; , + uint32_t vertical_offset : 14; , + uint32_t window_priority : 4; ); +} __ucsi_packed; + +/** + * Process an mpeg_video_window_descriptor. + * + * @param d Pointer to the generic descriptor structure. + * @return Pointer to the mpeg_video_window_descriptor structure, or NULL on error. + */ +static inline struct mpeg_video_window_descriptor* + mpeg_video_window_descriptor_codec(struct descriptor* d) +{ + if (d->len != (sizeof(struct mpeg_video_window_descriptor) - 2)) + return NULL; + + bswap32((uint8_t*) d + 2); + + return (struct mpeg_video_window_descriptor*) d; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/section.h b/kaffeine/src/input/dvb/lib/libucsi/section.h new file mode 100644 index 0000000..e2f7551 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/section.h @@ -0,0 +1,253 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_SECTION_H +#define _UCSI_SECTION_H 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/endianops.h> +#include <libucsi/descriptor.h> +#include <libucsi/crc32.h> +#include <stdint.h> +#include <string.h> + +#define CRC_SIZE 4 + + +/** + * Generic section header. + */ +struct section { + uint8_t table_id; + EBIT4(uint16_t syntax_indicator : 1; , + uint16_t private_indicator : 1; , /* 2.4.4.10 */ + uint16_t reserved : 2; , + uint16_t length :12; ) +} __ucsi_packed; + +/** + * Generic extended section header structure. + */ +struct section_ext { + uint8_t table_id; + EBIT4(uint16_t syntax_indicator : 1; , + uint16_t private_indicator : 1; , /* 2.4.4.10 */ + uint16_t reserved : 2; , + uint16_t length :12; ) + + uint16_t table_id_ext; + EBIT3(uint8_t reserved1 : 2; , + uint8_t version_number : 5; , + uint8_t current_next_indicator : 1; ) + uint8_t section_number; + uint8_t last_section_number; +} __ucsi_packed; + +/** + * Structure for keeping track of sections of a PSI table. + */ +struct psi_table_state { + uint8_t version_number; + uint16_t next_section_number; + uint8_t complete:1; + uint8_t new_table:1; +} __ucsi_packed; + + +/** + * Process a section structure in-place. + * + * @param buf Pointer to the data. + * @param len Length of data. + * @return Pointer to the section structure, or NULL if invalid. + */ +static inline struct section * section_codec(uint8_t * buf, int len) +{ + struct section * ret = (struct section *)buf; + + if (len < 3) + return NULL; + + bswap16(buf+1); + + if (len != ret->length + 3) + return NULL; + + return ret; +} + +/** + * Some sections have a CRC even though they are not section_exts. + * This function is to allow checking of them. + * + * @param section Pointer to the processed section structure. + * @return Nonzero on error, or 0 if the CRC was correct. + */ +static inline int section_check_crc(struct section *section) +{ + uint8_t * buf = (uint8_t *) section; + int len = sizeof(struct section) + section->length; + uint32_t crc; + + /* the crc check has to be performed on the unswapped data */ + bswap16(buf+1); + crc = crc32(CRC32_INIT, buf, len); + bswap16(buf+1); + + /* the crc check includes the crc value, + * the result should therefore be zero. + */ + if (crc) + return -1; + return 0; +} + + +/** + * Decode an extended section structure. + * + * @param section Pointer to the processed section structure. + * @param check_crc If 1, the CRC of the section will also be checked. + * @return Pointer to the parsed section_ext structure, or NULL if invalid. + */ +static inline struct section_ext * section_ext_decode(struct section * section, + int check_crc) +{ + if (section->syntax_indicator == 0) + return NULL; + + if (check_crc) { + if (section_check_crc(section)) + return NULL; + } + + bswap16((uint8_t *)section + sizeof(struct section)); + + return (struct section_ext *)section; +} + +/** + * Encode an extended section structure for transmission. + * + * @param section Pointer to the section_ext structure. + * @param update_crc If 1, the CRC of the section will also be updated. + * @return Pointer to the encoded section_ext structure, or NULL if invalid. + */ +static inline struct section_ext * section_ext_encode(struct section_ext* section, + int update_crc) +{ + if (section->syntax_indicator == 0) + return NULL; + + bswap16((uint8_t *)section + sizeof(struct section)); + + if (update_crc) { + uint8_t * buf = (uint8_t *) section; + int len = sizeof(struct section) + section->length; + uint32_t crc; + + /* zap the current CRC value */ + memset(buf+len-4, 0, 4); + + /* the crc has to be performed on the swapped data */ + bswap16(buf+1); + crc = crc32(CRC32_INIT, buf, len); + bswap16(buf+1); + + /* update the CRC */ + *((uint32_t*) (buf+len-4)) = crc; + bswap32(buf+len-4); + } + + return (struct section_ext *)section; +} + +/** + * Determine the total length of a section, including the header. + * + * @param section The parsed section structure. + * @return The length. + */ +static inline int section_length(struct section *section) +{ + return section->length + sizeof(struct section); +} + +/** + * Determine the total length of an extended section, including the header, + * but omitting the CRC. + * + * @param section The parsed section_ext structure. + * @return The length. + */ +static inline int section_ext_length(struct section_ext * section) +{ + return section->length + sizeof(struct section) - CRC_SIZE; +} + +/** + * Reset a psi_table_state structure. + * + * @param tstate The structure to reset. + */ +static inline void psi_table_state_reset(struct psi_table_state *tstate) +{ + tstate->version_number = 0xff; +} + +/** + * Check if a supplied section_ext is something we want to process. + * + * @param section The parsed section_ext structure. + * @param tstate The state structure for this PSI table. + * @return 0=> not useful. nonzero => useful. + */ +static inline int section_ext_useful(struct section_ext *section, struct psi_table_state *tstate) +{ + if ((section->version_number == tstate->version_number) && tstate->complete) + return 0; + if ((section->version_number != tstate->version_number) && (section->section_number == 0)) { + tstate->next_section_number = 0; + tstate->complete = 0; + tstate->version_number = section->version_number; + tstate->new_table = 1; + } else if (section->section_number == tstate->next_section_number) { + tstate->new_table = 0; + } else { + return 0; + } + + tstate->next_section_number++; + if (section->last_section_number < tstate->next_section_number) { + tstate->complete = 1; + } + + return 1; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/section_buf.c b/kaffeine/src/input/dvb/lib/libucsi/section_buf.c new file mode 100644 index 0000000..35d465e --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/section_buf.c @@ -0,0 +1,173 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include <errno.h> +#include <string.h> +#include "section_buf.h" + +#define SECTION_HDR_SIZE 3 +#define SECTION_PAD 0xff + +int section_buf_init(struct section_buf *section, int max) +{ + if (max < SECTION_HDR_SIZE) + return -EINVAL; + + memset(section, 0, sizeof(struct section_buf)); + section->max = max; /* max size of data */ + section->len = SECTION_HDR_SIZE; + section->wait_pdu = 1; + + return 0; +} + +int section_buf_add(struct section_buf *section, uint8_t* frag, int len, int *section_status) +{ + int copy; + int used = 0; + uint8_t *data; + uint8_t *pos = (uint8_t*) section + sizeof(struct section_buf) + section->count; + + /* have we finished? */ + if (section->header && (section->len == section->count)) { + *section_status = 1; + return 0; + } + + /* skip over section padding bytes */ + *section_status = 0; + if (section->count == 0) { + while(len && (*frag == SECTION_PAD)) { + frag++; + len--; + used++; + } + + if (len == 0) + return used; + } + + /* grab the header to get the section length */ + if (!section->header) { + /* copy the header frag */ + copy = SECTION_HDR_SIZE - section->count; + if (copy > len) + copy = len; + memcpy(pos, frag, copy); + section->count += copy; + pos += copy; + frag += copy; + used += copy; + len -= copy; + + /* we need 3 bytes for the section header */ + if (section->count != SECTION_HDR_SIZE) + return used; + + /* work out the length & check it isn't too big */ + data = (uint8_t*) section + sizeof(struct section_buf); + section->len = SECTION_HDR_SIZE + (((data[1] & 0x0f) << 8) | data[2]); + if (section->len > section->max) { + *section_status = -ERANGE; + return len + used; + } + + /* update fields */ + section->header = 1; + } + + /* accumulate frag */ + copy = section->len - section->count; + if (copy > len) + copy = len; + memcpy(pos, frag, copy); + section->count += copy; + used += copy; + + /* have we finished? */ + if (section->header && (section->len == section->count)) + *section_status = 1; + + /* return number of bytes used */ + return used; +} + +int section_buf_add_transport_payload(struct section_buf *section, + uint8_t* payload, int len, + int pdu_start, int *section_status) +{ + int used = 0; + int tmp; + + /* have we finished? */ + if (section->header && (section->len == section->count)) { + *section_status = 1; + return 0; + } + + /* don't bother if we're waiting for a PDU */ + *section_status = 0; + if (section->wait_pdu && (!pdu_start)) + return len; + + /* if we're at a PDU start, we need extra handling for the extra first + * byte giving the offset to the start of the next section. */ + if (pdu_start) { + /* we have received a pdu */ + section->wait_pdu = 0; + + /* work out the offset to the _next_ payload */ + int offset = payload[0]; + if ((offset+1) > len) { + section->wait_pdu = 1; + *section_status = -EINVAL; + return len; + } + + /* accumulate the end if we need to */ + if (section->count != 0) { + /* add the final fragment. */ + tmp = section_buf_add(section, payload + 1, offset, section_status); + + /* the stream said this was the final fragment + * (PDU START bit) - check that it really was! */ + if ((tmp != offset) || section_buf_remaining(section) || (*section_status != 1)) { + *section_status = -ERANGE; + section->wait_pdu = 1; + return 1 + tmp; + } + + /* it is complete - return the number of bytes we used */ + return 1 + tmp; + } + + /* otherwise, we skip the end of the previous section, and + * start accumulating the new data. */ + used = 1 + offset; + } + + /* ok, just accumulate the data as normal */ + tmp = section_buf_add(section, payload+used, len - used, section_status); + if (*section_status < 0) { + section->wait_pdu = 1; + } + + return used + tmp; +} diff --git a/kaffeine/src/input/dvb/lib/libucsi/section_buf.h b/kaffeine/src/input/dvb/lib/libucsi/section_buf.h new file mode 100644 index 0000000..e15cc1d --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/section_buf.h @@ -0,0 +1,125 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_SECTION_BUF_H +#define _UCSI_SECTION_BUF_H 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <stdint.h> + +#define DVB_MAX_SECTION_BYTES 4096 + +/** + * Buffer used to keep track of section fragments. You should allocate an + * area of memory of size (sizeof(section_buf) + <maxsectionsize>), and pass that area + * to section_buf_init() to set it up. + */ +struct section_buf { + uint32_t max; /* maximum size of section - setup by section_buf_init() */ + uint32_t count; /* number of bytes currently accumulated */ + uint32_t len; /* total number of bytes expected in the complete section */ + uint8_t header:1; /* flag indicating the section header has been commpletely received */ + uint8_t wait_pdu:1;/* flag indicating to wait till the next PDU start */ + /* uint8_t data[] */ +}; + +/** + * Initialise a section_buf structure. + * + * @param section The section_buf to initialise. + * @param max Maximum number of bytes in section (must be > 3) + * @return 0 on success, nonzero on error. + */ +extern int section_buf_init(struct section_buf *section, int max); + +/** + * Initialise a section_buf structure. + * + * @param section The section_buf to initialise. + * @param max Maximum number of bytes in section (must be > 3) + * @return 0 on success, nonzero on error. + */ +static inline void section_buf_reset(struct section_buf *section) +{ + int tmp = section->wait_pdu; + section_buf_init(section, section->max); + section->wait_pdu = tmp; +} + +/** + * Add a data fragment to a section_buf. + * + * @param section section_buf to add to. + * @param frag Pointer to data fragment. + * @param len Number of bytes of data. + * @param section_status 0: nothing special. 1: section complete. -ERANGE indicates that the + * section is larger than section->max. + * @return Number of bytes which were consumed. + */ +extern int section_buf_add(struct section_buf *section, uint8_t* frag, int len, int *section_status); + +/** + * Add a transport packet PSI payload to a section_buf. This takes into account + * the extra byte present in PDU_START flagged packets. + * + * @param section section_buf to add to. + * @param payload Pointer to packet payload data. + * @param len Number of bytes of data. + * @param pdu_start True if the payload_unit_start_indicator flag was set in the + * TS packet. + * @param section_status 0: nothing special. 1: section complete. -ERANGE indicates that the + * section is larger than section->max. -EINVAL indicates the pointer_field was completely + * invalid (too large). + */ +extern int section_buf_add_transport_payload(struct section_buf *section, + uint8_t* payload, int len, + int pdu_start, int *section_status); + +/** + * Get the number of bytes left to be received in a section_buf. + * + * @param section The section_buf concerned. + * @return The number of bytes. + */ +static inline int section_buf_remaining(struct section_buf *section) +{ + return section->len - section->count; +} + +/** + * Return a pointer to the start of the data in the section_buf. + * + * @param section The section_buf concerned. + * @return The data. + */ +static inline uint8_t* section_buf_data(struct section_buf *section) +{ + return (uint8_t*) section + sizeof(struct section_buf); +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/testrecord.txt b/kaffeine/src/input/dvb/lib/libucsi/testrecord.txt new file mode 100644 index 0000000..259ffe1 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/testrecord.txt @@ -0,0 +1,101 @@ +libucsi test record. Anything without PASS is either not tested, or is +currently broken. + +Testing means (a) ensure there are no segfaults etc. (b) dump the raw hex, +decode it by hand, and check it matches the output. + +Sections: +PASS mpeg/cat_section.h + mpeg/odsmt_section.h +PASS mpeg/pat_section.h +PASS mpeg/pmt_section.h + mpeg/tsdt_section.h + mpeg/metadata_section.h +PASS dvb/bat_section.h + dvb/dit_section.h +PASS dvb/eit_section.h + dvb/int_section.h +PASS dvb/nit_section.h + dvb/rst_section.h +PASS dvb/sdt_section.h + dvb/sit_section.h +PASS dvb/st_section.h +PASS dvb/tdt_section.h +PASS dvb/tot_section.h + +Descriptors: +PASS mpeg/audio_stream_descriptor.h +PASS mpeg/ca_descriptor.h +PASS mpeg/copyright_descriptor.h +PASS mpeg/data_stream_alignment_descriptor.h +PASS mpeg/external_es_id_descriptor.h + mpeg/fmc_descriptor.h +PASS mpeg/fmxbuffer_size_descriptor.h + mpeg/hierarchy_descriptor.h + mpeg/ibp_descriptor.h + mpeg/iod_descriptor.h +PASS mpeg/iso_639_language_descriptor.h +PASS mpeg/maximum_bitrate_descriptor.h + mpeg/mpeg4_audio_descriptor.h + mpeg/mpeg4_video_descriptor.h + mpeg/multiplex_buffer_descriptor.h +PASS mpeg/multiplex_buffer_utilization_descriptor.h + mpeg/muxcode_descriptor.h +PASS mpeg/private_data_indicator_descriptor.h +PASS mpeg/registration_descriptor.h + mpeg/sl_descriptor.h +PASS mpeg/smoothing_buffer_descriptor.h +PASS mpeg/std_descriptor.h +PASS mpeg/system_clock_descriptor.h + mpeg/target_background_grid_descriptor.h +PASS mpeg/video_stream_descriptor.h + mpeg/video_window_descriptor.h + + dvb/ac3_descriptor.h + dvb/ancillary_data_descriptor.h + dvb/announcement_support_descriptor.h + dvb/bouquet_name_descriptor.h + dvb/ca_identifier_descriptor.h + dvb/ca_system_descriptor.h + dvb/cable_delivery_descriptor.h + dvb/cell_frequency_link_descriptor.h + dvb/cell_list_descriptor.h + dvb/component_descriptor.h + dvb/content_descriptor.h + dvb/country_availability_descriptor.h + dvb/data_broadcast_descriptor.h + dvb/data_broadcast_id_descriptor.h + dvb/descriptor.h + dvb/dsng_descriptor.h + dvb/extended_event_descriptor.h + dvb/frequency_list_descriptor.h + dvb/linkage_descriptor.h + dvb/local_time_offset_descriptor.h + dvb/mosaic_descriptor.h + dvb/multilingual_bouquet_name_descriptor.h + dvb/multilingual_component_descriptor.h + dvb/multilingual_network_name_descriptor.h + dvb/multilingual_service_name_descriptor.h + dvb/network_name_descriptor.h + dvb/nvod_reference_descriptor.h + dvb/parental_rating_descriptor.h + dvb/partial_transport_stream_descriptor.h + dvb/pdc_descriptor.h + dvb/private_data_specifier_descriptor.h + dvb/satellite_delivery_descriptor.h + dvb/service_descriptor.h + dvb/service_list_descriptor.h + dvb/service_move_descriptor.h + dvb/short_event_descriptor.h + dvb/short_smoothing_buffer_descriptor.h + dvb/stream_identifier_descriptor.h + dvb/stuffing_descriptor.h + dvb/subtitling_descriptor.h + dvb/telephone_descriptor.h + dvb/teletext_descriptor.h + dvb/terrestrial_delivery_descriptor.h + dvb/time_shifted_event_descriptor.h + dvb/time_shifted_service_descriptor.h + dvb/transport_stream_descriptor.h + dvb/vbi_data_descriptor.h + dvb/vbi_teletext_descriptor.h diff --git a/kaffeine/src/input/dvb/lib/libucsi/transport_packet.c b/kaffeine/src/input/dvb/lib/libucsi/transport_packet.c new file mode 100644 index 0000000..ca6c2e1 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/transport_packet.c @@ -0,0 +1,256 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "transport_packet.h" + +#define CONTINUITY_VALID 0x80 +#define CONTINUITY_DUPESEEN 0x40 + +int transport_packet_values_extract(struct transport_packet *pkt, + struct transport_values *out, + enum transport_value extract) +{ + uint8_t *end = (uint8_t*) pkt + TRANSPORT_PACKET_LENGTH; + uint8_t *adapend; + uint8_t *pos = (uint8_t*) pkt + sizeof(struct transport_packet); + enum transport_value extracted = 0; + enum transport_adaptation_flags adapflags = 0; + enum transport_adaptation_extension_flags adapextflags = 0; + int adaplength = 0; + int adapextlength = 0; + + /* does the packet contain an adaptation field ? */ + if ((pkt->adaptation_field_control & 2) == 0) + goto extract_payload; + + /* get the adaptation field length and skip the byte */ + adaplength = *pos++; + + /* do we actually have any adaptation data? */ + if (adaplength == 0) + goto extract_payload; + + /* sanity check */ + adapend = pos + adaplength; + if (adapend > end) + return -1; + + /* extract the adaptation flags (we must have at least 1 byte to be here) */ + adapflags = *pos++; + + /* do we actually want anything else? */ + if ((extract & 0xffff) == 0) + goto extract_payload; + + /* PCR? */ + if (adapflags & transport_adaptation_flag_pcr) { + if ((pos+6) > adapend) + return -1; + + if (extract & transport_value_pcr) { + uint64_t base = ((uint64_t) pos[0] << 25) | + ((uint64_t) pos[1] << 17) | + ((uint64_t) pos[2] << 9) | + ((uint64_t) pos[3] << 1) | + ((uint64_t) pos[4] >> 7); + uint64_t ext = (((uint64_t) pos[4] & 1) << 8) | + (uint64_t) pos[5]; + out->pcr= base * 300ULL + ext; + extracted |= transport_value_pcr; + } + pos += 6; + } + + /* OPCR? */ + if (adapflags & transport_adaptation_flag_opcr) { + if ((pos+6) > adapend) + return -1; + + if (extract & transport_value_opcr) { + uint64_t base = ((uint64_t) pos[0] << 25) | + ((uint64_t) pos[1] << 17) | + ((uint64_t) pos[2] << 9) | + ((uint64_t) pos[3] << 1) | + ((uint64_t) pos[4] >> 7); + uint64_t ext = (((uint64_t) pos[4] & 1) << 8) | + (uint64_t) pos[5]; + out->opcr= base * 300ULL + ext; + extracted |= transport_value_opcr; + } + pos += 6; + } + + /* splice countdown? */ + if (adapflags & transport_adaptation_flag_splicing_point) { + if ((pos+1) > adapend) + return -1; + + if (extract & transport_value_splice_countdown) { + out->splice_countdown = *pos; + extracted |= transport_value_splice_countdown; + } + pos++; + } + + /* private data? */ + if (adapflags & transport_adaptation_flag_private_data) { + if ((pos+1) > adapend) + return -1; + if ((pos+1+*pos) > adapend) + return -1; + + if (extract & transport_value_private_data) { + out->private_data_length = *pos; + out->private_data = pos + 1; + extracted |= transport_value_private_data; + } + pos += 1 + *pos; + } + + /* is there an adaptation extension? */ + if (!(adapflags & transport_adaptation_flag_extension)) + goto extract_payload; + + /* get/check the length */ + if (pos >= adapend) + return -1; + adapextlength = *pos++; + if ((pos + adapextlength) > adapend) + return -1; + + /* do we want/have anything in the adaptation extension? */ + if (((extract & 0xff00) == 0) || (adapextlength == 0)) + goto extract_payload; + + /* extract the adaptation extension flags (we must have at least 1 byte + * to be here) */ + adapextflags = *pos++; + + /* LTW? */ + if (adapextflags & transport_adaptation_extension_flag_ltw) { + if ((pos+2) > adapend) + return -1; + + if (extract & transport_value_ltw) { + if (*pos & 0x80) { + out->ltw_offset = ((pos[0] & 0x7f) << 8) | + (pos[1]); + extracted |= transport_value_ltw; + } + } + pos += 2; + } + + /* piecewise_rate? */ + if (adapextflags & transport_adaptation_extension_flag_piecewise_rate) { + if ((pos+3) > adapend) + return -1; + + if (extract & transport_value_piecewise_rate) { + out->piecewise_rate = ((pos[0] & 0x3f) << 16) | + (pos[1] << 8) | + pos[2]; + extracted |= transport_value_piecewise_rate; + } + pos += 3; + } + + /* seamless_splice? */ + if (adapextflags & transport_adaptation_extension_flag_seamless_splice) { + if ((pos+5) > adapend) + return -1; + + if (extract & transport_value_piecewise_rate) { + out->splice_type = pos[0] >> 4; + out->dts_next_au = ((pos[0] & 0x0e) << 29) | + (pos[1] << 22) | + ((pos[2] & 0xfe) << 14) | + (pos[3] << 7) | + ((pos[4] & 0xfe) >> 1); + extracted |= transport_value_seamless_splice; + } + pos += 5; + } + + + +extract_payload: + /* does the packet contain a payload? */ + if (pkt->adaptation_field_control & 1) { + int off = sizeof(struct transport_packet); + if (pkt->adaptation_field_control & 2) + off++; + off += adaplength; + + out->payload = (uint8_t*) pkt + off; + out->payload_length = TRANSPORT_PACKET_LENGTH - off; + } else { + out->payload = NULL; + out->payload_length = 0; + } + + out->flags = adapflags; + return extracted; +} + +int transport_packet_continuity_check(struct transport_packet *pkt, + int discontinuity_indicator, unsigned char *cstate) +{ + unsigned char pktcontinuity = pkt->continuity_counter; + unsigned char prevcontinuity = *cstate & 0x0f; + unsigned char nextcontinuity; + + /* NULL packets have undefined continuity */ + if (transport_packet_pid(pkt) == TRANSPORT_NULL_PID) + return 0; + + /* is the state valid? */ + if (!(*cstate & CONTINUITY_VALID)) { + *cstate = pktcontinuity | CONTINUITY_VALID; + return 0; + } + + /* check for discontinuity_indicator */ + if (discontinuity_indicator) { + *cstate = pktcontinuity | CONTINUITY_VALID; + return 0; + } + + /* only packets with a payload should increment the counter */ + if (pkt->adaptation_field_control & 1) + nextcontinuity = (prevcontinuity + 1) & 0xf; + else + nextcontinuity = prevcontinuity; + + /* check for a normal continuity progression */ + if (nextcontinuity == pktcontinuity) { + *cstate = pktcontinuity | CONTINUITY_VALID; + return 0; + } + + /* one dupe is allowed */ + if ((prevcontinuity == pktcontinuity) && (!(*cstate & CONTINUITY_DUPESEEN))) { + *cstate = pktcontinuity | (CONTINUITY_VALID|CONTINUITY_DUPESEEN); + return 0; + } + + /* continuity error */ + return -1; +} diff --git a/kaffeine/src/input/dvb/lib/libucsi/transport_packet.h b/kaffeine/src/input/dvb/lib/libucsi/transport_packet.h new file mode 100644 index 0000000..7dfbd78 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/transport_packet.h @@ -0,0 +1,195 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_TRANSPORT_PACKET_H +#define _UCSI_TRANSPORT_PACKET_H 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <stdint.h> +#include "descriptor.h" + +#define TRANSPORT_PACKET_LENGTH 188 +#define TRANSPORT_PACKET_SYNC 0x47 +#define TRANSPORT_MAX_PIDS 0x2000 +#define TRANSPORT_NULL_PID 0x1fff + + +/** + * Enumeration of adaptation field control values. + */ +enum transport_adaptation_field_control { + transport_adaptation_field_control_reserved = 0x00, + transport_adaptation_field_control_payload_only = 0x01, + transport_adaptation_field_control_adaptation_only = 0x02, + transport_adaptation_field_control_adaptation_payload = 0x03, +}; + +/** + * Enumeration of scrambling control values. + */ +enum transport_scrambling_control { + transport_scrambling_control_unscrambled = 0x00, + transport_scrambling_control_user_1 = 0x01, + transport_scrambling_control_user_2 = 0x02, + transport_scrambling_control_user_3 = 0x03, +}; + +/** + * Enumeration of adaptation flags. + */ +enum transport_adaptation_flags { + transport_adaptation_flag_discontinuity = 0x80, + transport_adaptation_flag_random_access = 0x40, + transport_adaptation_flag_es_priority = 0x20, + transport_adaptation_flag_pcr = 0x10, + transport_adaptation_flag_opcr = 0x08, + transport_adaptation_flag_splicing_point = 0x04, + transport_adaptation_flag_private_data = 0x02, + transport_adaptation_flag_extension = 0x01, +}; + +/** + * Enumeration of adaptation extension flags. + */ +enum transport_adaptation_extension_flags { + transport_adaptation_extension_flag_ltw = 0x80, + transport_adaptation_extension_flag_piecewise_rate = 0x40, + transport_adaptation_extension_flag_seamless_splice = 0x20, +}; + +/** + * Enumeration of flags controlling which values to extract using the + * transport_packet_values_extract() function. + */ +enum transport_value { + /* normal adaptation */ + transport_value_pcr = 0x0001, + transport_value_opcr = 0x0002, + transport_value_splice_countdown = 0x0004, + transport_value_private_data = 0x0008, + + /* extension adaptation */ + transport_value_ltw = 0x0100, + transport_value_piecewise_rate = 0x0200, + transport_value_seamless_splice = 0x0400, +}; + +/** + * Structure describing a transport packet header. + */ +struct transport_packet { + uint8_t sync_byte; + EBIT4(uint8_t transport_error_indicator : 1; , + uint8_t payload_unit_start_indicator : 1; , + uint8_t transport_priority : 1; , + uint8_t pid_hi : 5; ); + uint8_t pid_lo; + EBIT3(uint8_t transport_scrambling_control : 2; , + uint8_t adaptation_field_control : 2; , + uint8_t continuity_counter : 4; ); + /* values */ +} __ucsi_packed; + +/** + * Structure to extract values into using the transport_packet_values_extract() + * function. + */ +struct transport_values { + enum transport_adaptation_flags flags; /* always extracted */ + uint8_t *payload; /* always extracted */ + uint16_t payload_length; /* always extracted */ + + uint64_t pcr; + uint64_t opcr; + uint8_t splice_countdown; + uint8_t private_data_length; + uint8_t *private_data; + uint16_t ltw_offset; + uint32_t piecewise_rate; + uint8_t splice_type; + uint64_t dts_next_au; +}; + +/** + * Extract the PID from a transport packet. + * + * @param pkt The packet. + * @return The PID. + */ +static inline int transport_packet_pid(struct transport_packet *pkt) +{ + return (pkt->pid_hi << 8) | (pkt->pid_lo); +} + +/** + * Process a buffer into a transport packet. + * + * @param buf Raw buffer. + * @return transport_packet pointer, or NULL on error. + */ +static inline struct transport_packet *transport_packet_init(unsigned char *buf) +{ + struct transport_packet *pkt = (struct transport_packet*) buf; + + if (pkt->sync_byte != TRANSPORT_PACKET_SYNC) + return NULL; + + if (transport_packet_pid(pkt) >= TRANSPORT_MAX_PIDS) + return NULL; + + return pkt; +} + +/** + * Check the continuity counter for a packet in a PID stream. + * + * @param pkt transport_packet to check. + * @param discontinuity_indicator Set to 1 if the packet's discontinuity_indicator flag is set. + * @param cstate Pointer to a single 8 bit character, used to store state for validating + * continuity. To initialise the state, simply set it to 0 before the first call. + * @return 0 if the continuity was correct, or nonzero on error. cstate will not be updated on error, + * it is up to the caller to clear it to accept the next packet. + */ +extern int transport_packet_continuity_check(struct transport_packet *pkt, + int discontinuity_indicator, unsigned char *cstate); + +/** + * Extract selected fields from a transport packet. + * + * @param pkt The packet. + * @param out Destination structure for values. + * @param extract Orred bitmask of enum transport_value - tells it what fields + * to extract if they are available. + * @return < 0 => error. Otherwise, an orred bitmask of enum transport_value + * telling you what fields were successfully extracted. + */ +extern int transport_packet_values_extract(struct transport_packet *pkt, + struct transport_values *out, + enum transport_value extract); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/types.h b/kaffeine/src/input/dvb/lib/libucsi/types.h new file mode 100644 index 0000000..b01d79a --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/types.h @@ -0,0 +1,36 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_TYPES_H +#define _UCSI_TYPES_H 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +typedef uint8_t iso639lang_t[3]; +typedef uint8_t iso639country_t[3]; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/plugins/Makefile.am b/kaffeine/src/input/dvb/plugins/Makefile.am new file mode 100644 index 0000000..63f5318 --- /dev/null +++ b/kaffeine/src/input/dvb/plugins/Makefile.am @@ -0,0 +1 @@ +SUBDIRS = epg stream
\ No newline at end of file diff --git a/kaffeine/src/input/dvb/plugins/epg/Makefile.am b/kaffeine/src/input/dvb/plugins/epg/Makefile.am new file mode 100644 index 0000000..28ef5bf --- /dev/null +++ b/kaffeine/src/input/dvb/plugins/epg/Makefile.am @@ -0,0 +1,16 @@ +lib_LTLIBRARIES = libkaffeineepgplugin.la + +METASOURCES = AUTO + +INCLUDES = -I$(top_srcdir)/kaffeine/src/input/dvb \ + -I$(top_srcdir)/kaffeine/src \ + $(all_includes) + +kaffeineincludedir = $(includedir)/kaffeine +kaffeineinclude_HEADERS = kaffeinedvbevents.h kaffeinedvbsection.h + +libkaffeineepgplugin_la_SOURCES = kaffeinedvbevents.cpp kaffeinedvbsection.cpp +libkaffeineepgplugin_la_LIBADD = $(LIB_KPARTS) +libkaffeineepgplugin_la_LDFLAGS = $(all_libraries) -version-info 0:1:0 -no-undefined + +kde_servicetypes_DATA = kaffeineepgplugin.desktop diff --git a/kaffeine/src/input/dvb/plugins/epg/kaffeinedvbevents.cpp b/kaffeine/src/input/dvb/plugins/epg/kaffeinedvbevents.cpp new file mode 100644 index 0000000..afa5e55 --- /dev/null +++ b/kaffeine/src/input/dvb/plugins/epg/kaffeinedvbevents.cpp @@ -0,0 +1,496 @@ +/* + * kaffeinedvbevents.cpp + * + * Copyright (C) 2003-2007 Christophe Thommeret <hftom@free.fr> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include <stdio.h> +#include <unistd.h> +#include <sys/time.h> +#include <sys/resource.h> + +#include <qdatetime.h> +#include <qfile.h> + +#include <klocale.h> +#include <kstandarddirs.h> + +#include "kaffeinedvbevents.h" + + + +ShortEvent::ShortEvent() +{ + name=text=""; +} + +ShortEvent::~ShortEvent() +{ +} + +EventDesc::EventDesc() +{ + loop = 0; + nid=sid=tsid=eid=0; + tid=sn=lsn=running=0; + title=subtitle=""; + source=""; + shortEvents.setAutoDelete( true ); + extEvents.setAutoDelete( true ); +} + +EventDesc::~EventDesc() +{ + shortEvents.clear(); + extEvents.clear(); +} + + + +EventSid::EventSid( int s ) +{ + sid = s; + events.setAutoDelete( true ); +} + +EventSid::~EventSid() +{ + QMutexLocker locker( &mutex ); + events.clear(); +} + +void EventSid::remove( EventDesc *d ) +{ + QMutexLocker locker( &mutex ); + events.remove( d ); +} + +EventDesc *EventSid::getEventDesc( int n ) +{ + QMutexLocker locker( &mutex ); + return events.at(n); +} + + + +EventTsid::EventTsid( int n, int t ) +{ + tsid = t; + nid = n; + sidList.setAutoDelete( true ); +} + +EventTsid::~EventTsid() +{ + QMutexLocker locker( &mutex ); + sidList.clear(); +} + +EventSid *EventTsid::getNEventSid( int n ) +{ + QMutexLocker locker( &mutex ); + return sidList.at( n ); +} + +EventSid *EventTsid::getEventSid( int sid ) +{ + int i; + + QMutexLocker locker( &mutex ); + for ( i=0; i<(int)sidList.count(); i++ ) { + if ( sidList.at(i)->getSid()==sid ) + return sidList.at(i); + } + EventSid *es = new EventSid( sid ); + sidList.append( es ); + return es; +} + +EventDesc *EventTsid::getEventDesc( int sid, int n ) +{ + int i; + EventSid *es=0; + + mutex.lock(); + for ( i=0; i<(int)sidList.count(); i++ ) { + if ( sidList.at(i)->getSid()==sid ) { + es = sidList.at(i); + break; + } + } + mutex.unlock(); + if ( !es ) + return 0; + return es->getEventDesc( n ); +} + + + +EventSource::EventSource( QString src ) +{ + source = src; + tsidList.setAutoDelete( true ); +} + +EventSource::~EventSource() +{ + QMutexLocker locker( &mutex ); + tsidList.clear(); +} + +EventTsid *EventSource::getNEventTsid( int n ) +{ + QMutexLocker locker( &mutex ); + return tsidList.at( n ); +} + +EventSid *EventSource::getEventSid( int nid, int tsid, int sid ) +{ + int i; + EventTsid *et=0; + + mutex.lock(); + for ( i=0; i<(int)tsidList.count(); i++ ) { + if ( tsidList.at(i)->getTsid()==tsid && (nid==0 || tsidList.at(i)->getNid()==nid) ) { + et = tsidList.at(i); + break; + } + } + if ( !et ) { + if ( nid==0) { + mutex.unlock(); + return 0; + } + et = new EventTsid( nid, tsid ); + tsidList.append( et ); + } + mutex.unlock(); + return et->getEventSid( sid ); +} + +EventDesc *EventSource::getEventDesc( int nid, int tsid, int sid, int n ) +{ + int i; + EventTsid *et=0; + + mutex.lock(); + for ( i=0; i<(int)tsidList.count(); i++ ) { + if ( tsidList.at(i)->getTsid()==tsid && (nid==0 || tsidList.at(i)->getNid()==nid) ) { + et = tsidList.at(i); + break; + } + } + mutex.unlock(); + if ( !et ) + return 0; + return et->getEventDesc( sid, n ); +} + + + + +EventTable::EventTable() +{ + srcList.setAutoDelete( true ); + connect ( &cleanTimer, SIGNAL(timeout()), this, SLOT(setClean()) ); + cleanTimer.start( 10000 ); + epgLoaded = false; +} + +EventTable::~EventTable() +{ + QMutexLocker locker( &mutex ); + srcList.clear(); +} + +void EventTable::saveEpg() +{ + EventSource *esrc; + EventTsid *et; + EventSid *es; + QPtrList<EventDesc> *esEvents; + EventDesc *desc; + int i, k, j, m, n; + QCString c; + int count=0; + unsigned char sync=0xff; + QTime t1=QTime::currentTime(); + + QFile f( locateLocal("appdata", "dvbepg.data" ) ); + if ( f.open(IO_WriteOnly|IO_Truncate) ) { + QDataStream dt( &f ); + for( i=0; i<getNSource(); i++ ) { + if ( !(esrc=getNEventSource( i )) ) + continue; + for ( m=0; m<esrc->getNTsid(); m++ ) { + if ( !(et=esrc->getNEventTsid( m )) ) + continue; + for ( n=0; n<et->getNSid(); n++ ) { + if ( !(es=et->getNEventSid( n )) ) + continue; + esEvents = es->getEvents(); + es->lock(); + for ( j=0; j<(int)esEvents->count(); j++ ) { + if ( !(desc=esEvents->at( j )) ) + continue; + dt << sync; // sync byte + c = desc->source.utf8(); + dt << c.data(); + dt << desc->tid; + dt << desc->sid; + dt << desc->tsid; + dt << desc->nid; + dt << desc->sn; + dt << desc->lsn; + dt << desc->eid; + dt << desc->running; + dt << desc->startDateTime.toTime_t(); + dt << (uint)((desc->duration.hour()*3600)+(desc->duration.minute()*60)+desc->duration.second()); + dt << desc->shortEvents.count(); + for ( k=0; k<(int)desc->shortEvents.count(); k++ ) { + c = desc->shortEvents.at(k)->name.utf8(); + dt << c.data(); + c = desc->shortEvents.at(k)->text.utf8(); + dt << c.data(); + } + dt << (uint)desc->extEvents.count(); + for ( k=0; k<(int)desc->extEvents.count(); k++ ) { + c = desc->extEvents.at(k)->utf8(); + dt << c.data(); + } + c = desc->title.utf8(); + dt << c.data(); + c = desc->subtitle.utf8(); + dt << c.data(); + ++count; + } + es->unlock(); + } + } + } + f.close(); + fprintf( stderr, "Saved epg data : %d events (%d msecs)\n", count, t1.msecsTo(QTime::currentTime()) ); + } +} + +void EventTable::loadEpg() +{ + EventDesc *desc; + ShortEvent *sev; + EventSid *slist; + uint count, tmp, i; +#define EPGBUFSIZE 500 + char buf[EPGBUFSIZE]; + int num=0; + unsigned char sync; + QDateTime cur=QDateTime::currentDateTime(); + QTime t1=QTime::currentTime(); + + if ( epgLoaded ) + return; + + epgLoaded = true; + QFile f( locateLocal("appdata", "dvbepg.data" ) ); + if ( f.open(IO_ReadOnly) ) { + QDataStream dt( &f ); + while (!dt.eof() ) { + dt >> sync; + if ( sync!=0xff ) { + f.close(); + fprintf( stderr, "Sync error while loading epg data : %d events loaded\n", num ); + return; + } + desc = new EventDesc(); + dt >> tmp; + if ( !validString( f, desc, tmp, EPGBUFSIZE, num ) ) return; + dt.readRawBytes( buf, tmp ); + desc->source = QString::fromUtf8( buf ); + dt >> desc->tid; + dt >> desc->sid; + dt >> desc->tsid; + dt >> desc->nid; + dt >> desc->sn; + dt >> desc->lsn; + dt >> desc->eid; + dt >> desc->running; + dt >> tmp; + desc->startDateTime.setTime_t( tmp ); + dt >> tmp; + desc->duration = QTime().addSecs( tmp ); + dt >> count; + for ( i=0; i<count; i++ ) { + sev = new ShortEvent(); + dt >> tmp; + if ( !validString( f, desc, tmp, EPGBUFSIZE, num ) ) return; + dt.readRawBytes( buf, tmp ); + sev->name = QString::fromUtf8( buf ); + dt >> tmp; + if ( !validString( f, desc, tmp, EPGBUFSIZE, num ) ) return; + dt.readRawBytes( buf, tmp ); + sev->text = QString::fromUtf8( buf ); + desc->shortEvents.append( sev ); + } + dt >> count; + for ( i=0; i<count; i++ ) { + dt >> tmp; + if ( !validString( f, desc, tmp, EPGBUFSIZE, num ) ) return; + dt.readRawBytes( buf, tmp ); + desc->extEvents.append( new QString( QString::fromUtf8( buf ) ) ); + } + dt >> tmp; + if ( !validString( f, desc, tmp, EPGBUFSIZE, num ) ) return; + dt.readRawBytes( buf, tmp ); + desc->title = QString::fromUtf8( buf ); + dt >> tmp; + if ( !validString( f, desc, tmp, EPGBUFSIZE, num ) ) return; + dt.readRawBytes( buf, tmp ); + desc->subtitle = QString::fromUtf8( buf ); + if ( desc->startDateTime.addSecs( (desc->duration.hour()*3600)+(desc->duration.minute()*60)+desc->duration.second() )<cur ) + delete desc; + else { + slist = getEventSource( desc->source )->getEventSid( desc->nid, desc->tsid, desc->sid ); + if ( !slist ) + continue; + slist->lock(); + slist->getEvents()->append( desc ); + slist->unlock(); + ++num; + } + } + f.close(); + fprintf( stderr, "Loaded epg data : %d events (%d msecs)\n", num, t1.msecsTo(QTime::currentTime()) ); + } +} + +bool EventTable::validString( QFile &f, EventDesc *d, int len, int buflen, int nev ) +{ + if ( len<1 || len>buflen ) { + f.close(); + fprintf( stderr, "Error while loading epg data : %d events loaded\n", nev ); + delete d; + return false; + } + return true; +} + +void EventTable::setClean() +{ + start(); +} + +void EventTable::doClean( bool b ) +{ + if ( b ) { + if ( cleanTimer.isActive() ) + return; + cleanTimer.start( 10000 ); + } + else { + cleanTimer.stop(); + wait(); + } +} + +void EventTable::run() +{ + int k, m, n, sec; + EventSource *esrc; + EventTsid *et; + EventSid *es; + EventDesc *desc; + QDateTime dt, cur; + + setpriority(PRIO_PROCESS, 0, 19); + + cur = QDateTime::currentDateTime(); + for( k=0; k<getNSource(); k++ ) { + if ( !(esrc=getNEventSource( k )) ) + continue; + for ( m=0; m<esrc->getNTsid(); m++ ) { + if ( !(et=esrc->getNEventTsid( m )) ) + continue; + for ( n=0; n<et->getNSid(); n++ ) { + if ( !(es=et->getNEventSid( n )) ) + continue; + if ( !(desc=es->getEventDesc( 0 )) ) + continue; + dt = desc->startDateTime; + sec = desc->duration.hour()*3600+desc->duration.minute()*60+desc->duration.second(); + if ( dt.addSecs( sec )<cur ) + es->remove( desc ); + } + } + } +} + +EventSource *EventTable::getNEventSource( int n ) +{ + QMutexLocker locker( &mutex ); + return srcList.at( n ); +} + +EventSource *EventTable::getEventSource( QString src ) +{ + int i; + + QMutexLocker locker( &mutex ); + for ( i=0; i<(int)srcList.count(); i++ ) { + if ( srcList.at(i)->getSource()==src ) + return srcList.at(i); + } + EventSource *es = new EventSource( src ); + srcList.append( es ); + return es; +} + +EventDesc *EventTable::getEventDesc( QString src, int nid, int tsid, int sid, int n ) +{ + int i; + EventSource *es=0; + + mutex.lock(); + for ( i=0; i<(int)srcList.count(); i++ ) { + if ( srcList.at(i)->getSource()==src ) { + es = srcList.at(i); + break; + } + } + mutex.unlock(); + if ( !es ) + return 0; + return es->getEventDesc( nid, tsid, sid, n ); +} + + + +KaffeineEpgPlugin::KaffeineEpgPlugin( QObject* parent, const char* name ) : KParts::Part( parent, name ) +{ +} + +KaffeineEpgPlugin::~KaffeineEpgPlugin() +{ +} + +bool KaffeineEpgPlugin::safeLen( unsigned char* buf ) +{ + if ( buf<(secbuf+readSize) ) + return true; + fprintf( stderr, "EIT (%d:%d) : buffer overflow! Rejected\n", adapter, tuner ); + return false; +} + +#include "kaffeinedvbevents.moc" diff --git a/kaffeine/src/input/dvb/plugins/epg/kaffeinedvbevents.h b/kaffeine/src/input/dvb/plugins/epg/kaffeinedvbevents.h new file mode 100644 index 0000000..07dbd16 --- /dev/null +++ b/kaffeine/src/input/dvb/plugins/epg/kaffeinedvbevents.h @@ -0,0 +1,177 @@ +/* + * kaffeinedvbevents.h + * + * Copyright (C) 2003-2007 Christophe Thommeret <hftom@free.fr> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef KAFFEINEDVBEVENTS_H +#define KAFFEINEDVBEVENTS_H + +#include <qtimer.h> +#include <qmutex.h> +#include <qfile.h> +#include <qobject.h> + +#include <kparts/part.h> + +#include "kaffeinedvbsection.h" + + + +class ShortEvent +{ + +public: + + ShortEvent(); + ~ShortEvent(); + + QString name; + QString text; +}; + +class EventDesc +{ + +public: + + EventDesc(); + ~EventDesc(); + + QString source; + unsigned char tid; + unsigned short sid; + unsigned short tsid; + unsigned short nid; + unsigned char sn; + unsigned char lsn; + unsigned short eid; + unsigned char running; + QDateTime startDateTime; + QTime duration; + QPtrList<ShortEvent> shortEvents; + QPtrList<QString> extEvents; + QString title; + QString subtitle; + unsigned int loop; +}; + + + +class EventSid +{ +public: + EventSid( int s ); + ~EventSid(); + int getSid() { return sid; } + void lock() { mutex.lock(); } + void unlock() { mutex.unlock(); } + QPtrList<EventDesc> *getEvents() { return &events; } + EventDesc *getEventDesc( int n ); + int getNDesc() { return events.count(); } + void remove( EventDesc *d ); +private: + QMutex mutex; + int sid; + QPtrList<EventDesc> events; +}; + + + +class EventTsid +{ +public: + EventTsid( int n, int t ); + ~EventTsid(); + int getTsid() { return tsid; } + int getNid() { return nid; } + EventSid *getEventSid( int sid ); + EventSid *getNEventSid( int n ); + int getNSid() { return sidList.count(); } + EventDesc *getEventDesc( int sid, int n ); +private: + QMutex mutex; + int tsid, nid; + QPtrList<EventSid> sidList; +}; + + + +class EventSource +{ +public: + EventSource( QString src ); + ~EventSource(); + EventSid *getEventSid( int nid, int tsid, int sid ); + EventTsid *getNEventTsid( int n ); + int getNTsid() { return tsidList.count(); } + EventDesc *getEventDesc( int nid, int tsid, int sid, int n ); + QString getSource() { return source; } +private: + QMutex mutex; + QString source; + QPtrList<EventTsid> tsidList; +}; + + + +class EventTable : public QObject, public QThread +{ + Q_OBJECT +public: + EventTable(); + ~EventTable(); + EventSource *getEventSource( QString src ); + EventDesc *getEventDesc( QString src, int nid, int tsid, int sid, int n ); + EventSource *getNEventSource( int n ); + int getNSource() { return srcList.count(); } + void doClean( bool b ); + void saveEpg(); + void loadEpg(); +protected: + virtual void run(); +private: + bool validString( QFile &f, EventDesc *d, int len, int buflen, int nev ); + QMutex mutex; + QPtrList<EventSource> srcList; + QTimer cleanTimer; + bool epgLoaded; +private slots: + void setClean(); +}; + + + +class KDE_EXPORT KaffeineEpgPlugin : public KParts::Part, public KaffeineDVBsection +{ + Q_OBJECT +public: + KaffeineEpgPlugin( QObject* parent, const char* name ); + virtual ~KaffeineEpgPlugin(); + virtual bool go( QString /*src*/, int /*freqKhz*/ ) { return false; } + virtual void stop() {} + void setTable( EventTable *table ) { events = table; } + +protected: + bool safeLen( unsigned char* buf ); + + unsigned char secbuf[4096]; + int readSize; + EventTable *events; +}; + +#endif /* KAFFEINEDVBEVENTS_H */ diff --git a/kaffeine/src/input/dvb/plugins/epg/kaffeinedvbsection.cpp b/kaffeine/src/input/dvb/plugins/epg/kaffeinedvbsection.cpp new file mode 100644 index 0000000..d6170e8 --- /dev/null +++ b/kaffeine/src/input/dvb/plugins/epg/kaffeinedvbsection.cpp @@ -0,0 +1,327 @@ +/* + * kaffeinedvbsection.cpp + * + * Copyright (C) 2003-2007 Christophe Thommeret <hftom@free.fr> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/types.h> +#include <errno.h> +#include <fcntl.h> +#include <sys/ioctl.h> +#include <time.h> +#include <iconv.h> + +#include <klocale.h> + +#include "kaffeinedvbsection.h" + + + +KaffeineDVBsection::KaffeineDVBsection() +{ +} + + + +KaffeineDVBsection::KaffeineDVBsection( int anum, int tnum, const QString &charset ) +{ + initSection( anum, tnum, charset ); +} + + + +void KaffeineDVBsection::initSection( int anum, int tnum, const QString &charset ) +{ + defaultCharset = charset.ascii(); + adapter = anum; + tuner = tnum; + isRunning = false; + fdDemux = -1; +} + + + +KaffeineDVBsection::~KaffeineDVBsection() +{ + if ( fdDemux>-1 ) + close( fdDemux ); +} + + + +bool KaffeineDVBsection::setFilter( int pid, int tid, int timeout, bool checkcrc ) +{ + struct dmx_sct_filter_params sctfilter; + QString demuxer = QString("/dev/dvb/adapter%1/demux%2").arg( adapter ).arg( tuner ); + + if ((fdDemux = open( demuxer.ascii(), O_RDWR | O_NONBLOCK )) < 0) { + perror ("open failed"); + return false; + } + + pf[0].fd = fdDemux; + pf[0].events = POLLIN; + + memset( &sctfilter, 0, sizeof( sctfilter ) ); + + sctfilter.pid = pid; + if ( tid<256 && tid>0 ) { + sctfilter.filter.filter[0] = tid; + sctfilter.filter.mask[0] = 0xff; + } + sctfilter.flags = DMX_IMMEDIATE_START; + if ( checkcrc ) + sctfilter.flags|= DMX_CHECK_CRC; + sctfilter.timeout = timeout; + + if ( ioctl( fdDemux, DMX_SET_FILTER, &sctfilter ) < 0 ) { + perror ( "ioctl DMX_SET_FILTER failed" ); + return false; + } + return true; +} + + + +void KaffeineDVBsection::stopFilter() +{ + ioctl( fdDemux, DMX_STOP ); + close( fdDemux ); + fdDemux = -1; +} + + + +unsigned int KaffeineDVBsection::getBits( unsigned char *b, int offbits, int nbits ) +{ + int i, nbytes; + unsigned int ret = 0; + unsigned char *buf; + + buf = b+(offbits/8); + offbits %=8; + nbytes = (offbits+nbits)/8; + if ( ((offbits+nbits)%8)>0 ) + nbytes++; + for ( i=0; i<nbytes; i++ ) + ret += buf[i]<<((nbytes-i-1)*8); + i = (4-nbytes)*8+offbits; + ret = ((ret<<i)>>i)>>((nbytes*8)-nbits-offbits); + + return ret; +} + + + +bool KaffeineDVBsection::doIconv( QCString &s, QCString table, char *buffer, int buflen ) +{ + size_t inSize, outSize=buflen; + char *inBuf, *outBuf; + iconv_t cd; + + inSize = s.length(); + if ( inSize<1 ) + return false; + cd = iconv_open( "UTF8", table ); + inBuf = s.data(); + outBuf = buffer; + outBuf[0] = 0; + iconv( cd, &inBuf, &inSize, &outBuf, &outSize ); + *outBuf = 0; + iconv_close( cd ); + return true; +} + + + +QString KaffeineDVBsection::getText( unsigned char *buf, int length ) +{ + QCString s; + QString ret=""; + int i=0; + char buffer[1000]; + QCString table=defaultCharset; + + if ( length==0 ) + return ""; + + while ( i<length ) { + if ( buf[i]<0x20 && (i+2)<length ) { + if ( !s.isEmpty() ) { + if ( doIconv( s, table, buffer, sizeof(buffer) ) ) { + ret += QString::fromUtf8( buffer ); + s = ""; + } + } + switch ( buf[i] ) { + case 0x01: table = "ISO8859-5"; ++i; break; + case 0x02: table = "ISO8859-6"; ++i; break; + case 0x03: table = "ISO8859-7"; ++i; break; + case 0x04: table = "ISO8859-8"; ++i; break; + case 0x05: table = "ISO8859-9"; ++i; break; + case 0x06: table = "ISO8859-10"; ++i; break; + case 0x07: table = "ISO8859-11"; ++i; break; + case 0x09: table = "ISO8859-13"; ++i; break; + case 0x0A: table = "ISO8859-14"; ++i; break; + case 0x0B: table = "ISO8859-15"; ++i; break; + case 0x13: table = "GB2312"; ++i; break; + case 0x14: table = "BIG5"; ++i; break; + case 0x10: { + switch ( buf[i+2] ) { + case 0x01: table = "ISO8859-1"; break; + case 0x02: table = "ISO8859-2"; break; + case 0x03: table = "ISO8859-3"; break; + case 0x04: table = "ISO8859-4"; break; + case 0x05: table = "ISO8859-5"; break; + case 0x06: table = "ISO8859-6"; break; + case 0x07: table = "ISO8859-7"; break; + case 0x08: table = "ISO8859-8"; break; + case 0x09: table = "ISO8859-9"; break; + case 0x0A: table = "ISO8859-10"; break; + case 0x0B: table = "ISO8859-11"; break; + case 0x0D: table = "ISO8859-13"; break; + case 0x0E: table = "ISO8859-14"; break; + case 0x0F: table = "ISO8859-15"; break; + } + i+= 3; + break; + } + default: ++i; + } + } + + if ( buf[i]>=0x80 && buf[i]<=0x9f ) { + ++i; + continue; // control codes + } + s += buf[i++]; + } + + if ( !s.isEmpty() ) { + if ( doIconv( s, table, buffer, sizeof(buffer) ) ) { + ret += QString::fromUtf8( buffer ); + } + } + return ret; +} + + + +QString KaffeineDVBsection::langDesc( unsigned char* buf ) +{ + char c[4]; + QString s; + + memset( mempcpy( c, buf+2, 3 ), 0, 1 ); + s = c; + return s; +} + + + +QTime KaffeineDVBsection::getTime( unsigned char *buf ) +{ + int h, m, s; + + h = ((getBits(buf,0,4)*10)+getBits(buf,4,4))%24; + m = ((getBits(buf,8,4)*10)+getBits(buf,12,4))%60; + s = ((getBits(buf,16,4)*10)+getBits(buf,20,4))%60; + return QTime( h, m, s ); +} + + + +QDate KaffeineDVBsection::getDate( unsigned char *buf ) +{ + int i, j, m, D, Y, M, k, mjd; + + mjd = getBits(buf,0,16); + i = (int)((mjd-15078.2)/365.25); + j = (int)(i*365.25); + m = (int)((mjd-14956.1-j)/30.6001); + D = mjd-14956-j-(int)(m*30.6001); + if ( m==14 || m==15 ) + k = 1; + else + k = 0; + Y = i+k+1900; + M = m-1-k*12; + + return QDate( (Y>=1970)?Y:1970, (M>0 && M<13)?M:1, (D>0 && D<32)?D:1 ); +} + + + +QDateTime KaffeineDVBsection::getDateTime( unsigned char *buf ) +{ + /*int hh, mm, ss; + int i, j, m, D, Y, M, k, mjd; + int sec; + + mjd = getBits(buf,0,16); + i = (int)((mjd-15078.2)/365.25); + j = (int)(i*365.25); + m = (int)((mjd-14956.1-j)/30.6001); + D = mjd-14956-j-(int)(m*30.6001); + if ( m==14 || m==15 ) k = 1; + else k = 0; + Y = i+k+1900; + M = m-1-k*12; + + hh = ((getBits(buf+2,0,4)*10)+getBits(buf+2,4,4))%24; + mm = ((getBits(buf+2,8,4)*10)+getBits(buf+2,12,4))%60; + ss = ((getBits(buf+2,16,4)*10)+getBits(buf+2,20,4))%60; + + QDateTime dt( QDate( (Y>=1970)?Y:1970, (M>0 && M<13)?M:1, (D>0 && D<32)?D:1 ), QTime( hh, mm, ss ) ); + QDateTime u( QDate( 1970, 1, 1 ), QTime( 0, 0, 0 ) ); + sec = u.secsTo( dt ); + u.setTime_t( sec ); // UTC to local + return u;*/ + + int i, j, m, k, mjd; + struct tm tt; + struct tm *t=&tt; + + mjd = getBits(buf,0,16); + i = (int)((mjd-15078.2)/365.25); + j = (int)(i*365.25); + m = (int)((mjd-14956.1-j)/30.6001); + t->tm_mday = mjd-14956-j-(int)(m*30.6001); + if ( m==14 || m==15 ) + k = 1; + else + k = 0; + t->tm_year = i+k; + t->tm_mon = m-1-k*12-1; + t->tm_sec = ((getBits(buf+2,16,4)*10)+getBits(buf+2,20,4))%60; + t->tm_min = ((getBits(buf+2,8,4)*10)+getBits(buf+2,12,4))%60; + t->tm_hour = ((getBits(buf+2,0,4)*10)+getBits(buf+2,4,4))%24; + t->tm_isdst = -1; + t->tm_gmtoff = 0; + + time_t p=timegm(t); + if ( p>0 ) { + t = localtime(&p); + return QDateTime( QDate( t->tm_year+1900, t->tm_mon+1, t->tm_mday ), QTime( t->tm_hour, t->tm_min, t->tm_sec ) ); + } + else + return QDateTime( QDate( 1970, 1, 1 ), QTime( 0, 0, 0 ) ); +} diff --git a/kaffeine/src/input/dvb/plugins/epg/kaffeinedvbsection.h b/kaffeine/src/input/dvb/plugins/epg/kaffeinedvbsection.h new file mode 100644 index 0000000..af451f2 --- /dev/null +++ b/kaffeine/src/input/dvb/plugins/epg/kaffeinedvbsection.h @@ -0,0 +1,64 @@ +/* + * kaffeinedvbsection.h + * + * Copyright (C) 2003-2007 Christophe Thommeret <hftom@free.fr> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef KAFFEINEDVBSECTION_H +#define KAFFEINEDVBSECTION_H + +#include <sys/poll.h> +#include <linux/dvb/dmx.h> + +#include <qthread.h> +#include <qdatetime.h> + + + +class KaffeineDVBsection : public QThread +{ + +public: + + KaffeineDVBsection(); + KaffeineDVBsection( int anum, int tnum, const QString &charset="ISO8859-1" ); + ~KaffeineDVBsection(); + void initSection( int anum, int tnum, const QString &charset="ISO8859-1" ); + static unsigned int getBits( unsigned char *b, int offbits, int nbits ); + +protected: + + virtual void run() {} + QString langDesc( unsigned char* buf ); + bool setFilter( int pid, int tid, int timeout=5000, bool checkcrc=true ); + void stopFilter(); + QString getText( unsigned char *buf, int length ); + bool doIconv( QCString &s, QCString table, char *buffer, int buflen ); + QTime getTime( unsigned char *buf ); + QDate getDate( unsigned char *buf ); + QDateTime getDateTime( unsigned char *buf ); + + int fdDemux; + int indexChannels; + bool isRunning; + int adapter; + int tuner; + QCString defaultCharset; + struct pollfd pf[1]; +}; + +#endif /* KAFFEINEDVBSECTION_H */ diff --git a/kaffeine/src/input/dvb/plugins/epg/kaffeineepgplugin.desktop b/kaffeine/src/input/dvb/plugins/epg/kaffeineepgplugin.desktop new file mode 100644 index 0000000..2a71d4f --- /dev/null +++ b/kaffeine/src/input/dvb/plugins/epg/kaffeineepgplugin.desktop @@ -0,0 +1,4 @@ +[Desktop Entry] +Encoding=UTF-8 +Type=ServiceType +X-KDE-ServiceType=KaffeineEpgPlugin diff --git a/kaffeine/src/input/dvb/plugins/stream/Makefile.am b/kaffeine/src/input/dvb/plugins/stream/Makefile.am new file mode 100644 index 0000000..3d3f9b9 --- /dev/null +++ b/kaffeine/src/input/dvb/plugins/stream/Makefile.am @@ -0,0 +1,16 @@ +lib_LTLIBRARIES = libkaffeinedvbplugin.la + +METASOURCES = AUTO + +INCLUDES = -I$(top_srcdir)/kaffeine/src/input/dvb \ + -I$(top_srcdir)/kaffeine/src \ + $(all_includes) + +kaffeineincludedir = $(includedir)/kaffeine +kaffeineinclude_HEADERS = kaffeinedvbplugin.h + +libkaffeinedvbplugin_la_SOURCES = kaffeinedvbplugin.cpp +libkaffeinedvbplugin_la_LIBADD = $(LIB_KPARTS) +libkaffeinedvbplugin_la_LDFLAGS = $(all_libraries) -version-info 0:1:0 -no-undefined + +kde_servicetypes_DATA = kaffeinedvbplugin.desktop diff --git a/kaffeine/src/input/dvb/plugins/stream/kaffeinedvbplugin.cpp b/kaffeine/src/input/dvb/plugins/stream/kaffeinedvbplugin.cpp new file mode 100644 index 0000000..bd3e5b3 --- /dev/null +++ b/kaffeine/src/input/dvb/plugins/stream/kaffeinedvbplugin.cpp @@ -0,0 +1,30 @@ +/* + * kaffeinedvbplugin.cpp + * + * Copyright (C) 2006 Christophe Thommeret <hftom@free.fr> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "kaffeinedvbplugin.h" +#include "kaffeinedvbplugin.moc" + +KaffeineDvbPlugin::KaffeineDvbPlugin(QObject* parent, const char* name) : KParts::Part( parent, name ) +{ +} + +KaffeineDvbPlugin::~KaffeineDvbPlugin() +{ +} diff --git a/kaffeine/src/input/dvb/plugins/stream/kaffeinedvbplugin.desktop b/kaffeine/src/input/dvb/plugins/stream/kaffeinedvbplugin.desktop new file mode 100644 index 0000000..cc28b16 --- /dev/null +++ b/kaffeine/src/input/dvb/plugins/stream/kaffeinedvbplugin.desktop @@ -0,0 +1,4 @@ +[Desktop Entry] +Encoding=UTF-8 +Type=ServiceType +X-KDE-ServiceType=KaffeineDvbPlugin diff --git a/kaffeine/src/input/dvb/plugins/stream/kaffeinedvbplugin.h b/kaffeine/src/input/dvb/plugins/stream/kaffeinedvbplugin.h new file mode 100644 index 0000000..f112397 --- /dev/null +++ b/kaffeine/src/input/dvb/plugins/stream/kaffeinedvbplugin.h @@ -0,0 +1,52 @@ +/* + * kaffeinedvbplugin.h + * + * Copyright (C) 2006 Christophe Thommeret <hftom@free.fr> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef KAFFEINEDVBPLUGIN_H +#define KAFFEINEDVBPLUGIN_H + +#include <qpopupmenu.h> +#include <qstring.h> + +#include <kparts/part.h> +#include <kconfig.h> + +/* + * Base-Class for Kaffeine DVB plugins. + */ + +class KDE_EXPORT KaffeineDvbPlugin : public KParts::Part +{ + Q_OBJECT +public: + KaffeineDvbPlugin(QObject* parent, const char* name); + virtual ~KaffeineDvbPlugin(); + virtual QString pluginName() { return QString(); } + + // returns a "handle". + virtual void* init( int /*sid*/ , int /*anum*/, int /*tnum*/, int /*fta*/ ) { return NULL; } + + virtual void process( void* /*handle*/, unsigned char* /*buf*/, int /*len*/ ) {}; + virtual void close( void* /*handle*/ ) {}; + +public slots: + virtual void configDialog() {}; +}; + +#endif /* KAFFEINEDVBPLUGIN_H */ diff --git a/kaffeine/src/input/dvb/scandialog.cpp b/kaffeine/src/input/dvb/scandialog.cpp new file mode 100644 index 0000000..2399c74 --- /dev/null +++ b/kaffeine/src/input/dvb/scandialog.cpp @@ -0,0 +1,1019 @@ +/* + * scandialog.cpp + * + * Copyright (C) 2004-2007 Christophe Thommeret <hftom@free.fr> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include <qlayout.h> +#include <qdir.h> +#include <qpushbutton.h> +#include <qcheckbox.h> +#include <qcombobox.h> +#include <qgroupbox.h> +#include <qlistview.h> +#include <qpopupmenu.h> +#include <qcursor.h> +#include <qwhatsthis.h> +#include <qapplication.h> +#include <qaccel.h> + +#include <klocale.h> +#include <kiconloader.h> +#include <kmessagebox.h> + +#include "scandialog.h" +#include "channeleditor.h" +#include "dvbsi.h" + + + +DListViewItem::DListViewItem( QListView *parent, ChannelDesc *desc, QString label1, QString label2 ) + : QListViewItem( parent, label1, label2 ) +{ + chan = desc; +} + + + +ScanDialog::ScanDialog( QPtrList<DvbStream> *d, QPtrList<ChannelDesc> *ch, QSize size, QString src, const QString &charset ) +{ + QString s; + int i, j; + QStringList list, tmp; + + KIconLoader *icon = new KIconLoader(); + tvPix = icon->loadIcon( "kdvbtv", KIcon::Small ); + tvcPix = icon->loadIcon( "kdvbtvc", KIcon::Small ); + raPix = icon->loadIcon( "kdvbra", KIcon::Small ); + racPix = icon->loadIcon( "kdvbrac", KIcon::Small ); + + chandesc = ch; + dvbsi = 0; + dvb = d; + sourcesPath = src; + defaultCharset = charset; + + for ( i=0; i<(int)dvb->count(); i++ ) { + tmp = dvb->at(i)->getSources( true ); + for ( j=0; j<(int)tmp.count(); j++ ) { + if ( tmp[j].startsWith( "AUTO" ) ) + list.append( QString("AUTO(%1:%2)").arg(dvb->at(i)->getAdapter()).arg(dvb->at(i)->getTuner()) ); + else + list.append( tmp[j] ); + } + } + searchComb->insertStringList( list ); + + setCaption( i18n("Channels") ); + + transponders.setAutoDelete( true ); + + QGridLayout *statLayout = new QGridLayout( statusFrame, 1, 1, 11, 6 ); + + QLabel *lab = new QLabel( i18n("Signal:"), statusFrame ); + statLayout->addWidget( lab, 0, 0 ); + signal = new KGradProgress( statusFrame ); + statLayout->addWidget( signal, 0, 1 ); + lab = new QLabel( i18n("SNR:"), statusFrame ); + statLayout->addWidget( lab, 1, 0 ); + snr = new KGradProgress( statusFrame ); + statLayout->addWidget( snr, 1, 1 ); + lab = new QLabel( i18n("Tuned:"), statusFrame ); + statLayout->addWidget( lab, 2, 0 ); + lock = new KLed( statusFrame, "lockLed" ); + lock->setState( KLed::Off ); + lock->setDarkFactor( 500 ); + statLayout->addWidget( lock, 2, 1 ); + progress = new QProgressBar( 100, statusFrame ); + progress->setIndicatorFollowsStyle( false ); + progress->setProgress( 0 ); + statLayout->addMultiCellWidget( progress, 3, 3, 0, 1 ); + progressLab = new QLabel( statusFrame ); + statLayout->addMultiCellWidget( progressLab, 4, 4, 0, 1 ); + + channelsList->clear(); + foundList->clear(); + foundList->setAllColumnsShowFocus( true ); + foundList->setSelectionMode( QListView::Extended ); + channelsList->setSorting( 0 ); + + ChannelDesc *chan; + QListViewItem *it; + for ( int i=0; i<(int)chandesc->count(); i++ ) { + chan = chandesc->at(i); + it = new QListViewItem( channelsList, chan->name ); + if ( !chan->pix.isNull() ) + it->setPixmap( 0, chan->pix ); + else { + if ( chan->type==1 ) { + if ( chan->fta ) + it->setPixmap( 0, tvcPix ); + else + it->setPixmap( 0, tvPix ); + } + else { + if ( chan->fta ) + it->setPixmap( 0, racPix ); + else + it->setPixmap( 0, raPix ); + } + } + } + + startBtn->setPaletteForegroundColor( QColor(255,0,0) ); + + connect( searchComb, SIGNAL(activated(int)), this, SLOT(setDvb(int)) ); + + ds = dvb->at(0); + ds->setScanning( true ); + if ( searchComb->currentText().startsWith( "AUTO" ) ) + offsetGroup->show(); + else + offsetGroup->hide(); + bool ok=false; + dvbsi = new DVBsi( &ok, ds->getAdapter(), ds->getTuner(), ds, defaultCharset ); + connect( ds, SIGNAL(snrStatus(int)), snr, SLOT(setProgress(int)) ); + connect( ds, SIGNAL(signalStatus(int)), signal, SLOT(setProgress(int)) ); + connect( ds, SIGNAL(lockStatus(bool)), this, SLOT(setLock(bool)) ); + connect( dvbsi, SIGNAL(end(bool)), this, SLOT(siEnded(bool)) ); + + connect( &checkTimer, SIGNAL( timeout() ), this, SLOT( checkNewChannel() ) ); + connect( &progressTimer, SIGNAL( timeout() ), this, SLOT( setProgress() ) ); + connect( startBtn, SIGNAL(toggled(bool)), this, SLOT(scan(bool)) ); + connect( addfilteredBtn, SIGNAL(clicked()), this, SLOT(addFiltered()) ); + connect( addselectedBtn, SIGNAL(clicked()), this, SLOT(addSelected()) ); + connect( channelsList, SIGNAL(contextMenuRequested(QListViewItem*,const QPoint&,int)), this, SLOT(pop(QListViewItem*,const QPoint&,int)) ); + connect( channelsList, SIGNAL(doubleClicked(QListViewItem*,const QPoint &,int)), this, SLOT( slotChannelChanged(QListViewItem*,const QPoint &,int) ) ); + connect( newBtn, SIGNAL(clicked()), this, SLOT(newChannel()) ); + connect( delBtn, SIGNAL(clicked()), this, SLOT(deleteAll()) ); + connect( selectallBtn, SIGNAL(clicked()), this, SLOT(selectAll()) ); + + QAccel *ac = new QAccel( channelsList ); + ac->insertItem( Key_Delete, 100 ); + ac->connectItem( 100, this, SLOT(deleteChannel()) ); + + resize( size ); + delete icon; +} + + + +void ScanDialog::selectAll() +{ + foundList->selectAll( true ); +} + + + +void ScanDialog::slotChannelChanged( QListViewItem *_channel, const QPoint &, int ) +{ + if ( !_channel ) + return; + QPixmap pix; + QString s = _channel->text(0); + if ( edit( s, pix ) ) { + _channel->setText( 0, s ); + _channel->setPixmap( 0, pix ); + } +} + + + +void ScanDialog::setDvb( int index ) +{ + int i, pos=0; + QStringList list; + bool ok=false; + + for ( i=0; i<(int)dvb->count(); i++ ) { + list = dvb->at(i)->getSources( true ); + pos+= list.count(); + if ( index<pos ) { + if ( checkTimer.isActive() ) + checkTimer.stop(); + if ( progressTimer.isActive() ) + progressTimer.stop(); + disconnect( ds, SIGNAL(snrStatus(int)), snr, SLOT(setProgress(int)) ); + disconnect( ds, SIGNAL(signalStatus(int)), signal, SLOT(setProgress(int)) ); + disconnect( ds, SIGNAL(lockStatus(bool)), this, SLOT(setLock(bool)) ); + disconnect( dvbsi, SIGNAL(end(bool)), this, SLOT(siEnded(bool)) ); + ds->setScanning( false ); + dvbsi->stop(); + delete dvbsi; + ds = dvb->at(i); + ds->setScanning( true ); + dvbsi = new DVBsi( &ok, ds->getAdapter(), ds->getTuner(), ds, defaultCharset ); + connect( ds, SIGNAL(snrStatus(int)), snr, SLOT(setProgress(int)) ); + connect( ds, SIGNAL(signalStatus(int)), signal, SLOT(setProgress(int)) ); + connect( ds, SIGNAL(lockStatus(bool)), this, SLOT(setLock(bool)) ); + connect( dvbsi, SIGNAL(end(bool)), this, SLOT(siEnded(bool)) ); + break; + } + } + if ( searchComb->currentText().startsWith( "AUTO" ) ) + offsetGroup->show(); + else + offsetGroup->hide(); +} + + + +void ScanDialog::pop( QListViewItem *it, const QPoint &pos, int col ) +{ + QPoint p=pos; + + if ( !it ) + return; + + int i=col; + QPixmap pix; + QString s = it->text(0); + + QPopupMenu *pop = new QPopupMenu(); + pop->insertItem( i18n("Edit..."), 1 ); + pop->insertItem( i18n("Delete"), 2 ); + i = 0; + i = pop->exec( QCursor::pos() ); + switch ( i ) { + case 0 : + break; + case 1 : + if ( edit( s, pix ) ) { + it->setText( 0, s ); + it->setPixmap( 0, pix ); + } + break; + case 2 : + deleteChannel( it->text(0) ); + break; + } + delete pop; +} + + + +void ScanDialog::deleteChannel() +{ + QListViewItem *it = channelsList->currentItem(); + if ( it ) + deleteChannel( it->text(0) ); +} + + + +void ScanDialog::deleteChannel( QString name ) +{ + int j, i; + QListViewItem *it; + + for ( j=0; j<(int)chandesc->count(); j++ ) { + if ( chandesc->at(j)->name==name ) { + for ( i=0; i<(int)chandesc->count(); i++ ) { + if ( chandesc->at(i)->num==chandesc->count() ) { + chandesc->at(i)->num = chandesc->at(j)->num; + break; + } + } + dvbsi->channels.append( new ChannelDesc( *chandesc->at(j) ) ); + addFound( dvbsi->channels.getLast(), false ); + chandesc->remove(j); + it = channelsList->firstChild(); + while ( it!=0 ) { + if ( name==it->text(0) ) { + channelsList->removeItem( it ); + break; + } + it = it->nextSibling(); + } + break; + } + } +} + + + +void ScanDialog::newChannel() +{ + ChannelDesc chan; + QStringList list; + //int i; + + //for ( i=0; i<(int)searchComb->count(); i++ ) list.append( searchComb->text(i) ); + if ( ds->getType()==FE_QPSK ) + list.append( searchComb->currentText() ); + else + list = ds->getSources(); + + chandesc->append( new ChannelDesc( chan ) ); + chan.tp.type = ds->getType(); + chan.num = chandesc->count(); + + ChannelEditor dlg( list, false, &chan, chandesc, this ); + + int ret = dlg.exec(); + chandesc->remove(); + if ( ret==ChannelEditor::Accepted ) { + chandesc->append( new ChannelDesc( chan ) ); + QListViewItem *it = new QListViewItem( channelsList, chan.name ); + if ( chan.type==1 ) { + if ( chan.fta ) + it->setPixmap( 0, tvcPix ); + else + it->setPixmap( 0, tvPix ); + } + else { + if ( chan.fta ) + it->setPixmap( 0, racPix ); + else + it->setPixmap( 0, raPix ); + } + } +} + + + +void ScanDialog::deleteAll() +{ + int i, ret; + + ret = KMessageBox::questionYesNo( this, i18n("Do you really want to delete all channels?") ); + if ( ret!=KMessageBox::Yes ) + return; + for ( i=0; i<(int)chandesc->count(); i++ ) { + dvbsi->channels.append( new ChannelDesc( *chandesc->at(i) ) ); + addFound( dvbsi->channels.getLast(), false ); + } + channelsList->clear(); + chandesc->clear(); +} + + + +bool ScanDialog::edit( QString &name, QPixmap &pix ) +{ + int j; + ChannelDesc *chan=0; + QStringList list, tmp; + int i; + + for ( i=0; i<(int)dvb->count(); i++ ) { + tmp = dvb->at(i)->getSources(); + for ( j=0; j<(int)tmp.count(); j++ ) + list.append( tmp[j] ); + } + + for ( j=0; j<(int)chandesc->count(); j++ ) { + chan = chandesc->at(j); + if ( chan->name==name ) { + j = -1; + break; + } + } + if ( j==-1 ) { + ChannelEditor dlg( list, false, chan, chandesc, this ); + int ret = dlg.exec(); + if ( ret==ChannelEditor::Accepted ) { + name = chan->name; + if ( chan->type==1 ) { + if ( chan->fta ) + pix = tvcPix; + else + pix = tvPix; + } + else { + if ( chan->fta ) + pix = racPix; + else + pix = raPix; + } + return true; + } + } + return false; +} + + + +void ScanDialog::parseTp( QString s, fe_type_t type, QString src ) +{ + Transponder *trans; + QString t; + int pos; + + s = s.stripWhiteSpace(); + trans = new Transponder(); + pos = s.find(" "); + if ( s.left(pos)=="T" ) { + trans->type=FE_OFDM; + trans->source = "Terrestrial"; + } + else if ( s.left(pos)=="C" ) { + trans->type=FE_QAM; + trans->source = "Cable"; + } + else { + trans->type=FE_QPSK; + trans->source = src; + } + if ( trans->type!=type ) { + delete trans; + return; + } + s = s.right( s.length()-pos-1 ); + s = s.stripWhiteSpace(); + pos = s.find(" "); + trans->freq = s.left(pos).toULong()/1000; + s = s.right( s.length()-pos-1 ); + s = s.stripWhiteSpace(); + pos = s.find(" "); + if ( trans->type==FE_QPSK ) { + trans->pol = s.left(pos).lower()[0].latin1(); + s = s.right( s.length()-pos-1 ); + s = s.stripWhiteSpace(); + pos = s.find(" "); + } + if ( trans->type!=FE_OFDM ) { + trans->sr = s.left(pos).toULong()/1000; + } + else { + if ( s.left(pos)=="8MHz" ) + trans->bandwidth = BANDWIDTH_8_MHZ; + else if ( s.left(pos)=="7MHz" ) + trans->bandwidth = BANDWIDTH_7_MHZ; + else if ( s.left(pos)=="6MHz" ) + trans->bandwidth = BANDWIDTH_6_MHZ; + else + trans->bandwidth = BANDWIDTH_AUTO; + } + s = s.right( s.length()-pos-1 ); + s = s.stripWhiteSpace(); + pos = s.find(" "); + if ( s.left(pos)=="1/2" ) + trans->coderateH = FEC_1_2; + else if ( s.left(pos)=="2/3" ) + trans->coderateH = FEC_2_3; + else if ( s.left(pos)=="3/4" ) + trans->coderateH = FEC_3_4; + else if ( s.left(pos)=="4/5" ) + trans->coderateH = FEC_4_5; + else if ( s.left(pos)=="5/6" ) + trans->coderateH = FEC_5_6; + else if ( s.left(pos)=="6/7" ) + trans->coderateH = FEC_6_7; + else if ( s.left(pos)=="7/8" ) + trans->coderateH = FEC_7_8; + else if ( s.left(pos)=="8/9" ) + trans->coderateH = FEC_8_9; + else if ( s.left(pos)=="NONE" ) + trans->coderateH = FEC_NONE; + else + trans->coderateH = FEC_AUTO; + s = s.right( s.length()-pos-1 ); + s = s.stripWhiteSpace(); + pos = s.find(" "); + if ( trans->type==FE_OFDM ) { + if ( s.left(pos)=="1/2" ) + trans->coderateL = FEC_1_2; + else if ( s.left(pos)=="2/3" ) + trans->coderateL = FEC_2_3; + else if ( s.left(pos)=="3/4" ) + trans->coderateL = FEC_3_4; + else if ( s.left(pos)=="4/5" ) + trans->coderateL = FEC_4_5; + else if ( s.left(pos)=="5/6" ) + trans->coderateL = FEC_5_6; + else if ( s.left(pos)=="6/7" ) + trans->coderateL = FEC_6_7; + else if ( s.left(pos)=="7/8" ) + trans->coderateL = FEC_7_8; + else if ( s.left(pos)=="8/9" ) + trans->coderateL = FEC_8_9; + else if ( s.left(pos)=="NONE" ) + trans->coderateL = FEC_NONE; + else + trans->coderateL = FEC_AUTO; + + if ( trans->coderateH==FEC_NONE ) + trans->coderateH = FEC_AUTO; + if ( trans->coderateL==FEC_NONE ) + trans->coderateL = FEC_AUTO; + + s = s.right( s.length()-pos-1 ); + s = s.stripWhiteSpace(); + pos = s.find(" "); + } + if ( trans->type!=FE_QPSK ) { + if ( s.left(pos)=="QPSK" ) + trans->modulation = QPSK; + else if ( s.left(pos)=="QAM16" ) + trans->modulation = QAM_16; + else if ( s.left(pos)=="QAM32" ) + trans->modulation = QAM_32; + else if ( s.left(pos)=="QAM64" ) + trans->modulation = QAM_64; + else if ( s.left(pos)=="QAM128" ) + trans->modulation = QAM_128; + else if ( s.left(pos)=="QAM256" ) + trans->modulation = QAM_256; + else + trans->modulation = QAM_AUTO; + } + if ( trans->type==FE_OFDM ) { + s = s.right( s.length()-pos-1 ); + s = s.stripWhiteSpace(); + pos = s.find(" "); + if ( s.left(pos)=="8k" ) + trans->transmission = TRANSMISSION_MODE_8K; + else if ( s.left(pos)=="2k" ) + trans->transmission = TRANSMISSION_MODE_2K; + else + trans->transmission = TRANSMISSION_MODE_AUTO; + + s = s.right( s.length()-pos-1 ); + s = s.stripWhiteSpace(); + pos = s.find(" "); + if ( s.left(pos)=="1/32" ) + trans->guard = GUARD_INTERVAL_1_32; + else if ( s.left(pos)=="1/16" ) + trans->guard = GUARD_INTERVAL_1_16; + else if ( s.left(pos)=="1/8" ) + trans->guard = GUARD_INTERVAL_1_8; + else if ( s.left(pos)=="1/4" ) + trans->guard = GUARD_INTERVAL_1_4; + else + trans->guard = GUARD_INTERVAL_AUTO; + + s = s.right( s.length()-pos-1 ); + s = s.stripWhiteSpace(); + pos = s.find(" "); + if ( s.left(pos)=="1" ) + trans->hierarchy = HIERARCHY_1; + else if ( s.left(pos)=="2" ) + trans->hierarchy = HIERARCHY_2; + else if ( s.left(pos)=="4" ) + trans->hierarchy = HIERARCHY_4; + else if ( s.left(pos)=="NONE" ) + trans->hierarchy = HIERARCHY_NONE; + else + trans->hierarchy = HIERARCHY_AUTO; + } + transponders.append( trans ); +} + + + +bool ScanDialog::getTransData() +{ + QString s=sourcesPath; + + transponders.clear(); + + if ( searchComb->currentText().startsWith("AUTO") ) { + int i; + for ( i=402; i<900; i+=8 ) { + if ( offset167m->isChecked() ) { + s = QString("T %1 8MHz AUTO AUTO AUTO AUTO AUTO AUTO").arg( (i*1000000)-167000 ); + parseTp( s, ds->getType(), "" ); + } + if ( offset0->isChecked() ) { + s = QString("T %1 8MHz AUTO AUTO AUTO AUTO AUTO AUTO").arg( i*1000000 ); + parseTp( s, ds->getType(), "" ); + } + if ( offset167p->isChecked() ) { + s = QString("T %1 8MHz AUTO AUTO AUTO AUTO AUTO AUTO").arg( (i*1000000)+167000 ); + parseTp( s, ds->getType(), "" ); + } + } + return true; + } + + switch ( ds->getType() ) { + case FE_QPSK : s += "dvb-s/"; break; + case FE_QAM : s += "dvb-c/"; break; + case FE_OFDM : s += "dvb-t/"; break; + case FE_ATSC : return false; + } + s += searchComb->currentText(); + QFile f( s ); + if ( f.open(IO_ReadOnly) ) { + QTextStream tt( &f ); + while ( !tt.eof() ) { + s = tt.readLine(); + if ( s.startsWith("#") ) + continue; + if ( s.length()==0 ) + continue; + parseTp( s, ds->getType(), searchComb->currentText() ); + } + f.close(); + return true; + } + else + return false; +} + + + +void ScanDialog::checkDuplicateName( ChannelDesc *chan ) +{ + QString org, name; + int i, j=1; + bool loop; + + org = name = chan->name; + + do { + loop = false; + for ( i=0; i<(int)chandesc->count(); i++ ) { + if ( name==chandesc->at(i)->name ) { + name = org+"-"+QString().setNum(j); + loop = true; + ++j; + break; + } + } + } while ( loop ); + chan->name = name; +} + +bool ScanDialog::checkChannUpdate( ChannelDesc *chan ) +{ + int i, j; + AudioPid a; + SubPid s; + ChannelDesc *desc; + + for ( i=0; i<(int)chandesc->count(); i++ ) { + desc = chandesc->at(i); + if ( chan->tp.source==desc->tp.source && chan->tp.freq==desc->tp.freq && chan->sid==desc->sid ) { + chan->category=desc->category; + chan->num=desc->num; + chan->name=desc->name; + chan->fta=desc->fta; + for ( j=0; j<chan->napid; j++ ) { + if ( desc->apid[0].pid==chan->apid[j].pid ) { + if ( j>0 ) { + a = chan->apid[0]; + chan->apid[0]=chan->apid[j]; + chan->apid[j]=a; + } + break; + } + } + for ( j=0; j<chan->nsubpid; j++ ) { + if ( desc->subpid[0].pid==chan->subpid[j].pid ) { + if ( j>0 ) { + s = chan->subpid[0]; + chan->subpid[0]=chan->subpid[j]; + chan->subpid[j]=s; + } + break; + } + } + chandesc->replace(i,new ChannelDesc(*chan)); + return false; + } + } + return true; +} + + +void ScanDialog::addSelected() +{ + ChannelDesc *chan; + DListViewItem *dit, *odit; + QListViewItem *it; + + dit = (DListViewItem*)foundList->firstChild(); + while( dit ) { + chan = 0; + if ( !dit->isSelected( ) ) { + dit = (DListViewItem*)dit->nextSibling(); + continue; + } + chan = dit->chan; + if ( !chan ) { + dit = (DListViewItem*)dit->nextSibling(); + continue; + } + if(checkChannUpdate(chan)){ + checkDuplicateName( chan ); + + chan->num = chandesc->count()+1; + chandesc->append( new ChannelDesc( *chan ) ); + it = new QListViewItem( channelsList, chan->name ); + if ( chan->type==1 ) { + if ( chan->fta ) + it->setPixmap( 0, tvcPix ); + else + it->setPixmap( 0, tvPix ); + } + else { + if ( chan->fta ) + it->setPixmap( 0, racPix ); + else + it->setPixmap( 0, raPix ); + } + } + odit = dit; + dit = (DListViewItem*)dit->nextSibling(); + delete odit; + dvbsi->channels.remove( chan ); + } +} + + + +void ScanDialog::working( bool b ) +{ + offsetGroup->setEnabled( !b ); + addfilteredBtn->setEnabled( !b ); + addselectedBtn->setEnabled( !b ); + //if ( !isTuned ) searchGroup->setEnabled( !b ); + newBtn->setEnabled( !b ); + delBtn->setEnabled( !b ); +} + + + +void ScanDialog::addFiltered() +{ + ChannelDesc *chan; + QListViewItem *it; + DListViewItem *dit, *odit; + int m = dvbsi->channels.count(); + int t=0; + + working( true ); + startBtn->setEnabled( false ); + progress->setProgress(0); + qApp->processEvents(); + + dit = (DListViewItem*)foundList->firstChild(); + while( dit ) { + t++; + progress->setProgress( t*100/m ); + chan = dit->chan; + if ( !chan->completed ) { + dit = (DListViewItem*)dit->nextSibling(); + continue; + } + if ( chan->name.isEmpty() ) { + dit = (DListViewItem*)dit->nextSibling(); + continue; + } + if ( chan->type<1 ) { + dit = (DListViewItem*)dit->nextSibling(); + continue; + } + if ( chan->type>2 ) { + dit = (DListViewItem*)dit->nextSibling(); + continue; + } + if ( chan->type==1 && chan->vpid==0 ) { + dit = (DListViewItem*)dit->nextSibling(); + continue; + } + if ( chan->type==1 && chan->napid==0 ) { + dit = (DListViewItem*)dit->nextSibling(); + continue; + } + if ( chan->type==2 && chan->napid==0 ) { + dit = (DListViewItem*)dit->nextSibling(); + continue; + } + if ( chan->type==2 && chan->vpid!=0 ) { + dit = (DListViewItem*)dit->nextSibling(); + continue; + } + if ( ftaCb->isChecked() && chan->fta ) { + dit = (DListViewItem*)dit->nextSibling(); + continue; + } + if ( !tvCb->isChecked() && chan->type==1 ) { + dit = (DListViewItem*)dit->nextSibling(); + continue; + } + if ( !radioCb->isChecked() && chan->type==2 ) { + dit = (DListViewItem*)dit->nextSibling(); + continue; + } + if ( providerCb->isChecked() && chan->provider!=providerComb->currentText() ) { + dit = (DListViewItem*)dit->nextSibling(); + continue; + } + if(checkChannUpdate(chan)){ + checkDuplicateName( chan ); + + chan->num = chandesc->count()+1; + chandesc->append( new ChannelDesc( *chan ) ); + it = new QListViewItem( channelsList, chan->name ); + if ( chan->type==1 ) { + if ( chan->fta ) + it->setPixmap( 0, tvcPix ); + else + it->setPixmap( 0, tvPix ); + } + else { + if ( chan->fta ) + it->setPixmap( 0, racPix ); + else + it->setPixmap( 0, raPix ); + } + } + odit = dit; + dit = (DListViewItem*)dit->nextSibling(); + delete odit; + dvbsi->channels.remove( chan ); + } + + progress->setProgress(0); + startBtn->setEnabled( true ); + working( false ); +} + + + +void ScanDialog::siEnded( bool b ) +{ + checkTimer.stop(); + progressTimer.stop(); + checkNewChannel(); + snr->setProgress( 0 ); + signal->setProgress( 0 ); + setLock( false ); + progress->setProgress( 0 ); + startBtn->setOn( !b ); + working( false ); + startBtn->setText( i18n("START scan") ); + startBtn->setPaletteForegroundColor( QColor(255,0,0) ); +} + + + +void ScanDialog::scan( bool b ) +{ + if ( b ) { + if ( checkTimer.isActive() ) + checkTimer.stop(); + foundList->clear(); + nChannels = 0; + ntv = nradio = 0; + if ( ds->isTuned() ) + dvbsi->go( transponders, 2 ); + else { + if ( !getTransData() ) + return; + if ( searchComb->currentText().startsWith("AUTO") ) + dvbsi->go( transponders, 0 ); // no NIT + else + dvbsi->go( transponders ); + } + checkTimer.start( 100 ); + progressTimer.start( 1000 ); + working( true ); + startBtn->setText( i18n("STOP scan") ); + startBtn->setPaletteForegroundColor( QColor(0,255,0) ); + searchComb->setEnabled( false ); + } + else { + //setCursor(QCursor(Qt::WaitCursor)); + startBtn->setText( i18n("Stopping...") ); + startBtn->setEnabled( false ); + qApp->processEvents(); + dvbsi->stop(); + checkTimer.stop(); + progressTimer.stop(); + checkNewChannel(); + snr->setProgress( 0 ); + signal->setProgress( 0 ); + setLock( false ); + progress->setProgress( 0 ); + working( false ); + //setCursor(QCursor(Qt::ArrowCursor)); + startBtn->setText( i18n("START scan") ); + startBtn->setEnabled( true ); + startBtn->setPaletteForegroundColor( QColor(255,0,0) ); + searchComb->setEnabled( true ); + } +} + + + +void ScanDialog::setProgress() +{ + if ( !dvbsi->transponders.count() ) + return; + progress->setProgress( dvbsi->progressTransponder*100/dvbsi->transponders.count() ); +} + + + +void ScanDialog::setLock( bool on ) +{ + if ( on ) + lock->on(); + else + lock->off(); +} + + + +void ScanDialog::checkNewChannel() +{ + ChannelDesc *chan; + int j; + + for ( j=nChannels; j<(int)dvbsi->channels.count(); j++ ) { + chan = dvbsi->channels.at(j); + if ( chan->completed==0 ) + break; + nChannels++; + if ( chan->name.isEmpty() ) + continue; + if ( chan->type<1 ) + continue; + if ( chan->type>2 ) + continue; + if ( chan->type==1 && chan->vpid==0 ) + continue; + if ( chan->type==1 && chan->napid==0 ) + continue; + if ( chan->type==2 && chan->napid==0 ) + continue; + if ( chan->type==2 && chan->vpid!=0 ) + continue; + addFound( chan, true ); + } +} + + + +void ScanDialog::addFound( ChannelDesc *chan, bool scan ) +{ + int i; + DListViewItem *it; + + it = new DListViewItem( foundList, chan, QString( "%1").arg( chan->tp.snr ), chan->name ); + + if ( chan->type==1 ) { + if ( scan ) + ntv++; + if ( chan->fta ) + it->setPixmap( 1, tvcPix ); + else + it->setPixmap( 1, tvPix ); + } + else { + if ( scan ) + nradio++; + if ( chan->fta ) + it->setPixmap( 1, racPix ); + else + it->setPixmap( 1, raPix ); + } + + if ( scan ) + progressLab->setText( QString( i18n("Found: %1 TV - %2 radio") ).arg(ntv).arg(nradio) ); + if ( chan->provider.isEmpty() ) + return; + for ( i=0; i<providerComb->count(); i++ ) { + if ( chan->provider==providerComb->text(i) ) { + i = -1; + break; + } + } + if ( i>-1 ) + providerComb->insertItem( chan->provider ); +} + + + +ScanDialog::~ScanDialog() +{ + if ( checkTimer.isActive() ) + checkTimer.stop(); + if ( progressTimer.isActive() ) + progressTimer.stop(); + dvbsi->stop(); + delete dvbsi; + + ds->setScanning( false ); + transponders.clear(); +} + +#include "scandialog.moc" diff --git a/kaffeine/src/input/dvb/scandialog.h b/kaffeine/src/input/dvb/scandialog.h new file mode 100644 index 0000000..b73e6d2 --- /dev/null +++ b/kaffeine/src/input/dvb/scandialog.h @@ -0,0 +1,106 @@ +/* + * scandialog.h + * + * Copyright (C) 2004-2007 Christophe Thommeret <hftom@free.fr> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef SCANDIALOG_H +#define SCANDIALOG_H + +#include <qtimer.h> +#include <qprogressbar.h> +#include <qlabel.h> + +#include <kled.h> + +#include "kgradprogress.h" +#include "scandialogui.h" +#include "channeldesc.h" + +class DVBsi; +class DvbStream; + + + +class DListViewItem : public QListViewItem +{ + +public: + + DListViewItem( QListView *parent, ChannelDesc *desc, QString label1, QString label2 ); + + ChannelDesc *chan; +}; + + + +class ScanDialog : public ScanDialogUI +{ + Q_OBJECT + +public: + + ScanDialog( QPtrList<DvbStream> *d, QPtrList<ChannelDesc> *ch, QSize size, QString src, const QString &charset ); + ~ScanDialog(); + + QPtrList<Transponder> transponders; + QPtrList<ChannelDesc> *chandesc; + +private slots: + + void scan( bool b ); + void checkNewChannel(); + void setLock( bool on ); + void siEnded( bool b ); + void addFiltered(); + void addSelected(); + void setProgress(); + void pop( QListViewItem *it, const QPoint &pos, int col ); + void deleteAll(); + void selectAll(); + void newChannel(); + void deleteChannel( QString name ); + void deleteChannel(); + void setDvb(int); + void slotChannelChanged( QListViewItem*, const QPoint &, int ); + +private: + + bool getTransData(); + bool edit( QString &name, QPixmap &pix ); + void working( bool b ); + void parseTp( QString s, fe_type_t type, QString src ); + void addFound( ChannelDesc *chan, bool scan ); + void checkDuplicateName( ChannelDesc *chan ); + bool checkChannUpdate( ChannelDesc *chan ); + + QPtrList<DvbStream> *dvb; + DvbStream *ds; + KGradProgress *snr, *signal; + QProgressBar *progress; + KLed *lock; + DVBsi *dvbsi; + QTimer checkTimer, progressTimer; + int nChannels; + QPixmap tvPix, raPix, tvcPix, racPix; + int ntv, nradio; + QLabel *progressLab; + QString sourcesPath; + QString defaultCharset; +}; + +#endif /* SCANDIALOG_H */ diff --git a/kaffeine/src/input/dvb/scandialogui.ui b/kaffeine/src/input/dvb/scandialogui.ui new file mode 100644 index 0000000..04cbdd1 --- /dev/null +++ b/kaffeine/src/input/dvb/scandialogui.ui @@ -0,0 +1,514 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>ScanDialogUI</class> +<widget class="QDialog"> + <property name="name"> + <cstring>ScanDialogUI</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>725</width> + <height>560</height> + </rect> + </property> + <property name="caption"> + <string>Channels</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLayoutWidget" row="0" column="0"> + <property name="name"> + <cstring>layout10</cstring> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout9</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QGroupBox"> + <property name="name"> + <cstring>groupBox10</cstring> + </property> + <property name="title"> + <string>Channels</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel" row="0" column="0" rowspan="1" colspan="3"> + <property name="name"> + <cstring>textLabel1</cstring> + </property> + <property name="text"> + <string>(Right click to edit/delete)</string> + </property> + </widget> + <widget class="QListView" row="1" column="0" rowspan="1" colspan="3"> + <column> + <property name="text"> + <string>Name</string> + </property> + <property name="clickable"> + <bool>true</bool> + </property> + <property name="resizable"> + <bool>true</bool> + </property> + </column> + <property name="name"> + <cstring>channelsList</cstring> + </property> + <property name="rootIsDecorated"> + <bool>false</bool> + </property> + </widget> + <widget class="QPushButton" row="2" column="0"> + <property name="name"> + <cstring>newBtn</cstring> + </property> + <property name="text"> + <string>New...</string> + </property> + </widget> + <widget class="QPushButton" row="2" column="2"> + <property name="name"> + <cstring>delBtn</cstring> + </property> + <property name="text"> + <string>Delete All</string> + </property> + </widget> + <spacer row="2" column="1"> + <property name="name"> + <cstring>spacer7</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </grid> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout7</cstring> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QGroupBox"> + <property name="name"> + <cstring>searchGroup</cstring> + </property> + <property name="title"> + <string>Search On</string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QComboBox"> + <property name="name"> + <cstring>searchComb</cstring> + </property> + </widget> + <widget class="QGroupBox"> + <property name="name"> + <cstring>offsetGroup</cstring> + </property> + <property name="title"> + <string>Offset (KHz)</string> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QCheckBox"> + <property name="name"> + <cstring>offset0</cstring> + </property> + <property name="text"> + <string>0</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + </widget> + <widget class="QCheckBox"> + <property name="name"> + <cstring>offset167p</cstring> + </property> + <property name="text"> + <string>+167</string> + </property> + </widget> + <widget class="QCheckBox"> + <property name="name"> + <cstring>offset167m</cstring> + </property> + <property name="text"> + <string>-167</string> + </property> + </widget> + </hbox> + </widget> + </vbox> + </widget> + <widget class="QPushButton"> + <property name="name"> + <cstring>startBtn</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>1</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Start Scan</string> + </property> + <property name="toggleButton"> + <bool>true</bool> + </property> + </widget> + <spacer> + <property name="name"> + <cstring>spacer15</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>20</height> + </size> + </property> + </spacer> + <widget class="QGroupBox"> + <property name="name"> + <cstring>statusFrame</cstring> + </property> + <property name="title"> + <string></string> + </property> + </widget> + <spacer> + <property name="name"> + <cstring>spacer11</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>21</width> + <height>20</height> + </size> + </property> + </spacer> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout38</cstring> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QGroupBox"> + <property name="name"> + <cstring>filtersGroup</cstring> + </property> + <property name="title"> + <string>Filters</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QCheckBox" row="0" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>ftaCb</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>4</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Free to air</string> + </property> + </widget> + <widget class="QCheckBox" row="2" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>radioCb</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>4</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Radio</string> + </property> + </widget> + <widget class="QCheckBox" row="1" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>tvCb</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>4</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>TV</string> + </property> + </widget> + <widget class="QCheckBox" row="3" column="0"> + <property name="name"> + <cstring>providerCb</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>0</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Provider:</string> + </property> + </widget> + <widget class="QComboBox" row="3" column="1"> + <property name="name"> + <cstring>providerComb</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>3</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + </grid> + </widget> + <widget class="QPushButton"> + <property name="name"> + <cstring>addselectedBtn</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>1</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string><< Add Selected</string> + </property> + </widget> + <widget class="QPushButton"> + <property name="name"> + <cstring>addfilteredBtn</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>1</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string><< Add Filtered</string> + </property> + </widget> + </vbox> + </widget> + </vbox> + </widget> + <widget class="QGroupBox"> + <property name="name"> + <cstring>groupBox11</cstring> + </property> + <property name="title"> + <string>Found</string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout8</cstring> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QListView"> + <column> + <property name="text"> + <string>SNR</string> + </property> + <property name="clickable"> + <bool>true</bool> + </property> + <property name="resizable"> + <bool>true</bool> + </property> + </column> + <column> + <property name="text"> + <string>Name</string> + </property> + <property name="clickable"> + <bool>true</bool> + </property> + <property name="resizable"> + <bool>true</bool> + </property> + </column> + <property name="name"> + <cstring>foundList</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>7</hsizetype> + <vsizetype>3</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + <widget class="QPushButton"> + <property name="name"> + <cstring>selectallBtn</cstring> + </property> + <property name="text"> + <string>Select All</string> + </property> + </widget> + </vbox> + </widget> + </vbox> + </widget> + </hbox> + </widget> + <widget class="Line"> + <property name="name"> + <cstring>line1</cstring> + </property> + <property name="frameShape"> + <enum>HLine</enum> + </property> + <property name="frameShadow"> + <enum>Sunken</enum> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout9</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <spacer> + <property name="name"> + <cstring>spacer4</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + <widget class="QPushButton"> + <property name="name"> + <cstring>okBtn</cstring> + </property> + <property name="text"> + <string>Done</string> + </property> + </widget> + </hbox> + </widget> + </vbox> + </widget> + </grid> +</widget> +<connections> + <connection> + <sender>okBtn</sender> + <signal>clicked()</signal> + <receiver>ScanDialogUI</receiver> + <slot>accept()</slot> + </connection> +</connections> +<tabstops> + <tabstop>okBtn</tabstop> + <tabstop>searchComb</tabstop> + <tabstop>startBtn</tabstop> + <tabstop>ftaCb</tabstop> + <tabstop>tvCb</tabstop> + <tabstop>radioCb</tabstop> + <tabstop>providerCb</tabstop> + <tabstop>providerComb</tabstop> + <tabstop>addselectedBtn</tabstop> + <tabstop>addfilteredBtn</tabstop> +</tabstops> +<layoutdefaults spacing="6" margin="11"/> +</UI> diff --git a/kaffeine/src/input/dvb/sender.cpp b/kaffeine/src/input/dvb/sender.cpp new file mode 100644 index 0000000..27e5d9d --- /dev/null +++ b/kaffeine/src/input/dvb/sender.cpp @@ -0,0 +1,114 @@ +/* + * sender.cpp + * + * Copyright (C) 2003-2007 Christophe Thommeret <hftom@free.fr> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include <kmessagebox.h> +#include <klocale.h> + +#include "sender.h" + + + +Sender::Sender() +{ + isRunning = false; + senderSocket = 0; + sendList = "\n"; +} + + + +bool Sender::makeSenderSocket( const QString &addr, int m_senderPort ) +{ + int sockopt=1; + + if ( senderSocket ) return true; + + if ( ( senderSocket = socket(AF_INET, SOCK_DGRAM, 0)) == -1) { + KMessageBox::error( 0, i18n("Can't open DVB info socket.") ); + senderSocket = 0; + return false; + } + + senderAddr.sin_family = AF_INET; // host byte order + senderAddr.sin_port = htons( m_senderPort ); // short, network byte order + senderAddr.sin_addr.s_addr = inet_addr( addr.ascii() ); + + memset( &( senderAddr.sin_zero ), '\0', 8 ); // zero the rest of the struct + + if ( setsockopt( senderSocket, SOL_SOCKET, SO_BROADCAST, &sockopt, sizeof(sockopt) ) < 0 ) { + KMessageBox::error( 0, i18n("Can't open DVB info socket.") ); + close( senderSocket ); + senderSocket = 0; + return false; + } + fprintf( stderr, "Sender socket opened\n" ); + return true; +} + + + +Sender::~Sender() +{ + stop(); +} + + + +void Sender::closeSender() +{ + if ( senderSocket ) { + sendto( senderSocket, "quit\n", 5, 0, (struct sockaddr *)&senderAddr, sizeof(senderAddr) ); + close( senderSocket ); + senderSocket = 0; + fprintf( stderr, "Sender socket closed\n" ); + } +} + + + +void Sender::run() +{ + int i; + + while( isRunning ) { + sendto( senderSocket, sendList.latin1(), sendList.length(), 0, (struct sockaddr *)&senderAddr, sizeof(senderAddr) ); + msleep(500); + } +} + + + +void Sender::go() +{ + isRunning = true; + start(); +} + + + +void Sender::stop() +{ + isRunning = false; + if ( !wait(10000) ) { + terminate(); + wait(); + } + closeSender(); +} diff --git a/kaffeine/src/input/dvb/sender.h b/kaffeine/src/input/dvb/sender.h new file mode 100644 index 0000000..22e3a08 --- /dev/null +++ b/kaffeine/src/input/dvb/sender.h @@ -0,0 +1,59 @@ +/* + * sender.h + * + * Copyright (C) 2003-2007 Christophe Thommeret <hftom@free.fr> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef SENDER_H +#define SENDER_H + +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <unistd.h> + +#include <qthread.h> +#include <qstring.h> +#include <qobject.h> + + + +class Sender : public QThread, public QObject +{ + +public: + + Sender(); + ~Sender(); + void run(); + void stop(); + void go(); + + int senderSocket; + struct sockaddr_in senderAddr; + +protected: + + bool makeSenderSocket( const QString &addr, int m_senderPort ); + void closeSender(); + + bool isRunning; + QString sendList; + +}; + +#endif /* SENDER_H */ diff --git a/kaffeine/src/input/dvb/subeditor.cpp b/kaffeine/src/input/dvb/subeditor.cpp new file mode 100644 index 0000000..1863606 --- /dev/null +++ b/kaffeine/src/input/dvb/subeditor.cpp @@ -0,0 +1,182 @@ +/* + * subeditor.cpp + * + * Copyright (C) 2005 Christophe Thommeret <hftom@free.fr> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include <qlistbox.h> +#include <qspinbox.h> +#include <qpushbutton.h> +#include <qlineedit.h> +#include <qcheckbox.h> + +#include <kmessagebox.h> +#include <klocale.h> + +#include "subeditor.h" + + + +SubEditor::SubEditor( ChannelDesc *chan, QWidget *parent ) : SubEditorUI( parent ) +{ + QString s, t; + int i; + + channel = chan; + pidList->clear(); + + for ( i=0; i<channel->nsubpid; i++ ) insertItem( i ); + + if ( channel->nsubpid==channel->maxsubpid ) newBtn->setEnabled( false ); + + connect( pidList, SIGNAL(highlighted(int)), this, SLOT(showProp(int)) ); + connect( upBtn, SIGNAL(clicked()), this, SLOT(itemUp()) ); + connect( downBtn, SIGNAL(clicked()), this, SLOT(itemDown()) ); + connect( delBtn, SIGNAL(clicked()), this, SLOT(itemDelete()) ); + connect( updateBtn, SIGNAL(clicked()), this, SLOT(itemUpdate()) ); + connect( newBtn, SIGNAL(clicked()), this, SLOT(itemNew()) ); +} + + + +void SubEditor::insertItem( int index, bool updt ) +{ + QString s, t; + + s = t.setNum( channel->subpid[index].pid ); + s = s+"("+t.setNum( channel->subpid[index].page )+")"; + s = s+"("+t.setNum( channel->subpid[index].id )+")"; + if ( !channel->subpid[index].lang.isEmpty() ) s = s+"("+channel->subpid[index].lang+")"; + if ( updt ) pidList->changeItem( s, index ); + else pidList->insertItem( s, index ); +} + + + +void SubEditor::showProp( int index ) +{ + if ( index<0 ) { + pidSpin->setValue( 0 ); + pageSpin->setValue( 0 ); + ancSpin->setValue( 0 ); + langLe->setText( "" ); + } + else { + pidSpin->setValue( channel->subpid[index].pid ); + pageSpin->setValue( channel->subpid[index].page ); + ancSpin->setValue( channel->subpid[index].id ); + langLe->setText( channel->subpid[index].lang ); + } +} + + + +void SubEditor::itemUp() +{ + SubPid a; + + int n = pidList->currentItem(); + + if ( n<1 ) return; + + a = channel->subpid[n-1]; + channel->subpid[n-1] = channel->subpid[n]; + channel->subpid[n] = a; + + insertItem( n, true ); + insertItem( n-1, true ); +} + + + +void SubEditor::itemDown() +{ + SubPid a; + + int n = pidList->currentItem(); + + if ( (n<0) || (n>(channel->nsubpid-2)) ) return; + + a = channel->subpid[n+1]; + channel->subpid[n+1] = channel->subpid[n]; + channel->subpid[n] = a; + + insertItem( n, true ); + insertItem( n+1, true ); +} + + + +void SubEditor::itemDelete() +{ + int n = pidList->currentItem(); + + if ( channel->nsubpid==0 || (n<0) ) return; //for sure + + for ( int i=n; i<channel->nsubpid-1; i++ ) channel->subpid[i] = channel->subpid[i+1]; + channel->nsubpid--; + pidList->removeItem( n ); + + newBtn->setEnabled( true ); +} + + + +void SubEditor::itemUpdate() +{ + int n = pidList->currentItem(); + + if ( n<0 ) return; + + channel->subpid[n].pid = pidSpin->value(); + channel->subpid[n].page = pageSpin->value(); + channel->subpid[n].id = ancSpin->value(); + channel->subpid[n].lang = langLe->text().stripWhiteSpace(); + + insertItem( n, true ); +} + + + +void SubEditor::itemNew() +{ + if ( channel->nsubpid==channel->maxsubpid ) { //for sure + newBtn->setEnabled( false ); + return; + } + + if ( !pidSpin->value() ) { + KMessageBox::sorry( this, i18n("Pid must be non zero!") ); + return; + } + channel->nsubpid++; + channel->subpid[channel->nsubpid-1].pid = pidSpin->value(); + channel->subpid[channel->nsubpid-1].page = pageSpin->value(); + channel->subpid[channel->nsubpid-1].id = ancSpin->value(); + channel->subpid[channel->nsubpid-1].lang = langLe->text().stripWhiteSpace(); + insertItem( channel->nsubpid-1 ); + if ( channel->nsubpid==channel->maxsubpid ) newBtn->setEnabled( false ); +} + + + +SubEditor::~SubEditor() +{ + +} + +#include "subeditor.moc" diff --git a/kaffeine/src/input/dvb/subeditor.h b/kaffeine/src/input/dvb/subeditor.h new file mode 100644 index 0000000..0a2b332 --- /dev/null +++ b/kaffeine/src/input/dvb/subeditor.h @@ -0,0 +1,55 @@ +/* + * subeditor.h + * + * Copyright (C) 2005 Christophe Thommeret <hftom@free.fr> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef SUBEDITOR_H +#define SUBEDITOR_H + +#include "channeldesc.h" +#include "subeditorui.h" + + + +class SubEditor : public SubEditorUI +{ + Q_OBJECT + +public: + + SubEditor( ChannelDesc *chan, QWidget *parent ); + ~SubEditor(); + +private slots: + + void showProp( int index ); + void itemUp(); + void itemDown(); + void itemDelete(); + void itemUpdate(); + void itemNew(); + +private: + + void insertItem( int index, bool updt=false ); + + ChannelDesc *channel; + +}; + +#endif /* SUBEDITOR_H */ diff --git a/kaffeine/src/input/dvb/subeditorui.ui b/kaffeine/src/input/dvb/subeditorui.ui new file mode 100644 index 0000000..790b089 --- /dev/null +++ b/kaffeine/src/input/dvb/subeditorui.ui @@ -0,0 +1,354 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>SubEditorUI</class> +<widget class="QDialog"> + <property name="name"> + <cstring>SubEditorUI</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>558</width> + <height>444</height> + </rect> + </property> + <property name="caption"> + <string>Subtitle PIDs Editor</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="Line" row="1" column="0"> + <property name="name"> + <cstring>line3</cstring> + </property> + <property name="frameShape"> + <enum>HLine</enum> + </property> + <property name="frameShadow"> + <enum>Sunken</enum> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + </widget> + <widget class="QLayoutWidget" row="2" column="0"> + <property name="name"> + <cstring>layout19</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <spacer> + <property name="name"> + <cstring>spacer9</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + <widget class="QPushButton"> + <property name="name"> + <cstring>okBtn</cstring> + </property> + <property name="text"> + <string>&Close</string> + </property> + </widget> + </hbox> + </widget> + <widget class="QLayoutWidget" row="0" column="0"> + <property name="name"> + <cstring>layout13</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QGroupBox"> + <property name="name"> + <cstring>groupBox10</cstring> + </property> + <property name="title"> + <string>Subtitle PIDs</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QListBox" row="0" column="0"> + <item> + <property name="text"> + <string>New Item</string> + </property> + </item> + <property name="name"> + <cstring>pidList</cstring> + </property> + </widget> + </grid> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout12</cstring> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout16</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout15</cstring> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QPushButton"> + <property name="name"> + <cstring>upBtn</cstring> + </property> + <property name="text"> + <string>Move Up</string> + </property> + </widget> + <widget class="QPushButton"> + <property name="name"> + <cstring>downBtn</cstring> + </property> + <property name="text"> + <string>Move Down</string> + </property> + </widget> + <widget class="QPushButton"> + <property name="name"> + <cstring>delBtn</cstring> + </property> + <property name="text"> + <string>Remove</string> + </property> + </widget> + </vbox> + </widget> + <spacer> + <property name="name"> + <cstring>spacer8</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </hbox> + </widget> + <spacer> + <property name="name"> + <cstring>spacer10</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>180</height> + </size> + </property> + </spacer> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout11</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout13</cstring> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QPushButton"> + <property name="name"> + <cstring>updateBtn</cstring> + </property> + <property name="text"> + <string><< Update Selected</string> + </property> + </widget> + <widget class="QPushButton"> + <property name="name"> + <cstring>newBtn</cstring> + </property> + <property name="text"> + <string><< New</string> + </property> + </widget> + </vbox> + </widget> + <widget class="QGroupBox"> + <property name="name"> + <cstring>groupBox9</cstring> + </property> + <property name="title"> + <string>Properties</string> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout10</cstring> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>textLabel3</cstring> + </property> + <property name="text"> + <string>Pid:</string> + </property> + </widget> + <widget class="QLabel"> + <property name="name"> + <cstring>textLabel1</cstring> + </property> + <property name="text"> + <string>Page:</string> + </property> + </widget> + <widget class="QLabel"> + <property name="name"> + <cstring>textLabel2</cstring> + </property> + <property name="text"> + <string>Sub page:</string> + </property> + </widget> + <widget class="QLabel"> + <property name="name"> + <cstring>textLabel4</cstring> + </property> + <property name="text"> + <string>Lang:</string> + </property> + </widget> + </vbox> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout9</cstring> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QSpinBox"> + <property name="name"> + <cstring>pidSpin</cstring> + </property> + <property name="maxValue"> + <number>8191</number> + </property> + </widget> + <widget class="QSpinBox"> + <property name="name"> + <cstring>pageSpin</cstring> + </property> + <property name="maxValue"> + <number>99999</number> + </property> + </widget> + <widget class="QSpinBox"> + <property name="name"> + <cstring>ancSpin</cstring> + </property> + <property name="maxValue"> + <number>99999</number> + </property> + </widget> + <widget class="QLineEdit"> + <property name="name"> + <cstring>langLe</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>2</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + </vbox> + </widget> + </hbox> + </widget> + </hbox> + </widget> + </vbox> + </widget> + </hbox> + </widget> + </grid> +</widget> +<connections> + <connection> + <sender>okBtn</sender> + <signal>clicked()</signal> + <receiver>SubEditorUI</receiver> + <slot>accept()</slot> + </connection> +</connections> +<tabstops> + <tabstop>okBtn</tabstop> + <tabstop>pidList</tabstop> + <tabstop>upBtn</tabstop> + <tabstop>downBtn</tabstop> + <tabstop>delBtn</tabstop> + <tabstop>updateBtn</tabstop> + <tabstop>newBtn</tabstop> + <tabstop>pidSpin</tabstop> + <tabstop>pageSpin</tabstop> + <tabstop>ancSpin</tabstop> + <tabstop>langLe</tabstop> +</tabstops> +<layoutdefaults spacing="6" margin="11"/> +</UI> diff --git a/kaffeine/src/input/dvb/ts2rtp.cpp b/kaffeine/src/input/dvb/ts2rtp.cpp new file mode 100644 index 0000000..9f87a84 --- /dev/null +++ b/kaffeine/src/input/dvb/ts2rtp.cpp @@ -0,0 +1,478 @@ +/* + * ts2rtp.cpp + * + * Copyright (C) 2003-2007 Christophe Thommeret <hftom@free.fr> + * + * some code from dvbstream (GPL) + * Copyright (C) 2001,2002 Dave Chapman + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include <sys/time.h> + +#include <kmessagebox.h> +#include <klocale.h> + +#include "ts2rtp.h" +#include "gdvb.h" +#include "channeldesc.h" + +#define TS_SIZE 188 + + + +Ts2Rtp::Ts2Rtp() +{ + unsigned int i, j=0, k; + + for( i = 0 ; i < 256 ; i++ ) { + k = 0; + for (j = (i << 24) | 0x800000 ; j != 0x80000000 ; j <<= 1) { + k = (k << 1) ^ (((k ^ j) & 0x80000000) ? 0x04c11db7 : 0); + } + CRC32[i] = k; + } + + thWrite = 0; + rtpSocket = 0; + writePsi = false; + psiPackets = 0; + // fill in the MPEG-2 TS deefaults + // Note: MPEG-2 TS defines a timestamping base frequency of 90000 Hz. + hRtp.b.v=2; + hRtp.b.p=0; + hRtp.b.x=0; + hRtp.b.cc=0; + hRtp.b.m=0; + hRtp.b.pt=33; + hRtp.b.sequence=rand() & 65535; + hRtp.timestamp=rand(); + hRtp.ssrc=rand(); + + psiBufferSize = 20*TS_SIZE; + psiBuffer = (unsigned char*)malloc(psiBufferSize); + + connect( &psiTimer, SIGNAL(timeout()), this, SLOT(setPSI()) ); +} + + + +Ts2Rtp::~Ts2Rtp() +{ + stop(); + if ( rtpSocket ) { + close( rtpSocket ); + } + free( psiBuffer ); +} + + + +void Ts2Rtp::setSocket( const QString &addr, int m_port, int m_senderPort ) +{ + address = addr; + port = m_port; + senderPort = m_senderPort; +} + + + +bool Ts2Rtp::addChannels( QPtrList<ChannelDesc> *channels ) +{ + int i, j, k, pmtpid=8191; + ChannelDesc *desc, *d; + QValueList<int> pids; + + if ( !rtpSocket && !makeSocket() ) + return false; + + sendList = ""; + for ( i=0; i<(int)channels->count(); i++ ) { + desc = channels->at( i ); + sendList = sendList+desc->name+"|"+QString().setNum(desc->vpid)+"|"+QString().setNum(desc->apid[0].pid)+"|"; + if ( desc->apid[0].ac3 ) sendList+= "y|"; + else sendList+= "n|"; + sendList+= QString().setNum(desc->subpid[0].pid); + sendList+= "|"; + sendList+= QString().setNum(desc->subpid[0].page); + sendList+= "|"; + sendList+= QString().setNum(desc->subpid[0].id); + sendList+= "|"; + sendList+= QString().setNum(desc->subpid[0].type); + sendList+= "|"; + sendList+= desc->subpid[0].lang+"|"; + for ( j=i; j<(int)channels->count(); j++ ) { + pids.clear(); + d = channels->at( j ); + if ( d->vpid ) + pids.append( d->vpid ); + for ( k=0; k<d->napid && k<MAX_AUDIO; k++ ) + pids.append( d->apid[k].pid ); + for ( k=0; k<d->nsubpid && k<MAX_DVBSUB; k++ ) + pids.append( d->subpid[k].pid ); + while ( pmtpid==17 || pids.contains( pmtpid ) ) + --pmtpid; + } + desc->pmtpid = pmtpid--; + } + sendList+="\n"; + psiTables( channels ); + writePsi = true; + psiTimer.start( 500 ); + return true; +} + + + +void Ts2Rtp::removeChannels() +{ + if ( !rtpSocket ) + return; + stop(); + close( rtpSocket ); + rtpSocket = 0; + fprintf( stderr, "rtp socket closed\n" ); + thWrite = 0; + psiPackets = 0; + if ( psiTimer.isActive() ) + psiTimer.stop(); +} + + + +bool Ts2Rtp::makeSocket() +{ + int iRet, iLoop = 1; + + if ( !makeSenderSocket( address, senderPort ) ) return false; + + rtpSocket = socket( AF_INET, SOCK_DGRAM, 0 ); + + if ( rtpSocket < 0) { + KMessageBox::error( 0, i18n("Can't open DVB broadcast socket.") ); + rtpSocket = 0; + closeSender(); + return false; + } + + rtpAddr.sin_family = AF_INET; + rtpAddr.sin_port = htons( port ); + rtpAddr.sin_addr.s_addr = inet_addr( address.ascii() ); + + iRet = setsockopt( rtpSocket, SOL_SOCKET, SO_BROADCAST, &iLoop, sizeof(iLoop)); + if (iRet < 0) { + KMessageBox::error( 0, i18n("Can't init DVB broadcast socket.") ); + close( rtpSocket ); + rtpSocket = 0; + closeSender(); + return false; + } + go(); + fprintf( stderr, "rtp socket opened\n" ); + return true; +} + + + +void Ts2Rtp::process( unsigned char *buf, int size ) +{ + int i, n; + unsigned char *buffer=buf; + + if ( writePsi ) { + i = 0; + while ( i<psiPackets ) { + n = psiPackets-i; + if ( n>8 ) + n = 8; + sendrtp( (char*)(psiBuffer+(TS_SIZE*i)), TS_SIZE*n ); + i+= n; + } + writePsi = false; + } + + for ( i=0; i<size; i+=TS_SIZE ) { + memcpy( thBuf+thWrite, buffer, TS_SIZE ); + thWrite+=TS_SIZE; + if ( thWrite==(TS_SIZE*8 ) ) { + sendrtp( (char*)thBuf, TS_SIZE*8 ); + thWrite = 0; + } + buffer+=TS_SIZE; + } +} + + + +/* Send a single RTP packet, converting the RTP header to network byte order. */ +void Ts2Rtp::sendrtp( char *data, int len ) +{ + struct timeval tv; + + gettimeofday( &tv, (struct timezone*) NULL ); + hRtp.timestamp = ((tv.tv_sec%1000000)*1000 + tv.tv_usec/1000)*90; + + char *buf=(char*)alloca(len+72); + unsigned int intP; + char* charP = (char*) &intP; + int headerSize; + buf[0] = 0x00; + buf[0] |= ((((char) hRtp.b.v)<<6)&0xc0); + buf[0] |= ((((char) hRtp.b.p)<<5)&0x20); + buf[0] |= ((((char) hRtp.b.x)<<4)&0x10); + buf[0] |= ((((char) hRtp.b.cc)<<0)&0x0f); + buf[1] = 0x00; + buf[1] |= ((((char) hRtp.b.m)<<7)&0x80); + buf[1] |= ((((char) hRtp.b.pt)<<0)&0x7f); + intP = htonl(hRtp.b.sequence); + memcpy(&buf[2],charP+2,2); + intP = htonl(hRtp.timestamp); + memcpy(&buf[4],&intP,4); + /* SSRC: not implemented */ + buf[8] = 0x0f; + buf[9] = 0x0f; + buf[10] = 0x0f; + buf[11] = 0x0f; + headerSize = 12 + 4*hRtp.b.cc; /* in bytes */ + memcpy(buf+headerSize,data,len); + + hRtp.b.sequence++; + if ( rtpSocket ) sendto( rtpSocket, buf, len+headerSize, 0, (struct sockaddr *)&rtpAddr, sizeof(rtpAddr) ); +} + + + +void Ts2Rtp::setPSI() +{ + writePsi = true; +} + + +void Ts2Rtp::psiTables( QPtrList<ChannelDesc> *channels ) +{ + unsigned char buf[15000]; + int off, i, j, sectionOff, loopOff, descOff, max; + int npack=0; + unsigned short tsid = channels->at(0)->tp.tsid; + ChannelDesc *desc; + + psiPackets = 0; + + // SDT + off = 0; + // CRC calculation begins here + buf[off++] = 0x42; // service description section + buf[off++] = 0x80; + sectionOff = off; + buf[off++] = 0x00; // section_length (12bits) + buf[off++] = tsid>>8; buf[off++] = tsid&0xff; + buf[off++] = 0x01; // current_next_indicator + buf[off++] = 0x00; // section_number + buf[off++] = 0x00; // last_section_number + buf[off++] = 0x00; buf[off++] = 0x00; // network_id + buf[off++] = 0x00; // reserved + + for ( i=0; i<(int)channels->count(); i++ ) { + desc = channels->at( i ); + buf[off++] = desc->sid>>8; buf[off++] = desc->sid&0xff; // service_id + buf[off++] = 0x00; // reserved + buf[off++] = 0x80; // running_status(3bits) + free_ca(1bit) + descriptors_loop_length + loopOff = off; + buf[off++] = 0x00; // descriptors_loop_length + + buf[off++] = 0x48; // descriptor_tag + descOff = off; + buf[off++] = 0x00; //descriptor_length + buf[off++] = desc->type; //service_type + buf[off++] = 0x03; // provider_name_length + buf[off++] = 0x4c; buf[off++] = 0x41; buf[off++] = 0x4e; // provider_name + buf[off++] = desc->name.length(); // service_name_length + memcpy( buf+off, desc->name.latin1(), desc->name.length() ); + off+= desc->name.length(); + buf[descOff] = off-descOff-1; + buf[loopOff] = off-loopOff-1; + } + buf[sectionOff-1] |= (off+1)>>8; + buf[sectionOff] = (off+1)&0xff; + calculateCRC( buf, buf+off ); + fillPackets( 17, buf, off+4, npack ); + + // PAT + off = 0; + // CRC calculation begins here + buf[off++] = 0x00; // program association section + buf[off++] = 0x80; + sectionOff = off; + buf[off++] = 0x00; // section_length (12bits) + buf[off++] = tsid>>8; buf[off++] = tsid&0xff; + buf[off++] = 0x01; // current_next_indicator + buf[off++] = 0x00; // section_number + buf[off++] = 0x00; // last_section_number + + for ( i=0; i<(int)channels->count(); i++ ) { + desc = channels->at( i ); + buf[off++] = desc->sid>>8; buf[off++] = desc->sid&0xff; // service_id + buf[off++] = desc->pmtpid>>8; buf[off++] = desc->pmtpid&0xff; // program_map_PID(13bits) + } + buf[sectionOff-1] |= (off+1)>>8; + buf[sectionOff] = (off+1)&0xff; + calculateCRC( buf, buf+off ); + fillPackets( 0, buf, off+4, npack ); + + // PMT + for ( i=0; i<(int)channels->count(); i++ ) { + desc = channels->at( i ); + off = 0; + // CRC calculation begins here + buf[off++] = 0x02; // program map section + buf[off++] = 0x80; + sectionOff = off; + buf[off++] = 0x00; // section_length (12bits) + buf[off++] = desc->sid>>8; buf[off++] = desc->sid&0xff; + buf[off++] = 0x01; // current_next_indicator + buf[off++] = 0x00; // section_number + buf[off++] = 0x00; // last_section_number + buf[off++] = desc->vpid>>8; buf[off++] = desc->vpid&0xff; // PCR pid + buf[off++] = 0x00; buf[off++] = 0x00; // infos_length + if ( desc->vpid ) { + buf[off++] = desc->vType; // stream_type + buf[off++] = desc->vpid>>8; buf[off++] = desc->vpid&0xff; // pid + buf[off++] = 0x00; buf[off++] = 0x00; // infos_length + } + + for ( j=0; j<desc->napid && j<MAX_AUDIO; j++ ) { + if ( desc->apid[j].ac3 ) { + buf[off++] = 0x06; // stream type + buf[off++] = desc->apid[j].pid>>8; buf[off++] = desc->apid[j].pid&0xff; + buf[off++] = 0x00; buf[off++] = 0x09; // es info length + buf[off++] = 0x6a; // descriptor tag + buf[off++] = 0x01; // descriptor length + buf[off++] = 0x00; + } + else { + buf[off++] = 0x04; // stream type = audio + buf[off++] = desc->apid[j].pid>>8; buf[off++] = desc->apid[j].pid&0xff; + buf[off++] = 0x00; buf[off++] = 0x06; // es info length + } + buf[off++] = 0x0a; // iso639 descriptor tag + buf[off++] = 0x04; // descriptor length + if ( !desc->apid[j].lang.isEmpty() ) { + buf[off++] = desc->apid[j].lang.constref(0); + buf[off++] = desc->apid[j].lang.constref(1); + if ( desc->apid[j].ac3 ) + buf[off++] = '_'; + else + buf[off++] = desc->apid[j].lang.constref(2); + } + else if ( desc->apid[j].ac3 ) { + buf[off++] = 'd'; + buf[off++] = 'd'; + buf[off++] = 49+j; + } + else { + buf[off++] = 'c'; + buf[off++] = 'h'; + buf[off++] = 49+j; + } + buf[off++] = 0x00; // audio type + } + + for ( j=0; j<desc->nsubpid && j<MAX_DVBSUB; j++ ) { + buf[off++] = 0x06; // stream type = ISO_13818_PES_PRIVATE + buf[off++] = desc->subpid[j].pid>>8; buf[off++] = desc->subpid[j].pid&0xff; + buf[off++] = 0x00; buf[off++] = 0x0a; // es info length + buf[off++] = 0x59; //DVB sub tag + buf[off++] = 0x08; // descriptor length + if ( !desc->subpid[j].lang.isEmpty() ) { + buf[off++] = desc->subpid[j].lang.constref(0); + buf[off++] = desc->subpid[j].lang.constref(1); + buf[off++] = desc->subpid[j].lang.constref(2); + } + else { + buf[off++] = 'c'; + buf[off++] = 'h'; + buf[off++] = 49+j; + } + buf[off++] = desc->subpid[j].type; //sub type + buf[off++] = desc->subpid[j].page>>8; buf[off++] = desc->subpid[j].page&0xff; // comp_page_id + buf[off++] = desc->subpid[j].id>>8; buf[off++] = desc->subpid[j].id&0xff; // anc_page_id + } + + buf[sectionOff-1] |= (off+1)>>8; + buf[sectionOff] = (off+1)&0xff; + calculateCRC( buf, buf+off ); + fillPackets( desc->pmtpid, buf, off+4, npack ); + } + + psiPackets = npack; +} + + + +void Ts2Rtp::fillPackets( unsigned short pid, unsigned char *buf, int len, int &npack ) +{ + int i, off=npack*TS_SIZE, offbuf=0, inc; + bool pus=true; + int continuity=0; + + while ( (off-(npack*TS_SIZE))<len ) { + if ( (off+TS_SIZE)>(psiBufferSize-(10*TS_SIZE)) ) { + psiBufferSize+= 10*TS_SIZE; + psiBuffer = (unsigned char*)realloc( psiBuffer, psiBufferSize ); + fprintf(stderr,"psiBufferSize = %d\n",psiBufferSize); + } + psiBuffer[off++] = 0x47; // sync_byte + if ( pus ) + psiBuffer[off++] = 0x40|(pid>>8); + else + psiBuffer[off++] = pid>>8; + psiBuffer[off++] = pid&0xff; // PID + psiBuffer[off++] = 0x10|continuity; + if ( pus ) { + psiBuffer[off++] = 0x00; // pointer_field + pus = false; + } + inc = TS_SIZE-(off%TS_SIZE); + if ( (len-offbuf)<inc ) + inc = len-offbuf; + memcpy( psiBuffer+off, buf+offbuf, inc ); + off+= inc; + offbuf+= inc; + ++continuity; + } + // needed stuffing bytes + for ( i=0 ; i<(off%TS_SIZE) ; i++) + psiBuffer[off++] = 0xff; + npack+= (off-(npack*TS_SIZE))/TS_SIZE; +} + + + +void Ts2Rtp::calculateCRC( unsigned char *p_begin, unsigned char *p_end ) +{ + unsigned int i_crc = 0xffffffff; + + // Calculate the CRC + while( p_begin < p_end ) { + i_crc = (i_crc<<8) ^ CRC32[ (i_crc>>24) ^ ((unsigned int)*p_begin) ]; + p_begin++; + } + // Store it after the data + p_end[0] = (i_crc >> 24) & 0xff; + p_end[1] = (i_crc >> 16) & 0xff; + p_end[2] = (i_crc >> 8) & 0xff; + p_end[3] = (i_crc >> 0) & 0xff; +} diff --git a/kaffeine/src/input/dvb/ts2rtp.h b/kaffeine/src/input/dvb/ts2rtp.h new file mode 100644 index 0000000..36165e9 --- /dev/null +++ b/kaffeine/src/input/dvb/ts2rtp.h @@ -0,0 +1,99 @@ +/* + * ts2rtp.h + * + * Copyright (C) 2003-2007 Christophe Thommeret <hftom@free.fr> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef TS2RTP_H +#define TS2RTP_H + +#include <stdlib.h> +#include <string.h> +#include <netinet/in.h> +#include <unistd.h> +#include <stdlib.h> +#include <stdio.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <arpa/inet.h> + +#include <qptrlist.h> +#include <qtimer.h> + +#include "sender.h" + +class ChannelDesc; + + + +struct rtpbits { + unsigned int v:2; /* version: 2 */ + unsigned int p:1; /* is there padding appended: 0 */ + unsigned int x:1; /* number of extension headers: 0 */ + unsigned int cc:4; /* number of CSRC identifiers: 0 */ + unsigned int m:1; /* marker: 0 */ + unsigned int pt:7; /* payload type: 33 for MPEG2 TS - RFC 1890 */ + unsigned int sequence:16; /* sequence number: random */ +}; + +struct rtpheader { /* in network byte order */ + struct rtpbits b; + int timestamp; /* start: random */ + int ssrc; /* random */ +}; + + + +class Ts2Rtp : public Sender +{ + Q_OBJECT +public: + + Ts2Rtp(); + ~Ts2Rtp(); + void setSocket( const QString &addr, int m_port, int m_senderPort ); + bool addChannels( QPtrList<ChannelDesc> *channels ); + void removeChannels(); + void process( unsigned char *buf, int size ); + +private: + + bool makeSocket(); + void sendrtp( char *data, int len ); + void psiTables( QPtrList<ChannelDesc> *channels ); + void fillPackets( unsigned short pid, unsigned char *buf, int len, int &npack ); + void calculateCRC( unsigned char *p_begin, unsigned char *p_end ); + + int rtpSocket; + struct sockaddr_in rtpAddr; + struct rtpheader hRtp; + QString address; + int port, senderPort; + unsigned char thBuf[188*10]; + unsigned int CRC32[256]; + int thWrite; + unsigned char *psiBuffer; + int psiBufferSize; + int psiPackets; + QTimer psiTimer; + bool writePsi; + +private slots: + void setPSI(); +}; + +#endif /* TS2RTP_H */ diff --git a/kaffeine/src/input/dvbclient/Makefile.am b/kaffeine/src/input/dvbclient/Makefile.am new file mode 100644 index 0000000..fb4a110 --- /dev/null +++ b/kaffeine/src/input/dvbclient/Makefile.am @@ -0,0 +1,23 @@ +INCLUDES = -I$(top_srcdir)/kaffeine/src/input/ \ + $(all_includes) + +METASOURCES = AUTO + +noinst_LTLIBRARIES = libkaffeinedvbclient.la + +libkaffeinedvbclient_la_SOURCES = cdchannel.cpp \ + cdchannel.h \ + cdwidget.cpp \ + cdwidget.h \ + cddump.cpp \ + cddump.h \ + cdlisten.cpp \ + cdlisten.h \ + cdcleaner.cpp \ + cdcleaner.h + +libkaffeinedvbclient_la_LDFLAGS = $(KDE_RPATH) \ + $(all_libraries) \ + -L$(top_srcdir)/kaffeine/src/input + +libkaffeinedvbclient_la_LIBADD = $(top_builddir)/kaffeine/src/input/libkaffeineinput.la diff --git a/kaffeine/src/input/dvbclient/cdchannel.cpp b/kaffeine/src/input/dvbclient/cdchannel.cpp new file mode 100644 index 0000000..6b0fad1 --- /dev/null +++ b/kaffeine/src/input/dvbclient/cdchannel.cpp @@ -0,0 +1,54 @@ +/* + * cdchannel.cpp + * + * Copyright (C) 2005 Christophe Thommeret <hftom@free.fr> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "cdchannel.h" + + + +CdChannel::CdChannel() +{ + name = ""; + vpid = apid = 0; + ac3 = 0; + subpid = page = id = 0; + type = 0; + lang = ""; +} + + + +CdChannel::CdChannel( const QString &n, int vp, int ap, int ac, int spid, int pg, int an, int tp, const QString &lg ) +{ + name = n; + vpid = vp; + apid = ap; + ac3 = ac; + subpid = spid; + page = pg; + id = an; + type = tp; + lang = lg; +} + + + +CdChannel::~CdChannel() +{ +} diff --git a/kaffeine/src/input/dvbclient/cdchannel.h b/kaffeine/src/input/dvbclient/cdchannel.h new file mode 100644 index 0000000..880d95e --- /dev/null +++ b/kaffeine/src/input/dvbclient/cdchannel.h @@ -0,0 +1,45 @@ +/* + * cdchannel.h + * + * Copyright (C) 2005 Christophe Thommeret <hftom@free.fr> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef CDCHANNEL_H +#define CDCHANNEL_H + +#include <qstring.h> + + + +class CdChannel +{ + +public: + + CdChannel(); + CdChannel( const QString &n, int vp, int ap, int ac, int spid, int pg, int an, int tp, const QString &lg ); + ~CdChannel(); + + QString name; + unsigned short vpid, apid; + char ac3; + unsigned short subpid, page, id; + unsigned char type; + QString lang; +}; + +#endif /* CDCHANNEL_H */ diff --git a/kaffeine/src/input/dvbclient/cdcleaner.cpp b/kaffeine/src/input/dvbclient/cdcleaner.cpp new file mode 100644 index 0000000..58445a5 --- /dev/null +++ b/kaffeine/src/input/dvbclient/cdcleaner.cpp @@ -0,0 +1,69 @@ +/* + * cdcleaner.cpp + * + * Copyright (C) 2005 Christophe Thommeret <hftom@free.fr> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include <qdir.h> +#include <qstringlist.h> + +#include "cdcleaner.h" + + + +CdCleaner::CdCleaner( const QString &path ) +{ + livePath = path; + + connect( &timer, SIGNAL(timeout()), this, SLOT(doClean()) ); + timer.start( 60*1000 ); +} + + + +CdCleaner::~CdCleaner() +{ + wait(); +} + + + +void CdCleaner::doClean() +{ + start( QThread::LowestPriority ); +} + + + +void CdCleaner::setPath( const QString &path ) +{ + livePath = path; +} + + + +void CdCleaner::run() +{ + QStringList list; + QDir d; + + d.setPath( livePath ); + list = d.entryList( "DVBClient-*.ts", QDir::Files, QDir::Name ); + if ( list.count()>1 ) d.remove( list[0] ); +} + +#include "cdcleaner.moc" diff --git a/kaffeine/src/input/dvbclient/cdcleaner.h b/kaffeine/src/input/dvbclient/cdcleaner.h new file mode 100644 index 0000000..e4423d6 --- /dev/null +++ b/kaffeine/src/input/dvbclient/cdcleaner.h @@ -0,0 +1,56 @@ +/* + * cdcleaner.h + * + * Copyright (C) 2005 Christophe Thommeret <hftom@free.fr> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef CDCLEANER_H +#define CDCLEANER_H + +#include <qobject.h> +#include <qthread.h> +#include <qstring.h> +#include <qtimer.h> + + + +class CdCleaner : public QObject, public QThread +{ + + Q_OBJECT + +public: + + CdCleaner( const QString &path ); + ~CdCleaner(); + void setPath( const QString &path ); + +protected: + + virtual void run(); + +private slots: + + void doClean(); + +private: + + QTimer timer; + QString livePath; +}; + +#endif /* CDCLEANER_H */ diff --git a/kaffeine/src/input/dvbclient/cddump.cpp b/kaffeine/src/input/dvbclient/cddump.cpp new file mode 100644 index 0000000..075025a --- /dev/null +++ b/kaffeine/src/input/dvbclient/cddump.cpp @@ -0,0 +1,362 @@ +/* + * cddump.cpp + * + * Copyright (C) 2005 Christophe Thommeret <hftom@free.fr> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include <fcntl.h> +#include <unistd.h> + +#include <klocale.h> +#include <kapplication.h> +#include <kmessagebox.h> + +#include "cddump.h" + + + +CdDump::CdDump( const QString &pipe ) +{ + unsigned int i, j, k; + + for( i = 0 ; i < 256 ; i++ ) { + k = 0; + for (j = (i << 24) | 0x800000 ; j != 0x80000000 ; j <<= 1) { + k = (k << 1) ^ (((k ^ j) & 0x80000000) ? 0x04c11db7 : 0); + } + CRC32[i] = k; + } + + isRunning = false; + fifoName = pipe; + connect( &timerPatPmt, SIGNAL(timeout()), this, SLOT(setPatPmt()) ); + timerPatPmt.start( 500 ); +} + + + +void CdDump::calculateCRC( unsigned char *p_begin, unsigned char *p_end ) +{ + unsigned int i_crc = 0xffffffff; + + // Calculate the CRC + while( p_begin < p_end ) { + i_crc = (i_crc<<8) ^ CRC32[ (i_crc>>24) ^ ((unsigned int)*p_begin) ]; + p_begin++; + } + + // Store it after the data + p_end[0] = (i_crc >> 24) & 0xff; + p_end[1] = (i_crc >> 16) & 0xff; + p_end[2] = (i_crc >> 8) & 0xff; + p_end[3] = (i_crc >> 0) & 0xff; +} + + + +void CdDump::writePat() +{ + int i; + + tspat[0x00] = 0x47; // sync_byte + tspat[0x01] = 0x40; + tspat[0x02] = 0x00; // PID = 0x0000 + tspat[0x03] = 0x10; // | (ps->pat_counter & 0x0f); + tspat[0x04] = 0x00; // CRC calculation begins here + tspat[0x05] = 0x00; // 0x00: Program association section + tspat[0x06] = 0xb0; + tspat[0x07] = 0x11; // section_length = 0x011 + tspat[0x08] = 0x00; + tspat[0x09] = 0xbb; // TS id = 0x00b0 (what the vlc calls "Stream ID") + tspat[0x0a] = 0xc1; + // section # and last section # + tspat[0x0b] = tspat[0x0c] = 0x00; + // Network PID (useless) + tspat[0x0d] = tspat[0x0e] = 0x00; tspat[0x0f] = 0xe0; tspat[0x10] = 0x10; + // Program Map PID + pmtpid = 0x64; + while ( pmtpid==chan.vpid || pmtpid==chan.apid ) pmtpid--; + tspat[0x11] = 0x03; tspat[0x12] = 0xe8; tspat[0x13] = 0xe0; tspat[0x14] = pmtpid; + // Put CRC in ts[0x15...0x18] + calculateCRC( tspat + 0x05, tspat + 0x15 ); + // needed stuffing bytes + for (i=0x19 ; i < 188 ; i++) tspat[i]=0xff; +} + + + +void CdDump::writePmt() +{ + int i, off=0; + + tspmt[0x00] = 0x47; //sync_byte + tspmt[0x01] = 0x40; + tspmt[0x02] = pmtpid; + tspmt[0x03] = 0x10; + tspmt[0x04] = 0x00; // CRC calculation begins here + tspmt[0x05] = 0x02; // 0x02: Program map section + tspmt[0x06] = 0xb0; + tspmt[0x07] = 0x20; // section_length + tspmt[0x08] = 0x03; + tspmt[0x09] = 0xe8; // prog number + tspmt[0x0a] = 0xc1; + // section # and last section # + tspmt[0x0b] = tspmt[0x0c] = 0x00; + // PCR PID + tspmt[0x0d] = chan.vpid>>8; tspmt[0x0e] = chan.vpid&0xff; + // program_info_length == 0 + tspmt[0x0f] = 0xf0; tspmt[0x10] = 0x00; + // Program Map / Video PID + tspmt[0x11] = 0x02; // stream type = video + tspmt[0x12] = chan.vpid>>8; tspmt[0x13] = chan.vpid&0xff; + tspmt[0x14] = 0xf0; tspmt[0x15] = 0x09; // es info length + // useless info + tspmt[0x16] = 0x07; tspmt[0x17] = 0x04; tspmt[0x18] = 0x08; tspmt[0x19] = 0x80; + tspmt[0x1a] = 0x24; tspmt[0x1b] = 0x02; tspmt[0x1c] = 0x11; tspmt[0x1d] = 0x01; + tspmt[0x1e] = 0xfe; + off = 0x1e; + // audio pid + if ( chan.ac3 ) { + tspmt[++off] = 0x81; // stream type = xine see this as ac3 + tspmt[++off] = chan.apid>>8; tspmt[++off] = chan.apid&0xff; + tspmt[++off] = 0xf0; tspmt[++off] = 0x0c; // es info length + tspmt[++off] = 0x05; tspmt[++off] = 0x04; tspmt[++off] = 0x41; + tspmt[++off] = 0x43; tspmt[++off] = 0x2d; tspmt[++off] = 0x33; + } + else { + tspmt[++off] = 0x04; // stream type = audio + tspmt[++off] = chan.apid>>8; tspmt[++off] = chan.apid&0xff; + tspmt[++off] = 0xf0; tspmt[++off] = 0x06; // es info length + } + tspmt[++off] = 0x0a; // iso639 descriptor tag + tspmt[++off] = 0x04; // descriptor length + tspmt[++off] = '?'; + tspmt[++off] = '?'; + tspmt[++off] = '?'; + tspmt[++off] = 0x00; // audio type + // subtitles + if ( chan.subpid ) { + tspmt[++off] = 0x06; // stream type = ISO_13818_PES_PRIVATE + tspmt[++off] = chan.subpid>>8; tspmt[++off] = chan.subpid&0xff; + tspmt[++off] = 0xf0; tspmt[++off] = 0x0a; // es info length + tspmt[++off] = 0x59; //DVB sub tag + tspmt[++off] = 0x08; // descriptor length + if ( !chan.lang.isEmpty() ) { + tspmt[++off] = chan.lang.constref(0); + tspmt[++off] = chan.lang.constref(1); + tspmt[++off] = chan.lang.constref(2); + } + else { + tspmt[++off] = '?'; + tspmt[++off] = '?'; + tspmt[++off] = '?'; + } + tspmt[++off] = chan.type; //sub type + tspmt[++off] = chan.page>>8; tspmt[++off] = chan.page&0xff; // comp_page_id + tspmt[++off] = chan.id>>8; tspmt[++off] = chan.id&0xff; // anc_page_id + } + tspmt[0x07] = off-3; // update section_length + // Put CRC in ts[0x29...0x2c] + calculateCRC( tspmt+0x05, tspmt+off+1 ); + // needed stuffing bytes + for (i=off+5 ; i < 188 ; i++) tspmt[i]=0xff; +} + + + +void CdDump::setPatPmt() +{ + patpmt = true; +} + + + +bool CdDump::go( const QString &ad, int port, CdChannel c ) +{ + int sockopt=1; + + if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1) { + KMessageBox::information( 0, i18n("Can't open socket."), i18n("DVB Client") ); + sock = 0; + return false; + } + + addr.sin_family = AF_INET; // host byte order + addr.sin_port = htons( port ); // short, network byte order + addr.sin_addr.s_addr = inet_addr( ad.ascii() ); + memset( &( addr.sin_zero ), '\0', 8 ); // zero the rest of the struct + + if( setsockopt( sock, SOL_SOCKET, SO_REUSEADDR, &sockopt, sizeof(sockopt) ) < 0 ){ + KMessageBox::information( 0, i18n("Can't set socket option!!!"), i18n("DVB Client") ); + close( sock ); + sock = 0; + return false; + } + + if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) == -1) { + KMessageBox::information( 0, i18n("Can't bind socket!!!"), i18n("DVB Client") ); + close( sock ); + sock = 0; + return false; + } + + chan = c; + writePat(); + writePmt(); + patpmt = true; + timeShiftFileName = ""; + timeShifting = false; + isRunning = true; + start(); + return true; +} + + + +void CdDump::stop() +{ + isRunning = false; + if ( !wait(1000) ) { + terminate(); + wait(); + } + if ( fdPipe ) { + close( fdPipe ); + fdPipe = 0; + } + if ( timeShifting ) + liveFile.close(); + if ( sock ) { + close( sock ); + sock = 0; + } +} + + + +bool CdDump::running() const +{ + return isRunning; +} + + + +CdDump::~CdDump() +{ + stop(); +} + + + +bool CdDump::doPause( const QString &name ) +{ + if ( !timeShifting ) { + timeShiftFileName = name; + liveFile.setName( timeShiftFileName ); + liveFile.open( IO_WriteOnly|IO_Truncate ); + liveFile.writeBlock( (char*)tspat, 188 ); + liveFile.writeBlock( (char*)tspmt, 188 ); + timeShifting = true; + return true; + } + return false; +} + + + +void CdDump::run() +{ + struct srtpheader rh; + int lengthData; + char buf[1600]; + unsigned char *b; +#define NTS 64 + unsigned char tbuf[NTS*188]; + int twrite; + unsigned int intP; + char* charP = (char*) &intP; + int headerSize; + int lengthPacket; + int len; + int pid; + + if ( (fdPipe=open( fifoName.ascii(), O_WRONLY))<0 ) { + perror("DUMP PIPE FILE: "); + return; + } + fprintf(stderr,"Dump pipe opened\n"); + + twrite = 0; + + while( isRunning ) { + lengthPacket = recv( sock, buf, 1590, 0 ); + rh.b.v = (unsigned int) ((buf[0]>>6)&0x03); + rh.b.p = (unsigned int) ((buf[0]>>5)&0x01); + rh.b.x = (unsigned int) ((buf[0]>>4)&0x01); + rh.b.cc = (unsigned int) ((buf[0]>>0)&0x0f); + rh.b.m = (unsigned int) ((buf[1]>>7)&0x01); + rh.b.pt = (unsigned int) ((buf[1]>>0)&0x7f); + intP = 0; + memcpy( charP+2, &buf[2], 2 ); + rh.b.sequence = ntohl( intP ); + intP = 0; + memcpy( charP, &buf[4], 4 ); + rh.timestamp = ntohl( intP ); + headerSize = 12 + 4*rh.b.cc; /* in bytes */ + lengthData = lengthPacket - headerSize; + + b = (unsigned char*)buf+headerSize; + len = lengthData; + while ( len>0 ) { + pid = (((b[1] & 0x1f) << 8) | b[2]); + if ( pid==chan.vpid || pid==chan.apid || pid==chan.subpid ) { + memcpy( tbuf+twrite, b, 188 ); + twrite+= 188; + if ( twrite==NTS*188 ) { + if ( fdPipe ) { + if ( patpmt ) { + write( fdPipe, tspat, 188 ); + write( fdPipe, tspmt, 188 ); + } + write( fdPipe, tbuf, NTS*188 ); + if ( timeShifting ) { + if ( close( fdPipe )<0 ) + perror("close out pipe: "); + else { + fprintf(stderr,"out pipe closed\n"); + fdPipe = 0; + } + } + } + else { + if ( patpmt ) { + liveFile.writeBlock( (char*)tspat, 188 ); + liveFile.writeBlock( (char*)tspmt, 188 ); + } + liveFile.writeBlock( (char*)tbuf, 188*NTS ); + } + patpmt = false; + twrite = 0; + } + } + b+=188; + len-=188; + } + } +} + +#include "cddump.moc" diff --git a/kaffeine/src/input/dvbclient/cddump.h b/kaffeine/src/input/dvbclient/cddump.h new file mode 100644 index 0000000..695eb4b --- /dev/null +++ b/kaffeine/src/input/dvbclient/cddump.h @@ -0,0 +1,106 @@ +/* + * cddump.h + * + * Copyright (C) 2005 Christophe Thommeret <hftom@free.fr> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef CDDUMP_H +#define CDDUMP_H + +#include <sys/poll.h> +#include <sys/stat.h> +#include <netinet/in.h> +#include <sys/socket.h> +#include <arpa/inet.h> + +#include <qthread.h> +#include <qobject.h> +#include <qstring.h> +#include <qfile.h> +#include <qtimer.h> + +#include "cdchannel.h" + + + +struct srtpbits { + unsigned int v:2; /* version: 2 */ + unsigned int p:1; /* is there padding appended: 0 */ + unsigned int x:1; /* number of extension headers: 0 */ + unsigned int cc:4; /* number of CSRC identifiers: 0 */ + unsigned int m:1; /* marker: 0 */ + unsigned int pt:7; /* payload type: 33 for MPEG2 TS - RFC 1890 */ + unsigned int sequence:16; /* sequence number: random */ +}; + +struct srtpheader { /* in network byte order */ + struct srtpbits b; + int timestamp; /* start: random */ + int ssrc; /* random */ +}; + + + +class CdDump : public QObject, public QThread +{ + Q_OBJECT + +public : + + CdDump( const QString &pipe ); + ~CdDump(); + virtual void run(); + bool go( const QString &ad, int port, CdChannel c ); + void stop(); + bool doPause( const QString &name ); + bool running() const; + +private slots: + + void setPatPmt(); + +private : + + void writePmt(); + void writePat(); + void calculateCRC( unsigned char *p_begin, unsigned char *p_end ); + + QFile liveFile; + bool timeShifting; + QString timeShiftFileName; + int waitPause; + int fdPipe; + QString fifoName; + bool isRunning; + int sock; + struct sockaddr_in addr; + CdChannel chan; + unsigned char tspat[188]; + unsigned char tspmt[188]; + unsigned int CRC32[256]; + int pmtpid; + QTimer timerPatPmt; + bool patpmt; + +signals: + + void playDvb(); + void shifting( bool ); + +}; + +#endif /* CDDUMP_H */ diff --git a/kaffeine/src/input/dvbclient/cdlisten.cpp b/kaffeine/src/input/dvbclient/cdlisten.cpp new file mode 100644 index 0000000..89ea3c7 --- /dev/null +++ b/kaffeine/src/input/dvbclient/cdlisten.cpp @@ -0,0 +1,113 @@ +/* + * cdlisten.cpp + * + * Copyright (C) 2005 Christophe Thommeret <hftom@free.fr> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include <unistd.h> + +#include <kmessagebox.h> +#include <klocale.h> + +#include "cdlisten.h" + + + +CdListen::CdListen() +{ + connect( &timer, SIGNAL(timeout()), this, SLOT(updateList()) ); +} + + + +CdListen::~CdListen() +{ + stop(); +} + + + +void CdListen::updateList() +{ + if ( newList==currentList ) return; + + currentList = newList; + emit listChanged( currentList ); +} + + + +void CdListen::stop() +{ + isRunning = false; + timer.stop(); + if ( !wait(100) ) { + terminate(); + wait(); + } + close( sock ); + sock = 0; +} + + + +bool CdListen::go( const QString &ad, int port ) +{ + if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1) { + KMessageBox::information( 0, i18n("Can't open info socket."), i18n("DVB Client") ); + sock = 0; + return false; + } + + addr.sin_family = AF_INET; // host byte order + addr.sin_port = htons( port ); // short, network byte order + addr.sin_addr.s_addr = inet_addr( ad.ascii() ); + memset( &( addr.sin_zero ), '\0', 8 ); // zero the rest of the struct + + if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) == -1) { + KMessageBox::information( 0, i18n("Can't bind info socket!!!"), i18n("DVB Client") ); + close( sock ); + sock = 0; + return false; + } + + currentList = ""; + newList = currentList; + isRunning = true; + timer.start( 500, false ); + start(); + return true; +} + + + +void CdListen::run() +{ + char buf[1500]; + int n; + struct sockaddr_in a; + socklen_t len = sizeof(struct sockaddr); + + while ( isRunning ) { + memset( buf, '\0', 1500 ); + n = recvfrom( sock, buf, 1500, 0, (struct sockaddr *)&a, &len ); + if ( n>0 ) newList = buf; + else msleep(500); + } +} + +#include "cdlisten.moc" diff --git a/kaffeine/src/input/dvbclient/cdlisten.h b/kaffeine/src/input/dvbclient/cdlisten.h new file mode 100644 index 0000000..2e1bc7e --- /dev/null +++ b/kaffeine/src/input/dvbclient/cdlisten.h @@ -0,0 +1,62 @@ +/* + * cdlisten.h + * + * Copyright (C) 2005 Christophe Thommeret <hftom@free.fr> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef CDLISTEN_H +#define CDLISTEN_H + +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> + +#include <qobject.h> +#include <qthread.h> +#include <qtimer.h> +#include <qstring.h> + +class CdListen : public QObject, public QThread +{ + Q_OBJECT + +public: + + CdListen(); + ~CdListen(); + virtual void run(); + bool go( const QString &ad, int port ); + void stop(); + +private slots: + + void updateList(); + +private: + + int sock; + struct sockaddr_in addr; + bool isRunning; + QTimer timer; + QString currentList, newList; + +signals: + + void listChanged( const QString& ); +}; + +#endif /* CDLISTEN_H */ diff --git a/kaffeine/src/input/dvbclient/cdwidget.cpp b/kaffeine/src/input/dvbclient/cdwidget.cpp new file mode 100644 index 0000000..f28d128 --- /dev/null +++ b/kaffeine/src/input/dvbclient/cdwidget.cpp @@ -0,0 +1,371 @@ +/* + * cdwidget.cpp + * + * Copyright (C) 2005 Christophe Thommeret <hftom@free.fr> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include <qapplication.h> +#include <qlayout.h> +#include <qdir.h> + +#include <kiconloader.h> +#include <klocale.h> + +#include "cdwidget.h" + + + +CdWidget::CdWidget( const QString &ad, int port, int info, const QString &tspath, QWidget *parent, QObject *objParent, const char *name ) + : KaffeineInput( objParent, name ) +{ + mainWidget = new QVBox( parent ); + mainWidget->setSizePolicy( QSizePolicy (QSizePolicy::Preferred, QSizePolicy::Preferred) ); + split = new QSplitter( mainWidget ); + split->setOpaqueResize( true ); + playerBox = new QVBox( split ); + playerBox->setMinimumWidth( 200 ); + channelsLb = new QListBox( split ); + split->moveToFirst( channelsLb ); + channelsLb->setSizePolicy( QSizePolicy (QSizePolicy::Preferred, QSizePolicy::MinimumExpanding) ); + split->setResizeMode( channelsLb, QSplitter::KeepSize ); + + cdAddress = ad; + cdPort = port; + cdInfo = info; + cdShiftDir = tspath; + if ( !cdShiftDir.endsWith("/") ) cdShiftDir+= "/"; + + cleaner = new CdCleaner( cdShiftDir ); + + chan.setAutoDelete( true ); + + KIconLoader *icon = new KIconLoader(); + + tvPix = icon->loadIcon( "kdvbtv", KIcon::Small ); + raPix = icon->loadIcon( "kdvbra", KIcon::Small ); + delete icon; + + listen = new CdListen(); + listen->go( cdAddress, cdInfo ); + + fifoName = QDir::homeDirPath()+"/.kaxclient.ts"; + QFile f( fifoName ); + if ( f.exists() ) f.remove(); + if ( (mkfifo( fifoName.ascii(), 0644 ))<0 ) { + perror( fifoName.latin1() ); + fifoName = ""; + dump = 0; + } + else { + dump = new CdDump( fifoName ); + connect( channelsLb, SIGNAL(selected(const QString &)), this, SLOT(channelSelected(const QString &)) ); + connect( listen, SIGNAL(listChanged(const QString&)), this, SLOT(updateList(const QString&)) ); + } + + lastChannel = 0; + enableLive( false ); + loadConfig( KGlobal::config() ); +} + + + +void CdWidget::togglePanel() +{ + if ( channelsLb->isHidden() ) + channelsLb->show(); + else + channelsLb->hide(); +} + + + +void CdWidget::getTargets( QStringList &uiNames, QStringList &iconNames, QStringList &targetNames ) +{ + uiNames.append( i18n("DVB Client") ); + iconNames.append( "network" ); + targetNames.append( "DVBCLIENT" ); +} + + + +bool CdWidget::execTarget( const QString &target ) +{ + if ( target=="DVBCLIENT" ) { + emit showMe( this ); + QTimer::singleShot( 100, this, SLOT(playLastChannel()) ); + return true; + } + return false; +} + + + +QWidget* CdWidget::wantPlayerWindow() +{ + return playerBox; +} + + + +QWidget* CdWidget::inputMainWidget() +{ + return mainWidget; +} + + + +CdWidget::~CdWidget() +{ + if ( dump->running() ) + emit dvbStop(); + stopLive(); + delete dump; + delete listen; + delete cleaner; +} + + + +void CdWidget::loadConfig( KConfig* config ) +{ + QValueList<int> sl; + + config->setGroup("DVBClient"); + sl = config->readIntListEntry("SplitSizes"); + if ( !sl.count() ) { + sl.append( 200 ); + sl.append( 200 ); + } + split->setSizes( sl ); +} + + + +void CdWidget::saveConfig() +{ + KConfig* config = KGlobal::config(); + config->setGroup("DVBClient"); + config->writeEntry( "SplitSizes", split->sizes() ); +} + + + +void CdWidget::updateList( const QString &list ) +{ + QString c; + QString s = list; + int pos; + QString name, lang; + int apid, vpid, ac3, subpid, page, id, type; + + if ( dump->running() ) + emit dvbStop(); + dump->stop(); + + channelsLb->clear(); + chan.clear(); + if ( list=="quit" ) return; + + while ( (pos = s.find("|"))!=-1 ) { + name = s.left( pos ); + s = s.right( s.length()-pos-1 ); + pos = s.find("|"); + vpid = s.left( pos ).toInt(); + s = s.right( s.length()-pos-1 ); + pos = s.find("|"); + apid = s.left( pos ).toInt(); + s = s.right( s.length()-pos-1 ); + pos = s.find("|"); + if ( s.left( pos )=="n" ) ac3 = 0; + else ac3 = 1; + s = s.right( s.length()-pos-1 ); + pos = s.find("|"); + subpid = s.left( pos ).toInt(); + s = s.right( s.length()-pos-1 ); + pos = s.find("|"); + page = s.left( pos ).toInt(); + s = s.right( s.length()-pos-1 ); + pos = s.find("|"); + id = s.left( pos ).toInt(); + s = s.right( s.length()-pos-1 ); + pos = s.find("|"); + type = s.left( pos ).toInt(); + s = s.right( s.length()-pos-1 ); + pos = s.find("|"); + lang = s.left( pos ); + s = s.right( s.length()-pos-1 ); + chan.append( new CdChannel( name, vpid, apid, ac3, subpid, page, id, type, lang ) ); + if ( vpid ) channelsLb->insertItem( tvPix, name ); + else channelsLb->insertItem( raPix, name ); + } +} + + + +bool CdWidget::nextTrack( MRL& ) +{ + next(); + return false; +} + + + +bool CdWidget::previousTrack( MRL& ) +{ + previous(); + return false; +} + + + +bool CdWidget::currentTrack( MRL& ) +{ + playLastChannel(); + return false; +} + + + +bool CdWidget::trackNumber( int num, MRL& ) +{ + playNumChannel( num ); + return false; +} + + + +bool CdWidget::playbackFinished( MRL& ) +{ + return false; +} + + + +void CdWidget::playLastChannel() +{ + if ( !channelsLb->count() ) + return; + if ( !lastChannel ) { + lastChannel++; + } + else if ( lastChannel>(int)channelsLb->count() ) { + lastChannel = 1; + } + channelSelected( channelsLb->text( lastChannel-1 ) ); +} + + + +void CdWidget::playNumChannel( int num ) +{ + if ( num>0 && num<=(int)channelsLb->count() ) + channelSelected( channelsLb->text( num-1 ) ); +} + + + +void CdWidget::next() +{ + if ( !channelsLb->count() ) + return; + if ( (lastChannel+1)>(int)channelsLb->count() ) + return; + lastChannel++; + channelSelected( channelsLb->text( lastChannel-1 ) ); +} + + + +void CdWidget::previous() +{ + if ( !channelsLb->count() ) + return; + if ( (lastChannel-1)<1 ) + return; + lastChannel--; + channelSelected( channelsLb->text( lastChannel-1 ) ); +} + + + +void CdWidget::channelSelected( const QString &name ) +{ + int i; + + for ( i=0; i<(int)chan.count(); i++ ) { + if ( chan.at(i)->name==name ) { + emit setCurrentPlugin( this ); + dump->stop(); + dump->go( cdAddress, cdPort, *chan.at(i) ); + emit dvbOpen( fifoName, chan.at(i)->name, chan.at(i)->vpid ); + break; + } + } +} + + + +void CdWidget::pauseLiveTV() +{ + if ( !dump ) + return; + if ( dump->running() ) { + timeShiftFileName = cdShiftDir+"DVBClient-"+QDateTime::currentDateTime().toString( Qt::ISODate )+".ts"; + if ( dump->doPause( timeShiftFileName ) ) emit setTimeShiftFilename( timeShiftFileName ); + } +} + + + +void CdWidget::stopLive() +{ + if ( !dump ) + return; + dump->stop(); + emit setTimeShiftFilename( "" ); +} + + + +void CdWidget::enableLive( bool b ) +{ + channelsLb->setEnabled( b ); +} + + + +void CdWidget::setParam( const QString &ad, int port, int info, const QString &tspath ) +{ + cdAddress = ad; + cdPort = port; + cdInfo = info; + cdShiftDir = tspath; + if ( !cdShiftDir.endsWith("/") ) cdShiftDir+= "/"; + cleaner->setPath( cdShiftDir ); + + channelsLb->clear(); + chan.clear(); + if ( dump ) { + if ( dump->running() ) + emit dvbStop(); + dump->stop(); + } + listen->stop(); + listen->go( cdAddress, cdInfo ); +} + +#include "cdwidget.moc" diff --git a/kaffeine/src/input/dvbclient/cdwidget.h b/kaffeine/src/input/dvbclient/cdwidget.h new file mode 100644 index 0000000..2862320 --- /dev/null +++ b/kaffeine/src/input/dvbclient/cdwidget.h @@ -0,0 +1,107 @@ +/* + * cdwidget.h + * + * Copyright (C) 2005 Christophe Thommeret <hftom@free.fr> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef CDWIDGET_H +#define CDWIDGET_H + +#include <qlistbox.h> +#include <qpixmap.h> +#include <qptrlist.h> +#include <qvbox.h> +#include <qsplitter.h> + +#include <kconfig.h> + +#include "cddump.h" +#include "cdlisten.h" +#include "cdcleaner.h" +#include "kaffeineinput.h" + + + +class CdWidget : public KaffeineInput +{ + Q_OBJECT + +public: + + CdWidget( const QString &ad, int port, int info, const QString &tspath, QWidget *parent, QObject *objParent, const char *name ); + ~CdWidget(); + void setParam( const QString &ad, int port, int info, const QString &tspath ); + void enableLive( bool b ); + void playNumChannel( int num ); + void next(); + void previous(); + + // Reimplemented from KaffeineInput + QWidget *wantPlayerWindow(); + QWidget *inputMainWidget(); + bool nextTrack( MRL& ); + bool previousTrack( MRL& ); + bool currentTrack( MRL& ); + bool trackNumber( int, MRL& ); + bool playbackFinished( MRL& ); + void getTargets( QStringList &uiNames, QStringList &iconNames, QStringList &targetNames ); + void togglePanel(); + bool execTarget( const QString& ); + void saveConfig(); + //*************************************** + + QListBox *channelsLb; + QVBox *mainWidget; + QVBox *playerBox; + +public slots: + + void playLastChannel(); + void stopLive(); + void pauseLiveTV(); + +private: + void loadConfig( KConfig* config ); + void saveConfig( KConfig* config ); + + QSplitter *split; + CdDump *dump; + CdListen *listen; + QString cdAddress; + int cdPort; + int cdInfo; + QString cdShiftDir; + QPixmap tvPix, raPix; + QPtrList<CdChannel> chan; + QString fifoName; + QString timeShiftFileName; + CdCleaner *cleaner; + int lastChannel; + +private slots: + + void updateList( const QString &list ); + void channelSelected( const QString &name ); + +signals: + + void dvbOpen(const QString&, const QString&, int); + void dvbStop(); + void setTimeShiftFilename( const QString& ); +}; + +#endif /* CDWIDGET_H */ diff --git a/kaffeine/src/input/kaffeineinput.cpp b/kaffeine/src/input/kaffeineinput.cpp new file mode 100644 index 0000000..74d4a8b --- /dev/null +++ b/kaffeine/src/input/kaffeineinput.cpp @@ -0,0 +1,31 @@ +/* + * kaffeineinput.cpp + * + * Copyright (C) 2005-2006 Christophe Thommeret <hftom@free.fr> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "kaffeineinput.h" + +KaffeineInput::KaffeineInput(QObject* parent, const char* name) : QObject( parent, name ) +{ +} + +KaffeineInput::~KaffeineInput() +{ +} + +#include "kaffeineinput.moc" diff --git a/kaffeine/src/input/kaffeineinput.h b/kaffeine/src/input/kaffeineinput.h new file mode 100644 index 0000000..0670178 --- /dev/null +++ b/kaffeine/src/input/kaffeineinput.h @@ -0,0 +1,115 @@ +/* + * kaffeineinput.h + * + * Copyright (C) 2005-2006 Christophe Thommeret <hftom@free.fr> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef KAFFEINEINPUT_H +#define KAFFEINEINPUT_H + +#include <qstring.h> +#include <qwidget.h> + +#include <kxmlguiclient.h> + +class MRL; + +class KaffeineInput : public QObject, public KXMLGUIClient +{ + Q_OBJECT +public: + KaffeineInput(QObject* parent, const char* name); + virtual ~KaffeineInput(); + + // if you want the player window to be displayed on one of your widgets, return a pointer to that one. + virtual QWidget *wantPlayerWindow() {return NULL;} + + // you MUST return your main widget (the one containing all your gui). + virtual QWidget *inputMainWidget() {return NULL;} + + // called when the user want next track and you are the current input. + // fill the MRL and return true to play your next track. + virtual bool nextTrack( MRL& ) {return false;} + + // called when the user want previous track and you are the current input. + // fill the MRL and return true to play your previous track. + virtual bool previousTrack( MRL& ) {return false;} + + // called when the user starts playing and you are the current input. + // fill the MRL and return true to play your current track. + virtual bool currentTrack( MRL& ) {return false;} + + // called when the user enters a track number and you are the current input. + // fill the MRL and return true to play that track. + virtual bool trackNumber( int, MRL& ) {return false;} + + // called when the player has reached the end of current track and you are the current input. + // fill the MRL and return true to play your next track. + virtual bool playbackFinished( MRL& ) {return false;} + + // called when the player is paused and you are the current input. + virtual void playerPaused() {} + + // called when the player is stopped and you are the current input. + virtual void playerStopped() {} + + // called when playing failed and you are the current input. + virtual void playbackFailed() {} + + // called when the player finds metadata(tags) and you are the current input. + virtual void mergeMeta(const MRL&) {} + + // shortcuts buttons to be displayed in the start window. + virtual void getTargets( QStringList&/*uiNames*/, QStringList&/*iconNames*/, QStringList&/*targetNames*/ ) {} + + // play shortcut, return false if the target is not yours; + virtual bool execTarget( const QString&/*target*/ ) {return false;} + + // toggle your panel (show / hide) if any + virtual void togglePanel() {} + + // called when kaffeine is about to quit. Here, you could ask the user to confirm if you have pending + // operations. Return accordingly. + virtual bool close() {return true;} + + // called when kaffeine is about to quit. Save your settings now. + virtual void saveConfig() {} + + // called when a video is to be played, return false to not automatically switch to player window. + virtual bool showPlayer() {return true;} + +signals: + // emit that to play your mrl (you'll become the current input, if not yet). + void play(const MRL&, KaffeineInput*/*this*/); + + // emit that if you want a message to be displayed in statusbar. (do that only if you are the current input, e.g. after play()) + void statusBarMessage(const QString&); + + // emit that if you want to stop the player. Be aware that it'll end with a call to playerStopped(). + // you usually don't need that. + void stop(); + + // emit that if you want to pause the player. Be aware that it'll end with a call to playerPaused(). + // you usually don't need that. + void pause(); + + // for special uses. + void setCurrentPlugin( KaffeineInput* ); + void showMe( KaffeineInput* ); +}; + +#endif /* KAFFEINEINPUT_H */ |