aboutsummaryrefslogtreecommitdiff
path: root/lib/service
diff options
context:
space:
mode:
Diffstat (limited to 'lib/service')
-rw-r--r--lib/service/listboxservice.cpp2
-rw-r--r--lib/service/servicedvb.cpp336
-rw-r--r--lib/service/servicedvb.h1
-rw-r--r--lib/service/servicedvbrecord.cpp115
-rw-r--r--lib/service/servicedvbrecord.h9
-rw-r--r--lib/service/servicemp3.cpp502
-rw-r--r--lib/service/servicemp3.h1
7 files changed, 547 insertions, 419 deletions
diff --git a/lib/service/listboxservice.cpp b/lib/service/listboxservice.cpp
index bee0e322..6cd7c625 100644
--- a/lib/service/listboxservice.cpp
+++ b/lib/service/listboxservice.cpp
@@ -584,7 +584,7 @@ void eListboxServiceContent::paint(gPainter &painter, eWindowStyle &style, const
case celServiceInfo:
{
ePtr<eServiceEvent> evt;
- if ( service_info && !service_info->getEvent(*m_cursor, evt) )
+ if ( isPlayable && service_info && !service_info->getEvent(*m_cursor, evt) )
{
std::string name = evt->getEventName();
if (!name.length())
diff --git a/lib/service/servicedvb.cpp b/lib/service/servicedvb.cpp
index af3ab206..33cd865e 100644
--- a/lib/service/servicedvb.cpp
+++ b/lib/service/servicedvb.cpp
@@ -96,217 +96,50 @@ int eStaticServiceDVBInformation::isPlayable(const eServiceReference &ref, const
return false;
}
-static void PutToDict(ePyObject &dict, const char*key, long value)
-{
- ePyObject item = PyString_FromFormat("%d", value);
- if (item)
- {
- if (PyDict_SetItemString(dict, key, item))
- eDebug("put %s to dict failed", key);
- Py_DECREF(item);
- }
- else
- eDebug("could not create PyObject for %s", key);
-}
-
-extern void PutToDict(ePyObject &dict, const char*key, const char *value);
+extern void PutToDict(ePyObject &dict, const char*key, long value); // defined in dvb/frontend.cpp
+extern void PutToDict(ePyObject &dict, const char*key, ePyObject item); // defined in dvb/frontend.cpp
+extern void PutToDict(ePyObject &dict, const char*key, const char *value); // defined in dvb/frontend.cpp
void PutSatelliteDataToDict(ePyObject &dict, eDVBFrontendParametersSatellite &feparm)
{
- const char *tmp=0;
- PutToDict(dict, "type", "Satellite");
+ PutToDict(dict, "tuner_type", "DVB-S");
PutToDict(dict, "frequency", feparm.frequency);
- PutToDict(dict, "symbolrate", feparm.symbol_rate);
- PutToDict(dict, "orbital position", feparm.orbital_position);
- switch (feparm.inversion)
- {
- case eDVBFrontendParametersSatellite::Inversion::On: tmp="ON"; break;
- case eDVBFrontendParametersSatellite::Inversion::Off: tmp="OFF"; break;
- default:
- case eDVBFrontendParametersSatellite::Inversion::Unknown: tmp="AUTO"; break;
- }
- PutToDict(dict, "inversion", tmp);
- switch (feparm.fec)
- {
- case eDVBFrontendParametersSatellite::FEC::fNone: tmp="NONE"; break;
- case eDVBFrontendParametersSatellite::FEC::f1_2: tmp="1/2"; break;
- case eDVBFrontendParametersSatellite::FEC::f2_3: tmp="2/3"; break;
- case eDVBFrontendParametersSatellite::FEC::f3_4: tmp="3/4"; break;
- case eDVBFrontendParametersSatellite::FEC::f5_6: tmp="5/6"; break;
- case eDVBFrontendParametersSatellite::FEC::f7_8: tmp="7/8"; break;
- case eDVBFrontendParametersSatellite::FEC::f3_5: tmp="3/5"; break;
- case eDVBFrontendParametersSatellite::FEC::f4_5: tmp="4/5"; break;
- case eDVBFrontendParametersSatellite::FEC::f8_9: tmp="8/9"; break;
- case eDVBFrontendParametersSatellite::FEC::f9_10: tmp="9/10"; break;
- default:
- case eDVBFrontendParametersSatellite::FEC::fAuto: tmp="AUTO"; break;
- }
- PutToDict(dict, "fec inner", tmp);
- switch (feparm.modulation)
- {
- case eDVBFrontendParametersSatellite::Modulation::Auto: tmp="AUTO"; break;
- case eDVBFrontendParametersSatellite::Modulation::QPSK: tmp="QPSK"; break;
- case eDVBFrontendParametersSatellite::Modulation::M8PSK: tmp="8PSK"; break;
- case eDVBFrontendParametersSatellite::Modulation::QAM_16: tmp="QAM16"; break;
- }
- PutToDict(dict, "modulation", tmp);
- switch(feparm.polarisation)
+ PutToDict(dict, "symbol_rate", feparm.symbol_rate);
+ PutToDict(dict, "orbital_position", feparm.orbital_position);
+ PutToDict(dict, "inversion", feparm.inversion);
+ PutToDict(dict, "fec_inner", feparm.fec);
+ PutToDict(dict, "modulation", feparm.modulation);
+ PutToDict(dict, "polarization", feparm.polarisation);
+ if (feparm.system == eDVBFrontendParametersSatellite::System_DVB_S2)
{
- case eDVBFrontendParametersSatellite::Polarisation::Horizontal: tmp="HORIZONTAL"; break;
- case eDVBFrontendParametersSatellite::Polarisation::Vertical: tmp="VERTICAL"; break;
- case eDVBFrontendParametersSatellite::Polarisation::CircularLeft: tmp="CIRCULAR LEFT"; break;
- default:
- case eDVBFrontendParametersSatellite::Polarisation::CircularRight: tmp="CIRCULAR RIGHT"; break;
- }
- PutToDict(dict, "polarization", tmp);
- switch(feparm.system)
- {
- default:
- case eDVBFrontendParametersSatellite::System::DVB_S: tmp="DVB-S"; break;
- case eDVBFrontendParametersSatellite::System::DVB_S2:
- switch(feparm.rolloff)
- {
- default:
- case eDVBFrontendParametersSatellite::RollOff::alpha_0_35: tmp="0.35"; break;
- case eDVBFrontendParametersSatellite::RollOff::alpha_0_25: tmp="0.25"; break;
- case eDVBFrontendParametersSatellite::RollOff::alpha_0_20: tmp="0.20"; break;
- }
- PutToDict(dict, "roll off", tmp);
- switch(feparm.pilot)
- {
- case eDVBFrontendParametersSatellite::Pilot::On: tmp="ON"; break;
- case eDVBFrontendParametersSatellite::Pilot::Off: tmp="OFF"; break;
- default:
- case eDVBFrontendParametersSatellite::Pilot::Unknown: tmp="AUTO"; break;
- }
- PutToDict(dict, "pilot", tmp);
- tmp="DVB-S2";
- break;
+ PutToDict(dict, "rolloff", feparm.rolloff);
+ PutToDict(dict, "pilot", feparm.pilot);
}
- PutToDict(dict, "system", tmp);
+ PutToDict(dict, "system", feparm.system);
}
void PutTerrestrialDataToDict(ePyObject &dict, eDVBFrontendParametersTerrestrial &feparm)
{
- PutToDict(dict, "type", "Terrestrial");
+ PutToDict(dict, "tuner_type", "DVB-T");
PutToDict(dict, "frequency", feparm.frequency);
- const char *tmp=0;
- switch (feparm.bandwidth)
- {
- case eDVBFrontendParametersTerrestrial::Bandwidth::Bw8MHz: tmp="8 MHz"; break;
- case eDVBFrontendParametersTerrestrial::Bandwidth::Bw7MHz: tmp="7 MHz"; break;
- case eDVBFrontendParametersTerrestrial::Bandwidth::Bw6MHz: tmp="6 MHz"; break;
- default:
- case eDVBFrontendParametersTerrestrial::Bandwidth::BwAuto: tmp="AUTO"; break;
- }
- PutToDict(dict, "bandwidth", tmp);
- switch (feparm.code_rate_LP)
- {
- case eDVBFrontendParametersTerrestrial::FEC::f1_2: tmp="1/2"; break;
- case eDVBFrontendParametersTerrestrial::FEC::f2_3: tmp="2/3"; break;
- case eDVBFrontendParametersTerrestrial::FEC::f3_4: tmp="3/4"; break;
- case eDVBFrontendParametersTerrestrial::FEC::f5_6: tmp="5/6"; break;
- case eDVBFrontendParametersTerrestrial::FEC::f7_8: tmp="7/8"; break;
- default:
- case eDVBFrontendParametersTerrestrial::FEC::fAuto: tmp="AUTO"; break;
- }
- PutToDict(dict, "code rate lp", tmp);
- switch (feparm.code_rate_HP)
- {
- case eDVBFrontendParametersTerrestrial::FEC::f1_2: tmp="1/2"; break;
- case eDVBFrontendParametersTerrestrial::FEC::f2_3: tmp="2/3"; break;
- case eDVBFrontendParametersTerrestrial::FEC::f3_4: tmp="3/4"; break;
- case eDVBFrontendParametersTerrestrial::FEC::f5_6: tmp="5/6"; break;
- case eDVBFrontendParametersTerrestrial::FEC::f7_8: tmp="7/8"; break;
- default:
- case eDVBFrontendParametersTerrestrial::FEC::fAuto: tmp="AUTO"; break;
- }
- PutToDict(dict, "code rate hp", tmp);
- switch (feparm.modulation)
- {
- case eDVBFrontendParametersTerrestrial::Modulation::QPSK: tmp="QPSK"; break;
- case eDVBFrontendParametersTerrestrial::Modulation::QAM16: tmp="QAM16"; break;
- case eDVBFrontendParametersTerrestrial::Modulation::QAM64: tmp="QAM64"; break;
- default:
- case eDVBFrontendParametersTerrestrial::Modulation::Auto: tmp="AUTO"; break;
- }
- PutToDict(dict, "constellation", tmp);
- switch (feparm.transmission_mode)
- {
- case eDVBFrontendParametersTerrestrial::TransmissionMode::TM2k: tmp="2k"; break;
- case eDVBFrontendParametersTerrestrial::TransmissionMode::TM8k: tmp="8k"; break;
- default:
- case eDVBFrontendParametersTerrestrial::TransmissionMode::TMAuto: tmp="AUTO"; break;
- }
- PutToDict(dict, "transmission mode", tmp);
- switch (feparm.guard_interval)
- {
- case eDVBFrontendParametersTerrestrial::GuardInterval::GI_1_32: tmp="1/32"; break;
- case eDVBFrontendParametersTerrestrial::GuardInterval::GI_1_16: tmp="1/16"; break;
- case eDVBFrontendParametersTerrestrial::GuardInterval::GI_1_8: tmp="1/8"; break;
- case eDVBFrontendParametersTerrestrial::GuardInterval::GI_1_4: tmp="1/4"; break;
- default:
- case eDVBFrontendParametersTerrestrial::GuardInterval::GI_Auto: tmp="AUTO"; break;
- }
- PutToDict(dict, "guard interval", tmp);
- switch (feparm.hierarchy)
- {
- case eDVBFrontendParametersTerrestrial::Hierarchy::HNone: tmp="NONE"; break;
- case eDVBFrontendParametersTerrestrial::Hierarchy::H1: tmp="1"; break;
- case eDVBFrontendParametersTerrestrial::Hierarchy::H2: tmp="2"; break;
- case eDVBFrontendParametersTerrestrial::Hierarchy::H4: tmp="4"; break;
- default:
- case eDVBFrontendParametersTerrestrial::Hierarchy::HAuto: tmp="AUTO"; break;
- }
- PutToDict(dict, "hierarchy", tmp);
- switch (feparm.inversion)
- {
- case eDVBFrontendParametersSatellite::Inversion::On: tmp="ON"; break;
- case eDVBFrontendParametersSatellite::Inversion::Off: tmp="OFF"; break;
- default:
- case eDVBFrontendParametersSatellite::Inversion::Unknown: tmp="AUTO"; break;
- }
- PutToDict(dict, "inversion", tmp);
+ PutToDict(dict, "bandwidth", feparm.bandwidth);
+ PutToDict(dict, "code_rate_lp", feparm.code_rate_LP);
+ PutToDict(dict, "code_rate_hp", feparm.code_rate_HP);
+ PutToDict(dict, "constellation", feparm.modulation);
+ PutToDict(dict, "transmission_mode", feparm.transmission_mode);
+ PutToDict(dict, "guard_interval", feparm.guard_interval);
+ PutToDict(dict, "hierarchy_information", feparm.hierarchy);
+ PutToDict(dict, "inversion", feparm.inversion);
}
void PutCableDataToDict(ePyObject &dict, eDVBFrontendParametersCable &feparm)
{
- const char *tmp=0;
- PutToDict(dict, "type", "Cable");
+ PutToDict(dict, "tuner_type", "DVB-C");
PutToDict(dict, "frequency", feparm.frequency);
- PutToDict(dict, "symbolrate", feparm.symbol_rate);
- switch (feparm.modulation)
- {
- case eDVBFrontendParametersCable::Modulation::QAM16: tmp="QAM16"; break;
- case eDVBFrontendParametersCable::Modulation::QAM32: tmp="QAM32"; break;
- case eDVBFrontendParametersCable::Modulation::QAM64: tmp="QAM64"; break;
- case eDVBFrontendParametersCable::Modulation::QAM128: tmp="QAM128"; break;
- case eDVBFrontendParametersCable::Modulation::QAM256: tmp="QAM256"; break;
- default:
- case eDVBFrontendParametersCable::Modulation::Auto: tmp="AUTO"; break;
- }
- PutToDict(dict, "modulation", tmp);
- switch (feparm.inversion)
- {
- case eDVBFrontendParametersCable::Inversion::On: tmp="ON"; break;
- case eDVBFrontendParametersCable::Inversion::Off: tmp="OFF"; break;
- default:
- case eDVBFrontendParametersCable::Inversion::Unknown: tmp="AUTO"; break;
- }
- PutToDict(dict, "inversion", tmp);
- switch (feparm.fec_inner)
- {
- case eDVBFrontendParametersCable::FEC::fNone: tmp="NONE"; break;
- case eDVBFrontendParametersCable::FEC::f1_2: tmp="1/2"; break;
- case eDVBFrontendParametersCable::FEC::f2_3: tmp="2/3"; break;
- case eDVBFrontendParametersCable::FEC::f3_4: tmp="3/4"; break;
- case eDVBFrontendParametersCable::FEC::f5_6: tmp="5/6"; break;
- case eDVBFrontendParametersCable::FEC::f7_8: tmp="7/8"; break;
- case eDVBFrontendParametersCable::FEC::f8_9: tmp="8/9"; break;
- default:
- case eDVBFrontendParametersCable::FEC::fAuto: tmp="AUTO"; break;
- }
- PutToDict(dict, "fec inner", tmp);
+ PutToDict(dict, "symbol_rate", feparm.symbol_rate);
+ PutToDict(dict, "modulation", feparm.modulation);
+ PutToDict(dict, "inversion", feparm.inversion);
+ PutToDict(dict, "fec_inner", feparm.fec_inner);
}
PyObject *eStaticServiceDVBInformation::getInfoObject(const eServiceReference &r, int what)
@@ -534,14 +367,25 @@ int eStaticServiceDVBPVRInformation::getLength(const eServiceReference &ref)
eDVBTSTools tstools;
+ struct stat s;
+ stat(ref.path.c_str(), &s);
+
if (tstools.openFile(ref.path.c_str()))
return 0;
+ /* check if cached data is still valid */
+ if (m_parser.m_data_ok && (s.st_size == m_parser.m_filesize) && (m_parser.m_length))
+ return m_parser.m_length / 90000;
+
+ /* otherwise, re-calc length and update meta file */
pts_t len;
if (tstools.calcLen(len))
return 0;
- return len / 90000;
+ m_parser.m_length = len;
+ m_parser.m_filesize = s.st_size;
+ m_parser.updateMeta(ref.path);
+ return m_parser.m_length / 90000;
}
int eStaticServiceDVBPVRInformation::getInfo(const eServiceReference &ref, int w)
@@ -1042,7 +886,6 @@ RESULT eServiceFactoryDVB::lookupService(ePtr<eDVBService> &service, const eServ
eDVBServicePlay::eDVBServicePlay(const eServiceReference &ref, eDVBService *service):
m_reference(ref), m_dvb_service(service), m_have_video_pid(0), m_is_paused(0)
{
- memset(&m_videoEventData, 0, sizeof(struct iTSMPEGDecoder::videoEvent));
m_is_primary = 1;
m_is_pvr = !m_reference.path.empty();
@@ -1589,20 +1432,6 @@ RESULT eDVBServicePlay::getEvent(ePtr<eServiceEvent> &evt, int nownext)
return m_event_handler.getEvent(evt, nownext);
}
-static int readMpegProc(char *str, int decoder)
-{
- int val = -1;
- char tmp[64];
- sprintf(tmp, "/proc/stb/vmpeg/%d/%s", decoder, str);
- FILE *f = fopen(tmp, "r");
- if (f)
- {
- fscanf(f, "%x", &val);
- fclose(f);
- }
- return val;
-}
-
int eDVBServicePlay::getInfo(int w)
{
eDVBServicePMTHandler::program program;
@@ -1619,44 +1448,30 @@ int eDVBServicePlay::getInfo(int w)
switch (w)
{
-#if HAVE_DVB_API_VERSION >= 3
case sVideoHeight:
- if (m_videoEventData.type == iTSMPEGDecoder::videoEvent::eventSizeChanged)
- return m_videoEventData.height;
- else
- return readMpegProc("yres", !m_is_primary);
+ if (m_decoder)
+ return m_decoder->getVideoHeight();
+ break;
case sVideoWidth:
- if (m_videoEventData.type == iTSMPEGDecoder::videoEvent::eventSizeChanged)
- return m_videoEventData.width;
- else
- return readMpegProc("xres", !m_is_primary);
+ if (m_decoder)
+ return m_decoder->getVideoWidth();
+ break;
case sFrameRate:
- if (m_videoEventData.type == iTSMPEGDecoder::videoEvent::eventFrameRateChanged)
- return m_videoEventData.framerate;
- else
- return readMpegProc("framerate", !m_is_primary);
+ if (m_decoder)
+ return m_decoder->getVideoFrameRate();
+ break;
case sProgressive:
- if (m_videoEventData.type == iTSMPEGDecoder::videoEvent::eventProgressiveChanged)
- return m_videoEventData.progressive;
- return readMpegProc("progressive", !m_is_primary);
-#else
-#warning "FIXMEE implement sFrameRate, sProgressive, sVideoHeight, sVideoWidth for old DVB API"
-#endif
+ if (m_decoder)
+ return m_decoder->getVideoProgressive();
+ break;
case sAspect:
{
- int val;
-#if HAVE_DVB_API_VERSION >= 3
- if (m_videoEventData.type == iTSMPEGDecoder::videoEvent::eventSizeChanged)
- return m_videoEventData.aspect == VIDEO_FORMAT_4_3 ? 1 : 3;
- else if ((val=readMpegProc("aspect", !m_is_primary)) != -1)
- return val;
- else
-#else
-#warning "FIXMEE implement sAspect for old DVB API"
-#endif
+ int aspect = -1;
+ if (m_decoder)
+ aspect = m_decoder->getVideoAspect();
if (no_program_info)
- return -1;
- else if (!program.videoStreams.empty() && program.videoStreams[0].component_tag != -1)
+ break;
+ else if (aspect == -1 && !program.videoStreams.empty() && program.videoStreams[0].component_tag != -1)
{
ePtr<eServiceEvent> evt;
if (!m_event_handler.getEvent(evt, 0))
@@ -1693,7 +1508,9 @@ int eDVBServicePlay::getInfo(int w)
}
}
}
- return -1;
+ else
+ return aspect;
+ break;
}
case sIsCrypted: if (no_program_info) return -1; return program.isCrypted();
case sVideoPID: if (no_program_info) return -1; if (program.videoStreams.empty()) return -1; return program.videoStreams[0].pid;
@@ -1710,8 +1527,9 @@ int eDVBServicePlay::getInfo(int w)
case sServiceref: return resIsString;
case sDVBState: return m_tune_state;
default:
- return -1;
+ break;
}
+ return -1;
}
std::string eDVBServicePlay::getInfoString(int w)
@@ -1798,6 +1616,8 @@ RESULT eDVBServicePlay::getTrackInfo(struct iAudioTrackInfo &info, unsigned int
info.m_description = "AC3";
else if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atAAC)
info.m_description = "AAC";
+ else if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atAACHE)
+ info.m_description = "AAC-HE";
else if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atDTS)
info.m_description = "DTS";
else
@@ -2056,19 +1876,8 @@ PyObject *eDVBServiceBase::getTransponderData(bool original)
eDVBFrontendParametersSatellite osat;
if (!feparm->getDVBS(osat))
{
- void PutToDict(ePyObject &, const char*, long);
- void PutToDict(ePyObject &, const char*, const char*);
PutToDict(ret, "orbital_position", osat.orbital_position);
- const char *tmp = "UNKNOWN";
- switch(osat.polarisation)
- {
- case eDVBFrontendParametersSatellite::Polarisation::Horizontal: tmp="HORIZONTAL"; break;
- case eDVBFrontendParametersSatellite::Polarisation::Vertical: tmp="VERTICAL"; break;
- case eDVBFrontendParametersSatellite::Polarisation::CircularLeft: tmp="CIRCULAR_LEFT"; break;
- case eDVBFrontendParametersSatellite::Polarisation::CircularRight: tmp="CIRCULAR_RIGHT"; break;
- default:break;
- }
- PutToDict(ret, "polarization", tmp);
+ PutToDict(ret, "polarization", osat.polarisation);
}
}
}
@@ -2213,8 +2022,8 @@ PyObject *eDVBServicePlay::getCutList()
for (std::multiset<struct cueEntry>::iterator i(m_cue_entries.begin()); i != m_cue_entries.end(); ++i)
{
ePyObject tuple = PyTuple_New(2);
- PyTuple_SetItem(tuple, 0, PyLong_FromLongLong(i->where));
- PyTuple_SetItem(tuple, 1, PyInt_FromLong(i->what));
+ PyTuple_SET_ITEM(tuple, 0, PyLong_FromLongLong(i->where));
+ PyTuple_SET_ITEM(tuple, 1, PyInt_FromLong(i->what));
PyList_Append(list, tuple);
Py_DECREF(tuple);
}
@@ -3014,7 +2823,6 @@ void eDVBServicePlay::setPCMDelay(int delay)
void eDVBServicePlay::video_event(struct iTSMPEGDecoder::videoEvent event)
{
- memcpy(&m_videoEventData, &event, sizeof(event));
switch(event.type) {
case iTSMPEGDecoder::videoEvent::eventSizeChanged:
m_event((iPlayableService*)this, evVideoSizeChanged);
@@ -3041,18 +2849,16 @@ PyObject *eDVBServicePlay::getStreamingData()
eDVBServicePMTHandler::program program;
if (m_service_handler.getProgramInfo(program))
{
- Py_INCREF(Py_None);
- return Py_None;
+ Py_RETURN_NONE;
}
- PyObject *r = program.createPythonObject();
+ ePyObject r = program.createPythonObject();
ePtr<iDVBDemux> demux;
if (!m_service_handler.getDataDemux(demux))
{
uint8_t demux_id;
- demux->getCADemuxID(demux_id);
-
- PyDict_SetItemString(r, "demux", PyInt_FromLong(demux_id));
+ if (!demux->getCADemuxID(demux_id))
+ PutToDict(r, "demux", demux_id);
}
return r;
diff --git a/lib/service/servicedvb.h b/lib/service/servicedvb.h
index c19e1ed5..43e4690f 100644
--- a/lib/service/servicedvb.h
+++ b/lib/service/servicedvb.h
@@ -283,7 +283,6 @@ private:
ePtr<eConnection> m_video_event_connection;
void video_event(struct iTSMPEGDecoder::videoEvent);
- struct iTSMPEGDecoder::videoEvent m_videoEventData;
};
class eStaticServiceDVBBouquetInformation: public iStaticServiceInformation
diff --git a/lib/service/servicedvbrecord.cpp b/lib/service/servicedvbrecord.cpp
index 89d022cc..c2767e8d 100644
--- a/lib/service/servicedvbrecord.cpp
+++ b/lib/service/servicedvbrecord.cpp
@@ -3,11 +3,20 @@
#include <lib/dvb/epgcache.h>
#include <fcntl.h>
+ /* for cutlist */
+#include <byteswap.h>
+#include <netinet/in.h>
+
+#ifndef BYTE_ORDER
+#error no byte order defined!
+#endif
+
DEFINE_REF(eDVBServiceRecord);
eDVBServiceRecord::eDVBServiceRecord(const eServiceReferenceDVB &ref): m_ref(ref)
{
CONNECT(m_service_handler.serviceEvent, eDVBServiceRecord::serviceEvent);
+ CONNECT(m_event_handler.m_eit_changed, eDVBServiceRecord::gotNewEvent);
m_state = stateIdle;
m_want_record = 0;
m_tuned = 0;
@@ -15,6 +24,7 @@ eDVBServiceRecord::eDVBServiceRecord(const eServiceReferenceDVB &ref): m_ref(ref
m_error = 0;
m_streaming = 0;
m_simulate = false;
+ m_last_event_id = -1;
}
void eDVBServiceRecord::serviceEvent(int event)
@@ -26,6 +36,22 @@ void eDVBServiceRecord::serviceEvent(int event)
{
eDebug("tuned..");
m_tuned = 1;
+
+ /* start feeding EIT updates */
+ ePtr<iDVBDemux> m_demux;
+ if (!m_service_handler.getDataDemux(m_demux))
+ {
+ eServiceReferenceDVB &ref = (eServiceReferenceDVB&) m_ref;
+ int sid = ref.getParentServiceID().get();
+ if (!sid)
+ sid = ref.getServiceID().get();
+ if ( ref.getParentTransportStreamID().get() &&
+ ref.getParentTransportStreamID() != ref.getTransportStreamID() )
+ m_event_handler.startOther(m_demux, sid);
+ else
+ m_event_handler.start(m_demux, sid);
+ }
+
if (m_state == stateRecording && m_want_record)
doRecord();
m_event((iRecordableService*)this, evTunedIn);
@@ -145,6 +171,9 @@ RESULT eDVBServiceRecord::stop()
::close(m_target_fd);
m_target_fd = -1;
}
+
+ saveCutlist();
+
m_state = statePrepared;
} else if (!m_simulate)
eDebug("(was not recording)");
@@ -363,23 +392,23 @@ RESULT eDVBServiceRecord::stream(ePtr<iStreamableService> &ptr)
return 0;
}
+extern void PutToDict(ePyObject &dict, const char*key, long val); // defined in dvb/frontend.cpp
+
PyObject *eDVBServiceRecord::getStreamingData()
{
eDVBServicePMTHandler::program program;
if (!m_tuned || m_service_handler.getProgramInfo(program))
{
- Py_INCREF(Py_None);
- return Py_None;
+ Py_RETURN_NONE;
}
- PyObject *r = program.createPythonObject();
+ ePyObject r = program.createPythonObject();
ePtr<iDVBDemux> demux;
if (!m_service_handler.getDataDemux(demux))
{
uint8_t demux_id;
- demux->getCADemuxID(demux_id);
-
- PyDict_SetItemString(r, "demux", PyInt_FromLong(demux_id));
+ if (!demux->getCADemuxID(demux_id))
+ PutToDict(r, "demux", demux_id);
}
return r;
@@ -398,3 +427,77 @@ void eDVBServiceRecord::recordEvent(int event)
eDebug("unhandled record event %d", event);
}
}
+
+void eDVBServiceRecord::gotNewEvent()
+{
+ ePtr<eServiceEvent> event_now;
+ m_event_handler.getEvent(event_now, 0);
+
+ if (!event_now)
+ return;
+
+ int event_id = event_now->getEventId();
+
+ pts_t p;
+
+ if (m_record)
+ {
+ if (m_record->getCurrentPCR(p))
+ eDebug("getting PCR failed!");
+ else
+ {
+ static int i;
+ m_event_timestamps[/* event_id*/ ++i] = p;
+ eDebug("pcr of eit change: %llx", p);
+ }
+ }
+
+ if (event_id != m_last_event_id)
+ eDebug("[eDVBServiceRecord] now running: %s (%d seconds)", event_now->getEventName().c_str(), event_now->getDuration());
+
+ m_last_event_id = event_id;
+}
+
+void eDVBServiceRecord::saveCutlist()
+{
+ /* XXX: dupe of eDVBServicePlay::saveCuesheet, refactor plz */
+ std::string filename = m_filename + ".cuts";
+
+ eDVBTSTools tstools;
+
+ if (tstools.openFile(m_filename.c_str()))
+ {
+ eDebug("[eDVBServiceRecord] saving cutlist failed because tstools failed");
+ return;
+ }
+
+ FILE *f = fopen(filename.c_str(), "wb");
+
+ if (f)
+ {
+ unsigned long long where;
+ int what;
+
+ for (std::map<int,pts_t>::iterator i(m_event_timestamps.begin()); i != m_event_timestamps.end(); ++i)
+ {
+ pts_t p = i->second;
+ off_t offset = 0; // fixme, we need to note down both
+ if (tstools.fixupPTS(offset, p))
+ {
+ eDebug("[eDVBServiceRecord] fixing up PTS failed, not saving");
+ continue;
+ }
+ eDebug("fixed up %llx to %llx (offset %llx)", i->second, p, offset);
+#if BYTE_ORDER == BIG_ENDIAN
+ where = p;
+#else
+ where = bswap_64(p);
+#endif
+ what = htonl(2); /* mark */
+ fwrite(&where, sizeof(where), 1, f);
+ fwrite(&what, sizeof(what), 1, f);
+ }
+ fclose(f);
+ }
+
+}
diff --git a/lib/service/servicedvbrecord.h b/lib/service/servicedvbrecord.h
index 17de033e..856f92b3 100644
--- a/lib/service/servicedvbrecord.h
+++ b/lib/service/servicedvbrecord.h
@@ -36,6 +36,8 @@ private:
friend class eServiceFactoryDVB;
eDVBServiceRecord(const eServiceReferenceDVB &ref);
+ eDVBServiceEITHandler m_event_handler;
+
eServiceReferenceDVB m_ref;
ePtr<iDVBTSRecorder> m_record;
@@ -44,8 +46,11 @@ private:
int m_recording, m_tuned, m_error;
std::set<int> m_pids_active;
std::string m_filename;
+
+ std::map<int,pts_t> m_event_timestamps;
int m_target_fd;
int m_streaming;
+ int m_last_event_id;
int doPrepare();
int doRecord();
@@ -56,6 +61,10 @@ private:
/* recorder events */
void recordEvent(int event);
+
+ /* eit updates */
+ void gotNewEvent();
+ void saveCutlist();
};
#endif
diff --git a/lib/service/servicemp3.cpp b/lib/service/servicemp3.cpp
index 19b7735b..bbcb3b5c 100644
--- a/lib/service/servicemp3.cpp
+++ b/lib/service/servicemp3.cpp
@@ -36,9 +36,11 @@ eServiceFactoryMP3::eServiceFactoryMP3()
extensions.push_back("wave");
extensions.push_back("mkv");
extensions.push_back("avi");
+ extensions.push_back("divx");
extensions.push_back("dat");
extensions.push_back("flac");
extensions.push_back("mp4");
+ extensions.push_back("m4a");
sc->addServiceFactory(eServiceFactoryMP3::id, this, extensions);
}
@@ -184,11 +186,10 @@ eServiceMP3::eServiceMP3(const char *filename): m_filename(filename), m_pump(eAp
CONNECT(m_seekTimeout->timeout, eServiceMP3::seekTimeoutCB);
CONNECT(m_pump.recv_msg, eServiceMP3::gstPoll);
GstElement *source = 0;
-
- GstElement *decoder = 0, *conv = 0, *flt = 0, *sink = 0; /* for audio */
-
- GstElement *audio = 0, *switch_audio = 0, *queue_audio = 0, *video = 0, *queue_video = 0, *videodemux = 0;
-
+ GstElement *decoder = 0, *conv = 0, *flt = 0, *parser = 0, *sink = 0; /* for audio */
+ GstElement *audio = 0, *switch_audio = 0, *queue_audio = 0, *video = 0, *queue_video = 0, *videodemux = 0, *audiodemux = 0, *id3demux;
+ m_aspect = m_width = m_height = m_framerate = m_progressive = -1;
+
m_state = stIdle;
eDebug("SERVICEMP3 construct!");
@@ -200,25 +201,50 @@ eServiceMP3::eServiceMP3(const char *filename): m_filename(filename), m_pump(eAp
ext = filename;
sourceStream sourceinfo;
+ sourceinfo.is_video = FALSE;
+ sourceinfo.audiotype = atUnknown;
if ( (strcasecmp(ext, ".mpeg") && strcasecmp(ext, ".mpg") && strcasecmp(ext, ".vob") && strcasecmp(ext, ".bin") && strcasecmp(ext, ".dat") ) == 0 )
+ {
sourceinfo.containertype = ctMPEGPS;
+ sourceinfo.is_video = TRUE;
+ }
else if ( strcasecmp(ext, ".ts") == 0 )
+ {
sourceinfo.containertype = ctMPEGTS;
+ sourceinfo.is_video = TRUE;
+ }
else if ( strcasecmp(ext, ".mkv") == 0 )
+ {
sourceinfo.containertype = ctMKV;
- else if ( strcasecmp(ext, ".avi") == 0 )
+ sourceinfo.is_video = TRUE;
+ }
+ else if ( strcasecmp(ext, ".avi") == 0 || strcasecmp(ext, ".divx") == 0)
+ {
sourceinfo.containertype = ctAVI;
+ sourceinfo.is_video = TRUE;
+ }
else if ( strcasecmp(ext, ".mp4") == 0 )
+ {
+ sourceinfo.containertype = ctMP4;
+ sourceinfo.is_video = TRUE;
+ }
+ else if ( strcasecmp(ext, ".m4a") == 0 )
+ {
sourceinfo.containertype = ctMP4;
+ sourceinfo.audiotype = atAAC;
+ }
+ else if ( strcasecmp(ext, ".mp3") == 0 )
+ sourceinfo.audiotype = atMP3;
else if ( (strncmp(filename, "/autofs/", 8) || strncmp(filename+strlen(filename)-13, "/track-", 7) || strcasecmp(ext, ".wav")) == 0 )
sourceinfo.containertype = ctCDA;
if ( strcasecmp(ext, ".dat") == 0 )
+ {
sourceinfo.containertype = ctVCD;
+ sourceinfo.is_video = TRUE;
+ }
if ( (strncmp(filename, "http://", 7)) == 0 )
sourceinfo.is_streaming = TRUE;
- sourceinfo.is_video = ( sourceinfo.containertype && sourceinfo.containertype != ctCDA );
-
eDebug("filename=%s, containertype=%d, is_video=%d, is_streaming=%d", filename, sourceinfo.containertype, sourceinfo.is_video, sourceinfo.is_streaming);
int all_ok = 0;
@@ -250,10 +276,24 @@ eServiceMP3::eServiceMP3(const char *filename): m_filename(filename), m_pump(eAp
if (track > 0)
g_object_set (G_OBJECT (source), "track", track, NULL);
}
- else
- sourceinfo.containertype = ctNone;
}
- if ( !sourceinfo.is_streaming && sourceinfo.containertype != ctCDA )
+ else if ( sourceinfo.containertype == ctVCD )
+ {
+ int fd = open(filename,O_RDONLY);
+ char tmp[128*1024];
+ int ret = read(fd, tmp, 128*1024);
+ close(fd);
+ if ( ret == -1 ) // this is a "REAL" VCD
+ {
+ source = gst_element_factory_make ("vcdsrc", "vcd-source");
+ if (source)
+ {
+ g_object_set (G_OBJECT (source), "device", "/dev/cdroms/cdrom0", NULL);
+ eDebug("servicemp3: this is a 'REAL' video cd... we use vcdsrc !");
+ }
+ }
+ }
+ if ( !source && !sourceinfo.is_streaming )
{
source = gst_element_factory_make ("filesrc", "file-source");
if (source)
@@ -269,7 +309,7 @@ eServiceMP3::eServiceMP3(const char *filename): m_filename(filename), m_pump(eAp
audio = gst_element_factory_make("dvbaudiosink", "audiosink");
if (!audio)
m_error_message += "failed to create Gstreamer element dvbaudiosink\n";
-
+
video = gst_element_factory_make("dvbvideosink", "videosink");
if (!video)
m_error_message += "failed to create Gstreamer element dvbvideosink\n";
@@ -320,35 +360,105 @@ eServiceMP3::eServiceMP3(const char *filename): m_filename(filename), m_pump(eAp
}
} else /* is audio */
{
-
- /* filesrc -> decodebin -> audioconvert -> capsfilter -> alsasink */
- decoder = gst_element_factory_make ("decodebin", "decoder");
- if (!decoder)
- m_error_message += "failed to create Gstreamer element decodebin\n";
-
- conv = gst_element_factory_make ("audioconvert", "converter");
- if (!conv)
- m_error_message += "failed to create Gstreamer element audioconvert\n";
-
- flt = gst_element_factory_make ("capsfilter", "flt");
- if (!flt)
- m_error_message += "failed to create Gstreamer element capsfilter\n";
-
- /* for some reasons, we need to set the sample format to depth/width=16, because auto negotiation doesn't work. */
- /* endianness, however, is not required to be set anymore. */
- if (flt)
+ std::string demux_type;
+ switch ( sourceinfo.containertype )
{
- GstCaps *caps = gst_caps_new_simple("audio/x-raw-int", /* "endianness", G_TYPE_INT, 4321, */ "depth", G_TYPE_INT, 16, "width", G_TYPE_INT, 16, /*"channels", G_TYPE_INT, 2, */NULL);
- g_object_set (G_OBJECT (flt), "caps", caps, NULL);
- gst_caps_unref(caps);
+ case ctMP4:
+ demux_type = "qtdemux";
+ break;
+ default:
+ break;
+ }
+ if ( demux_type.length() )
+ {
+ audiodemux = gst_element_factory_make(demux_type.c_str(), "audiodemux");
+ if (!audiodemux)
+ m_error_message = "GStreamer plugin " + demux_type + " not available!\n";
+ }
+ switch ( sourceinfo.audiotype )
+ {
+ case atMP3:
+ {
+ id3demux = gst_element_factory_make("id3demux", "id3demux");
+ if ( !id3demux )
+ {
+ m_error_message += "failed to create Gstreamer element id3demux\n";
+ break;
+ }
+ parser = gst_element_factory_make("mp3parse", "audiosink");
+ if ( !parser )
+ {
+ m_error_message += "failed to create Gstreamer element mp3parse\n";
+ break;
+ }
+ sink = gst_element_factory_make("dvbaudiosink", "audiosink2");
+ if ( !sink )
+ m_error_message += "failed to create Gstreamer element dvbaudiosink\n";
+ else
+ all_ok = 1;
+ break;
+ }
+ case atAAC:
+ {
+ if ( !audiodemux )
+ {
+ m_error_message += "cannot parse raw AAC audio\n";
+ break;
+ }
+ sink = gst_element_factory_make("dvbaudiosink", "audiosink");
+ if (!sink)
+ m_error_message += "failed to create Gstreamer element dvbaudiosink\n";
+ else
+ all_ok = 1;
+ break;
+ }
+ case atAC3:
+ {
+ if ( !audiodemux )
+ {
+ m_error_message += "cannot parse raw AC3 audio\n";
+ break;
+ }
+ sink = gst_element_factory_make("dvbaudiosink", "audiosink");
+ if ( !sink )
+ m_error_message += "failed to create Gstreamer element dvbaudiosink\n";
+ else
+ all_ok = 1;
+ break;
+ }
+ default:
+ { /* filesrc -> decodebin -> audioconvert -> capsfilter -> alsasink */
+ decoder = gst_element_factory_make ("decodebin", "decoder");
+ if (!decoder)
+ m_error_message += "failed to create Gstreamer element decodebin\n";
+
+ conv = gst_element_factory_make ("audioconvert", "converter");
+ if (!conv)
+ m_error_message += "failed to create Gstreamer element audioconvert\n";
+
+ flt = gst_element_factory_make ("capsfilter", "flt");
+ if (!flt)
+ m_error_message += "failed to create Gstreamer element capsfilter\n";
+
+ /* for some reasons, we need to set the sample format to depth/width=16, because auto negotiation doesn't work. */
+ /* endianness, however, is not required to be set anymore. */
+ if (flt)
+ {
+ GstCaps *caps = gst_caps_new_simple("audio/x-raw-int", /* "endianness", G_TYPE_INT, 4321, */ "depth", G_TYPE_INT, 16, "width", G_TYPE_INT, 16, /*"channels", G_TYPE_INT, 2, */NULL);
+ g_object_set (G_OBJECT (flt), "caps", caps, NULL);
+ gst_caps_unref(caps);
+ }
+
+ sink = gst_element_factory_make ("alsasink", "alsa-output");
+ if (!sink)
+ m_error_message += "failed to create Gstreamer element alsasink\n";
+
+ if (source && decoder && conv && sink)
+ all_ok = 1;
+ break;
+ }
}
- sink = gst_element_factory_make ("alsasink", "alsa-output");
- if (!sink)
- m_error_message += "failed to create Gstreamer element alsasink\n";
-
- if (source && decoder && conv && sink)
- all_ok = 1;
}
if (m_gst_pipeline && all_ok)
{
@@ -384,8 +494,9 @@ eServiceMP3::eServiceMP3(const char *filename): m_filename(filename), m_pump(eAp
}
gst_bin_add_many(GST_BIN(m_gst_pipeline), source, videodemux, audio, queue_audio, video, queue_video, switch_audio, NULL);
- if ( sourceinfo.containertype == ctVCD )
+ if ( sourceinfo.containertype == ctVCD && gst_bin_get_by_name(GST_BIN(m_gst_pipeline),"file-source") )
{
+ eDebug("servicemp3: this is a fake video cd... we use filesrc ! cdxaparse !");
GstElement *cdxaparse = gst_element_factory_make("cdxaparse", "cdxaparse");
gst_bin_add(GST_BIN(m_gst_pipeline), cdxaparse);
gst_element_link(source, cdxaparse);
@@ -401,29 +512,52 @@ eServiceMP3::eServiceMP3(const char *filename): m_filename(filename), m_pump(eAp
} else /* is audio*/
{
- queue_audio = gst_element_factory_make("queue", "queue_audio");
-
- g_signal_connect (decoder, "new-decoded-pad", G_CALLBACK(gstCBnewPad), this);
- g_signal_connect (decoder, "unknown-type", G_CALLBACK(gstCBunknownType), this);
-
- g_object_set (G_OBJECT (sink), "preroll-queue-len", 80, NULL);
-
- /* gst_bin will take the 'floating references' */
- gst_bin_add_many (GST_BIN (m_gst_pipeline),
- source, queue_audio, decoder, NULL);
-
- /* in decodebin's case we can just connect the source with the decodebin, and decodebin will take care about id3demux (or whatever is required) */
- gst_element_link_many(source, queue_audio, decoder, NULL);
-
- /* create audio bin with the audioconverter, the capsfilter and the audiosink */
- audio = gst_bin_new ("audiobin");
-
- GstPad *audiopad = gst_element_get_static_pad (conv, "sink");
- gst_bin_add_many(GST_BIN(audio), conv, flt, sink, NULL);
- gst_element_link_many(conv, flt, sink, NULL);
- gst_element_add_pad(audio, gst_ghost_pad_new ("sink", audiopad));
- gst_object_unref(audiopad);
- gst_bin_add (GST_BIN(m_gst_pipeline), audio);
+ if ( decoder )
+ {
+ queue_audio = gst_element_factory_make("queue", "queue_audio");
+
+ g_signal_connect (decoder, "new-decoded-pad", G_CALLBACK(gstCBnewPad), this);
+ g_signal_connect (decoder, "unknown-type", G_CALLBACK(gstCBunknownType), this);
+
+ g_object_set (G_OBJECT (sink), "preroll-queue-len", 80, NULL);
+
+ /* gst_bin will take the 'floating references' */
+ gst_bin_add_many (GST_BIN (m_gst_pipeline),
+ source, queue_audio, decoder, NULL);
+
+ /* in decodebin's case we can just connect the source with the decodebin, and decodebin will take care about id3demux (or whatever is required) */
+ gst_element_link_many(source, queue_audio, decoder, NULL);
+
+ /* create audio bin with the audioconverter, the capsfilter and the audiosink */
+ audio = gst_bin_new ("audiobin");
+
+ GstPad *audiopad = gst_element_get_static_pad (conv, "sink");
+ gst_bin_add_many(GST_BIN(audio), conv, flt, sink, NULL);
+ gst_element_link_many(conv, flt, sink, NULL);
+ gst_element_add_pad(audio, gst_ghost_pad_new ("sink", audiopad));
+ gst_object_unref(audiopad);
+ gst_bin_add (GST_BIN(m_gst_pipeline), audio);
+ }
+ else
+ {
+ gst_bin_add_many (GST_BIN (m_gst_pipeline), source, sink, NULL);
+ if ( parser && id3demux )
+ {
+ gst_bin_add_many (GST_BIN (m_gst_pipeline), parser, id3demux, NULL);
+ gst_element_link(source, id3demux);
+ g_signal_connect(id3demux, "pad-added", G_CALLBACK (gstCBpadAdded), this);
+ gst_element_link(parser, sink);
+ }
+ if ( audiodemux )
+ {
+ gst_bin_add (GST_BIN (m_gst_pipeline), audiodemux);
+ g_signal_connect(audiodemux, "pad-added", G_CALLBACK (gstCBpadAdded), this);
+ gst_element_link(source, audiodemux);
+ }
+ audioStream audio;
+ audio.type = sourceinfo.audiotype;
+ m_audioStreams.push_back(audio);
+ }
}
} else
{
@@ -647,13 +781,13 @@ RESULT eServiceMP3::getPlayPosition(pts_t &pts)
return -1;
if (m_state != stRunning)
return -1;
-
+
GstFormat fmt = GST_FORMAT_TIME;
gint64 len;
if (!gst_element_query_position(m_gst_pipeline, &fmt, &len))
return -1;
-
+
/* len is in nanoseconds. we have 90 000 pts per second. */
pts = len / 11111;
return 0;
@@ -691,6 +825,11 @@ int eServiceMP3::getInfo(int w)
switch (w)
{
+ case sVideoHeight: return m_height;
+ case sVideoWidth: return m_width;
+ case sFrameRate: return m_framerate;
+ case sProgressive: return m_progressive;
+ case sAspect: return m_aspect;
case sTitle:
case sArtist:
case sAlbum:
@@ -898,103 +1037,165 @@ void eServiceMP3::gstBusCall(GstBus *bus, GstMessage *msg)
#endif
switch (GST_MESSAGE_TYPE (msg))
{
- case GST_MESSAGE_EOS:
- m_event((iPlayableService*)this, evEOF);
- break;
- case GST_MESSAGE_ERROR:
- {
- gchar *debug;
- GError *err;
-
- gst_message_parse_error (msg, &err, &debug);
- g_free (debug);
- eWarning("Gstreamer error: %s (%i)", err->message, err->code );
- if ( err->domain == GST_STREAM_ERROR && err->code == GST_STREAM_ERROR_DECODE )
+ case GST_MESSAGE_EOS:
+ m_event((iPlayableService*)this, evEOF);
+ break;
+ case GST_MESSAGE_ERROR:
{
- if ( g_strrstr(sourceName, "videosink") )
- m_event((iPlayableService*)this, evUser+11);
+ gchar *debug;
+ GError *err;
+
+ gst_message_parse_error (msg, &err, &debug);
+ g_free (debug);
+ eWarning("Gstreamer error: %s (%i) from %s", err->message, err->code, sourceName );
+ if ( err->domain == GST_STREAM_ERROR )
+ {
+ if ( err->code == GST_STREAM_ERROR_CODEC_NOT_FOUND && g_strrstr(sourceName, "videosink") )
+ m_event((iPlayableService*)this, evUser+11);
+ else if ( err->code == GST_STREAM_ERROR_FAILED && g_strrstr(sourceName, "file-source") )
+ {
+ eWarning("error in tag parsing, linking mp3parse directly to file-sink, bypassing id3demux...");
+ GstElement *source = gst_bin_get_by_name(GST_BIN(m_gst_pipeline),"file-source");
+ GstElement *parser = gst_bin_get_by_name(GST_BIN(m_gst_pipeline),"audiosink");
+ gst_element_set_state(m_gst_pipeline, GST_STATE_NULL);
+ gst_element_unlink(source, gst_bin_get_by_name(GST_BIN(m_gst_pipeline),"id3demux"));
+ gst_element_link(source, parser);
+ gst_element_set_state (m_gst_pipeline, GST_STATE_PLAYING);
+ }
+ }
+ g_error_free(err);
+ break;
}
- g_error_free(err);
- /* TODO: signal error condition to user */
- break;
- }
- case GST_MESSAGE_TAG:
- {
- GstTagList *tags, *result;
- gst_message_parse_tag(msg, &tags);
-
- result = gst_tag_list_merge(m_stream_tags, tags, GST_TAG_MERGE_PREPEND);
- if (result)
+ case GST_MESSAGE_INFO:
{
- if (m_stream_tags)
- gst_tag_list_free(m_stream_tags);
- m_stream_tags = result;
+ gchar *debug;
+ GError *inf;
+
+ gst_message_parse_info (msg, &inf, &debug);
+ g_free (debug);
+ if ( inf->domain == GST_STREAM_ERROR && inf->code == GST_STREAM_ERROR_DECODE )
+ {
+ if ( g_strrstr(sourceName, "videosink") )
+ m_event((iPlayableService*)this, evUser+14);
+ }
+ g_error_free(inf);
+ break;
}
-
- gchar *g_audiocodec;
- if ( gst_tag_list_get_string(tags, GST_TAG_AUDIO_CODEC, &g_audiocodec) && m_audioStreams.size() == 0 )
+ case GST_MESSAGE_TAG:
{
- GstPad* pad = gst_element_get_pad (GST_ELEMENT(source), "src");
- GstCaps* caps = gst_pad_get_caps(pad);
- GstStructure* str = gst_caps_get_structure(caps, 0);
- if ( !str )
- break;
- audioStream audio;
- audio.type = gstCheckAudioPad(str);
- m_audioStreams.push_back(audio);
+ GstTagList *tags, *result;
+ gst_message_parse_tag(msg, &tags);
+
+ result = gst_tag_list_merge(m_stream_tags, tags, GST_TAG_MERGE_PREPEND);
+ if (result)
+ {
+ if (m_stream_tags)
+ gst_tag_list_free(m_stream_tags);
+ m_stream_tags = result;
+ }
+
+ gchar *g_audiocodec;
+ if ( gst_tag_list_get_string(tags, GST_TAG_AUDIO_CODEC, &g_audiocodec) && m_audioStreams.size() == 0 )
+ {
+ GstPad* pad = gst_element_get_pad (GST_ELEMENT(source), "src");
+ GstCaps* caps = gst_pad_get_caps(pad);
+ GstStructure* str = gst_caps_get_structure(caps, 0);
+ if ( !str )
+ break;
+ audioStream audio;
+ audio.type = gstCheckAudioPad(str);
+ m_audioStreams.push_back(audio);
+ }
+
+ const GValue *gv_image = gst_tag_list_get_value_index(tags, GST_TAG_IMAGE, 0);
+ if ( gv_image )
+ {
+ GstBuffer *buf_image;
+ buf_image = gst_value_get_buffer (gv_image);
+ int fd = open("/tmp/.id3coverart", O_CREAT|O_WRONLY|O_TRUNC, 0644);
+ write(fd, GST_BUFFER_DATA(buf_image), GST_BUFFER_SIZE(buf_image));
+ close(fd);
+ m_event((iPlayableService*)this, evUser+13);
+ }
+
+ gst_tag_list_free(tags);
+ m_event((iPlayableService*)this, evUpdatedInfo);
+ break;
}
-
- gst_tag_list_free(tags);
- m_event((iPlayableService*)this, evUpdatedInfo);
- break;
- }
- case GST_MESSAGE_ASYNC_DONE:
- {
- GstTagList *tags;
- for (std::vector<audioStream>::iterator IterAudioStream(m_audioStreams.begin()); IterAudioStream != m_audioStreams.end(); ++IterAudioStream)
+ case GST_MESSAGE_ASYNC_DONE:
{
- if ( IterAudioStream->pad )
+ GstTagList *tags;
+ for (std::vector<audioStream>::iterator IterAudioStream(m_audioStreams.begin()); IterAudioStream != m_audioStreams.end(); ++IterAudioStream)
{
- g_object_get(IterAudioStream->pad, "tags", &tags, NULL);
- gchar *g_language;
- if ( gst_is_tag_list(tags) && gst_tag_list_get_string(tags, GST_TAG_LANGUAGE_CODE, &g_language) )
+ if ( IterAudioStream->pad )
{
- eDebug("found audio language %s",g_language);
- IterAudioStream->language_code = std::string(g_language);
- g_free (g_language);
+ g_object_get(IterAudioStream->pad, "tags", &tags, NULL);
+ gchar *g_language;
+ if ( tags && gst_is_tag_list(tags) && gst_tag_list_get_string(tags, GST_TAG_LANGUAGE_CODE, &g_language) )
+ {
+ eDebug("found audio language %s",g_language);
+ IterAudioStream->language_code = std::string(g_language);
+ g_free (g_language);
+ }
}
}
- }
- for (std::vector<subtitleStream>::iterator IterSubtitleStream(m_subtitleStreams.begin()); IterSubtitleStream != m_subtitleStreams.end(); ++IterSubtitleStream)
- {
- if ( IterSubtitleStream->pad )
+ for (std::vector<subtitleStream>::iterator IterSubtitleStream(m_subtitleStreams.begin()); IterSubtitleStream != m_subtitleStreams.end(); ++IterSubtitleStream)
{
- g_object_get(IterSubtitleStream->pad, "tags", &tags, NULL);
- gchar *g_language;
- if ( gst_is_tag_list(tags) && gst_tag_list_get_string(tags, GST_TAG_LANGUAGE_CODE, &g_language) )
+ if ( IterSubtitleStream->pad )
{
- eDebug("found subtitle language %s",g_language);
- IterSubtitleStream->language_code = std::string(g_language);
- g_free (g_language);
+ g_object_get(IterSubtitleStream->pad, "tags", &tags, NULL);
+ gchar *g_language;
+ if ( tags && gst_is_tag_list(tags) && gst_tag_list_get_string(tags, GST_TAG_LANGUAGE_CODE, &g_language) )
+ {
+ eDebug("found subtitle language %s",g_language);
+ IterSubtitleStream->language_code = std::string(g_language);
+ g_free (g_language);
+ }
}
}
}
- }
- case GST_MESSAGE_ELEMENT:
- {
- if ( gst_is_missing_plugin_message(msg) )
+ case GST_MESSAGE_ELEMENT:
{
- gchar *description = gst_missing_plugin_message_get_description(msg);
- if ( description )
+ if ( gst_is_missing_plugin_message(msg) )
+ {
+ gchar *description = gst_missing_plugin_message_get_description(msg);
+ if ( description )
+ {
+ m_error_message = "GStreamer plugin " + (std::string)description + " not available!\n";
+ g_free(description);
+ m_event((iPlayableService*)this, evUser+12);
+ }
+ }
+ else if (const GstStructure *msgstruct = gst_message_get_structure(msg))
{
- m_error_message = "GStreamer plugin " + (std::string)description + " not available!\n";
- g_free(description);
- m_event((iPlayableService*)this, evUser+12);
+ const gchar *eventname = gst_structure_get_name(msgstruct);
+ if ( eventname )
+ {
+ if (!strcmp(eventname, "eventSizeChanged") || !strcmp(eventname, "eventSizeAvail"))
+ {
+ gst_structure_get_int (msgstruct, "aspect_ratio", &m_aspect);
+ gst_structure_get_int (msgstruct, "width", &m_width);
+ gst_structure_get_int (msgstruct, "height", &m_height);
+ if (strstr(eventname, "Changed"))
+ m_event((iPlayableService*)this, evVideoSizeChanged);
+ }
+ else if (!strcmp(eventname, "eventFrameRateChanged") || !strcmp(eventname, "eventFrameRateAvail"))
+ {
+ gst_structure_get_int (msgstruct, "frame_rate", &m_framerate);
+ if (strstr(eventname, "Changed"))
+ m_event((iPlayableService*)this, evVideoFramerateChanged);
+ }
+ else if (!strcmp(eventname, "eventProgressiveChanged") || !strcmp(eventname, "eventProgressiveAvail"))
+ {
+ gst_structure_get_int (msgstruct, "progressive", &m_progressive);
+ if (strstr(eventname, "Changed"))
+ m_event((iPlayableService*)this, evVideoProgressiveChanged);
+ }
+ }
}
}
- }
- default:
- break;
+ default:
+ break;
}
g_free (sourceName);
}
@@ -1081,8 +1282,14 @@ void eServiceMP3::gstCBpadAdded(GstElement *decodebin, GstPad *pad, gpointer use
}
else
{
- gst_pad_link(pad, gst_element_get_static_pad(gst_bin_get_by_name(pipeline,"queue_audio"), "sink"));
- _this->m_audioStreams.push_back(audio);
+ GstElement *queue_audio = gst_bin_get_by_name(pipeline , "queue_audio");
+ if ( queue_audio )
+ {
+ gst_pad_link(pad, gst_element_get_static_pad(queue_audio, "sink"));
+ _this->m_audioStreams.push_back(audio);
+ }
+ else
+ gst_pad_link(pad, gst_element_get_static_pad(gst_bin_get_by_name(pipeline , "audiosink"), "sink"));
}
}
if (g_strrstr(type,"video"))
@@ -1232,14 +1439,17 @@ eAutoInitPtr<eServiceFactoryMP3> init_eServiceFactoryMP3(eAutoInitNumbers::servi
void eServiceMP3::gstCBsubtitleAvail(GstElement *element, GstBuffer *buffer, GstPad *pad, gpointer user_data)
{
gint64 duration_ns = GST_BUFFER_DURATION(buffer);
- const unsigned char *text = (unsigned char *)GST_BUFFER_DATA(buffer);
- eDebug("gstCBsubtitleAvail: %s",text);
+ size_t len = GST_BUFFER_SIZE(buffer);
+ unsigned char tmp[len+1];
+ memcpy(tmp, GST_BUFFER_DATA(buffer), len);
+ tmp[len] = 0;
+ eDebug("gstCBsubtitleAvail: %s", tmp);
eServiceMP3 *_this = (eServiceMP3*)user_data;
if ( _this->m_subtitle_widget )
{
ePangoSubtitlePage page;
gRGB rgbcol(0xD0,0xD0,0xD0);
- page.m_elements.push_back(ePangoSubtitlePageElement(rgbcol, (const char*)text));
+ page.m_elements.push_back(ePangoSubtitlePageElement(rgbcol, (const char*)tmp));
page.m_timeout = duration_ns / 1000000;
(_this->m_subtitle_widget)->setPage(page);
}
diff --git a/lib/service/servicemp3.h b/lib/service/servicemp3.h
index a43c8ad9..5e706e9b 100644
--- a/lib/service/servicemp3.h
+++ b/lib/service/servicemp3.h
@@ -180,6 +180,7 @@ private:
static void gstCBsubtitlePadEvent(GstPad *pad, GstEvent *event, gpointer user_data);
GstPad* gstCreateSubtitleSink(eServiceMP3* _this, subtype_t type);
void gstPoll(const int&);
+ gint m_aspect, m_width, m_height, m_framerate, m_progressive;
};
#endif