summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile10
-rw-r--r--PVideo.cpp1
-rw-r--r--PVideo.h1
-rw-r--r--PlexHTTPRequestHandler.cpp6
-rw-r--r--Plexservice.cpp148
-rw-r--r--Plexservice.h32
-rw-r--r--README.md7
-rw-r--r--SubscriptionManager.cpp3
-rw-r--r--SubscriptionManager.h2
-rw-r--r--hlsPlayer.cpp326
-rw-r--r--hlsPlayer.h90
-rw-r--r--hlsPlayerControl.cpp24
-rw-r--r--hlsPlayerControl.h27
-rw-r--r--m3u8Parser.cpp121
-rw-r--r--m3u8Parser.h37
-rw-r--r--player.c984
-rw-r--r--player.h160
-rw-r--r--plex.cpp803
-rw-r--r--plex.h5
-rw-r--r--video.c775
-rw-r--r--video.h62
21 files changed, 812 insertions, 2812 deletions
diff --git a/Makefile b/Makefile
index 551c4c7..30abf93 100644
--- a/Makefile
+++ b/Makefile
@@ -9,7 +9,7 @@
PLUGIN = plex
-LIBS += -lPocoUtil -lPocoNet -lPocoNetSSL -lPocoXML -lPocoFoundation
+LIBS += -lPocoUtil -lPocoNet -lPocoNetSSL -lPocoXML -lPocoFoundation -lpcrecpp
### Configuration (edit this for your needs)
@@ -17,11 +17,11 @@ LIBS += -lPocoUtil -lPocoNet -lPocoNetSSL -lPocoXML -lPocoFoundation
# FIXME: AVFS isn't working, corrupts memory
#AVFS ?= $(shell test -x /usr/bin/avfs-config && echo 1)
# use ffmpeg libswscale
-SWSCALE ?= $(shell pkg-config --exists libswscale && echo 1)
+#SWSCALE ?= $(shell pkg-config --exists libswscale && echo 1)
# support png images
-PNG ?= $(shell pkg-config --exists libpng && echo 1)
+#PNG ?= $(shell pkg-config --exists libpng && echo 1)
# support jpg images
-JPG ?= $(shell test -r /usr/include/jpeglib.h && echo 1)
+#JPG ?= $(shell test -r /usr/include/jpeglib.h && echo 1)
CONFIG := #-DDEBUG # uncomment to build DEBUG
@@ -49,7 +49,7 @@ endif
_CFLAGS += $(shell pkg-config --cflags xcb xcb-image xcb-keysyms xcb-icccm)
-LIBS += -lrt $(shell pkg-config --libs xcb xcb-image xcb-keysyms xcb-icccm)
+#LIBS += -lrt $(shell pkg-config --libs xcb xcb-image xcb-keysyms xcb-icccm)
### The version number of this plugin (taken from the main source file):
diff --git a/PVideo.cpp b/PVideo.cpp
index b22bb66..21a7de6 100644
--- a/PVideo.cpp
+++ b/PVideo.cpp
@@ -15,6 +15,7 @@ Video::Video(Poco::XML::Node* pNode)
Poco::XML::AutoPtr<Poco::XML::NamedNodeMap> pAttribs = pNode->attributes();
m_iRatingKey = GetNodeValueAsInt(pAttribs->getNamedItem("ratingKey"));
+ m_sKey = GetNodeValue(pAttribs->getNamedItem("key"));
m_sStudio = GetNodeValue(pAttribs->getNamedItem("studio"));
m_tType = GetNodeValueAsMediaType(pAttribs->getNamedItem("type"));
m_sTitle = GetNodeValue(pAttribs->getNamedItem("title"));
diff --git a/PVideo.h b/PVideo.h
index ae61da4..3d69bc4 100644
--- a/PVideo.h
+++ b/PVideo.h
@@ -37,6 +37,7 @@ public:
public:
int m_iRatingKey;
+ std::string m_sKey;
std::string m_sStudio;
MediaType m_tType;
std::string m_sTitle;
diff --git a/PlexHTTPRequestHandler.cpp b/PlexHTTPRequestHandler.cpp
index f18001c..034a739 100644
--- a/PlexHTTPRequestHandler.cpp
+++ b/PlexHTTPRequestHandler.cpp
@@ -128,15 +128,15 @@ void PlayerRequestHandler::handleRequest(Poco::Net::HTTPServerRequest& request,
}
else if(request.getURI().find("/playback/playMedia")!= std::string::npos) {
- std::cout << "playMedia_1" << std::endl;
+ //std::cout << "playMedia_1" << std::endl;
AddHeaders(response, request);
- std::cout << "playMedia_2" << std::endl;
+ //std::cout << "playMedia_2" << std::endl;
std::string protocol = query["protocol"];
std::string address = query["address"];
std::string port = query["port"];
std::string key = query["key"];
- std::cout << "playMedia_3" << std::endl;
+ //std::cout << "playMedia_3" << std::endl;
std::string fullUrl = protocol + "://" + address + ":" + port + key; // Metainfo
std::cout << "FullUrl: " << fullUrl << std::endl;
diff --git a/Plexservice.cpp b/Plexservice.cpp
index 03775f2..f6d2db9 100644
--- a/Plexservice.cpp
+++ b/Plexservice.cpp
@@ -1,5 +1,4 @@
#include "Plexservice.h"
-#include <memory>
namespace plexclient
{
@@ -27,8 +26,7 @@ Poco::Net::HTTPClientSession* Plexservice::GetHttpSession(bool createNew)
m_pPlexSession = new Poco::Net::HTTPClientSession(pServer->GetIpAdress(), pServer->GetPort());
m_pPlexSession->setKeepAlive(true);
}
- }
- catch(Poco::Exception &exc) {
+ } catch(Poco::Exception &exc) {
esyslog("[plex]Exception in %s s%", __func__, exc.displayText().c_str() );
m_pPlexSession = 0;
}
@@ -39,7 +37,7 @@ std::string Plexservice::GetMyPlexToken()
{
// Syncronize
Poco::Mutex::ScopedLock lock(m_mutex);
-
+
//todo: cache token in file or db
if(&m_sToken != 0 || m_sToken.empty()) {
std::stringstream ss;
@@ -98,8 +96,7 @@ void Plexservice::Authenticate()
// TODO: process response
//Poco::StreamCopier::copyStream(rs, std::cout);
delete pRequest;
- }
- else {
+ } else {
esyslog("[plex] %s HttpSession is NULL", __func__);
}
} catch (Poco::Exception &exc) {
@@ -119,7 +116,8 @@ void Plexservice::DiscoverAllServers()
}
*/
-PlexServer* Plexservice::GetServer() {
+PlexServer* Plexservice::GetServer()
+{
return pServer;
}
@@ -147,14 +145,13 @@ MediaContainer* Plexservice::GetSection(std::string section)
std::istream &rs = m_pPlexSession->receiveResponse(response);
dsyslog("[plex] URI: %s[s%]", m_pPlexSession->getHost().c_str(), pRequest->getURI().c_str());
-
+
MediaContainer* pAllsections = new MediaContainer(&rs);
//Poco::StreamCopier::copyStream(rs, std::cout);
delete pRequest;
return pAllsections;
-
- }
- else {
+
+ } else {
esyslog("[plex] %s HttpSession is NULL", __func__);
return 0;
}
@@ -181,10 +178,11 @@ Poco::Net::HTTPRequest* Plexservice::CreateRequest(std::string path)
return pRequest;
}
-MediaContainer* Plexservice::GetMediaContainer(std::string fullUrl) {
-
+MediaContainer* Plexservice::GetMediaContainer(std::string fullUrl)
+{
+
Poco::URI fileuri(fullUrl);
-
+
Poco::Net::HTTPRequest* pRequest = new Poco::Net::HTTPRequest(Poco::Net::HTTPRequest::HTTP_GET,
fileuri.getPath(), Poco::Net::HTTPMessage::HTTP_1_1);
@@ -200,22 +198,136 @@ MediaContainer* Plexservice::GetMediaContainer(std::string fullUrl) {
pRequest->add("X-Plex-Product", "plex for vdr");
pRequest->add("X-Plex-Provides", "player");
pRequest->add("X-Plex-Version", "0.0.1a");
-
+
Poco::Net::HTTPClientSession* session = new Poco::Net::HTTPClientSession(fileuri.getHost(), fileuri.getPort());
-
+
session->sendRequest(*pRequest);
Poco::Net::HTTPResponse response;
std::istream &rs = session->receiveResponse(response);
std::cout << "URI: " << session->getHost() << "[" << pRequest->getURI() << "]" << std::endl;
-
+
delete pRequest;
delete session;
-
+
MediaContainer* pAllsections = new MediaContainer(&rs);
//Poco::StreamCopier::copyStream(rs, std::cout);
return pAllsections;
}
+#ifdef CRYPTOPP
+std::string Plexservice::computeHMAC(std::string message)
+{
+ using CryptoPP::Exception;
+ using CryptoPP::HMAC;
+ using CryptoPP::SHA256;
+ using CryptoPP::Base64Encoder;
+ using CryptoPP::Base64Decoder;
+ using CryptoPP::StringSink;
+ using CryptoPP::ArraySink;
+ using CryptoPP::StringSource;
+ using CryptoPP::HashFilter;
+
+ const std::string transcode_private = "k3U6GLkZOoNIoSgjDshPErvqMIFdE0xMTx8kgsrhnC0=";
+
+ std::string encoded;
+ byte key[32];
+
+ StringSource(transcode_private, true,
+ new Base64Decoder(
+ new ArraySink(key, 32)
+ ) // Base64Encoder
+ ); // StringSource
+
+ try {
+ HMAC<SHA256> hmac((byte*)key, sizeof(key));
+
+ StringSource(message, true,
+ new HashFilter(hmac,
+ new Base64Encoder(
+ new StringSink(encoded),
+ false
+ ) // Base64Encoder
+ ) // HashFilter
+ ); // StringSource
+ } catch(const CryptoPP::Exception& e) {
+ std::cerr << e.what() << std::endl;
+ }
+ return encoded;
+}
+
+std::string Plexservice::GetTranscodeUrl(Video* video)
+{
+ const std::string transcodeURL = "/video/:/transcode/segmented/start.m3u8?";
+ const std::string transcode_public = "KQMIY6GATPC63AIMC4R2";
+
+ std::stringstream params;
+ params << "identifier=com.plexapp.plugins.library";
+ params << "&url=" << encode(pServer->GetUri() + video->m_pMedia->m_sPartKey);
+ params << "&quality=8";
+ params << "&ratingKey=" << video->m_iRatingKey;
+ params << "&3g=0";
+ params << "&offset=0";
+ params << "&directStream=1";
+ params << "&maxVideoBitrate=30000";
+
+ int time = std::time(0);
+ std::string message = Poco::format("%s@%d", transcodeURL + params.str(), time);
+
+ std::string b64hmacMessage = computeHMAC(message);
+
+ std::stringstream plexAccess;
+ plexAccess << "&X-Plex-Access-Key=" << encode(transcode_public);
+ plexAccess << "&X-Plex-Access-Time=" << Poco::format("%d", time);
+ plexAccess << "&X-Plex-Access-Code=" << encode(b64hmacMessage);
+ plexAccess << "&X-Plex-Client-Capabilities=";
+ plexAccess << encode("protocols=http-live-streaming,http-streaming-video-720p,http-streaming-video-1080p;");
+ plexAccess << encode("videoDecoders=h264{profile:high&resolution:1080&level:51};");
+ plexAccess << encode("audioDecoders=aac,ac3{channels:6}");
+
+ std::string fullQuery = params.str() + plexAccess.str();
+ return pServer->GetUri() + transcodeURL + fullQuery;
+}
+#endif
+
+std::string Plexservice::encode(std::string message)
+{
+ std::string temp;
+ Poco::URI::encode(message, " !\"#$%&'()*+,/:;=?@[]", temp);
+ return temp;
+}
+
+
+std::string Plexservice::GetUniversalTranscodeUrl(Video* video)
+{
+ std::stringstream params;
+ params << "/video/:/transcode/universal/start.m3u8?";
+ params << "path=" << encode(pServer->GetUri() + video->m_sKey);
+ params << "&mediaIndex=0";
+ params << "&partIndex=0";
+ params << "&protocol=hls";
+ params << "&offset=0";
+ params << "&fastSeek=1";
+ params << "&directPlay=0";
+ params << "&directStream=1";
+ params << "&maxVideoBitrate=20000";
+ //params << "&subtitleSize=90";
+ params << "&skipSubtitles=1";
+ //params << "&audioBoost=100";
+ params << "&videoResolution=1920x1080";
+ params << "&videoQuality=100";
+ params << "&session=" << encode(Config::GetInstance().GetUUID()); // TODO: generate Random SessionID
+
+ params << "&X-Plex-Client-Identifier=" << encode(Config::GetInstance().GetUUID());
+ params << "&X-Plex-Product=Plex%20Home%20Theater";
+ params << "&X-Plex-Device=PC";
+ params << "&X-Plex-Platform=Plex%20Home%20Theater";
+ params << "&X-Plex-Model=Linux";
+ //params << "&X-Plex-Platform-Version=7";
+ //params << "&X-Plex-Version=1.2.12";
+ //params << "&X-Plex-Device-Name=" << "Plex%2FWeb%20(Chrome)";
+
+ return pServer->GetUri() + params.str();
}
+}
diff --git a/Plexservice.h b/Plexservice.h
index 456341b..ba16ccf 100644
--- a/Plexservice.h
+++ b/Plexservice.h
@@ -10,6 +10,8 @@
#include <vector>
#include <stdio.h>
#include <stdlib.h>
+#include <memory>
+#include <time.h>
#include <Poco/Base64Encoder.h>
#include <Poco/Net/HTTPClientSession.h>
@@ -21,6 +23,9 @@
#include <Poco/Exception.h>
#include <Poco/Format.h>
#include <Poco/URI.h>
+#include <Poco/ScopedLock.h>
+#include <Poco/Mutex.h>
+#include <Poco/Format.h>
#include <Poco/StreamCopier.h>
@@ -28,8 +33,14 @@
#include "user.h"
#include "MediaContainer.h"
-#include <Poco/ScopedLock.h>
-#include <Poco/Mutex.h>
+#ifdef CRYPTOPP
+#include <cryptopp/cryptlib.h>
+#include <cryptopp/hmac.h>
+#include <cryptopp/sha.h>
+#include <cryptopp/base64.h>
+#include <cryptopp/filters.h>
+#include <cryptopp/hex.h>
+#endif
namespace plexclient
{
@@ -48,14 +59,18 @@ public:
void Authenticate();
//void DiscoverFirstServer();
PlexServer* GetServer();
-
+ std::string GetUniversalTranscodeUrl(Video* video);
+
static MediaContainer* GetMediaContainer(std::string fullUrl);
- private:
+protected:
+ std::string encode(std::string message);
+
+private:
Poco::Mutex m_mutex;
// Never Access m_sToken directly! => possible race condition
std::string m_sToken;
-
+
std::string USERAGENT;
Poco::Net::HTTPClientSession *m_pPlexSession;
@@ -64,6 +79,13 @@ public:
Poco::Net::HTTPClientSession* GetHttpSession(bool createNew = false);
Poco::Net::HTTPRequest* CreateRequest(std::string path);
+#ifdef CRYPTOPP
+protected:
+ std::string computeHMAC(std::string message);
+public:
+ std::string GetTranscodeUrl(Video* video);
+#endif
+
};
}
diff --git a/README.md b/README.md
index 99e49ec..650b786 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,11 @@
vdr-plugin-plex
===============
+ALPHA!! May not work
+
A Plex plugin for Linux VDR
+Plays files via the Plexmediaserver transcoder directly in VDR
+
+deps:
+libpoco
+libpcrepp
diff --git a/SubscriptionManager.cpp b/SubscriptionManager.cpp
index c3e97b6..c4589ef 100644
--- a/SubscriptionManager.cpp
+++ b/SubscriptionManager.cpp
@@ -45,8 +45,7 @@ void SubscriptionManager::RemoveSubscriber(std::string uuid) {
}
std::string SubscriptionManager::GetMsg(std::string commandId) {
- PlayerGetCurrentPosition();
- int time = PlayerCurrent;
+ int time = 0;//PlayerGetCurrentPosition();
//bool paused = PlayerPaused;
diff --git a/SubscriptionManager.h b/SubscriptionManager.h
index 44ec899..b3f7f33 100644
--- a/SubscriptionManager.h
+++ b/SubscriptionManager.h
@@ -8,8 +8,6 @@
//#include <mutex>
#include <sstream>
-#include "player.h"
-
namespace plexclient
{
diff --git a/hlsPlayer.cpp b/hlsPlayer.cpp
new file mode 100644
index 0000000..5fa7b0e
--- /dev/null
+++ b/hlsPlayer.cpp
@@ -0,0 +1,326 @@
+#include "hlsPlayer.h"
+
+#include <Poco/Net/HTTPRequest.h>
+#include <Poco/Net/HTTPResponse.h>
+#include <Poco/StreamCopier.h>
+
+#include <pcrecpp.h>
+
+//--- cHlsSegmentLoader
+
+cHlsSegmentLoader::cHlsSegmentLoader(std::string startm3u8)
+{
+ m_bufferFilled = false;
+ m_lastLoadedSegment = 0;
+ m_segmentsToBuffer = 3;
+ m_pBuffer = new uchar[8192];
+
+ // Initialize members
+ m_pClientSession = NULL;
+
+ m_ringBufferSize = MEGABYTE(32);
+ m_pRingbuffer = NULL;
+
+ m_startUri = Poco::URI(startm3u8);
+ m_startParser = cM3u8Parser();
+ m_indexParser = cM3u8Parser();
+}
+
+cHlsSegmentLoader::~cHlsSegmentLoader()
+{
+ // Stop Thread
+ Cancel(0);
+
+ delete m_pClientSession;
+ delete[] m_pBuffer;
+ delete m_pRingbuffer;
+}
+
+void cHlsSegmentLoader::Action(void)
+{
+ LoadStartList();
+ LoadIndexList();
+
+ int estSize = EstimateSegmentSize();
+ m_ringBufferSize = MEGABYTE(estSize*3);
+
+ std::cout << "Create Ringbuffer " << estSize*3 << "MB" << std::endl;
+
+ m_pRingbuffer = new cRingBufferLinear(m_ringBufferSize, 2*TS_SIZE);
+
+ while(Running()) {
+ DoLoad();
+ cCondWait::SleepMs(3);
+ }
+}
+
+void cHlsSegmentLoader::LoadIndexList(void)
+{
+ if(m_startParser.MasterPlaylist && m_startParser.vPlaylistItems.size() > 0) {
+ // Todo: make it universal, might only work for Plexmediaserver
+ ConnectToServer();
+
+ std::string startUri = m_startUri.toString();
+ startUri = startUri.substr(0, startUri.find_last_of("/")+1);
+
+ Poco::URI indexUri(startUri+m_startParser.vPlaylistItems[0].file);
+
+ Poco::Net::HTTPRequest request(Poco::Net::HTTPRequest::HTTP_GET, indexUri.getPath());
+ // same server
+ m_pClientSession->sendRequest(request);
+
+ Poco::Net::HTTPResponse responseStart;
+ std::istream& indexFile = m_pClientSession->receiveResponse(responseStart);
+
+ if(responseStart.getStatus() != 200) {
+ // error
+ return;
+ }
+
+ m_indexParser.Parse(indexFile);
+
+ // Segment URI is relative to index.m3u8
+ std::string path = indexUri.getPath();
+ m_segmentUriPart = path.substr(0, path.find_last_of("/")+1);
+ }
+}
+
+void cHlsSegmentLoader::LoadStartList(void)
+{
+ ConnectToServer();
+
+ Poco::Net::HTTPRequest request(Poco::Net::HTTPRequest::HTTP_GET, m_startUri.getPathAndQuery());
+ m_pClientSession->sendRequest(request);
+
+ Poco::Net::HTTPResponse responseStart;
+ std::istream& startFile = m_pClientSession->receiveResponse(responseStart);
+
+ if(responseStart.getStatus() != 200) {
+ // error
+ return;
+ }
+
+ m_startParser.Parse(startFile);
+
+ pcrecpp::RE re("([0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12})", pcrecpp::RE_Options(PCRE_CASELESS));
+ string value;
+ re.PartialMatch(m_startParser.vPlaylistItems[0].file, &value);
+ m_sessionCookie = value;
+}
+
+int cHlsSegmentLoader::EstimateSegmentSize()
+{
+ double bandw = m_startParser.vPlaylistItems[0].bandwidth / 8.0 / 1000.0 / 1000.0;
+
+ int len = m_indexParser.TargetDuration;
+ double estSize = (bandw) * len;
+ estSize = max(estSize, 16.0); // default
+ return ceil(estSize);
+}
+
+bool cHlsSegmentLoader::LoadSegment(std::string segmentUri)
+{
+ std::cout << "Loading Segment: " << segmentUri << "... ";
+ Poco::Net::HTTPRequest segmentRequest(Poco::Net::HTTPRequest::HTTP_GET, segmentUri);
+ m_pClientSession->sendRequest(segmentRequest);
+
+ Poco::Net::HTTPResponse segmentResponse;
+ std::istream& segmentFile = m_pClientSession->receiveResponse(segmentResponse);
+
+ if(segmentResponse.getStatus() != 200) {
+ // error
+ std::cout << "failed." << std::endl;
+ return false;
+ }
+ std::cout << "successfully." << std::endl;
+
+ // copy response
+
+ int m = 0;
+ segmentFile.read(reinterpret_cast<char*>(m_pBuffer), sizeof(m_pBuffer));
+ std::streamsize n = segmentFile.gcount();
+ while(n > 0) {
+ m = m_pRingbuffer->Put(m_pBuffer, n);
+ if(m < n) {
+ // oops, this should not happen. Data doesn't fitted completly into ringbuffer
+ break;
+ } else {
+ segmentFile.read(reinterpret_cast<char*>(m_pBuffer), sizeof(m_pBuffer));
+ n = segmentFile.gcount();
+ }
+ }
+ return true;
+}
+
+int cHlsSegmentLoader::GetSegmentSize(int segmentIndex)
+{
+ if(m_indexParser.vPlaylistItems[segmentIndex].size > 0) {
+ return m_indexParser.vPlaylistItems[segmentIndex].size;
+ }
+ Poco::Net::HTTPRequest req(Poco::Net::HTTPRequest::HTTP_HEAD, GetSegmentUri(segmentIndex));
+ m_pClientSession->sendRequest(req);
+ Poco::Net::HTTPResponse reqResponse;
+ m_pClientSession->receiveResponse(reqResponse);
+
+ return m_indexParser.vPlaylistItems[segmentIndex].size = reqResponse.getContentLength();
+}
+
+std::string cHlsSegmentLoader::GetSegmentUri(int segmentIndex) const
+{
+ return m_segmentUriPart + m_indexParser.vPlaylistItems[segmentIndex].file;
+}
+
+void cHlsSegmentLoader::CloseConnection(void)
+{
+ if(m_pClientSession)
+ m_pClientSession->abort();
+
+ delete m_pClientSession;
+ m_pClientSession = NULL;
+}
+
+bool cHlsSegmentLoader::ConnectToServer(void)
+{
+ if(!m_pClientSession)
+ m_pClientSession = new Poco::Net::HTTPClientSession(m_startUri.getHost(), m_startUri.getPort());
+
+ return m_pClientSession->connected();
+}
+
+bool cHlsSegmentLoader::DoLoad(void)
+{
+ bool result = true;
+
+ int nextSegmentSize = GetSegmentSize(m_lastLoadedSegment + 1);
+ while(m_pRingbuffer->Free() > nextSegmentSize) {
+
+ if(m_lastLoadedSegment + 1 < m_indexParser.vPlaylistItems.size()) {
+ std::string segmentUri = GetSegmentUri(m_lastLoadedSegment + 1);
+ result = LoadSegment(segmentUri);
+ m_lastLoadedSegment++;
+ } else {
+ // out of segments
+ }
+ nextSegmentSize = GetSegmentSize(m_lastLoadedSegment + 1);
+ }
+ return m_bufferFilled = result;
+}
+
+bool cHlsSegmentLoader::BufferFilled(void)
+{
+ return m_bufferFilled;
+}
+
+bool cHlsSegmentLoader::StopLoader(void)
+{
+ std::string stopUri = "/video/:/transcode/segmented/stop?session=" + m_sessionCookie;
+ Poco::Net::HTTPRequest req(Poco::Net::HTTPRequest::HTTP_GET, stopUri);
+ m_pClientSession->sendRequest(req);
+ Poco::Net::HTTPResponse reqResponse;
+ m_pClientSession->receiveResponse(reqResponse);
+
+ Cancel();
+
+ return reqResponse.getStatus() == 200;
+}
+
+//--- cHlsPlayer
+
+cHlsPlayer::cHlsPlayer(std::string startm3u8)
+{
+ m_pSegmentLoader = new cHlsSegmentLoader(startm3u8);
+}
+
+cHlsPlayer::~cHlsPlayer()
+{
+ delete m_pSegmentLoader;
+}
+
+
+void cHlsPlayer::Action(void)
+{
+ // Start SegmentLoader
+ m_pSegmentLoader->Start();
+
+ while (Running()) {
+ if(m_pSegmentLoader->BufferFilled()) {
+ DoPlay();
+ } else {
+ // Pause
+ cCondWait::SleepMs(3);
+ }
+ }
+}
+
+bool cHlsPlayer::DoPlay(void)
+{
+ cPoller Poller;
+ if(DevicePoll(Poller, 10)) {
+ LOCK_THREAD;
+
+// Handle running out of packets. Buffer-> Play-> Pause-> Buffer-> Play
+
+ for(int i = 0; i < 100; i++) {
+ // Get a pointer to start of the data and the number of avaliable bytes
+ int bytesAvaliable = 0;
+ uchar* toPlay = m_pSegmentLoader->m_pRingbuffer->Get(bytesAvaliable);
+ if(bytesAvaliable >= TS_SIZE) {
+ int playedBytes = PlayTs(toPlay, TS_SIZE, false);
+ m_pSegmentLoader->m_pRingbuffer->Del(playedBytes);
+ } else {
+ // Pause & Buffer
+ break;
+ }
+ }
+ }
+ return true;
+}
+
+void cHlsPlayer::Activate(bool On)
+{
+ if(On) {
+ Start();
+ } else {
+ Cancel(1);
+ }
+}
+
+bool cHlsPlayer::GetIndex(int& Current, int& Total, bool SnapToIFrame)
+{
+ Total = 9999;
+ Current = -1;
+ return true;
+
+}
+
+bool cHlsPlayer::GetReplayMode(bool& Play, bool& Forward, int& Speed)
+{
+ Play = (playMode == pmPlay);
+ Forward = true;
+ Speed = -1;
+ return true;
+}
+
+void cHlsPlayer::Pause(void)
+{
+ // from vdr-1.7.34
+ if (playMode == pmPause) {
+ Play();
+ } else {
+ LOCK_THREAD;
+
+ DeviceFreeze();
+ playMode = pmPause;
+ }
+}
+
+void cHlsPlayer::Play(void)
+{
+ // from vdr-1.7.34
+ if (playMode != pmPlay) {
+ LOCK_THREAD;
+
+ DevicePlay();
+ playMode = pmPlay;
+ }
+}
diff --git a/hlsPlayer.h b/hlsPlayer.h
new file mode 100644
index 0000000..3df9c46
--- /dev/null
+++ b/hlsPlayer.h
@@ -0,0 +1,90 @@
+#ifndef HLSPLAYER_H
+#define HLSPLAYER_H
+
+#include <string>
+#include <iostream>
+#include <sstream>
+
+#include <vdr/thread.h>
+#include <vdr/player.h>
+#include <vdr/ringbuffer.h>
+#include <vdr/tools.h>
+
+#include <Poco/Net/HTTPClientSession.h>
+#include <Poco/URI.h>
+
+#include "m3u8Parser.h"
+
+class cHlsSegmentLoader : public cThread
+{
+private:
+ int m_ringBufferSize;
+ int m_segmentsToBuffer;
+ unsigned int m_lastLoadedSegment;
+ bool m_bufferFilled;
+
+ uchar* m_pBuffer;
+
+ Poco::Net::HTTPClientSession* m_pClientSession;
+ Poco::URI m_startUri;
+ std::string m_sessionUriPart;
+ std::string m_segmentUriPart;
+ std::string m_sessionCookie;
+
+ cM3u8Parser m_startParser;
+ cM3u8Parser m_indexParser;
+
+ bool ConnectToServer(void);
+ void CloseConnection(void);
+ void LoadStartList(void);
+ void LoadIndexList(void);
+ std::string GetSegmentUri(int segmentIndex) const;
+ int GetSegmentSize(int segmentIndex);
+ bool LoadSegment(std::string uri);
+ int EstimateSegmentSize();
+
+protected:
+ void Action(void);
+ bool DoLoad(void);
+ bool StopLoader(void);
+
+public:
+ cHlsSegmentLoader(std::string startm3u8);
+ ~cHlsSegmentLoader();
+
+ cRingBufferLinear* m_pRingbuffer;
+ bool BufferFilled();
+};
+
+class cHlsPlayer : public cPlayer, cThread
+{
+private:
+ cHlsSegmentLoader* m_pSegmentLoader;
+
+ int m_videoLenght;
+ int m_actualSegment;
+ int m_actualTime;
+
+ enum ePlayModes { pmPlay, pmPause };
+ ePlayModes playMode;
+
+ virtual void Activate(bool On);
+
+
+protected:
+ void Action(void);
+ bool DoPlay(void);
+
+
+public:
+ cHlsPlayer(std::string startm3u8);
+ ~cHlsPlayer();
+
+ virtual bool GetIndex(int &Current, int &Total, bool SnapToIFrame = false);
+ virtual bool GetReplayMode(bool &Play, bool &Forward, int &Speed);
+ void Pause(void);
+ void Play(void);
+
+};
+
+#endif // HLSPLAYER_H
diff --git a/hlsPlayerControl.cpp b/hlsPlayerControl.cpp
new file mode 100644
index 0000000..f572604
--- /dev/null
+++ b/hlsPlayerControl.cpp
@@ -0,0 +1,24 @@
+#include "hlsPlayerControl.h"
+
+cHlsPlayerControl::cHlsPlayerControl(cHlsPlayer* Player, std::string title) :cControl(Player)
+{
+ m_pPlayer = Player;
+ m_title = title;
+}
+
+cHlsPlayerControl::~cHlsPlayerControl()
+{
+}
+
+cString cHlsPlayerControl::GetHeader(void)
+{
+ return m_title.c_str();
+}
+
+void cHlsPlayerControl::Hide(void)
+{
+}
+
+void cHlsPlayerControl::Show(void)
+{
+}
diff --git a/hlsPlayerControl.h b/hlsPlayerControl.h
new file mode 100644
index 0000000..934feff
--- /dev/null
+++ b/hlsPlayerControl.h
@@ -0,0 +1,27 @@
+#ifndef HLSPLAYERCONTROL_H
+#define HLSPLAYERCONTROL_H
+
+#include <vdr/player.h>
+#include <vdr/tools.h>
+
+#include "hlsPlayer.h"
+
+class cHlsPlayerControl : public cControl
+{
+private:
+ cHlsPlayer* m_pPlayer;
+ std::string m_title;
+
+public:
+ cHlsPlayerControl(cHlsPlayer* Player, std::string title);
+ virtual ~cHlsPlayerControl();
+
+ virtual void Show(void);
+ virtual void Hide(void);
+
+ virtual cString GetHeader(void);
+ //virtual eOSState ProcessKey(eKeys Key);
+
+};
+
+#endif // HLSPLAYERCONTROL_H
diff --git a/m3u8Parser.cpp b/m3u8Parser.cpp
new file mode 100644
index 0000000..8d7382b
--- /dev/null
+++ b/m3u8Parser.cpp
@@ -0,0 +1,121 @@
+#include "m3u8Parser.h"
+#include <pcrecpp.h>
+
+cM3u8Parser::cM3u8Parser()
+{
+ Init();
+}
+cM3u8Parser::cM3u8Parser(std::istream& m3u8)
+{
+ Init();
+ Parse(m3u8);
+}
+void cM3u8Parser::Init()
+{
+ TargetDuration = -1;
+ MediaSequence = -1;
+ MasterPlaylist = false;
+ AllowCache = true;
+}
+
+
+bool cM3u8Parser::Parse(std::istream& m3u8)
+{
+ bool ok = true;
+ bool nextLineIsMedia = false;
+ int lineNo = 0;
+
+ // prepare regex
+ pcrecpp::RE re("#(EXT[^:\\n]+)(?::[^\\n]+)");
+ pcrecpp::RE reVal("(?::([^\\n]+))");
+
+ std::string line;
+ playListItem pItem;
+ pItem.bandwidth = -1;
+ pItem.file = "";
+ pItem.length = -1;
+ pItem.programId = -1;
+
+ while (std::getline(m3u8, line)) {
+ if(lineNo == 0 && "#EXTM3U" == line ) {
+ // Invalid File
+ ok = false;
+ continue;
+ }
+
+ if( re.FullMatch(line) ) {
+ string var;
+ //string value;
+ re.PartialMatch(line, &var);
+ if("EXT-X-TARGETDURATION" == var) {
+ int value;
+ reVal.PartialMatch(line, &value);
+ TargetDuration = value;
+ } else if ("EXT-X-ALLOW-CACHE" == var) {
+ string value;
+ reVal.PartialMatch(line, &value);
+ AllowCache = "YES" == value;
+ } else if ("EXT-X-MEDIA-SEQUENCE" == var) {
+ int value;
+ reVal.PartialMatch(line, &value);
+ MediaSequence = value;
+ } else if ("EXT-X-STREAM-INF" == var) {
+ MasterPlaylist = true;
+ nextLineIsMedia = true;
+
+ int bandw;
+ pcrecpp::RE reBand("BANDWIDTH=(\\d+)");
+ if(reBand.PartialMatch(line, &bandw)) {
+ pItem.bandwidth = bandw;
+ }
+
+ int id;
+ pcrecpp::RE reId("PROGRAM-ID=(\\d+)");
+ if(reId.PartialMatch(line, &id)) {
+ pItem.programId = id;
+ }
+
+ } else if ("EXTINF" == var) {
+ MasterPlaylist = false;
+ int value;
+ pcrecpp::RE reInt("(?:#EXTINF:([\\d]+))");
+ if( reInt.PartialMatch(line, &value)) {
+ nextLineIsMedia = true;
+ pItem.length = value;
+ }
+ }
+ }
+ // possible mediafile
+ else {
+ if(nextLineIsMedia) {
+ nextLineIsMedia = false;
+ pItem.file = line;
+ pItem.size = 0;
+ vPlaylistItems.push_back(pItem);
+ }
+ }
+ lineNo++;
+ }
+ return ok;
+}
+
+/*
+#EXTM3U
+#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=4000000
+session/731d4143-c05d-47ed-afa8-37913402630a/8/index.m3u8
+*/
+
+/*
+#EXTM3U
+#EXT-X-TARGETDURATION:3
+#EXT-X-ALLOW-CACHE:NO
+#EXT-X-MEDIA-SEQUENCE:0
+#EXTINF:3, nodesc
+00000.ts
+#EXTINF:3, nodesc
+00001.ts
+...
+#EXTINF:2, nodesc
+01935.ts
+#EXT-X-ENDLIST
+*/
diff --git a/m3u8Parser.h b/m3u8Parser.h
new file mode 100644
index 0000000..0f52002
--- /dev/null
+++ b/m3u8Parser.h
@@ -0,0 +1,37 @@
+#ifndef M3U8PARSER_H
+#define M3U8PARSER_H
+
+#include <vector>
+#include <string>
+#include <iostream>
+
+class cM3u8Parser
+{
+public:
+ struct playListItem {
+ int length;
+ int bandwidth;
+ int programId;
+ std::string file;
+ int size;
+ };
+private:
+ void Init();
+
+public:
+ std::vector<playListItem> vPlaylistItems;
+ int TargetDuration;
+ int MediaSequence;
+ bool MasterPlaylist;
+ bool AllowCache;
+ bool Parse(std::istream &m3u8);
+
+public:
+ cM3u8Parser(std::istream &m3u8);
+ cM3u8Parser();
+ ~cM3u8Parser() {};
+
+};
+
+
+#endif // M3U8PARSER_H
diff --git a/player.c b/player.c
deleted file mode 100644
index 56cb827..0000000
--- a/player.c
+++ /dev/null
@@ -1,984 +0,0 @@
-///
-/// @file player.c @brief A play plugin for VDR.
-///
-/// Copyright (c) 2012, 2013 by Johns. All Rights Reserved.
-///
-/// Contributor(s): Dennis Bendlin
-///
-/// License: AGPLv3
-///
-/// This program is free software: you can redistribute it and/or modify
-/// it under the terms of the GNU Affero General Public License as
-/// published by the Free Software Foundation, either version 3 of the
-/// License.
-///
-/// 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 Affero General Public License for more details.
-///
-/// $Id: 23f35b1a9358694e2b022aed1eff081887bc3f16 $
-//////////////////////////////////////////////////////////////////////////////
-
-#include <sys/types.h>
-#include <sys/wait.h>
-
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <errno.h>
-
-#include <poll.h>
-#include <pthread.h>
-
-#include <libintl.h>
-#define _(str) gettext(str) ///< gettext shortcut
-#define _N(str) str ///< gettext_noop shortcut
-
-#include "player.h"
-#include "video.h"
-#include "misc.h"
-
-//////////////////////////////////////////////////////////////////////////////
-
-const char *ConfigBrowserRoot = "/"; ///< browser starting point
-
-static char ConfigOsdOverlay; ///< show osd overlay
-static char ConfigUseSlave; ///< external player use slave mode
-static char ConfigFullscreen; ///< external player uses fullscreen
-static char *ConfigVideoOut; ///< video out device
-static char *ConfigAudioOut; ///< audio out device
-static char *ConfigAudioMixer; ///< audio mixer device
-static char *ConfigMixerChannel; ///< audio mixer channel
-static const char *ConfigMplayer = "/usr/bin/mplayer"; ///< mplayer executable
-static const char *ConfigMplayerArguments; ///< extra mplayer arguments
-static const char *ConfigX11Display = ":0.0"; ///< x11 display
-
- /// DVD-Drive for mplayer
-static const char *ConfigMplayerDevice = "/dev/dvd";
-static uint32_t ConfigColorKey = 0x00020507; ///< color key
-
-//////////////////////////////////////////////////////////////////////////////
-// Osd
-//////////////////////////////////////////////////////////////////////////////
-
-/**
-** Open OSD.
-*/
-void OsdOpen(void)
-{
- Debug(3, "plex: %s\n", __FUNCTION__);
-
- VideoWindowShow();
-}
-
-/**
-** Close OSD.
-*/
-void OsdClose(void)
-{
- Debug(3, "plex: %s\n", __FUNCTION__);
-
- VideoWindowHide();
- VideoWindowClear();
-}
-
-/**
-** Clear OSD.
-*/
-void OsdClear(void)
-{
- Debug(3, "plex: %s\n", __FUNCTION__);
-
- VideoWindowClear();
-}
-
-/**
-** Get OSD size and aspect.
-**
-** @param width[OUT] width of OSD
-** @param height[OUT] height of OSD
-** @param aspect[OUT] aspect ratio (4/3, 16/9, ...) of OSD
-*/
-void GetOsdSize(int *width, int *height, double *aspect)
-{
- VideoGetOsdSize(width, height);
- *aspect = 16.0 / 9.0 / (double)*width * (double)*height;
-}
-
-/**
-** Draw osd pixmap
-*/
-void OsdDrawARGB(int x, int y, int w, int h, const uint8_t * argb)
-{
- Debug(3, "plex: %s %d,%d %d,%d\n", __FUNCTION__, x, y, w, h);
-
- VideoDrawARGB(x, y, w, h, argb);
-}
-
-//////////////////////////////////////////////////////////////////////////////
-// External player
-//////////////////////////////////////////////////////////////////////////////
-
-static pid_t PlayerPid; ///< player pid
-static pthread_t PlayerThread; ///< player decode thread
-
-static char PlayerPipeBuf[4096]; ///< pipe buffer
-static int PlayerPipeCnt; ///< pipe buffer count
-static int PlayerPipeIdx; ///< pipe buffer index
-static int PlayerPipeOut[2]; ///< player write pipe
-static int PlayerPipeIn[2]; ///< player read pipe
-
-static int PlayerVolume = -1; ///< volume 0 - 100
-
-char PlayerDvdNav; ///< dvdnav active
-char PlayerPaused; ///< player paused
-char PlayerSpeed; ///< player playback speed
-int PlayerCurrent; ///< current postion in seconds
-int PlayerTotal; ///< total length in seconds
-char PlayerTitle[256]; ///< title from meta data
-char PlayerFilename[256]; ///< filename
-
-//////////////////////////////////////////////////////////////////////////////
-// Slave
-//////////////////////////////////////////////////////////////////////////////
-
-/**
-** Parse player output.
-**
-** @param data line pointer (\0 terminated)
-** @param size line length
-*/
-static void PlayerParseLine(const char *data, int size)
-{
- Debug(4, "play/parse: |%.*s|\n", size, data);
- (void)size;
-
- // data is \0 terminated
- if (!strncasecmp(data, "DVDNAV_TITLE_IS_MENU", 20)) {
- PlayerDvdNav = 1;
- } else if (!strncasecmp(data, "DVDNAV_TITLE_IS_MOVIE", 21)) {
- PlayerDvdNav = 2;
- } else if (!strncasecmp(data, "ID_DVD_VOLUME_ID=", 17)) {
- Debug(3, "DVD_VOLUME = %s\n", data + 17);
- } else if (!strncasecmp(data, "ID_AID_", 7)) {
- char lang[64];
- int aid;
-
- if (sscanf(data, "ID_AID_%d_LANG=%s", &aid, lang) == 2) {
- Debug(3, "AID(%d) = %s\n", aid, lang);
- }
- } else if (!strncasecmp(data, "ID_SID_", 7)) {
- char lang[64];
- int sid;
-
- if (sscanf(data, "ID_SID_%d_LANG=%s", &sid, lang) == 2) {
- Debug(3, "SID(%d) = %s\n", sid, lang);
- }
- } else if (!strncasecmp(data, "ANS_META_TITLE=", 14)) {
- if (sscanf(data, "ANS_META_TITLE='%[^\t\n]", PlayerTitle) == 1) {
- PlayerTitle[strlen(PlayerTitle) - 1] = 0;
- Debug(3, "PlayerTitle= %s\n", PlayerTitle);
- }
- } else if (!strncasecmp(data, "ANS_FILENAME=", 12)) {
- if (sscanf(data, "ANS_FILENAME='%[^\t\n]", PlayerFilename) == 1) {
- PlayerFilename[strlen(PlayerFilename) - 1] = 0;
- Debug(3, "PlayerFilename= %s\n", PlayerFilename);
- }
- } else if (!strncasecmp(data, "ANS_LENGTH=", 10)) {
- if (sscanf(data, "ANS_LENGTH=%d", &PlayerTotal) == 1) {
- Debug(3, "PlayerTotal=%d\n", PlayerTotal);
- }
- } else if (!strncasecmp(data, "ANS_TIME_POSITION=", 17)) {
- if (sscanf(data, "ANS_TIME_POSITION=%d", &PlayerCurrent) == 1) {
- Debug(3, "PlayerCurrent=%d\n", PlayerCurrent);
- }
- }
-}
-
-/**
-** Poll input pipe.
-*/
-static void PlayerPollPipe(void)
-{
- struct pollfd poll_fds[1];
- int n;
- int i;
- int l;
-
- // check if something to read
- poll_fds[0].fd = PlayerPipeOut[0];
- poll_fds[0].events = POLLIN;
-
- switch (poll(poll_fds, 1, 0)) {
- case 0: // timeout
- return;
- case -1: // error
- Error(_("play/player: poll failed: %s\n"), strerror(errno));
- return;
- default: // ready
- break;
- }
-
- // fill buffer
- if ((n = read(PlayerPipeOut[0], PlayerPipeBuf + PlayerPipeCnt,
- sizeof(PlayerPipeBuf) - PlayerPipeCnt)) < 0) {
- Error(_("play/player: read failed: %s\n"), strerror(errno));
- return;
- }
-
- PlayerPipeCnt += n;
- l = 0;
- for (i = PlayerPipeIdx; i < PlayerPipeCnt; ++i) {
- if (PlayerPipeBuf[i] == '\n') {
- PlayerPipeBuf[i] = '\0';
- PlayerParseLine(PlayerPipeBuf + PlayerPipeIdx, i - PlayerPipeIdx);
- PlayerPipeIdx = i + 1;
- l = PlayerPipeIdx;
- }
- }
-
- if (l) { // remove consumed bytes
- if (PlayerPipeCnt - l) {
- memmove(PlayerPipeBuf, PlayerPipeBuf + l, PlayerPipeCnt - l);
- }
- PlayerPipeCnt -= l;
- PlayerPipeIdx -= l;
- } else if (PlayerPipeCnt == sizeof(PlayerPipeBuf)) {
- // no '\n' in buffer use it as single line
- PlayerPipeBuf[sizeof(PlayerPipeBuf) - 1] = '\0';
- PlayerParseLine(PlayerPipeBuf + PlayerPipeIdx, PlayerPipeCnt);
- PlayerPipeIdx = 0;
- PlayerPipeCnt = 0;
- }
-}
-
-#define MPLAYER_MAX_ARGS 64 ///< number of arguments supported
-
-/**
-** Execute external player.
-**
-** @param filename path and name of file to play
-*/
-static void PlayerExec(const char *filename)
-{
- const char *args[MPLAYER_MAX_ARGS];
- int argn;
- char wid_buf[32];
- char volume_buf[32];
- int i;
-
- if (ConfigUseSlave) { // connect pipe to stdin/stdout
- dup2(PlayerPipeIn[0], STDIN_FILENO);
- close(PlayerPipeIn[0]);
- close(PlayerPipeIn[1]);
- close(PlayerPipeOut[0]);
- dup2(PlayerPipeOut[1], STDOUT_FILENO);
- dup2(PlayerPipeOut[1], STDERR_FILENO);
- close(PlayerPipeOut[1]);
- }
- // close all file handles
- for (i = getdtablesize() - 1; i > STDERR_FILENO; i--) {
- close(i);
- }
-
- // export DISPLAY=
-
- args[0] = ConfigMplayer;
- args[1] = "-quiet";
- args[2] = "-msglevel";
- // FIXME: play with the options
-#ifdef DEBUG
- args[3] = "all=6:global=4:cplayer=4:identify=4";
-#else
- args[3] = "all=2:global=4:cplayer=2:identify=4";
-#endif
- if (ConfigOsdOverlay) {
- args[4] = "-noontop";
- } else {
- args[4] = "-ontop";
- }
- args[5] = "-noborder";
- if (ConfigDisableRemote) {
- args[6] = "-lirc";
- } else {
- args[6] = "-nolirc";
- }
- args[7] = "-nojoystick"; // disable all unwanted inputs
- args[8] = "-noar";
- args[9] = "-nomouseinput";
- args[10] = "-nograbpointer";
- args[11] = "-noconsolecontrols";
- args[12] = "-fixed-vo";
- args[13] = "-sid"; // subtitle selection
- args[14] = "0";
- args[15] = "-slang";
- args[16] = "de,en"; // FIXME: use VDR config
- args[17] = "-alang";
- args[18] = "de,en"; // FIXME: use VDR config
- argn = 19;
- if (ConfigMplayerDevice) { // dvd-device
- args[argn++] = "-dvd-device";
- args[argn++] = ConfigMplayerDevice;
- }
- if (!strncasecmp(filename, "cdda://", 7)) {
- args[argn++] = "-cache"; // cdrom needs cache
- args[argn++] = "1000";
- } else {
- args[argn++] = "-nocache"; // dvdnav needs nocache
- }
- if (ConfigUseSlave) {
- args[argn++] = "-slave";
- //args[argn++] = "-idle";
- }
- if (ConfigOsdOverlay) { // no mplayer osd with overlay
- args[argn++] = "-osdlevel";
- args[argn++] = "0";
- }
- if (ConfigFullscreen) {
- args[argn++] = "-fs";
- args[argn++] = "-zoom";
- } else {
- args[argn++] = "-nofs";
- }
- if (VideoGetPlayWindow()) {
- snprintf(wid_buf, sizeof(wid_buf), "%d", VideoGetPlayWindow());
- args[argn++] = "-wid";
- args[argn++] = wid_buf;
- }
- if (ConfigVideoOut) {
- args[argn++] = "-vo";
- args[argn++] = ConfigVideoOut;
- // add options based on selected video out
- if (!strncmp(ConfigVideoOut, "vdpau", 5)) {
- args[argn++] = "-vc";
- args[argn++] =
- "ffmpeg12vdpau,ffwmv3vdpau,ffvc1vdpau,ffh264vdpau,ffodivxvdpau,";
- } else if (!strncmp(ConfigVideoOut, "vaapi", 5)) {
- args[argn++] = "-va";
- args[argn++] = "vaapi";
- }
- }
- if (ConfigAudioOut) {
- args[argn++] = "-ao";
- args[argn++] = ConfigAudioOut;
- // FIXME: -ac hwac3,hwdts,hwmpa,
- }
- if (ConfigAudioMixer) {
- args[argn++] = "-mixer";
- args[argn++] = ConfigAudioMixer;
- }
- if (ConfigMixerChannel) {
- args[argn++] = "-mixer-channel";
- args[argn++] = ConfigMixerChannel;
- }
- if (ConfigX11Display) {
- args[argn++] = "-display";
- args[argn++] = ConfigX11Display;
- }
- if (PlayerVolume != -1) {
- // FIXME: here could be a problem with LANG
- snprintf(volume_buf, sizeof(volume_buf), "%.2f",
- (PlayerVolume * 100.0) / 255);
- args[argn++] = "-volume";
- args[argn++] = volume_buf;
- }
- // split X server arguments string into words
- if (ConfigMplayerArguments) {
- const char *sval;
- char *buf;
- char *s;
-
- sval = ConfigMplayerArguments;
-#ifndef __FreeBSD__
- s = buf = strdupa(sval);
-#else
- s = buf = alloca(strlen(sval) + 1);
- strcpy(buf, sval);
-#endif
- while ((sval = strsep(&s, " \t"))) {
- args[argn++] = sval;
-
- if (argn == MPLAYER_MAX_ARGS - 3) { // argument overflow
- Error(_("play: too many arguments for mplayer\n"));
- // argn = 1;
- break;
- }
- }
- }
- args[argn++] = "--";
- args[argn++] = filename;
- args[argn] = NULL;
-#ifdef DEBUG
- if (argn + 1 >= (int)(sizeof(args) / sizeof(*args))) {
- Debug(3, "play: too many arguments %d\n", argn);
- }
- for (i = 0; i < argn; ++i) {
- Debug(3, "%s", args[i]);
- }
-#endif
-
- execvp(args[0], (char *const *)args);
-
- // shouldn't be reached
- Error(_("play: execvp of '%s' failed: %s\n"), args[0], strerror(errno));
- exit(-1);
-}
-
-/**
-** Execute external player.
-**
-** @param filename path and name of file to play
-*/
-static void PlayerForkAndExec(const char *filename)
-{
- pid_t pid;
-
- if (ConfigUseSlave) {
- if (pipe(PlayerPipeIn)) {
- Error(_("play: pipe failed: %s\n"), strerror(errno));
- return;
- }
- if (pipe(PlayerPipeOut)) {
- Error(_("play: pipe failed: %s\n"), strerror(errno));
- return;
- }
- }
-
- if ((pid = fork()) == -1) {
- Error(_("play: fork failed: %s\n"), strerror(errno));
- return;
- }
- if (!pid) { // child
- PlayerExec(filename);
- return;
- }
- PlayerPid = pid; // parent
- setpgid(pid, 0);
-
- if (ConfigUseSlave) {
- close(PlayerPipeIn[0]);
- close(PlayerPipeOut[1]);
- }
-
- Debug(3, "play: child pid=%d\n", pid);
-}
-
-/**
-** Close pipes.
-*/
-static void PlayerClosePipes(void)
-{
- if (ConfigUseSlave) {
- if (PlayerPipeIn[0] != -1) {
- close(PlayerPipeIn[0]);
- }
- if (PlayerPipeOut[1] != -1) {
- close(PlayerPipeOut[1]);
- }
- }
-}
-
-//////////////////////////////////////////////////////////////////////////////
-// Thread
-//////////////////////////////////////////////////////////////////////////////
-
-/**
-** External player handler thread.
-**
-** @param dummy dummy pointer
-*/
-static void *PlayerHandlerThread(void *dummy)
-{
- Debug(3, "play: player thread started\n");
-
- // Need: thread for video poll: while (PlayerIsRunning())
- for (;;) {
- if (ConfigUseSlave && PlayerIsRunning()) {
- PlayerPollPipe();
- // FIXME: wait only if pipe not ready
- }
- if (ConfigOsdOverlay) {
- VideoPollEvents(10);
- } else {
- usleep(10 * 1000);
- }
- }
-
- Debug(3, "play: player thread stopped\n");
- PlayerThread = 0;
-
- return dummy;
-}
-
-/**
-** Initialize player threads.
-*/
-static void PlayerThreadInit(void)
-{
- pthread_create(&PlayerThread, NULL, PlayerHandlerThread, NULL);
- //pthread_setname_np(PlayerThread, "play player");
-}
-
-/**
-** Exit and cleanup player threads.
-*/
-static void PlayerThreadExit(void)
-{
- if (PlayerThread) {
- void *retval;
-
- Debug(3, "play: player thread canceled\n");
- if (pthread_cancel(PlayerThread)) {
- Error(_("play: can't queue cancel player thread\n"));
- }
- if (pthread_join(PlayerThread, &retval) || retval != PTHREAD_CANCELED) {
- Error(_("play: can't cancel player thread\n"));
- }
- PlayerThread = 0;
- }
-}
-
-/**
-** Send command to player.
-**
-** @param formst printf format string
-*/
-static void SendCommand(const char *format, ...)
-{
- va_list va;
- char buf[256];
- int n;
-
- if (!PlayerPid) {
- return;
- }
- if (PlayerPipeIn[1] == -1) {
- Error(_("play: no pipe to send command available\n"));
- return;
- }
- va_start(va, format);
- n = vsnprintf(buf, sizeof(buf), format, va);
- va_end(va);
-
- Debug(3, "play: send '%.*s'\n", n - 1, buf);
-
- // FIXME: poll pipe if ready
- if (write(PlayerPipeIn[1], buf, n) != n) {
- fprintf(stderr, "play: write failed\n");
- }
-}
-
-/**
-** Send player quit.
-*/
-void PlayerSendQuit(void)
-{
- if (ConfigUseSlave) {
- SendCommand("quit\n");
- }
-}
-
-/**
-** Send player pause.
-*/
-void PlayerSendPause(void)
-{
- if (ConfigUseSlave) {
- SendCommand("pause\n");
- }
-}
-
-/**
-** Send player speed_set.
-**
-** @param speed mplayer speed
-*/
-void PlayerSendSetSpeed(int speed)
-{
- if (ConfigUseSlave) {
- SendCommand("pausing_keep speed_set %d\n", speed);
- }
-}
-
-/**
-** Send player seek.
-**
-** @param seconds seek in seconds relative to current position
-*/
-void PlayerSendSeek(int seconds)
-{
- if (ConfigUseSlave) {
- SendCommand("pausing_keep seek %+d 0\n", seconds);
- }
-}
-
-/**
-** Send player volume.
-*/
-void PlayerSendVolume(void)
-{
- if (ConfigUseSlave) {
- // FIXME: %.2f could have a problem with LANG
- SendCommand("pausing_keep volume %.2f 1\n",
- (PlayerVolume * 100.0) / 255);
- }
-}
-
-/**
-** Send switch audio track.
-*/
-void PlayerSendSwitchAudio(void)
-{
- if (ConfigUseSlave) {
- SendCommand("pausing_keep switch_audio\n");
- }
-}
-
-/**
-** Send select subtitle.
-*/
-void PlayerSendSubSelect(void)
-{
- if (ConfigUseSlave) {
- SendCommand("pausing_keep sub_select\n");
- }
-}
-
-/**
-** Send up for dvdnav.
-*/
-void PlayerSendDvdNavUp(void)
-{
- if (ConfigUseSlave) {
- SendCommand("pausing_keep dvdnav up\n");
- }
-}
-
-/**
-** Send down for dvdnav.
-*/
-void PlayerSendDvdNavDown(void)
-{
- if (ConfigUseSlave) {
- SendCommand("pausing_keep dvdnav down\n");
- }
-}
-
-/**
-** Send left for dvdnav.
-*/
-void PlayerSendDvdNavLeft(void)
-{
- if (ConfigUseSlave) {
- SendCommand("pausing_keep dvdnav left\n");
- }
-}
-
-/**
-** Send right for dvdnav.
-*/
-void PlayerSendDvdNavRight(void)
-{
- if (ConfigUseSlave) {
- SendCommand("pausing_keep dvdnav right\n");
- }
-}
-
-/**
-** Send select for dvdnav.
-*/
-void PlayerSendDvdNavSelect(void)
-{
- if (ConfigUseSlave) {
- SendCommand("pausing_keep dvdnav select\n");
- }
-}
-
-/**
-** Send prev for dvdnav.
-*/
-void PlayerSendDvdNavPrev(void)
-{
- if (ConfigUseSlave) {
- SendCommand("pausing_keep dvdnav prev\n");
- }
-}
-
-/**
-** Send menu for dvdnav.
-*/
-void PlayerSendDvdNavMenu(void)
-{
- if (ConfigUseSlave) {
- SendCommand("pausing_keep dvdnav menu\n");
- }
-}
-
-/**
-** Get length in seconds.
-*/
-void PlayerGetLength(void)
-{
- if (ConfigUseSlave) {
- SendCommand("get_time_length\n");
- }
-}
-
-/**
-** Get current position in seconds.
-*/
-void PlayerGetCurrentPosition(void)
-{
- if (ConfigUseSlave) {
- SendCommand("get_time_pos\n");
- }
-}
-
-/**
-** Get title from meta data.
-*/
-void PlayerGetMetaTitle(void)
-{
- if (ConfigUseSlave) {
- SendCommand("get_meta_title\n");
- }
-}
-
-/**
-** Get filename.
-*/
-void PlayerGetFilename(void)
-{
- if (ConfigUseSlave) {
- SendCommand("get_file_name\n");
- }
-}
-
-/**
-** Start external player.
-**
-** @param filename path and name of file to play
-*/
-void PlayerStart(const char *filename)
-{
- PlayerPipeCnt = 0; // reset to defaults
- PlayerPipeIdx = 0;
-
- PlayerPipeIn[0] = -1;
- PlayerPipeIn[1] = -1;
- PlayerPipeOut[0] = -1;
- PlayerPipeOut[1] = -1;
- PlayerPid = 0;
-
- PlayerPaused = 0;
- PlayerSpeed = 1;
-
- PlayerDvdNav = 0;
-
- if (ConfigOsdOverlay) { // overlay wanted
- VideoSetColorKey(ConfigColorKey);
- VideoInit(ConfigX11Display);
- EnableDummyDevice();
- }
- PlayerForkAndExec(filename);
-
- if (ConfigOsdOverlay || ConfigUseSlave) {
- PlayerThreadInit();
- }
-}
-
-/**
-** Stop external player.
-*/
-void PlayerStop(void)
-{
- PlayerThreadExit();
-
- //
- // stop mplayer, if it is still running.
- //
- if (PlayerIsRunning()) {
- int waittime;
- int timeout;
-
- waittime = 0;
- timeout = 500; // 0.5s
-
- kill(PlayerPid, SIGTERM);
- // wait for player finishing, with timeout
- while (PlayerIsRunning() && waittime++ < timeout) {
- usleep(1 * 1000);
- }
- if (PlayerIsRunning()) { // still running
- waittime = 0;
- timeout = 500; // 0.5s
-
- kill(PlayerPid, SIGKILL);
- // wait for player finishing, with timeout
- while (PlayerIsRunning() && waittime++ < timeout) {
- usleep(1 * 1000);
- }
- if (PlayerIsRunning()) {
- Error(_("play: can't stop player\n"));
- }
- }
- }
- PlayerPid = 0;
- PlayerClosePipes();
-
- if (ConfigOsdOverlay) {
- DisableDummyDevice();
- VideoExit();
- }
-}
-
-/**
-** Is external player still running?
-*/
-int PlayerIsRunning(void)
-{
- pid_t wpid;
- int status;
-
- if (!PlayerPid) { // no player
- return 0;
- }
-
- wpid = waitpid(PlayerPid, &status, WNOHANG);
- if (wpid <= 0) {
- return 1;
- }
- if (WIFEXITED(status)) {
- Debug(3, "play: player exited (%d)\n", WEXITSTATUS(status));
- }
- if (WIFSIGNALED(status)) {
- Debug(3, "play: player killed (%d)\n", WTERMSIG(status));
- }
- PlayerPid = 0;
- return 0;
-}
-
-/**
-** Set player volume.
-**
-** @param volume new volume (0..255)
-*/
-void PlayerSetVolume(int volume)
-{
- Debug(3, "player: set volume=%d\n", volume);
-
- if (PlayerVolume != volume) {
- PlayerVolume = volume;
- if (PlayerPid) {
- PlayerSendVolume();
- }
- }
-}
-
-//////////////////////////////////////////////////////////////////////////////
-// Device/Plugin C part
-//////////////////////////////////////////////////////////////////////////////
-
-/**
-** Return command line help string.
-*/
-const char *CommandLineHelp(void)
-{
- return " -% device\tmplayer dvd device\n"
- " -/\t/dir\tbrowser root directory\n"
- " -a audio\tmplayer -ao (alsa:device=hw=0.0) overwrites mplayer.conf\n"
- " -d display\tX11 display (default :0.0) overwrites $DISPLAY\n"
- " -f\t\tmplayer fullscreen playback\n"
- " -g geometry\tx11 window geometry wxh+x+y\n"
- " -k colorkey\tvideo color key (default=0x020507, mplayer2=0x76B901)\n"
- " -m mplayer\tfilename of mplayer executable\n"
- " -M args\targuments for mplayer\n"
- " -o\t\tosd overlay experiments\n" " -s\t\tmplayer slave mode\n"
- " -v video\tmplayer -vo (vdpau:deint=4:hqscaling=1) overwrites mplayer.conf\n";
-}
-
-/**
-** Process the command line arguments.
-**
-** @param argc number of arguments
-** @param argv arguments vector
-*/
-int ProcessArgs(int argc, char *const argv[])
-{
- const char *s;
-
- //
- // Parse arguments.
- //
-#ifdef __FreeBSD__
- if (!strcmp(*argv, "play")) {
- ++argv;
- --argc;
- }
-#endif
- if ((s = getenv("DISPLAY"))) {
- ConfigX11Display = s;
- }
-
- for (;;) {
- switch (getopt(argc, argv, "-%:/:a:b:d:fg:k:m:M:osv:")) {
- case '%': // dvd-device
- ConfigMplayerDevice = optarg;
- continue;
- case '/': // browser root
- ConfigBrowserRoot = optarg;
- continue;
- case 'a': // audio out
- ConfigAudioOut = optarg;
- continue;
- case 'd': // display x11
- ConfigX11Display = optarg;
- continue;
- case 'f': // fullscreen mode
- ConfigFullscreen = 1;
- continue;
- case 'g': // geometry
- VideoSetGeometry(optarg);
- continue;
- case 'k': // color key
- ConfigColorKey = strtol(optarg, NULL, 0);
- continue;
- case 'm': // mplayer executable
- ConfigMplayer = optarg;
- continue;
- case 'M': // mplayer extra arguments
- ConfigMplayerArguments = optarg;
- continue;
- case 'o': // osd / overlay
- ConfigOsdOverlay = 1;
- continue;
- case 's': // slave mode
- ConfigUseSlave = 1;
- continue;
- case 'v': // video out
- ConfigVideoOut = optarg;
- continue;
- case EOF:
- break;
- case '-':
- fprintf(stderr, _("We need no long options\n"));
- return 0;
- case ':':
- fprintf(stderr, _("Missing argument for option '%c'\n"),
- optopt);
- return 0;
- default:
- fprintf(stderr, _("Unkown option '%c'\n"), optopt);
- return 0;
- }
- break;
- }
- while (optind < argc) {
- fprintf(stderr, _("Unhandled argument '%s'\n"), argv[optind++]);
- }
-
- return 1;
-}
diff --git a/player.h b/player.h
deleted file mode 100644
index d4acedd..0000000
--- a/player.h
+++ /dev/null
@@ -1,160 +0,0 @@
-///
-/// @file player.h @brief A play plugin header file.
-///
-/// Copyright (c) 2012, 2013 by Johns. All Rights Reserved.
-///
-/// Contributor(s): Dennis Bendlin
-///
-/// License: AGPLv3
-///
-/// This program is free software: you can redistribute it and/or modify
-/// it under the terms of the GNU Affero General Public License as
-/// published by the Free Software Foundation, either version 3 of the
-/// License.
-///
-/// 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 Affero General Public License for more details.
-///
-/// $Id: 0c86be2575387d12e692ffa0cc8ce515bbc6f5e5 $
-//////////////////////////////////////////////////////////////////////////////
-
-#ifdef __cplusplus
-extern "C"
-{
-#endif
- /// C callback feed key press
- extern void FeedKeyPress(const char *, const char *, int, int);
-
- /// C callback enable dummy device
- extern void EnableDummyDevice(void);
- /// C callback disable dummy device
- extern void DisableDummyDevice(void);
-
- /// C plugin get osd size and ascpect
- extern void GetOsdSize(int *, int *, double *);
-
- /// C plugin open osd
- extern void OsdOpen(void);
- /// C plugin close osd
- extern void OsdClose(void);
- /// C plugin clear osd
- extern void OsdClear(void);
- /// C plugin draw osd pixmap
- extern void OsdDrawARGB(int, int, int, int, const uint8_t *);
-
- /// C plugin play audio packet
- extern int PlayAudio(const uint8_t *, int, uint8_t);
- /// C plugin play TS audio packet
- extern int PlayTsAudio(const uint8_t *, int);
- /// C plugin set audio volume
- extern void SetVolumeDevice(int);
-
- /// C plugin play video packet
- extern int PlayVideo(const uint8_t *, int);
- /// C plugin play TS video packet
- extern void PlayTsVideo(const uint8_t *, int);
- /// C plugin grab an image
- extern uint8_t *GrabImage(int *, int, int, int, int);
-
- /// C plugin set play mode
- extern int SetPlayMode(int);
- /// C plugin get current system time counter
- extern int64_t GetSTC(void);
- /// C plugin get video stream size and aspect
- extern void GetVideoSize(int *, int *, double *);
- /// C plugin set trick speed
- extern void TrickSpeed(int);
- /// C plugin clears all video and audio data from the device
- extern void Clear(void);
- /// C plugin sets the device into play mode
- extern void Play(void);
- /// C plugin sets the device into "freeze frame" mode
- extern void Freeze(void);
- /// C plugin mute audio
- extern void Mute(void);
- /// C plugin display I-frame as a still picture.
- extern void StillPicture(const uint8_t *, int);
- /// C plugin poll if ready
- extern int Poll(int);
- /// C plugin flush output buffers
- extern int Flush(int);
-
- /// C plugin command line help
- extern const char *CommandLineHelp(void);
- /// C plugin process the command line arguments
- extern int ProcessArgs(int, char *const[]);
-
- /// C plugin exit + cleanup
- extern void PlayExit(void);
- /// C plugin start code
- extern int Start(void);
- /// C plugin stop code
- extern void Stop(void);
- /// C plugin house keeping
- extern void Housekeeping(void);
- /// C plugin main thread hook
- extern void MainThreadHook(void);
-
- /// Browser root=start directory
- extern const char *ConfigBrowserRoot;
- ///< Disable remote during external play
- extern char ConfigDisableRemote;
- extern const char *X11DisplayName; ///< x11 display name
- extern char PlayerDvdNav; ///< dvdnav active
- extern char PlayerPaused; ///< player paused
- extern char PlayerSpeed; ///< player playback speed
- extern int PlayerCurrent; ///< current postion in seconds
- extern int PlayerTotal; ///< total length in seconds
- extern char PlayerTitle[256]; ///< title from meta data
- extern char PlayerFilename[256]; ///< filename
-
- /// Start external player
- extern void PlayerStart(const char *name);
- /// Stop external player
- extern void PlayerStop(void);
- /// Is external player still running
- extern int PlayerIsRunning(void);
-
- /// Set player volume
- extern void PlayerSetVolume(int);
-
- /// Player send quit command
- extern void PlayerSendQuit(void);
- /// Player send toggle pause command
- extern void PlayerSendPause(void);
- /// Player send set play speed
- extern void PlayerSendSetSpeed(int);
- /// Player send seek
- extern void PlayerSendSeek(int);
- /// Player send switch audio track
- extern void PlayerSendSwitchAudio(void);
- /// Player send select subtitle
- extern void PlayerSendSubSelect(void);
- /// Player send dvd-nav up
- extern void PlayerSendDvdNavUp(void);
- /// Player send dvd-nav down
- extern void PlayerSendDvdNavDown(void);
- /// Player send dvd-nav left
- extern void PlayerSendDvdNavLeft(void);
- /// Player send dvd-nav right
- extern void PlayerSendDvdNavRight(void);
- /// Player send dvd-nav menu select
- extern void PlayerSendDvdNavSelect(void);
- /// Player send dvd-nav menu prev
- extern void PlayerSendDvdNavPrev(void);
- /// Player send dvd-nav prev
- extern void PlayerSendDvdNavMenu(void);
- /// Get length in seconds.
- extern void PlayerGetLength(void);
- /// Get current position in seconds.
- extern void PlayerGetCurrentPosition(void);
- /// Get title from meta data.
- extern void PlayerGetMetaTitle(void);
- /// Get filename.
- extern void PlayerGetFilename(void);
-
-#ifdef __cplusplus
-}
-#endif
diff --git a/plex.cpp b/plex.cpp
index a5287ae..893d058 100644
--- a/plex.cpp
+++ b/plex.cpp
@@ -2,12 +2,6 @@
#include "SubscriptionManager.h"
#include "plex.h"
-extern "C"
-{
-#include "video.h"
-#include "player.h"
-}
-
static const char *const PLUGINNAME = "plex";
//////////////////////////////////////////////////////////////////////////////
@@ -118,443 +112,6 @@ extern "C" void DrawText(int x, int y, const char *s, uint32_t fg, uint32_t bg,
#endif
-//////////////////////////////////////////////////////////////////////////////
-// cPlayer
-//////////////////////////////////////////////////////////////////////////////
-
-
-/**
-** Player constructor.
-**
-** @param filename path and name of file to play
-*/
-cMyPlayer::cMyPlayer(const char *filename)
-:cPlayer(pmExtern_THIS_SHOULD_BE_AVOIDED)
-{
- dsyslog("[plex]%s: '%s'\n", __FUNCTION__, filename);
-
- PlayerSetVolume(cDevice::CurrentVolume());
- dsyslog("[plex]: initial volume %d\n", cDevice::CurrentVolume());
-
- FileName = strdup(filename);
- if (ConfigDisableRemote) {
- RemoteDisable();
- }
-}
-
-/**
-** Player destructor.
-*/
-cMyPlayer::~cMyPlayer()
-{
- dsyslog("[plex]%s: end\n", __FUNCTION__);
-
- PlayerStop();
- free(FileName);
- if (ConfigDisableRemote) {
- RemoteEnable();
- }
- // FIXME: wait until primary device is switched?
- dsyslog("[plex]: device %d->%d\n",
- cDevice::PrimaryDevice()->DeviceNumber(), DoMakePrimary);
-}
-
-/**
-** Player attached or detached.
-**
-** @param on flag turn player on or off
-*/
-void cMyPlayer::Activate(bool on)
-{
- dsyslog("[plex]%s: '%s' %d\n", __FUNCTION__, FileName, on);
-
- if (on) {
- PlayerStart(FileName);
- } else {
- PlayerStop();
- }
-}
-
-/**
-** Get current replay mode.
-*/
-bool cMyPlayer::GetReplayMode(bool & play, bool & forward, int &speed)
-{
- play = !PlayerPaused;
- forward = true;
- if (PlayerSpeed == 1) {
- speed = -1;
- } else {
- speed = PlayerSpeed;
- }
- return true;
-}
-
-//////////////////////////////////////////////////////////////////////////////
-// cStatus
-//////////////////////////////////////////////////////////////////////////////
-
-cMyStatus *Status; ///< status monitor for volume
-
-/**
-** Status constructor.
-*/
-cMyStatus::cMyStatus(void)
-{
- Volume = cDevice::CurrentVolume();
-
- dsyslog("[plex]: status volume %d\n", Volume);
-}
-
-/**
-** Called if volume is set.
-*/
-void cMyStatus::SetVolume(int volume, bool absolute)
-{
- dsyslog("[plex]: volume %d %s\n", volume, absolute ? "abs" : "rel");
-
- if (absolute) {
- Volume = volume;
- } else {
- Volume += volume;
- }
-
- PlayerSetVolume(Volume);
-}
-
-//////////////////////////////////////////////////////////////////////////////
-// cControl
-//////////////////////////////////////////////////////////////////////////////
-
-
-
-/**
-** Show replay mode.
-*/
-void cMyControl::ShowReplayMode(void)
-{
- dsyslog("[plex]%s: %d - %d\n", __FUNCTION__, Setup.ShowReplayMode,
- cOsd::IsOpen());
-
- // use vdr setup
- if (Display || (Setup.ShowReplayMode && !cOsd::IsOpen())) {
- bool play;
- bool forward;
- int speed;
-
- if (GetReplayMode(play, forward, speed)) {
- if (!Display) {
- // no need to show normal play
- if (play && forward && speed == 1) {
- return;
- }
- Display = Skins.Current()->DisplayReplay(true);
- }
- Display->SetMode(play, forward, speed);
- }
- }
-}
-
-/**
-** Show progress.
-*/
-void cMyControl::ShowProgress(void)
-{
- if (Display || (!cOsd::IsOpen())) {
- bool play;
- bool forward;
- int speed;
-
- if (GetReplayMode(play, forward, speed)) {
- if (!Display) {
- Display = Skins.Current()->DisplayReplay(false);
- }
-
- if (!infoVisible) {
- infoVisible = true;
- timeoutShow = time(0) + Setup.ChannelInfoTime;
- PlayerGetLength();
- PlayerGetMetaTitle();
- PlayerGetFilename();
- }
-
- PlayerGetCurrentPosition();
- if (strcmp(PlayerTitle, "") != 0) {
- Display->SetTitle(PlayerTitle);
- } else {
- Display->SetTitle(PlayerFilename);
- }
- Display->SetProgress(PlayerCurrent, PlayerTotal);
- Display->SetMode(play, forward, speed);
- Display->SetCurrent(IndexToHMSF(PlayerCurrent, false, 1));
- Display->SetTotal(IndexToHMSF(PlayerTotal, false, 1));
- }
- SetNeedsFastResponse(true);
- Skins.Flush();
- }
-}
-
-/**
-** Show control.
-*/
-void cMyControl::Show(void)
-{
- dsyslog("[plex]%s:\n", __FUNCTION__);
- if (Setup.ShowReplayMode)
- ShowReplayMode();
- else
- ShowProgress();
-}
-
-/**
-** Control constructor.
-**
-** @param filename pathname of file to play.
-*/
-cMyControl::cMyControl(const char *filename)
-:cControl(Player = new cMyPlayer(filename))
-{
- Display = NULL;
- Status = new cMyStatus; // start monitoring volume
- infoVisible = false;
-
- //LastSkipKey = kNone;
- //LastSkipSeconds = REPLAYCONTROLSKIPSECONDS;
- //LastSkipTimeout.Set(0);
- cStatus::MsgReplaying(this, filename, filename, true);
-
- cDevice::PrimaryDevice()->ClrAvailableTracks(true);
-}
-
-/**
-** Control destructor.
-*/
-cMyControl::~cMyControl()
-{
- dsyslog("[plex]%s\n", __FUNCTION__);
-
- delete Player;
-
- //delete Display;
- delete Status;
-
- Hide();
- cStatus::MsgReplaying(this, NULL, NULL, false);
- //Stop();
-}
-
-/**
-** Hide control.
-*/
-void cMyControl::Hide(void)
-{
- dsyslog("[plex]%s:\n", __FUNCTION__);
-
- if (Display) {
- delete Display;
-
- Display = NULL;
- SetNeedsFastResponse(false);
- }
-}
-
-/**
-** Process keyboard input.
-**
-** @param key pressed or releaded key
-*/
-eOSState cMyControl::ProcessKey(eKeys key)
-{
- eOSState state;
-
- if (key != kNone) {
- dsyslog("[plex]%s: key=%d\n", __FUNCTION__, key);
- }
-
- if (!PlayerIsRunning()) { // check if player is still alive
- dsyslog("[plex]: player died\n");
- Hide();
- //FIXME: Stop();
- cControl::Shutdown();
- return osEnd;
- }
-
- if (infoVisible) { // if RecordingInfo visible then update
- if (timeoutShow && time(0) > timeoutShow) {
- Hide();
- timeoutShow = 0;
- infoVisible = false;
- } else
- ShowProgress();
- }
- //state=cOsdMenu::ProcessKey(key);
- state = osContinue;
- switch ((int)key) { // cast to shutup g++ warnings
- case kUp:
- if (PlayerDvdNav) {
- PlayerSendDvdNavUp();
- break;
- }
- case kPlay:
- Hide();
- if (PlayerSpeed != 1) {
- PlayerSendSetSpeed(PlayerSpeed = 1);
- }
- if (PlayerPaused) {
- PlayerSendPause();
- PlayerPaused ^= 1;
- }
- Show();
- break;
-
- case kDown:
- if (PlayerDvdNav) {
- PlayerSendDvdNavDown();
- break;
- }
- case kPause:
- PlayerSendPause();
- PlayerPaused ^= 1;
- Show();
- break;
-
- case kFastRew | k_Release:
- case kLeft | k_Release:
- if (Setup.MultiSpeedMode) {
- break;
- }
- // FIXME:
- break;
- case kLeft:
- if (PlayerDvdNav) {
- PlayerSendDvdNavLeft();
- break;
- }
- case kFastRew:
- if (PlayerSpeed > 1) {
- PlayerSendSetSpeed(PlayerSpeed /= 2);
- } else {
- PlayerSendSeek(-10);
- }
- Show();
- break;
- case kRight:
- if (PlayerDvdNav) {
- PlayerSendDvdNavRight();
- break;
- }
- case kFastFwd:
- if (PlayerSpeed < 32) {
- PlayerSendSetSpeed(PlayerSpeed *= 2);
- }
- Show();
- break;
-
- case kRed:
- // FIXME: TimeSearch();
- break;
-
-#ifdef USE_JUMPINGSECONDS
- case kGreen | k_Repeat:
- PlayerSendSeek(-Setup.JumpSecondsRepeat);
- break;
- case kGreen:
- PlayerSendSeek(-Setup.JumpSeconds);
- break;
- case k1 | k_Repeat:
- case k1:
- PlayerSendSeek(-Setup.JumpSecondsSlow);
- break;
- case k3 | k_Repeat:
- case k3:
- PlayerSendSeek(Setup.JumpSecondsSlow);
- break;
- case kYellow | k_Repeat:
- PlayerSendSeek(Setup.JumpSecondsRepeat);
- break;
- case kYellow:
- PlayerSendSeek(Setup.JumpSeconds);
- break;
-#else
- case kGreen | k_Repeat:
- case kGreen:
- PlayerSendSeek(-60);
- break;
- case kYellow | k_Repeat:
- case kYellow:
- PlayerSendSeek(+60);
- break;
-#endif /* JUMPINGSECONDS */
-#ifdef USE_LIEMIKUUTIO
-#ifndef USE_JUMPINGSECONDS
- case k1 | k_Repeat:
- case k1:
- PlayerSendSeek(-20);
- break;
- case k3 | k_Repeat:
- case k3:
- PlayerSendSeek(+20);
- break;
-#endif /* JUMPINGSECONDS */
-#endif
-
- case kStop:
- case kBlue:
- dsyslog("[plex]: player stopped\n");
- Hide();
- // FIXME: Stop();
- cControl::Shutdown();
- return osEnd;
-
- case kOk:
- if (PlayerDvdNav) {
- PlayerSendDvdNavSelect();
- // FIXME: PlayerDvdNav = 0;
- break;
- }
- if (infoVisible) {
- Hide();
- infoVisible = false;
- } else
- Show();
- break;
-
- case kBack:
- if (PlayerDvdNav > 1) {
- PlayerSendDvdNavPrev();
- break;
- }
- PlayerSendQuit();
- // FIXME: need to select old directory and index
- // FIXME: this shows a half drawn OSD
- cRemote::CallPlugin(PLUGINNAME);
- return osBack;
-
- case kMenu: // VDR: eats the keys
- case k5:
- if (PlayerDvdNav) {
- PlayerSendDvdNavMenu();
- break;
- }
- break;
-
- case kAudio: // VDR: eats the keys
- case k7:
- // FIXME: audio menu
- PlayerSendSwitchAudio();
- break;
- case kSubtitles: // VDR: eats the keys
- case k9:
- // FIXME: subtitle menu
- PlayerSendSubSelect();
- break;
-
- default:
- break;
- }
-
- return state;
-}
/**
** Play a file.
@@ -564,7 +121,8 @@ eOSState cMyControl::ProcessKey(eKeys key)
static void PlayFile(const char *filename)
{
dsyslog("[plex]: play file '%s'\n", filename);
- cControl::Launch(new cMyControl(filename));
+ //cControl::Launch(new cMyControl(filename));
+ cControl::Launch(new cHlsPlayerControl(new cHlsPlayer(filename), "Test Title"));
}
//////////////////////////////////////////////////////////////////////////////
@@ -695,7 +253,11 @@ eOSState cPlexBrowser::ProcessSelected() {
if(item->IsVideo()) {
plexclient::Video* pVid = item->GetAttachedVideo();
fullUri = pService->GetServer()->GetUri() + pVid->m_pMedia->m_sPartKey;
- PlayFile(fullUri.c_str());
+ //PlayFile(fullUri.c_str());
+ //std::cout << "TrancodeUri: " << pService->GetTranscodeUrl(pVid) << std::endl;
+ std::cout << "TrancodeUri: " << pService->GetUniversalTranscodeUrl(pVid) << std::endl;
+
+ PlayFile(pService->GetUniversalTranscodeUrl(pVid).c_str());
return osEnd;
}
@@ -792,291 +354,9 @@ eOSState cPlayMenu::ProcessKey(eKeys key)
}
//////////////////////////////////////////////////////////////////////////////
-// cOsd
-//////////////////////////////////////////////////////////////////////////////
-
-
-
-volatile char cMyOsd::Dirty; ///< flag force redraw everything
-
-/**
-** Sets this OSD to be the active one.
-**
-** @param on true on, false off
-**
-** @note only needed as workaround for text2skin plugin with
-** undrawn areas.
-*/
-void cMyOsd::SetActive(bool on)
-{
- dsyslog("[plex]%s: %d\n", __FUNCTION__, on);
-
- if (Active() == on) {
- return; // already active, no action
- }
- cOsd::SetActive(on);
-
- // ignore sub-title, if menu is open
- if (OsdLevel >= OSD_LEVEL_SUBTITLES && IsOpen()) {
- return;
- }
-
- if (on) {
- Dirty = 1;
- // only flush here if there are already bitmaps
- //if (GetBitmap(0)) {
- // Flush();
- //}
- OsdOpen();
- } else {
- OsdClose();
- }
-}
-
-/**
-** Constructor OSD.
-**
-** Initializes the OSD with the given coordinates.
-**
-** @param left x-coordinate of osd on display
-** @param top y-coordinate of osd on display
-** @param level level of the osd (smallest is shown)
-*/
-cMyOsd::cMyOsd(int left, int top, uint level)
-:cOsd(left, top, level)
-{
- /* FIXME: OsdWidth/OsdHeight not correct!
- dsyslog("[plex]%s: %dx%d+%d+%d, %d\n", __FUNCTION__, OsdWidth(),
- OsdHeight(), left, top, level);
- */
-
- OsdLevel = level;
- SetActive(true);
-}
-
-/**
-** OSD Destructor.
-**
-** Shuts down the OSD.
-*/
-cMyOsd::~cMyOsd(void)
-{
- dsyslog("[plex]%s:\n", __FUNCTION__);
- SetActive(false);
- // done by SetActive: OsdClose();
-}
-
-/**
-** Actually commits all data to the OSD hardware.
-*/
-void cMyOsd::Flush(void)
-{
- cPixmapMemory *pm;
-
- dsyslog("[plex]%s: level %d active %d\n", __FUNCTION__, OsdLevel,
- Active());
-
- if (!Active()) { // this osd is not active
- return;
- }
- // don't draw sub-title if menu is active
- if (OsdLevel >= OSD_LEVEL_SUBTITLES && IsOpen()) {
- return;
- }
- //
- // VDR draws subtitle without clearing the old
- //
- if (OsdLevel >= OSD_LEVEL_SUBTITLES) {
- OsdClear();
- cMyOsd::Dirty = 1;
- dsyslog("[plex]%s: subtitle clear\n", __FUNCTION__);
- }
-
- if (!IsTrueColor()) {
- cBitmap *bitmap;
- int i;
-
- // draw all bitmaps
- for (i = 0; (bitmap = GetBitmap(i)); ++i) {
- uint8_t *argb;
- int x;
- int y;
- int w;
- int h;
- int x1;
- int y1;
- int x2;
- int y2;
-
- // get dirty bounding box
- if (Dirty) { // forced complete update
- x1 = 0;
- y1 = 0;
- x2 = bitmap->Width() - 1;
- y2 = bitmap->Height() - 1;
- } else if (!bitmap->Dirty(x1, y1, x2, y2)) {
- continue; // nothing dirty continue
- }
- // convert and upload only dirty areas
- w = x2 - x1 + 1;
- h = y2 - y1 + 1;
- if (1) { // just for the case it makes trouble
- int width;
- int height;
- double video_aspect;
-
- ::GetOsdSize(&width, &height, &video_aspect);
- if (w > width) {
- w = width;
- x2 = x1 + width - 1;
- }
- if (h > height) {
- h = height;
- y2 = y1 + height - 1;
- }
- }
-#ifdef DEBUG
- if (w > bitmap->Width() || h > bitmap->Height()) {
- esyslog(tr("[plex]: dirty area too big\n"));
- abort();
- }
-#endif
- argb = (uint8_t *) malloc(w * h * sizeof(uint32_t));
- for (y = y1; y <= y2; ++y) {
- for (x = x1; x <= x2; ++x) {
- ((uint32_t *) argb)[x - x1 + (y - y1) * w] =
- bitmap->GetColor(x, y);
- }
- }
- dsyslog("[plex]%s: draw %dx%d%+d%+d bm\n", __FUNCTION__, w, h,
- Left() + bitmap->X0() + x1, Top() + bitmap->Y0() + y1);
- OsdDrawARGB(Left() + bitmap->X0() + x1, Top() + bitmap->Y0() + y1,
- w, h, argb);
-
- bitmap->Clean();
- // FIXME: reuse argb
- free(argb);
- }
- cMyOsd::Dirty = 0;
- return;
- }
-
- LOCK_PIXMAPS;
- while ((pm = RenderPixmaps())) {
- int x;
- int y;
- int w;
- int h;
-
- x = Left() + pm->ViewPort().X();
- y = Top() + pm->ViewPort().Y();
- w = pm->ViewPort().Width();
- h = pm->ViewPort().Height();
-
- dsyslog("[plex]%s: draw %dx%d%+d%+d %p\n", __FUNCTION__, w, h, x, y,
- pm->Data());
- OsdDrawARGB(x, y, w, h, pm->Data());
-
- delete pm;
- }
- cMyOsd::Dirty = 0;
-}
-
-//////////////////////////////////////////////////////////////////////////////
-// cOsdProvider
-//////////////////////////////////////////////////////////////////////////////
-
-cOsd *cMyOsdProvider::Osd; ///< single osd
-
-/**
-** Create a new OSD.
-**
-** @param left x-coordinate of OSD
-** @param top y-coordinate of OSD
-** @param level layer level of OSD
-*/
-cOsd *cMyOsdProvider::CreateOsd(int left, int top, uint level)
-{
- dsyslog("[plex]%s: %d, %d, %d\n", __FUNCTION__, left, top, level);
-
- return Osd = new cMyOsd(left, top, level);
-}
-
-/**
-** Check if this OSD provider is able to handle a true color OSD.
-**
-** @returns true we are able to handle a true color OSD.
-*/
-bool cMyOsdProvider::ProvidesTrueColor(void)
-{
- return true;
-}
-
-/**
-** Create cOsdProvider class.
-*/
-cMyOsdProvider::cMyOsdProvider(void)
-: cOsdProvider()
-{
- dsyslog("[plex]%s:\n", __FUNCTION__);
-}
-
-
-//////////////////////////////////////////////////////////////////////////////
-// cDevice
-//////////////////////////////////////////////////////////////////////////////
-
-/**
-** Device constructor.
-*/
-cMyDevice::cMyDevice(void)
-{
- dsyslog("[plex]%s\n", __FUNCTION__);
-}
-
-/**
-** Device destructor. (never called!)
-*/
-cMyDevice::~cMyDevice(void)
-{
- dsyslog("[plex]%s:\n", __FUNCTION__);
-}
-
-/**
-** Informs a device that it will be the primary device.
-**
-** @param on flag if becoming or loosing primary
-*/
-void cMyDevice::MakePrimaryDevice(bool on)
-{
- dsyslog("[plex]%s: %d\n", __FUNCTION__, on);
-
- cDevice::MakePrimaryDevice(on);
- if (on) {
- new cMyOsdProvider();
- }
-}
-
-/**
-** Returns the width, height and pixel_aspect ratio the OSD.
-**
-** FIXME: Called every second, for nothing (no OSD displayed)?
-*/
-void cMyDevice::GetOsdSize(int &width, int &height, double &pixel_aspect)
-{
- if (!&width || !&height || !&pixel_aspect) {
- esyslog(tr("[plex]: GetOsdSize invalid pointer(s)\n"));
- return;
- }
- ::GetOsdSize(&width, &height, &pixel_aspect);
-}
-
-//////////////////////////////////////////////////////////////////////////////
// cPlugin
//////////////////////////////////////////////////////////////////////////////
-static cMyDevice *MyDevice; ///< dummy device needed for osd
-
/**
** Initialize any member variables here.
**
@@ -1125,7 +405,6 @@ const char *cMyPlugin::Description(void)
*/
const char *cMyPlugin::CommandLineHelp(void)
{
- return::CommandLineHelp();
}
/**
@@ -1133,7 +412,6 @@ const char *cMyPlugin::CommandLineHelp(void)
*/
bool cMyPlugin::ProcessArgs(int argc, char *argv[])
{
- return::ProcessArgs(argc, argv);
}
/**
@@ -1162,8 +440,6 @@ bool cMyPlugin::Initialize(void)
perror("No Plexserver found");
std::cout << "No Plexmediaserver found" << std::endl;
}
-
- MyDevice = new cMyDevice;
return true;
}
@@ -1198,14 +474,6 @@ cOsdObject *cMyPlugin::MainMenuAction(void)
*/
bool cMyPlugin::Service(const char *id, void *data)
{
- if (strcmp(id, PLEX_OSD_3DMODE_SERVICE) == 0) {
- VideoSetOsd3DMode(0);
- Play_Osd3DModeService_v1_0_t *r =
- (Play_Osd3DModeService_v1_0_t *) data;
- VideoSetOsd3DMode(r->Mode);
- return true;
- }
- return false;
}
/**
@@ -1216,11 +484,7 @@ bool cMyPlugin::Service(const char *id, void *data)
*/
const char **cMyPlugin::SVDRPHelpPages(void)
{
- static const char *HelpPages[] = {
- "3DOF\n" " TURN OFF 3D", "3DTB\n" " TURN ON 3D TB",
- "3DSB\n" " TURN ON 3D SBS", NULL
- };
- return HelpPages;
+ return NULL;
}
/**
@@ -1230,22 +494,8 @@ const char **cMyPlugin::SVDRPHelpPages(void)
** @param option all command arguments
** @param reply_code reply code
*/
-cString cMyPlugin::SVDRPCommand(const char *command,
- __attribute__ ((unused)) const char *option,
- __attribute__ ((unused)) int &reply_code)
+cString cMyPlugin::SVDRPCommand(const char *command, const char *option, int &reply_code)
{
- if (!strcasecmp(command, "3DOF")) {
- VideoSetOsd3DMode(0);
- return "3d off";
- }
- if (!strcasecmp(command, "3DSB")) {
- VideoSetOsd3DMode(1);
- return "3d sbs";
- }
- if (!strcasecmp(command, "3DTB")) {
- VideoSetOsd3DMode(2);
- return "3d tb";
- }
return NULL;
}
@@ -1301,39 +551,4 @@ bool cMyPlugin::SetupParse(const char *name, const char *value)
return true;
}
-//////////////////////////////////////////////////////////////////////////////
-
-int OldPrimaryDevice; ///< old primary device
-
-/**
-** Enable dummy device.
-*/
-extern "C" void EnableDummyDevice(void)
-{
- OldPrimaryDevice = cDevice::PrimaryDevice()->DeviceNumber() + 1;
-
- dsyslog("[plex]: primary device %d to new %d\n", OldPrimaryDevice,
- MyDevice->DeviceNumber() + 1);
-
- //if (!cDevice::SetPrimaryDevice(MyDevice->DeviceNumber() + 1)) {
- DoMakePrimary = MyDevice->DeviceNumber() + 1;
- cOsdProvider::Shutdown();
- //}
-}
-
-/**
-** Disable dummy device.
-*/
-extern "C" void DisableDummyDevice(void)
-{
- dsyslog("[plex]: primary device %d to old %d\n",
- cDevice::PrimaryDevice()->DeviceNumber() + 1, OldPrimaryDevice);
-
- //if (!cDevice::SetPrimaryDevice(OldPrimaryDevice)) {
- DoMakePrimary = OldPrimaryDevice;
- OldPrimaryDevice = 0;
- cOsdProvider::Shutdown();
- //}
-}
-
VDRPLUGINCREATOR(cMyPlugin); // Don't touch this!
diff --git a/plex.h b/plex.h
index a81f08e..d5e6dc5 100644
--- a/plex.h
+++ b/plex.h
@@ -16,6 +16,7 @@
#include "plexgdm.h"
#include "play_service.h"
#include "cPlexOsdItem.h"
+#include "hlsPlayerControl.h"
#include <iostream>
#include <string>
@@ -23,7 +24,6 @@
#include <iterator>
#include <algorithm>
-
/**
** Device plugin remote class.
*/
@@ -214,7 +214,8 @@ class cMyPlugin:public cPlugin
virtual const char **SVDRPHelpPages(void);
virtual cString SVDRPCommand(const char *, const char *, int &);
- private:
+private:
+ Poco::Crypto::OpenSSLInitializer _openSSLInitializer; //Bug in Poco::Crypto, see https://github.com/pocoproject/poco/issues/527
};
#endif \ No newline at end of file
diff --git a/video.c b/video.c
deleted file mode 100644
index 7fe2fff..0000000
--- a/video.c
+++ /dev/null
@@ -1,775 +0,0 @@
-///
-/// @file video.c @brief Video module
-///
-/// Copyright (c) 2012, 2013 by Johns. All Rights Reserved.
-///
-/// Contributor(s):
-///
-/// License: AGPLv3
-///
-/// This program is free software: you can redistribute it and/or modify
-/// it under the terms of the GNU Affero General Public License as
-/// published by the Free Software Foundation, either version 3 of the
-/// License.
-///
-/// 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 Affero General Public License for more details.
-///
-/// $Id: 54d117902655b23d2eff9ecaf59ce4eab5f46d42 $
-//////////////////////////////////////////////////////////////////////////////
-
-///
-/// @defgroup Video The video module.
-///
-/// This module contains all video rendering functions.
-///
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include <string.h>
-#include <unistd.h>
-#include <errno.h>
-
-#include <libintl.h>
-#define _(str) gettext(str) ///< gettext shortcut
-#define _N(str) str ///< gettext_noop shortcut
-
-#include "misc.h"
-#include "video.h"
-
-//////////////////////////////////////////////////////////////////////////////
-// X11 / XCB
-//////////////////////////////////////////////////////////////////////////////
-
-#include <xcb/xcb.h>
-#include <xcb/xcb_icccm.h>
-#include <xcb/xcb_image.h>
-#include <xcb/xcb_pixel.h>
-#include <xcb/xcb_event.h>
-#include <xcb/xcb_keysyms.h>
-#include <X11/keysym.h> // keysym XK_
-#include <X11/XF86keysym.h> // XF86XK_
-#include <poll.h>
-
-static xcb_connection_t *Connection; ///< xcb connection
-static xcb_colormap_t VideoColormap; ///< video colormap
-static xcb_window_t VideoOsdWindow; ///< video osd window
-static xcb_window_t VideoPlayWindow; ///< video player window
-static xcb_screen_t const *VideoScreen; ///< video screen
-static uint32_t VideoBlankTick; ///< blank cursor timer
-static xcb_pixmap_t VideoPixmap; ///< blank cursor pixmap
-static xcb_cursor_t VideoBlankCursor; ///< empty invisible cursor
-
-static uint32_t VideoColorKey; ///< color key pixel value
-
-static int VideoWindowX; ///< video output window x coordinate
-static int VideoWindowY; ///< video outout window y coordinate
-static unsigned VideoWindowWidth; ///< video output window width
-static unsigned VideoWindowHeight; ///< video output window height
-
-static char Osd3DMode; ///< 3D OSD mode
-
-///
-/// Create X11 window.
-///
-/// @param parent parent of new window
-/// @param visual visual of parent
-/// @param depth depth of parent
-///
-/// @returns created X11 window id
-///
-static xcb_window_t VideoCreateWindow(xcb_window_t parent,
- xcb_visualid_t visual, uint8_t depth)
-{
- uint32_t values[5];
- xcb_window_t window;
-
- Debug(3, "video: visual %#0x depth %d\n", visual, depth);
-
- //
- // create color map
- //
- if (VideoColormap == XCB_NONE) {
- VideoColormap = xcb_generate_id(Connection);
- xcb_create_colormap(Connection, XCB_COLORMAP_ALLOC_NONE, VideoColormap,
- parent, visual);
- }
- //
- // create blank cursor
- //
- if (VideoBlankCursor == XCB_NONE) {
- VideoPixmap = xcb_generate_id(Connection);
- xcb_create_pixmap(Connection, 1, VideoPixmap, parent, 1, 1);
- VideoBlankCursor = xcb_generate_id(Connection);
- xcb_create_cursor(Connection, VideoBlankCursor, VideoPixmap,
- VideoPixmap, 0, 0, 0, 0, 0, 0, 1, 1);
- VideoBlankTick = 0;
- }
-
- values[0] = VideoColorKey; // ARGB
- values[1] = VideoColorKey;
- values[2] =
- XCB_EVENT_MASK_KEY_PRESS | XCB_EVENT_MASK_KEY_RELEASE |
- XCB_EVENT_MASK_BUTTON_PRESS | XCB_EVENT_MASK_BUTTON_RELEASE |
- XCB_EVENT_MASK_POINTER_MOTION | XCB_EVENT_MASK_EXPOSURE |
- XCB_EVENT_MASK_STRUCTURE_NOTIFY;
- values[3] = VideoColormap;
- values[4] = VideoBlankCursor;
- window = xcb_generate_id(Connection);
- xcb_create_window(Connection, depth, window, parent, VideoWindowX,
- VideoWindowY, VideoWindowWidth, VideoWindowHeight, 0,
- XCB_WINDOW_CLASS_INPUT_OUTPUT, visual,
- XCB_CW_BACK_PIXEL | XCB_CW_BORDER_PIXEL | XCB_CW_EVENT_MASK |
- XCB_CW_COLORMAP | XCB_CW_CURSOR, values);
-
- // define only available with xcb-utils-0.3.8
-#ifdef XCB_ICCCM_NUM_WM_SIZE_HINTS_ELEMENTS
- // FIXME: utf _NET_WM_NAME
- xcb_icccm_set_wm_name(Connection, window, XCB_ATOM_STRING, 8,
- sizeof("play control") - 1, "play control");
- xcb_icccm_set_wm_icon_name(Connection, window, XCB_ATOM_STRING, 8,
- sizeof("play control") - 1, "play control");
-#endif
- // define only available with xcb-utils-0.3.6
-#ifdef XCB_NUM_WM_HINTS_ELEMENTS
- // FIXME: utf _NET_WM_NAME
- xcb_set_wm_name(Connection, window, XCB_ATOM_STRING,
- sizeof("play control") - 1, "play control");
- xcb_set_wm_icon_name(Connection, window, XCB_ATOM_STRING,
- sizeof("play control") - 1, "play control");
-#endif
-
- // FIXME: size hints
-
- // window above parent
- values[0] = parent;
- values[1] = XCB_STACK_MODE_ABOVE;
- xcb_configure_window(Connection, window,
- XCB_CONFIG_WINDOW_SIBLING | XCB_CONFIG_WINDOW_STACK_MODE, values);
-
- return window;
-}
-
-///
-/// Enable OSD 3d mode.
-///
-/// @param mode turn 3d mode on/off
-///
-void VideoSetOsd3DMode(int mode)
-{
- Osd3DMode = mode;
-}
-
-///
-/// Draw a ARGB image.
-///
-/// @param x x position of image in osd
-/// @param y y position of image in osd
-/// @param width width of image
-/// @param height height of image
-/// @param argb argb image
-///
-void VideoDrawARGB(int x, int y, int width, int height, const uint8_t * argb)
-{
- xcb_image_t *xcb_image;
- xcb_gcontext_t gc;
- int sx;
- int sy;
- int fs;
-
- if (!Connection) {
- Debug(3, "play: FIXME: must restore osd provider\n");
- return;
- }
-
- if (x + y < 1 && (unsigned)height == VideoWindowHeight
- && (unsigned)width == VideoWindowWidth) {
- fs = 1;
- } else {
- fs = 0;
- }
-
- gc = xcb_generate_id(Connection);
- xcb_create_gc(Connection, gc, VideoOsdWindow, 0, NULL);
-
- switch (Osd3DMode) {
- case 1: // SBS
- xcb_image =
- xcb_image_create_native(Connection, width / 2, height,
- XCB_IMAGE_FORMAT_Z_PIXMAP, VideoScreen->root_depth, NULL, 0L,
- NULL);
- break;
- case 2: // TB
- xcb_image =
- xcb_image_create_native(Connection, width, height / 2,
- XCB_IMAGE_FORMAT_Z_PIXMAP, VideoScreen->root_depth, NULL, 0L,
- NULL);
- break;
- default:
- xcb_image =
- xcb_image_create_native(Connection, width, height,
- XCB_IMAGE_FORMAT_Z_PIXMAP, VideoScreen->root_depth, NULL, 0L,
- NULL);
- }
-
- // fast 32it versions
- if (xcb_image->bpp == 32) {
- if (xcb_image->byte_order == XCB_IMAGE_ORDER_LSB_FIRST) {
- for (sy = 0; sy < height; ++sy) {
- for (sx = 0; sx < width; ++sx) {
- uint32_t pixel;
-
- if (argb[(width * sy + sx) * 4 + 3] < 200) {
- pixel = VideoColorKey;
- } else {
- pixel = argb[(width * sy + sx) * 4 + 0] << 0;
- pixel |= argb[(width * sy + sx) * 4 + 1] << 8;
- pixel |= argb[(width * sy + sx) * 4 + 2] << 16;
- }
- switch (Osd3DMode) {
- case 1: // SBS
- xcb_image_put_pixel_Z32L(xcb_image, sx / 2, sy,
- pixel);
- break;
- case 2: // TB
- xcb_image_put_pixel_Z32L(xcb_image, sx, sy / 2,
- pixel);
- break;
- default:
- xcb_image_put_pixel_Z32L(xcb_image, sx, sy, pixel);
- }
- }
- }
- } else {
- Error(_("play: unsupported put_image\n"));
- }
- } else {
- for (sy = 0; sy < height; ++sy) {
- for (sx = 0; sx < width; ++sx) {
- uint32_t pixel;
-
- if (argb[(width * sy + sx) * 4 + 3] < 200) {
- pixel = argb[(width * sy + sx) * 4 + 3] << 0;
- pixel |= argb[(width * sy + sx) * 4 + 3] << 8;
- pixel |= argb[(width * sy + sx) * 4 + 3] << 16;
- } else {
- pixel = argb[(width * sy + sx) * 4 + 0] << 0;
- pixel |= argb[(width * sy + sx) * 4 + 1] << 8;
- pixel |= argb[(width * sy + sx) * 4 + 2] << 16;
- }
- switch (Osd3DMode) {
- case 1: // SBS
- xcb_image_put_pixel(xcb_image, sx / 2, sy, pixel);
- break;
- case 2: // TB
- xcb_image_put_pixel(xcb_image, sx, sy / 2, pixel);
- break;
- default:
- xcb_image_put_pixel(xcb_image, sx, sy, pixel);
- }
- }
- }
- }
-
- // render xcb_image to color data pixmap
- switch (Osd3DMode) {
- case 1: // SBS
- if (fs) {
- xcb_image_put(Connection, VideoOsdWindow, gc, xcb_image, x, y,
- 0);
- xcb_image_put(Connection, VideoOsdWindow, gc, xcb_image,
- x + VideoWindowWidth / 2, y, 0);
- } else {
- xcb_image_put(Connection, VideoOsdWindow, gc, xcb_image, x / 2,
- y, 0);
- xcb_image_put(Connection, VideoOsdWindow, gc, xcb_image,
- x / 2 + VideoWindowWidth / 2, y, 0);
- }
- break;
- case 2: // TB
- if (fs) {
- xcb_image_put(Connection, VideoOsdWindow, gc, xcb_image, x, y,
- 0);
- xcb_image_put(Connection, VideoOsdWindow, gc, xcb_image, x,
- y + VideoWindowHeight / 2, 0);
- } else {
- xcb_image_put(Connection, VideoOsdWindow, gc, xcb_image, x,
- y / 2, 0);
- xcb_image_put(Connection, VideoOsdWindow, gc, xcb_image, x,
- y / 2 + VideoWindowHeight / 2, 0);
- }
- break;
- default:
- xcb_image_put(Connection, VideoOsdWindow, gc, xcb_image, x, y, 0);
- }
- // release xcb_image
- xcb_image_destroy(xcb_image);
- xcb_free_gc(Connection, gc);
- xcb_flush(Connection);
-}
-
-///
-/// Show window.
-///
-void VideoWindowShow(void)
-{
- if (!Connection) {
- Debug(3, "play: FIXME: must restore osd provider\n");
- return;
- }
- xcb_map_window(Connection, VideoOsdWindow);
-}
-
-///
-/// Hide window.
-///
-void VideoWindowHide(void)
-{
- if (!Connection) {
- Debug(3, "play: FIXME: must restore osd provider\n");
- return;
- }
- xcb_unmap_window(Connection, VideoOsdWindow);
-}
-
-///
-/// Clear window.
-///
-void VideoWindowClear(void)
-{
- if (!Connection) {
- Debug(3, "play: FIXME: must restore osd provider\n");
- return;
- }
- xcb_clear_area(Connection, 0, VideoOsdWindow, 0, 0, VideoWindowWidth,
- VideoWindowHeight);
- xcb_flush(Connection);
-}
-
-static xcb_key_symbols_t *XcbKeySymbols; ///< Keyboard symbols
-static uint16_t NumLockMask; ///< mod mask for num-lock
-static uint16_t ShiftLockMask; ///< mod mask for shift-lock
-static uint16_t CapsLockMask; ///< mod mask for caps-lock
-static uint16_t ModeSwitchMask; ///< mod mask for mode-switch
-
-///
-/// Handle key press event.
-///
-static void VideoKeyPress(const xcb_key_press_event_t * event)
-{
- char buf[2];
- xcb_keysym_t ks0;
- xcb_keysym_t ks1;
- xcb_keysym_t keysym;
- xcb_keycode_t keycode;
- unsigned modifier;
-
- if (!XcbKeySymbols) {
- XcbKeySymbols = xcb_key_symbols_alloc(Connection);
- if (!XcbKeySymbols) {
- Error(_("play/event: can't read key symbols\n"));
- return;
- }
- NumLockMask = ShiftLockMask = CapsLockMask = ModeSwitchMask = 0;
-
- // FIXME: lock and mode keys are not prepared!
- }
-
- keycode = event->detail;
- modifier = event->state;
- // handle mode-switch
- if (modifier & ModeSwitchMask) {
- ks0 = xcb_key_symbols_get_keysym(XcbKeySymbols, keycode, 2);
- ks1 = xcb_key_symbols_get_keysym(XcbKeySymbols, keycode, 3);
- } else {
- ks0 = xcb_key_symbols_get_keysym(XcbKeySymbols, keycode, 0);
- ks1 = xcb_key_symbols_get_keysym(XcbKeySymbols, keycode, 1);
- }
- // use first keysym, if second keysym didn't exists
- if (ks1 == XCB_NO_SYMBOL) {
- ks1 = ks0;
- }
- // see xcb-util-0.3.6/keysyms/keysyms.c:
- if (!(modifier & XCB_MOD_MASK_SHIFT) && !(modifier & XCB_MOD_MASK_LOCK)) {
- keysym = ks0;
- } else {
- // FIXME: more cases
-
- keysym = ks0;
- }
-
- // FIXME: use xcb_lookup_string
- switch (keysym) {
- case XK_space:
- FeedKeyPress("XKeySym", "space", 0, 0);
- break;
- case XK_exclam ... XK_slash:
- case XK_0 ... XK_9:
- case XK_A ... XK_Z:
- case XK_a ... XK_z:
- buf[0] = keysym;
- buf[1] = '\0';
- FeedKeyPress("XKeySym", buf, 0, 0);
- break;
-
- case XK_BackSpace:
- FeedKeyPress("XKeySym", "BackSpace", 0, 0);
- break;
- case XK_Tab:
- FeedKeyPress("XKeySym", "Tab", 0, 0);
- break;
- case XK_Return:
- FeedKeyPress("XKeySym", "Return", 0, 0);
- break;
- case XK_Escape:
- FeedKeyPress("XKeySym", "Escape", 0, 0);
- break;
- case XK_Delete:
- FeedKeyPress("XKeySym", "Delete", 0, 0);
- break;
-
- case XK_Home:
- FeedKeyPress("XKeySym", "Home", 0, 0);
- break;
- case XK_Left:
- FeedKeyPress("XKeySym", "Left", 0, 0);
- break;
- case XK_Up:
- FeedKeyPress("XKeySym", "Up", 0, 0);
- break;
- case XK_Right:
- FeedKeyPress("XKeySym", "Right", 0, 0);
- break;
- case XK_Down:
- FeedKeyPress("XKeySym", "Down", 0, 0);
- break;
- case XK_Page_Up:
- FeedKeyPress("XKeySym", "Page_Up", 0, 0);
- break;
- case XK_Page_Down:
- FeedKeyPress("XKeySym", "Page_Down", 0, 0);
- break;
- case XK_End:
- FeedKeyPress("XKeySym", "End", 0, 0);
- break;
- case XK_Begin:
- FeedKeyPress("XKeySym", "Begin", 0, 0);
- break;
-
- case XK_F1:
- FeedKeyPress("XKeySym", "F1", 0, 0);
- break;
- case XK_F2:
- FeedKeyPress("XKeySym", "F2", 0, 0);
- break;
- case XK_F3:
- FeedKeyPress("XKeySym", "F3", 0, 0);
- break;
- case XK_F4:
- FeedKeyPress("XKeySym", "F4", 0, 0);
- break;
- case XK_F5:
- FeedKeyPress("XKeySym", "F5", 0, 0);
- break;
- case XK_F6:
- FeedKeyPress("XKeySym", "F6", 0, 0);
- break;
- case XK_F7:
- FeedKeyPress("XKeySym", "F7", 0, 0);
- break;
- case XK_F8:
- FeedKeyPress("XKeySym", "F8", 0, 0);
- break;
- case XK_F9:
- FeedKeyPress("XKeySym", "F9", 0, 0);
- break;
- case XK_F10:
- FeedKeyPress("XKeySym", "F10", 0, 0);
- break;
- case XK_F11:
- FeedKeyPress("XKeySym", "F11", 0, 0);
- break;
- case XK_F12:
- FeedKeyPress("XKeySym", "F12", 0, 0);
- break;
-
- case XF86XK_Red:
- FeedKeyPress("XKeySym", "Red", 0, 0);
- break;
- case XF86XK_Green:
- FeedKeyPress("XKeySym", "Green", 0, 0);
- break;
- case XF86XK_Yellow:
- FeedKeyPress("XKeySym", "Yellow", 0, 0);
- break;
- case XF86XK_Blue:
- FeedKeyPress("XKeySym", "Blue", 0, 0);
- break;
-
- case XF86XK_HomePage:
- FeedKeyPress("XKeySym", "XF86HomePage", 0, 0);
- break;
- case XF86XK_AudioLowerVolume:
- FeedKeyPress("XKeySym", "XF86AudioLowerVolume", 0, 0);
- break;
- case XF86XK_AudioMute:
- FeedKeyPress("XKeySym", "XF86AudioMute", 0, 0);
- break;
- case XF86XK_AudioRaiseVolume:
- FeedKeyPress("XKeySym", "XF86AudioRaiseVolume", 0, 0);
- break;
- case XF86XK_AudioPlay:
- FeedKeyPress("XKeySym", "XF86AudioPlay", 0, 0);
- break;
- case XF86XK_AudioStop:
- FeedKeyPress("XKeySym", "XF86AudioStop", 0, 0);
- break;
- case XF86XK_AudioPrev:
- FeedKeyPress("XKeySym", "XF86AudioPrev", 0, 0);
- break;
- case XF86XK_AudioNext:
- FeedKeyPress("XKeySym", "XF86AudioNext", 0, 0);
- break;
-
- default:
- Debug(3, "play/event: keycode %d\n", event->detail);
- break;
-
- }
-}
-
-///
-/// Poll video events.
-///
-/// @param timeout timeout in milliseconds
-///
-void VideoPollEvents(int timeout)
-{
- struct pollfd fds[1];
- xcb_generic_event_t *event;
- int n;
- int delay;
-
- if (!Connection) {
- Debug(3, "play: poll without connection\n");
- return;
- }
-
- fds[0].fd = xcb_get_file_descriptor(Connection);
- fds[0].events = POLLIN | POLLPRI;
-
- delay = timeout;
- for (;;) {
- xcb_flush(Connection);
-
- // wait for events or timeout
- // FIXME: this can poll forever
- if ((n = poll(fds, 1, delay)) <= 0) {
- // error or timeout
- if (n) { // error
- Error(_("play/event: poll failed: %s\n"), strerror(errno));
- }
- return;
- }
- if (fds[0].revents & (POLLIN | POLLPRI)) {
- if ((event = xcb_poll_for_event(Connection))) {
-
- switch (XCB_EVENT_RESPONSE_TYPE(event)) {
-#if 0
- // background pixmap no need to redraw
- case XCB_EXPOSE:
- // collapse multi expose
- if (!((xcb_expose_event_t *) event)->count) {
- xcb_clear_area(Connection, 0, Window, 0, 0, 64,
- 64);
- // flush the request
- xcb_flush(Connection);
- }
- break;
-#endif
- case XCB_MAP_NOTIFY:
- Debug(3, "video/event: MapNotify\n");
- // hide cursor after mapping
- xcb_change_window_attributes(Connection,
- VideoOsdWindow, XCB_CW_CURSOR, &VideoBlankCursor);
- xcb_change_window_attributes(Connection,
- VideoPlayWindow, XCB_CW_CURSOR, &VideoBlankCursor);
- break;
- case XCB_DESTROY_NOTIFY:
- return;
- case XCB_KEY_PRESS:
- VideoKeyPress((xcb_key_press_event_t *) event);
- break;
- case XCB_KEY_RELEASE:
- case XCB_BUTTON_PRESS:
- case XCB_BUTTON_RELEASE:
- break;
- case XCB_MOTION_NOTIFY:
- break;
-
- case 0:
- // error_code
- Debug(3, "play/event: error %x\n",
- event->response_type);
- break;
- default:
- // unknown event type, ignore it
- Debug(3, "play/event: unknown %x\n",
- event->response_type);
- break;
- }
-
- free(event);
- } else {
- // no event, can happen, but we must check for close
- if (xcb_connection_has_error(Connection)) {
- return;
- }
- }
- }
- }
-}
-
-///
-/// Get OSD size.
-///
-/// @param[out] width OSD width
-/// @param[out] height OSD height
-///
-void VideoGetOsdSize(int *width, int *height)
-{
- *width = 1920;
- *height = 1080; // unknown default
- if (VideoWindowWidth && VideoWindowHeight) {
- *width = VideoWindowWidth;
- *height = VideoWindowHeight;
- }
-}
-
-///
-/// Get player video window id.
-///
-int VideoGetPlayWindow(void)
-{
- return VideoPlayWindow;
-}
-
-///
-/// Set video geometry.
-///
-/// @todo write/search the good version
-///
-void VideoSetGeometry(const char *geometry)
-{
- sscanf(geometry, "%dx%d%d%d", &VideoWindowWidth, &VideoWindowHeight,
- &VideoWindowX, &VideoWindowY);
-}
-
-///
-/// Set video color key.
-///
-/// Should be called before VideoInit().
-///
-void VideoSetColorKey(uint32_t color_key)
-{
- VideoColorKey = color_key;
-}
-
-///
-/// Initialize video.
-///
-int VideoInit(const char *display)
-{
- const char *display_name;
- xcb_connection_t *connection;
- xcb_screen_iterator_t iter;
- int screen_nr;
- int i;
-
- display_name = display ? display : getenv("DISPLAY");
-
- // Open the connection to the X server.
- connection = xcb_connect(display_name, &screen_nr);
- if (!connection || xcb_connection_has_error(connection)) {
- fprintf(stderr, "play: can't connect to X11 server on %s\n",
- display_name);
- return -1;
- }
- Connection = connection;
-
- // Get the requested screen number
- iter = xcb_setup_roots_iterator(xcb_get_setup(connection));
- for (i = 0; i < screen_nr; ++i) {
- xcb_screen_next(&iter);
- }
- VideoScreen = iter.data;
-
- //
- // Default window size
- //
- if (!VideoWindowHeight) {
- if (VideoWindowWidth) {
- VideoWindowHeight = (VideoWindowWidth * 9) / 16;
- } else { // default to fullscreen
- VideoWindowHeight = VideoScreen->height_in_pixels;
- VideoWindowWidth = VideoScreen->width_in_pixels;
- }
- }
- if (!VideoWindowWidth) {
- VideoWindowWidth = (VideoWindowHeight * 16) / 9;
- }
-
- VideoPlayWindow =
- VideoCreateWindow(VideoScreen->root, VideoScreen->root_visual,
- VideoScreen->root_depth);
- xcb_map_window(Connection, VideoPlayWindow);
- VideoOsdWindow =
- VideoCreateWindow(VideoPlayWindow, VideoScreen->root_visual,
- VideoScreen->root_depth);
- Debug(3, "play: osd %x, play %x\n", VideoOsdWindow, VideoPlayWindow);
-
- VideoWindowClear();
- // done by clear: xcb_flush(Connection);
-
- return 0;
-}
-
-///
-/// Cleanup video.
-///
-void VideoExit(void)
-{
- if (VideoOsdWindow != XCB_NONE) {
- xcb_destroy_window(Connection, VideoOsdWindow);
- VideoOsdWindow = XCB_NONE;
- }
- if (VideoPlayWindow != XCB_NONE) {
- xcb_destroy_window(Connection, VideoPlayWindow);
- VideoPlayWindow = XCB_NONE;
- }
- if (VideoColormap != XCB_NONE) {
- xcb_free_colormap(Connection, VideoColormap);
- VideoColormap = XCB_NONE;
- }
- if (VideoBlankCursor != XCB_NONE) {
- xcb_free_cursor(Connection, VideoBlankCursor);
- VideoBlankCursor = XCB_NONE;
- }
- if (VideoPixmap != XCB_NONE) {
- xcb_free_pixmap(Connection, VideoPixmap);
- VideoPixmap = XCB_NONE;
- }
- if (XcbKeySymbols != XCB_NONE) {
- xcb_key_symbols_free(XcbKeySymbols);
- XcbKeySymbols = XCB_NONE;
- }
-
- if (Connection) {
- xcb_flush(Connection);
- xcb_disconnect(Connection);
- Connection = NULL;
- }
-}
diff --git a/video.h b/video.h
deleted file mode 100644
index 246dc87..0000000
--- a/video.h
+++ /dev/null
@@ -1,62 +0,0 @@
-///
-/// @file video.h @brief Video module header file
-///
-/// Copyright (c) 2012 by Johns. All Rights Reserved.
-///
-/// Contributor(s):
-///
-/// License: AGPLv3
-///
-/// This program is free software: you can redistribute it and/or modify
-/// it under the terms of the GNU Affero General Public License as
-/// published by the Free Software Foundation, either version 3 of the
-/// License.
-///
-/// 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 Affero General Public License for more details.
-///
-/// $Id: bc7bb8f7e869de413ebadbe58e4af1b603b6531e $
-//////////////////////////////////////////////////////////////////////////////
-
-/// @addtogroup Video
-/// @{
-
- /// C callback feed key press
-extern void FeedKeyPress(const char *, const char *, int, int);
-
- /// Show window.
-extern void VideoWindowShow(void);
-
- /// Hide window.
-extern void VideoWindowHide(void);
-
- /// Clear window.
-extern void VideoWindowClear(void);
-
- /// Poll video events.
-extern void VideoPollEvents(int);
-
- /// Get player window id.
-extern int VideoGetPlayWindow(void);
-
- /// Set Osd 3D Mode
-extern void VideoSetOsd3DMode(int);
-
- /// Draw an OSD ARGB image.
-extern void VideoDrawARGB(int, int, int, int, const uint8_t *);
-
- /// Get OSD size.
-extern void VideoGetOsdSize(int *, int *);
-
- /// Set video geometry.
-extern void VideoSetGeometry(const char *);
-
- /// Set video color key.
-extern void VideoSetColorKey(uint32_t);
-
-extern int VideoInit(const char *); ///< Setup video module.
-extern void VideoExit(void); ///< Cleanup and exit video module.
-
-/// @}