Enigma2 plugin to to play various online streams (mostly Latvian).

servicemp3.cpp 80KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070
  1. /* note: this requires gstreamer 0.10.x and a big list of plugins. */
  2. /* it's currently hardcoded to use a big-endian alsasink as sink. */
  3. #include <lib/base/ebase.h>
  4. #include <lib/base/eerror.h>
  5. #include <lib/base/init_num.h>
  6. #include <lib/base/init.h>
  7. #include <lib/base/nconfig.h>
  8. #include <lib/base/object.h>
  9. #include <lib/dvb/epgcache.h>
  10. #include <lib/dvb/decoder.h>
  11. #include <lib/components/file_eraser.h>
  12. #include <lib/gui/esubtitle.h>
  13. #include <lib/service/servicemp3.h>
  14. #include <lib/service/servicemp3record.h>
  15. #include <lib/service/service.h>
  16. #include <lib/gdi/gpixmap.h>
  17. #include <string>
  18. #include <gst/gst.h>
  19. #include <gst/pbutils/missing-plugins.h>
  20. #include <sys/stat.h>
  21. #include <time.h>
  22. #define HTTP_TIMEOUT 30
  23. /*
  24. * UNUSED variable from service reference is now used as buffer flag for gstreamer
  25. * REFTYPE:FLAGS:STYPE:SID:TSID:ONID:NS:PARENT_SID:PARENT_TSID:UNUSED
  26. * D D X X X X X X X X
  27. * 4097:0:1:0:0:0:0:0:0:0:URL:NAME (no buffering)
  28. * 4097:0:1:0:0:0:0:0:0:1:URL:NAME (buffering enabled)
  29. * 4097:0:1:0:0:0:0:0:0:3:URL:NAME (progressive download and buffering enabled)
  30. *
  31. * Progressive download requires buffering enabled, so it's mandatory to use flag 3 not 2
  32. */
  33. typedef enum
  34. {
  35. BUFFERING_ENABLED = 0x00000001,
  36. PROGRESSIVE_DOWNLOAD = 0x00000002
  37. } eServiceMP3Flags;
  38. /*
  39. * GstPlayFlags flags from playbin2. It is the policy of GStreamer to
  40. * not publicly expose element-specific enums. That's why this
  41. * GstPlayFlags enum has been copied here.
  42. */
  43. typedef enum
  44. {
  45. GST_PLAY_FLAG_VIDEO = (1 << 0),
  46. GST_PLAY_FLAG_AUDIO = (1 << 1),
  47. GST_PLAY_FLAG_TEXT = (1 << 2),
  48. GST_PLAY_FLAG_VIS = (1 << 3),
  49. GST_PLAY_FLAG_SOFT_VOLUME = (1 << 4),
  50. GST_PLAY_FLAG_NATIVE_AUDIO = (1 << 5),
  51. GST_PLAY_FLAG_NATIVE_VIDEO = (1 << 6),
  52. GST_PLAY_FLAG_DOWNLOAD = (1 << 7),
  53. GST_PLAY_FLAG_BUFFERING = (1 << 8),
  54. GST_PLAY_FLAG_DEINTERLACE = (1 << 9),
  55. GST_PLAY_FLAG_SOFT_COLORBALANCE = (1 << 10),
  56. GST_PLAY_FLAG_FORCE_FILTERS = (1 << 11),
  57. } GstPlayFlags;
  58. // eServiceFactoryMP3
  59. /*
  60. * gstreamer suffers from a bug causing sparse streams to loose sync, after pause/resume / skip
  61. * see: https://bugzilla.gnome.org/show_bug.cgi?id=619434
  62. * As a workaround, we run the subsink in sync=false mode
  63. */
  64. #if GST_VERSION_MAJOR < 1
  65. #define GSTREAMER_SUBTITLE_SYNC_MODE_BUG
  66. #else
  67. #undef GSTREAMER_SUBTITLE_SYNC_MODE_BUG
  68. #endif
  69. /**/
  70. eServiceFactoryMP3::eServiceFactoryMP3()
  71. {
  72. ePtr<eServiceCenter> sc;
  73. eServiceCenter::getPrivInstance(sc);
  74. if (sc)
  75. {
  76. std::list<std::string> extensions;
  77. extensions.push_back("dts");
  78. extensions.push_back("mp2");
  79. extensions.push_back("mp3");
  80. extensions.push_back("ogg");
  81. extensions.push_back("ogm");
  82. extensions.push_back("ogv");
  83. extensions.push_back("mpg");
  84. extensions.push_back("vob");
  85. extensions.push_back("wav");
  86. extensions.push_back("wave");
  87. extensions.push_back("m4v");
  88. extensions.push_back("mkv");
  89. extensions.push_back("avi");
  90. extensions.push_back("divx");
  91. extensions.push_back("dat");
  92. extensions.push_back("flac");
  93. extensions.push_back("flv");
  94. extensions.push_back("mp4");
  95. extensions.push_back("mov");
  96. extensions.push_back("m4a");
  97. extensions.push_back("3gp");
  98. extensions.push_back("3g2");
  99. extensions.push_back("asf");
  100. extensions.push_back("wmv");
  101. extensions.push_back("wma");
  102. extensions.push_back("webm");
  103. extensions.push_back("stream");
  104. sc->addServiceFactory(eServiceFactoryMP3::id, this, extensions);
  105. }
  106. m_service_info = new eStaticServiceMP3Info();
  107. }
  108. eServiceFactoryMP3::~eServiceFactoryMP3()
  109. {
  110. ePtr<eServiceCenter> sc;
  111. eServiceCenter::getPrivInstance(sc);
  112. if (sc)
  113. sc->removeServiceFactory(eServiceFactoryMP3::id);
  114. }
  115. DEFINE_REF(eServiceFactoryMP3)
  116. // iServiceHandler
  117. RESULT eServiceFactoryMP3::play(const eServiceReference &ref, ePtr<iPlayableService> &ptr)
  118. {
  119. // check resources...
  120. ptr = new eServiceMP3(ref);
  121. return 0;
  122. }
  123. RESULT eServiceFactoryMP3::record(const eServiceReference &ref, ePtr<iRecordableService> &ptr)
  124. {
  125. if (ref.path.find("://") != std::string::npos)
  126. {
  127. ptr = new eServiceMP3Record((eServiceReference&)ref);
  128. return 0;
  129. }
  130. ptr=0;
  131. return -1;
  132. }
  133. RESULT eServiceFactoryMP3::list(const eServiceReference &, ePtr<iListableService> &ptr)
  134. {
  135. ptr=0;
  136. return -1;
  137. }
  138. RESULT eServiceFactoryMP3::info(const eServiceReference &ref, ePtr<iStaticServiceInformation> &ptr)
  139. {
  140. ptr = m_service_info;
  141. return 0;
  142. }
  143. class eMP3ServiceOfflineOperations: public iServiceOfflineOperations
  144. {
  145. DECLARE_REF(eMP3ServiceOfflineOperations);
  146. eServiceReference m_ref;
  147. public:
  148. eMP3ServiceOfflineOperations(const eServiceReference &ref);
  149. RESULT deleteFromDisk(int simulate);
  150. RESULT getListOfFilenames(std::list<std::string> &);
  151. RESULT reindex();
  152. };
  153. DEFINE_REF(eMP3ServiceOfflineOperations);
  154. eMP3ServiceOfflineOperations::eMP3ServiceOfflineOperations(const eServiceReference &ref): m_ref((const eServiceReference&)ref)
  155. {
  156. }
  157. RESULT eMP3ServiceOfflineOperations::deleteFromDisk(int simulate)
  158. {
  159. if (!simulate)
  160. {
  161. std::list<std::string> res;
  162. if (getListOfFilenames(res))
  163. return -1;
  164. eBackgroundFileEraser *eraser = eBackgroundFileEraser::getInstance();
  165. if (!eraser)
  166. eDebug("[eMP3ServiceOfflineOperations] FATAL !! can't get background file eraser");
  167. for (std::list<std::string>::iterator i(res.begin()); i != res.end(); ++i)
  168. {
  169. //eDebug("[eMP3ServiceOfflineOperations] Removing %s...", i->c_str());
  170. if (eraser)
  171. eraser->erase(i->c_str());
  172. else
  173. ::unlink(i->c_str());
  174. }
  175. }
  176. return 0;
  177. }
  178. RESULT eMP3ServiceOfflineOperations::getListOfFilenames(std::list<std::string> &res)
  179. {
  180. res.clear();
  181. res.push_back(m_ref.path);
  182. return 0;
  183. }
  184. RESULT eMP3ServiceOfflineOperations::reindex()
  185. {
  186. return -1;
  187. }
  188. RESULT eServiceFactoryMP3::offlineOperations(const eServiceReference &ref, ePtr<iServiceOfflineOperations> &ptr)
  189. {
  190. ptr = new eMP3ServiceOfflineOperations(ref);
  191. return 0;
  192. }
  193. // eStaticServiceMP3Info
  194. // eStaticServiceMP3Info is seperated from eServiceMP3 to give information
  195. // about unopened files.
  196. // probably eServiceMP3 should use this class as well, and eStaticServiceMP3Info
  197. // should have a database backend where ID3-files etc. are cached.
  198. // this would allow listing the mp3 database based on certain filters.
  199. DEFINE_REF(eStaticServiceMP3Info)
  200. eStaticServiceMP3Info::eStaticServiceMP3Info()
  201. {
  202. }
  203. RESULT eStaticServiceMP3Info::getName(const eServiceReference &ref, std::string &name)
  204. {
  205. if ( ref.name.length() )
  206. name = ref.name;
  207. else
  208. {
  209. size_t last = ref.path.rfind('/');
  210. if (last != std::string::npos)
  211. name = ref.path.substr(last+1);
  212. else
  213. name = ref.path;
  214. }
  215. return 0;
  216. }
  217. int eStaticServiceMP3Info::getLength(const eServiceReference &ref)
  218. {
  219. return -1;
  220. }
  221. int eStaticServiceMP3Info::getInfo(const eServiceReference &ref, int w)
  222. {
  223. switch (w)
  224. {
  225. case iServiceInformation::sTimeCreate:
  226. {
  227. struct stat s;
  228. if (stat(ref.path.c_str(), &s) == 0)
  229. {
  230. return s.st_mtime;
  231. }
  232. }
  233. break;
  234. case iServiceInformation::sFileSize:
  235. {
  236. struct stat s;
  237. if (stat(ref.path.c_str(), &s) == 0)
  238. {
  239. return s.st_size;
  240. }
  241. }
  242. break;
  243. }
  244. return iServiceInformation::resNA;
  245. }
  246. long long eStaticServiceMP3Info::getFileSize(const eServiceReference &ref)
  247. {
  248. struct stat s;
  249. if (stat(ref.path.c_str(), &s) == 0)
  250. {
  251. return s.st_size;
  252. }
  253. return 0;
  254. }
  255. RESULT eStaticServiceMP3Info::getEvent(const eServiceReference &ref, ePtr<eServiceEvent> &evt, time_t start_time)
  256. {
  257. if (ref.path.find("://") != std::string::npos)
  258. {
  259. eServiceReference equivalentref(ref);
  260. equivalentref.type = eServiceFactoryMP3::id;
  261. equivalentref.path.clear();
  262. return eEPGCache::getInstance()->lookupEventTime(equivalentref, start_time, evt);
  263. }
  264. evt = 0;
  265. return -1;
  266. }
  267. DEFINE_REF(eStreamBufferInfo)
  268. eStreamBufferInfo::eStreamBufferInfo(int percentage, int inputrate, int outputrate, int space, int size)
  269. : bufferPercentage(percentage),
  270. inputRate(inputrate),
  271. outputRate(outputrate),
  272. bufferSpace(space),
  273. bufferSize(size)
  274. {
  275. }
  276. int eStreamBufferInfo::getBufferPercentage() const
  277. {
  278. return bufferPercentage;
  279. }
  280. int eStreamBufferInfo::getAverageInputRate() const
  281. {
  282. return inputRate;
  283. }
  284. int eStreamBufferInfo::getAverageOutputRate() const
  285. {
  286. return outputRate;
  287. }
  288. int eStreamBufferInfo::getBufferSpace() const
  289. {
  290. return bufferSpace;
  291. }
  292. int eStreamBufferInfo::getBufferSize() const
  293. {
  294. return bufferSize;
  295. }
  296. DEFINE_REF(eServiceMP3InfoContainer);
  297. eServiceMP3InfoContainer::eServiceMP3InfoContainer()
  298. : doubleValue(0.0), bufferValue(NULL), bufferData(NULL), bufferSize(0)
  299. {
  300. }
  301. eServiceMP3InfoContainer::~eServiceMP3InfoContainer()
  302. {
  303. if (bufferValue)
  304. {
  305. #if GST_VERSION_MAJOR >= 1
  306. gst_buffer_unmap(bufferValue, &map);
  307. #endif
  308. gst_buffer_unref(bufferValue);
  309. bufferValue = NULL;
  310. bufferData = NULL;
  311. bufferSize = 0;
  312. }
  313. }
  314. double eServiceMP3InfoContainer::getDouble(unsigned int index) const
  315. {
  316. return doubleValue;
  317. }
  318. unsigned char *eServiceMP3InfoContainer::getBuffer(unsigned int &size) const
  319. {
  320. size = bufferSize;
  321. return bufferData;
  322. }
  323. void eServiceMP3InfoContainer::setDouble(double value)
  324. {
  325. doubleValue = value;
  326. }
  327. void eServiceMP3InfoContainer::setBuffer(GstBuffer *buffer)
  328. {
  329. bufferValue = buffer;
  330. gst_buffer_ref(bufferValue);
  331. #if GST_VERSION_MAJOR < 1
  332. bufferData = GST_BUFFER_DATA(bufferValue);
  333. bufferSize = GST_BUFFER_SIZE(bufferValue);
  334. #else
  335. gst_buffer_map(bufferValue, &map, GST_MAP_READ);
  336. bufferData = map.data;
  337. bufferSize = map.size;
  338. #endif
  339. }
  340. // eServiceMP3
  341. int eServiceMP3::ac3_delay = 0,
  342. eServiceMP3::pcm_delay = 0;
  343. eServiceMP3::eServiceMP3(eServiceReference ref):
  344. m_nownext_timer(eTimer::create(eApp)),
  345. m_cuesheet_changed(0),
  346. m_cutlist_enabled(1),
  347. m_ref(ref),
  348. m_pump(eApp, 1)
  349. {
  350. m_subtitle_sync_timer = eTimer::create(eApp);
  351. m_stream_tags = 0;
  352. m_currentAudioStream = -1;
  353. m_currentSubtitleStream = -1;
  354. m_cachedSubtitleStream = 0; /* report the first subtitle stream to be 'cached'. TODO: use an actual cache. */
  355. m_subtitle_widget = 0;
  356. m_currentTrickRatio = 1.0;
  357. m_buffer_size = 5 * 1024 * 1024;
  358. m_ignore_buffering_messages = 0;
  359. m_is_live = false;
  360. m_use_prefillbuffer = false;
  361. m_paused = false;
  362. m_cuesheet_loaded = false; /* cuesheet CVR */
  363. #if GST_VERSION_MAJOR >= 1
  364. m_use_chapter_entries = false; /* TOC chapter support CVR */
  365. m_last_seek_pos = 0; /* CVR last seek position */
  366. #endif
  367. m_useragent = "Enigma2 HbbTV/1.1.1 (+PVR+RTSP+DL;openATV;;;)";
  368. m_extra_headers = "";
  369. m_download_buffer_path = "";
  370. m_prev_decoder_time = -1;
  371. m_decoder_time_valid_state = 0;
  372. m_errorInfo.missing_codec = "";
  373. audioSink = videoSink = NULL;
  374. CONNECT(m_subtitle_sync_timer->timeout, eServiceMP3::pushSubtitles);
  375. CONNECT(m_pump.recv_msg, eServiceMP3::gstPoll);
  376. CONNECT(m_nownext_timer->timeout, eServiceMP3::updateEpgCacheNowNext);
  377. m_aspect = m_width = m_height = m_framerate = m_progressive = -1;
  378. m_state = stIdle;
  379. m_subtitles_paused = false;
  380. // eDebug("[eServiceMP3] construct!");
  381. const char *filename;
  382. std::string filename_str;
  383. size_t pos = m_ref.path.find('#');
  384. if (pos != std::string::npos && (m_ref.path.compare(0, 4, "http") == 0 || m_ref.path.compare(0, 4, "rtsp") == 0))
  385. {
  386. filename_str = m_ref.path.substr(0, pos);
  387. filename = filename_str.c_str();
  388. m_extra_headers = m_ref.path.substr(pos + 1);
  389. pos = m_extra_headers.find("User-Agent=");
  390. if (pos != std::string::npos)
  391. {
  392. size_t hpos_start = pos + 11;
  393. size_t hpos_end = m_extra_headers.find('&', hpos_start);
  394. if (hpos_end != std::string::npos)
  395. m_useragent = m_extra_headers.substr(hpos_start, hpos_end - hpos_start);
  396. else
  397. m_useragent = m_extra_headers.substr(hpos_start);
  398. }
  399. }
  400. else
  401. filename = m_ref.path.c_str();
  402. const char *ext = strrchr(filename, '.');
  403. if (!ext)
  404. ext = filename + strlen(filename);
  405. m_sourceinfo.is_video = FALSE;
  406. m_sourceinfo.audiotype = atUnknown;
  407. if ( (strcasecmp(ext, ".mpeg") && strcasecmp(ext, ".mpg") && strcasecmp(ext, ".vob") && strcasecmp(ext, ".bin") && strcasecmp(ext, ".dat") ) == 0 )
  408. {
  409. m_sourceinfo.containertype = ctMPEGPS;
  410. m_sourceinfo.is_video = TRUE;
  411. }
  412. else if ( strcasecmp(ext, ".ts") == 0 )
  413. {
  414. m_sourceinfo.containertype = ctMPEGTS;
  415. m_sourceinfo.is_video = TRUE;
  416. }
  417. else if ( strcasecmp(ext, ".mkv") == 0 )
  418. {
  419. m_sourceinfo.containertype = ctMKV;
  420. m_sourceinfo.is_video = TRUE;
  421. }
  422. else if ( strcasecmp(ext, ".ogm") == 0 || strcasecmp(ext, ".ogv") == 0)
  423. {
  424. m_sourceinfo.containertype = ctOGG;
  425. m_sourceinfo.is_video = TRUE;
  426. }
  427. else if ( strcasecmp(ext, ".avi") == 0 || strcasecmp(ext, ".divx") == 0)
  428. {
  429. m_sourceinfo.containertype = ctAVI;
  430. m_sourceinfo.is_video = TRUE;
  431. }
  432. else if ( strcasecmp(ext, ".mp4") == 0 || strcasecmp(ext, ".mov") == 0 || strcasecmp(ext, ".m4v") == 0 || strcasecmp(ext, ".3gp") == 0 || strcasecmp(ext, ".3g2") == 0)
  433. {
  434. m_sourceinfo.containertype = ctMP4;
  435. m_sourceinfo.is_video = TRUE;
  436. }
  437. else if ( strcasecmp(ext, ".asf") == 0 || strcasecmp(ext, ".wmv") == 0)
  438. {
  439. m_sourceinfo.containertype = ctASF;
  440. m_sourceinfo.is_video = TRUE;
  441. }
  442. else if ( strcasecmp(ext, ".webm") == 0)
  443. {
  444. m_sourceinfo.containertype = ctWEBM;
  445. m_sourceinfo.is_video = TRUE;
  446. }
  447. else if ( strcasecmp(ext, ".m4a") == 0 )
  448. {
  449. m_sourceinfo.containertype = ctMP4;
  450. m_sourceinfo.audiotype = atAAC;
  451. }
  452. else if ( strcasecmp(ext, ".mp3") == 0 )
  453. m_sourceinfo.audiotype = atMP3;
  454. else if ( strcasecmp(ext, ".wma") == 0 )
  455. m_sourceinfo.audiotype = atWMA;
  456. else if ( strcasecmp(ext, ".wav") == 0 )
  457. m_sourceinfo.audiotype = atPCM;
  458. else if ( strcasecmp(ext, ".cda") == 0)
  459. m_sourceinfo.containertype = ctCDA;
  460. if ( strcasecmp(ext, ".dat") == 0 )
  461. {
  462. m_sourceinfo.containertype = ctVCD;
  463. m_sourceinfo.is_video = TRUE;
  464. }
  465. if ( strstr(filename, "://") )
  466. m_sourceinfo.is_streaming = TRUE;
  467. gchar *uri;
  468. if ( m_sourceinfo.is_streaming )
  469. {
  470. uri = g_strdup_printf ("%s", filename);
  471. if ( m_ref.getData(7) & BUFFERING_ENABLED )
  472. {
  473. m_use_prefillbuffer = true;
  474. if ( m_ref.getData(7) & PROGRESSIVE_DOWNLOAD )
  475. {
  476. /* progressive download buffering */
  477. if (::access("/hdd/movie", X_OK) >= 0)
  478. {
  479. /* It looks like /hdd points to a valid mount, so we can store a download buffer on it */
  480. m_download_buffer_path = "/hdd/gstreamer_XXXXXXXXXX";
  481. }
  482. }
  483. }
  484. }
  485. else if ( m_sourceinfo.containertype == ctCDA )
  486. {
  487. int i_track = atoi(filename+(strlen(filename) - 6));
  488. uri = g_strdup_printf ("cdda://%i", i_track);
  489. }
  490. else if ( m_sourceinfo.containertype == ctVCD )
  491. {
  492. int ret = -1;
  493. int fd = open(filename,O_RDONLY);
  494. if (fd >= 0)
  495. {
  496. char* tmp = new char[128*1024];
  497. ret = read(fd, tmp, 128*1024);
  498. close(fd);
  499. delete [] tmp;
  500. }
  501. if ( ret == -1 ) // this is a "REAL" VCD
  502. uri = g_strdup_printf ("vcd://");
  503. else
  504. uri = g_filename_to_uri(filename, NULL, NULL);
  505. }
  506. else
  507. uri = g_filename_to_uri(filename, NULL, NULL);
  508. // eDebug("[eServiceMP3] playbin uri=%s", uri);
  509. #if GST_VERSION_MAJOR < 1
  510. m_gst_playbin = gst_element_factory_make("playbin2", "playbin");
  511. #else
  512. m_gst_playbin = gst_element_factory_make("playbin", "playbin");
  513. #endif
  514. if ( m_gst_playbin )
  515. {
  516. /*
  517. * avoid video conversion, let the dvbmediasink handle that using native video flag
  518. * volume control is done by hardware, do not use soft volume flag
  519. */
  520. guint flags = GST_PLAY_FLAG_AUDIO | GST_PLAY_FLAG_VIDEO | \
  521. GST_PLAY_FLAG_TEXT | GST_PLAY_FLAG_NATIVE_VIDEO;
  522. if ( m_sourceinfo.is_streaming )
  523. {
  524. g_signal_connect (G_OBJECT (m_gst_playbin), "notify::source", G_CALLBACK (playbinNotifySource), this);
  525. if (m_download_buffer_path != "")
  526. {
  527. /* use progressive download buffering */
  528. flags |= GST_PLAY_FLAG_DOWNLOAD;
  529. g_signal_connect(G_OBJECT(m_gst_playbin), "element-added", G_CALLBACK(handleElementAdded), this);
  530. /* limit file size */
  531. g_object_set(m_gst_playbin, "ring-buffer-max-size", (guint64)(8LL * 1024LL * 1024LL), NULL);
  532. }
  533. /*
  534. * regardless whether or not we configured a progressive download file, use a buffer as well
  535. * (progressive download might not work for all formats)
  536. */
  537. flags |= GST_PLAY_FLAG_BUFFERING;
  538. /* increase the default 2 second / 2 MB buffer limitations to 5s / 5MB */
  539. g_object_set(G_OBJECT(m_gst_playbin), "buffer-duration", 5LL * GST_SECOND, NULL);
  540. g_object_set(G_OBJECT(m_gst_playbin), "buffer-size", m_buffer_size, NULL);
  541. }
  542. g_object_set (G_OBJECT (m_gst_playbin), "flags", flags, NULL);
  543. g_object_set (G_OBJECT (m_gst_playbin), "uri", uri, NULL);
  544. GstElement *subsink = gst_element_factory_make("subsink", "subtitle_sink");
  545. if (!subsink)
  546. eDebug("[eServiceMP3] sorry, can't play: missing gst-plugin-subsink");
  547. else
  548. {
  549. m_subs_to_pull_handler_id = g_signal_connect (subsink, "new-buffer", G_CALLBACK (gstCBsubtitleAvail), this);
  550. #if GST_VERSION_MAJOR < 1
  551. g_object_set (G_OBJECT (subsink), "caps", gst_caps_from_string("text/plain; text/x-plain; text/x-raw; text/x-pango-markup; video/x-dvd-subpicture; subpicture/x-pgs"), NULL);
  552. #else
  553. g_object_set (G_OBJECT (subsink), "caps", gst_caps_from_string("text/plain; text/x-plain; text/x-raw; text/x-pango-markup; subpicture/x-dvd; subpicture/x-pgs"), NULL);
  554. #endif
  555. g_object_set (G_OBJECT (m_gst_playbin), "text-sink", subsink, NULL);
  556. g_object_set (G_OBJECT (m_gst_playbin), "current-text", m_currentSubtitleStream, NULL);
  557. }
  558. GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE (m_gst_playbin));
  559. #if GST_VERSION_MAJOR < 1
  560. gst_bus_set_sync_handler(bus, gstBusSyncHandler, this);
  561. #else
  562. gst_bus_set_sync_handler(bus, gstBusSyncHandler, this, NULL);
  563. #endif
  564. gst_object_unref(bus);
  565. char srt_filename[ext - filename + 5];
  566. strncpy(srt_filename,filename, ext - filename);
  567. srt_filename[ext - filename] = '\0';
  568. strcat(srt_filename, ".srt");
  569. if (::access(srt_filename, R_OK) >= 0)
  570. {
  571. eDebug("[eServiceMP3] subtitle uri: %s", g_filename_to_uri(srt_filename, NULL, NULL));
  572. g_object_set (G_OBJECT (m_gst_playbin), "suburi", g_filename_to_uri(srt_filename, NULL, NULL), NULL);
  573. }
  574. } else
  575. {
  576. m_event((iPlayableService*)this, evUser+12);
  577. m_gst_playbin = 0;
  578. m_errorInfo.error_message = "failed to create GStreamer pipeline!\n";
  579. eDebug("[eServiceMP3] sorry, can't play: %s",m_errorInfo.error_message.c_str());
  580. }
  581. g_free(uri);
  582. }
  583. eServiceMP3::~eServiceMP3()
  584. {
  585. // disconnect subtitle callback
  586. GstElement *subsink = gst_bin_get_by_name(GST_BIN(m_gst_playbin), "subtitle_sink");
  587. if (subsink)
  588. {
  589. g_signal_handler_disconnect (subsink, m_subs_to_pull_handler_id);
  590. gst_object_unref(subsink);
  591. }
  592. if (m_subtitle_widget) m_subtitle_widget->destroy();
  593. m_subtitle_widget = 0;
  594. if (m_gst_playbin)
  595. {
  596. // disconnect sync handler callback
  597. GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE (m_gst_playbin));
  598. #if GST_VERSION_MAJOR < 1
  599. gst_bus_set_sync_handler(bus, NULL, NULL);
  600. #else
  601. gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
  602. #endif
  603. gst_object_unref(bus);
  604. }
  605. stop();
  606. if (m_stream_tags)
  607. gst_tag_list_free(m_stream_tags);
  608. if (audioSink)
  609. {
  610. gst_object_unref(GST_OBJECT(audioSink));
  611. audioSink = NULL;
  612. }
  613. if (videoSink)
  614. {
  615. gst_object_unref(GST_OBJECT(videoSink));
  616. videoSink = NULL;
  617. }
  618. if (m_gst_playbin)
  619. {
  620. gst_object_unref (GST_OBJECT (m_gst_playbin));
  621. // eDebug("[eServiceMP3] destruct!");
  622. }
  623. }
  624. void eServiceMP3::updateEpgCacheNowNext()
  625. {
  626. bool update = false;
  627. ePtr<eServiceEvent> next = 0;
  628. ePtr<eServiceEvent> ptr = 0;
  629. eServiceReference ref(m_ref);
  630. ref.type = eServiceFactoryMP3::id;
  631. ref.path.clear();
  632. if (eEPGCache::getInstance() && eEPGCache::getInstance()->lookupEventTime(ref, -1, ptr) >= 0)
  633. {
  634. ePtr<eServiceEvent> current = m_event_now;
  635. if (!current || !ptr || current->getEventId() != ptr->getEventId())
  636. {
  637. update = true;
  638. m_event_now = ptr;
  639. time_t next_time = ptr->getBeginTime() + ptr->getDuration();
  640. if (eEPGCache::getInstance()->lookupEventTime(ref, next_time, ptr) >= 0)
  641. {
  642. next = ptr;
  643. m_event_next = ptr;
  644. }
  645. }
  646. }
  647. int refreshtime = 60;
  648. if (!next)
  649. {
  650. next = m_event_next;
  651. }
  652. if (next)
  653. {
  654. time_t now = eDVBLocalTimeHandler::getInstance()->nowTime();
  655. refreshtime = (int)(next->getBeginTime() - now) + 3;
  656. if (refreshtime <= 0 || refreshtime > 60)
  657. {
  658. refreshtime = 60;
  659. }
  660. }
  661. m_nownext_timer->startLongTimer(refreshtime);
  662. if (update)
  663. {
  664. m_event((iPlayableService*)this, evUpdatedEventInfo);
  665. }
  666. }
  667. DEFINE_REF(eServiceMP3);
  668. DEFINE_REF(GstMessageContainer);
  669. RESULT eServiceMP3::connectEvent(const Slot2<void,iPlayableService*,int> &event, ePtr<eConnection> &connection)
  670. {
  671. connection = new eConnection((iPlayableService*)this, m_event.connect(event));
  672. return 0;
  673. }
  674. RESULT eServiceMP3::start()
  675. {
  676. ASSERT(m_state == stIdle);
  677. m_subtitles_paused = false;
  678. if (m_gst_playbin)
  679. {
  680. // eDebug("[eServiceMP3] starting pipeline");
  681. GstStateChangeReturn ret;
  682. ret = gst_element_set_state (m_gst_playbin, GST_STATE_PLAYING);
  683. switch(ret)
  684. {
  685. case GST_STATE_CHANGE_FAILURE:
  686. eDebug("[eServiceMP3] failed to start pipeline");
  687. stop();
  688. break;
  689. case GST_STATE_CHANGE_SUCCESS:
  690. m_is_live = false;
  691. break;
  692. case GST_STATE_CHANGE_NO_PREROLL:
  693. m_is_live = true;
  694. break;
  695. default:
  696. break;
  697. }
  698. }
  699. return 0;
  700. }
  701. RESULT eServiceMP3::stop()
  702. {
  703. if (!m_gst_playbin || m_state == stStopped)
  704. return -1;
  705. eDebug("[eServiceMP3] stop %s", m_ref.path.c_str());
  706. m_state = stStopped;
  707. GstStateChangeReturn ret;
  708. GstState state, pending;
  709. /* make sure that last state change was successfull */
  710. ret = gst_element_get_state(m_gst_playbin, &state, &pending, 5 * GST_SECOND);
  711. eDebug("[eServiceMP3] stop state:%s pending:%s ret:%s",
  712. gst_element_state_get_name(state),
  713. gst_element_state_get_name(pending),
  714. gst_element_state_change_return_get_name(ret));
  715. ret = gst_element_set_state(m_gst_playbin, GST_STATE_NULL);
  716. if (ret != GST_STATE_CHANGE_SUCCESS)
  717. eDebug("[eServiceMP3] stop GST_STATE_NULL failure");
  718. saveCuesheet();
  719. m_subtitles_paused = false;
  720. m_nownext_timer->stop();
  721. return 0;
  722. }
  723. RESULT eServiceMP3::setTarget(int target)
  724. {
  725. return -1;
  726. }
  727. RESULT eServiceMP3::pause(ePtr<iPauseableService> &ptr)
  728. {
  729. ptr=this;
  730. return 0;
  731. }
  732. RESULT eServiceMP3::setSlowMotion(int ratio)
  733. {
  734. if (!ratio)
  735. return 0;
  736. eDebug("[eServiceMP3] setSlowMotion ratio=%f",1.0/(gdouble)ratio);
  737. return trickSeek(1.0/(gdouble)ratio);
  738. }
  739. RESULT eServiceMP3::setFastForward(int ratio)
  740. {
  741. eDebug("[eServiceMP3] setFastForward ratio=%i",ratio);
  742. return trickSeek(ratio);
  743. }
  744. // iPausableService
  745. RESULT eServiceMP3::pause()
  746. {
  747. if (!m_gst_playbin || m_state != stRunning)
  748. return -1;
  749. m_subtitles_paused = true;
  750. m_subtitle_sync_timer->start(1, true);
  751. eDebug("[eServiceMP3] pause");
  752. trickSeek(0.0);
  753. return 0;
  754. }
  755. RESULT eServiceMP3::unpause()
  756. {
  757. if (!m_gst_playbin || m_state != stRunning)
  758. return -1;
  759. m_subtitles_paused = false;
  760. m_subtitle_sync_timer->start(1, true);
  761. /* no need to unpase if we are not paused already */
  762. if (m_currentTrickRatio == 1.0 && !m_paused)
  763. {
  764. eDebug("[eServiceMP3] trickSeek no need to unpause!");
  765. return 0;
  766. }
  767. eDebug("[eServiceMP3] unpause");
  768. trickSeek(1.0);
  769. return 0;
  770. }
  771. /* iSeekableService */
  772. RESULT eServiceMP3::seek(ePtr<iSeekableService> &ptr)
  773. {
  774. ptr = this;
  775. return 0;
  776. }
  777. RESULT eServiceMP3::getLength(pts_t &pts)
  778. {
  779. if (!m_gst_playbin || m_state != stRunning)
  780. return -1;
  781. GstFormat fmt = GST_FORMAT_TIME;
  782. gint64 len;
  783. #if GST_VERSION_MAJOR < 1
  784. if (!gst_element_query_duration(m_gst_playbin, &fmt, &len))
  785. #else
  786. if (!gst_element_query_duration(m_gst_playbin, fmt, &len))
  787. #endif
  788. return -1;
  789. /* len is in nanoseconds. we have 90 000 pts per second. */
  790. pts = len / 11111LL;
  791. return 0;
  792. }
  793. RESULT eServiceMP3::seekToImpl(pts_t to)
  794. {
  795. /* convert pts to nanoseconds */
  796. #if GST_VERSION_MAJOR < 1
  797. gint64 time_nanoseconds = to * 11111LL;
  798. if (!gst_element_seek (m_gst_playbin, m_currentTrickRatio, GST_FORMAT_TIME, (GstSeekFlags)(GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT),
  799. GST_SEEK_TYPE_SET, time_nanoseconds,
  800. GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE))
  801. #else
  802. m_last_seek_pos = to * 11111LL;
  803. if (!gst_element_seek (m_gst_playbin, m_currentTrickRatio, GST_FORMAT_TIME, (GstSeekFlags)(GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT),
  804. GST_SEEK_TYPE_SET, m_last_seek_pos,
  805. GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE))
  806. #endif
  807. {
  808. eDebug("[eServiceMP3] seekTo failed");
  809. return -1;
  810. }
  811. if (m_paused)
  812. {
  813. m_event((iPlayableService*)this, evUpdatedInfo);
  814. }
  815. return 0;
  816. }
  817. RESULT eServiceMP3::seekTo(pts_t to)
  818. {
  819. RESULT ret = -1;
  820. if (m_gst_playbin)
  821. {
  822. m_prev_decoder_time = -1;
  823. m_decoder_time_valid_state = 0;
  824. ret = seekToImpl(to);
  825. }
  826. return ret;
  827. }
  828. RESULT eServiceMP3::trickSeek(gdouble ratio)
  829. {
  830. if (!m_gst_playbin)
  831. return -1;
  832. GstState state, pending;
  833. if (ratio > -0.01 && ratio < 0.01)
  834. {
  835. gst_element_set_state(m_gst_playbin, GST_STATE_PAUSED);
  836. /* pipeline sometimes block due to audio track issue off gstreamer.
  837. If the pipeline is blocked up on pending state change to paused ,
  838. this issue is solved be just reslecting the current audio track.*/
  839. gst_element_get_state(m_gst_playbin, &state, &pending, 1 * GST_SECOND);
  840. if (state == GST_STATE_PLAYING && pending == GST_STATE_PAUSED)
  841. {
  842. if (m_currentAudioStream >= 0)
  843. selectTrack(m_currentAudioStream);
  844. else
  845. selectTrack(0);
  846. }
  847. return 0;
  848. }
  849. bool unpause = (m_currentTrickRatio == 1.0 && ratio == 1.0);
  850. if (unpause)
  851. {
  852. GstElement *source = NULL;
  853. GstElementFactory *factory = NULL;
  854. const gchar *name = NULL;
  855. g_object_get (G_OBJECT (m_gst_playbin), "source", &source, NULL);
  856. if (!source)
  857. {
  858. eDebugNoNewLineStart("[eServiceMP3] trickSeek - cannot get source");
  859. goto seek_unpause;
  860. }
  861. factory = gst_element_get_factory(source);
  862. g_object_unref(source);
  863. if (!factory)
  864. {
  865. eDebugNoNewLineStart("[eServiceMP3] trickSeek - cannot get source factory");
  866. goto seek_unpause;
  867. }
  868. name = gst_plugin_feature_get_name(GST_PLUGIN_FEATURE(factory));
  869. if (!name)
  870. {
  871. eDebugNoNewLineStart("[eServiceMP3] trickSeek - cannot get source name");
  872. goto seek_unpause;
  873. }
  874. /*
  875. * We know that filesrc and souphttpsrc will not timeout after long pause
  876. * If there are other sources which will not timeout, add them here
  877. */
  878. if (!strcmp(name, "filesrc") || !strcmp(name, "souphttpsrc"))
  879. {
  880. GstStateChangeReturn ret;
  881. /* make sure that last state change was successfull */
  882. ret = gst_element_get_state(m_gst_playbin, &state, &pending, 0);
  883. if (ret == GST_STATE_CHANGE_SUCCESS)
  884. {
  885. gst_element_set_state(m_gst_playbin, GST_STATE_PLAYING);
  886. ret = gst_element_get_state(m_gst_playbin, &state, &pending, 0);
  887. if (ret == GST_STATE_CHANGE_SUCCESS)
  888. return 0;
  889. }
  890. eDebugNoNewLineStart("[eServiceMP3] trickSeek - invalid state, state:%s pending:%s ret:%s",
  891. gst_element_state_get_name(state),
  892. gst_element_state_get_name(pending),
  893. gst_element_state_change_return_get_name(ret));
  894. }
  895. else
  896. {
  897. eDebugNoNewLineStart("[eServiceMP3] trickSeek - source '%s' is not supported", name);
  898. }
  899. seek_unpause:
  900. eDebugNoNewLine(", doing seeking unpause\n");
  901. }
  902. m_currentTrickRatio = ratio;
  903. bool validposition = false;
  904. gint64 pos = 0;
  905. pts_t pts;
  906. if (getPlayPosition(pts) >= 0)
  907. {
  908. validposition = true;
  909. pos = pts * 11111LL;
  910. }
  911. gst_element_get_state(m_gst_playbin, &state, &pending, 1 * GST_SECOND);
  912. if (state != GST_STATE_PLAYING)
  913. gst_element_set_state(m_gst_playbin, GST_STATE_PLAYING);
  914. if (validposition)
  915. {
  916. if (ratio >= 0.0)
  917. {
  918. gst_element_seek(m_gst_playbin, ratio, GST_FORMAT_TIME, (GstSeekFlags)(GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SKIP), GST_SEEK_TYPE_SET, pos, GST_SEEK_TYPE_SET, -1);
  919. }
  920. else
  921. {
  922. /* note that most elements will not support negative speed */
  923. gst_element_seek(m_gst_playbin, ratio, GST_FORMAT_TIME, (GstSeekFlags)(GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SKIP), GST_SEEK_TYPE_SET, 0, GST_SEEK_TYPE_SET, pos);
  924. }
  925. }
  926. m_prev_decoder_time = -1;
  927. m_decoder_time_valid_state = 0;
  928. return 0;
  929. }
  930. RESULT eServiceMP3::seekRelative(int direction, pts_t to)
  931. {
  932. if (!m_gst_playbin)
  933. return -1;
  934. pts_t ppos;
  935. if (getPlayPosition(ppos) < 0) return -1;
  936. ppos += to * direction;
  937. if (ppos < 0)
  938. ppos = 0;
  939. return seekTo(ppos);
  940. }
  941. #if GST_VERSION_MAJOR < 1
  942. gint eServiceMP3::match_sinktype(GstElement *element, gpointer type)
  943. {
  944. return strcmp(g_type_name(G_OBJECT_TYPE(element)), (const char*)type);
  945. }
  946. #else
  947. gint eServiceMP3::match_sinktype(const GValue *velement, const gchar *type)
  948. {
  949. GstElement *element = GST_ELEMENT_CAST(g_value_get_object(velement));
  950. return strcmp(g_type_name(G_OBJECT_TYPE(element)), type);
  951. }
  952. #endif
  953. RESULT eServiceMP3::getPlayPosition(pts_t &pts)
  954. {
  955. gint64 pos;
  956. pts = 0;
  957. if (!m_gst_playbin || m_state != stRunning)
  958. return -1;
  959. if ((audioSink || videoSink) && !m_paused)
  960. {
  961. g_signal_emit_by_name(videoSink ? videoSink : audioSink, "get-decoder-time", &pos);
  962. if (!GST_CLOCK_TIME_IS_VALID(pos)) return -1;
  963. }
  964. else
  965. {
  966. GstFormat fmt = GST_FORMAT_TIME;
  967. #if GST_VERSION_MAJOR < 1
  968. if (!gst_element_query_position(m_gst_playbin, &fmt, &pos))
  969. #else
  970. if (!gst_element_query_position(m_gst_playbin, fmt, &pos))
  971. #endif
  972. {
  973. // eDebug("[eServiceMP3] gst_element_query_position failed in getPlayPosition");
  974. return -1;
  975. }
  976. }
  977. /* pos is in nanoseconds. we have 90 000 pts per second. */
  978. pts = pos / 11111LL;
  979. return 0;
  980. }
  981. RESULT eServiceMP3::setTrickmode(int trick)
  982. {
  983. /* trickmode is not yet supported by our dvbmediasinks. */
  984. return -1;
  985. }
  986. RESULT eServiceMP3::isCurrentlySeekable()
  987. {
  988. int ret = 3; /* just assume that seeking and fast/slow winding are possible */
  989. if (!m_gst_playbin)
  990. return 0;
  991. return ret;
  992. }
  993. RESULT eServiceMP3::info(ePtr<iServiceInformation>&i)
  994. {
  995. i = this;
  996. return 0;
  997. }
  998. RESULT eServiceMP3::getName(std::string &name)
  999. {
  1000. std::string title = m_ref.getName();
  1001. if (title.empty())
  1002. {
  1003. name = m_ref.path;
  1004. size_t n = name.rfind('/');
  1005. if (n != std::string::npos)
  1006. name = name.substr(n + 1);
  1007. }
  1008. else
  1009. name = title;
  1010. return 0;
  1011. }
  1012. RESULT eServiceMP3::getEvent(ePtr<eServiceEvent> &evt, int nownext)
  1013. {
  1014. evt = nownext ? m_event_next : m_event_now;
  1015. if (!evt)
  1016. return -1;
  1017. return 0;
  1018. }
  1019. int eServiceMP3::getInfo(int w)
  1020. {
  1021. const gchar *tag = 0;
  1022. switch (w)
  1023. {
  1024. case sServiceref: return m_ref;
  1025. case sVideoHeight: return m_height;
  1026. case sVideoWidth: return m_width;
  1027. case sFrameRate: return m_framerate;
  1028. case sProgressive: return m_progressive;
  1029. case sAspect: return m_aspect;
  1030. case sTagTitle:
  1031. case sTagArtist:
  1032. case sTagAlbum:
  1033. case sTagTitleSortname:
  1034. case sTagArtistSortname:
  1035. case sTagAlbumSortname:
  1036. case sTagDate:
  1037. case sTagComposer:
  1038. case sTagGenre:
  1039. case sTagComment:
  1040. case sTagExtendedComment:
  1041. case sTagLocation:
  1042. case sTagHomepage:
  1043. case sTagDescription:
  1044. case sTagVersion:
  1045. case sTagISRC:
  1046. case sTagOrganization:
  1047. case sTagCopyright:
  1048. case sTagCopyrightURI:
  1049. case sTagContact:
  1050. case sTagLicense:
  1051. case sTagLicenseURI:
  1052. case sTagCodec:
  1053. case sTagAudioCodec:
  1054. case sTagVideoCodec:
  1055. case sTagEncoder:
  1056. case sTagLanguageCode:
  1057. case sTagKeywords:
  1058. case sTagChannelMode:
  1059. case sUser+12:
  1060. return resIsString;
  1061. case sTagTrackGain:
  1062. case sTagTrackPeak:
  1063. case sTagAlbumGain:
  1064. case sTagAlbumPeak:
  1065. case sTagReferenceLevel:
  1066. case sTagBeatsPerMinute:
  1067. case sTagImage:
  1068. case sTagPreviewImage:
  1069. case sTagAttachment:
  1070. return resIsPyObject;
  1071. case sTagTrackNumber:
  1072. tag = GST_TAG_TRACK_NUMBER;
  1073. break;
  1074. case sTagTrackCount:
  1075. tag = GST_TAG_TRACK_COUNT;
  1076. break;
  1077. case sTagAlbumVolumeNumber:
  1078. tag = GST_TAG_ALBUM_VOLUME_NUMBER;
  1079. break;
  1080. case sTagAlbumVolumeCount:
  1081. tag = GST_TAG_ALBUM_VOLUME_COUNT;
  1082. break;
  1083. case sTagBitrate:
  1084. tag = GST_TAG_BITRATE;
  1085. break;
  1086. case sTagNominalBitrate:
  1087. tag = GST_TAG_NOMINAL_BITRATE;
  1088. break;
  1089. case sTagMinimumBitrate:
  1090. tag = GST_TAG_MINIMUM_BITRATE;
  1091. break;
  1092. case sTagMaximumBitrate:
  1093. tag = GST_TAG_MAXIMUM_BITRATE;
  1094. break;
  1095. case sTagSerial:
  1096. tag = GST_TAG_SERIAL;
  1097. break;
  1098. case sTagEncoderVersion:
  1099. tag = GST_TAG_ENCODER_VERSION;
  1100. break;
  1101. case sTagCRC:
  1102. tag = "has-crc";
  1103. break;
  1104. case sBuffer: return m_bufferInfo.bufferPercent;
  1105. default:
  1106. return resNA;
  1107. }
  1108. if (!m_stream_tags || !tag)
  1109. return 0;
  1110. guint value;
  1111. if (gst_tag_list_get_uint(m_stream_tags, tag, &value))
  1112. return (int) value;
  1113. return 0;
  1114. }
  1115. std::string eServiceMP3::getInfoString(int w)
  1116. {
  1117. if ( m_sourceinfo.is_streaming )
  1118. {
  1119. switch (w)
  1120. {
  1121. case sProvider:
  1122. return "IPTV";
  1123. case sServiceref:
  1124. {
  1125. eServiceReference ref(m_ref);
  1126. ref.type = eServiceFactoryMP3::id;
  1127. ref.path.clear();
  1128. return ref.toString();
  1129. }
  1130. default:
  1131. break;
  1132. }
  1133. }
  1134. if ( !m_stream_tags && w < sUser && w > 26 )
  1135. return "";
  1136. const gchar *tag = 0;
  1137. switch (w)
  1138. {
  1139. case sTagTitle:
  1140. tag = GST_TAG_TITLE;
  1141. break;
  1142. case sTagArtist:
  1143. tag = GST_TAG_ARTIST;
  1144. break;
  1145. case sTagAlbum:
  1146. tag = GST_TAG_ALBUM;
  1147. break;
  1148. case sTagTitleSortname:
  1149. tag = GST_TAG_TITLE_SORTNAME;
  1150. break;
  1151. case sTagArtistSortname:
  1152. tag = GST_TAG_ARTIST_SORTNAME;
  1153. break;
  1154. case sTagAlbumSortname:
  1155. tag = GST_TAG_ALBUM_SORTNAME;
  1156. break;
  1157. case sTagDate:
  1158. GDate *date;
  1159. GstDateTime *date_time;
  1160. if (gst_tag_list_get_date(m_stream_tags, GST_TAG_DATE, &date))
  1161. {
  1162. gchar res[5];
  1163. snprintf(res, sizeof(res), "%04d", g_date_get_year(date));
  1164. g_date_free(date);
  1165. return (std::string)res;
  1166. }
  1167. #if GST_VERSION_MAJOR >= 1
  1168. else if (gst_tag_list_get_date_time(m_stream_tags, GST_TAG_DATE_TIME, &date_time))
  1169. {
  1170. if (gst_date_time_has_year(date_time))
  1171. {
  1172. gchar res[5];
  1173. snprintf(res, sizeof(res), "%04d", gst_date_time_get_year(date_time));
  1174. gst_date_time_unref(date_time);
  1175. return (std::string)res;
  1176. }
  1177. gst_date_time_unref(date_time);
  1178. }
  1179. #endif
  1180. break;
  1181. case sTagComposer:
  1182. tag = GST_TAG_COMPOSER;
  1183. break;
  1184. case sTagGenre:
  1185. tag = GST_TAG_GENRE;
  1186. break;
  1187. case sTagComment:
  1188. tag = GST_TAG_COMMENT;
  1189. break;
  1190. case sTagExtendedComment:
  1191. tag = GST_TAG_EXTENDED_COMMENT;
  1192. break;
  1193. case sTagLocation:
  1194. tag = GST_TAG_LOCATION;
  1195. break;
  1196. case sTagHomepage:
  1197. tag = GST_TAG_HOMEPAGE;
  1198. break;
  1199. case sTagDescription:
  1200. tag = GST_TAG_DESCRIPTION;
  1201. break;
  1202. case sTagVersion:
  1203. tag = GST_TAG_VERSION;
  1204. break;
  1205. case sTagISRC:
  1206. tag = GST_TAG_ISRC;
  1207. break;
  1208. case sTagOrganization:
  1209. tag = GST_TAG_ORGANIZATION;
  1210. break;
  1211. case sTagCopyright:
  1212. tag = GST_TAG_COPYRIGHT;
  1213. break;
  1214. case sTagCopyrightURI:
  1215. tag = GST_TAG_COPYRIGHT_URI;
  1216. break;
  1217. case sTagContact:
  1218. tag = GST_TAG_CONTACT;
  1219. break;
  1220. case sTagLicense:
  1221. tag = GST_TAG_LICENSE;
  1222. break;
  1223. case sTagLicenseURI:
  1224. tag = GST_TAG_LICENSE_URI;
  1225. break;
  1226. case sTagCodec:
  1227. tag = GST_TAG_CODEC;
  1228. break;
  1229. case sTagAudioCodec:
  1230. tag = GST_TAG_AUDIO_CODEC;
  1231. break;
  1232. case sTagVideoCodec:
  1233. tag = GST_TAG_VIDEO_CODEC;
  1234. break;
  1235. case sTagEncoder:
  1236. tag = GST_TAG_ENCODER;
  1237. break;
  1238. case sTagLanguageCode:
  1239. tag = GST_TAG_LANGUAGE_CODE;
  1240. break;
  1241. case sTagKeywords:
  1242. tag = GST_TAG_KEYWORDS;
  1243. break;
  1244. case sTagChannelMode:
  1245. tag = "channel-mode";
  1246. break;
  1247. case sUser+12:
  1248. return m_errorInfo.error_message;
  1249. default:
  1250. return "";
  1251. }
  1252. if ( !tag )
  1253. return "";
  1254. gchar *value = NULL;
  1255. if (m_stream_tags && gst_tag_list_get_string(m_stream_tags, tag, &value))
  1256. {
  1257. std::string res = value;
  1258. g_free(value);
  1259. return res;
  1260. }
  1261. return "";
  1262. }
  1263. ePtr<iServiceInfoContainer> eServiceMP3::getInfoObject(int w)
  1264. {
  1265. eServiceMP3InfoContainer *container = new eServiceMP3InfoContainer;
  1266. ePtr<iServiceInfoContainer> retval = container;
  1267. const gchar *tag = 0;
  1268. bool isBuffer = false;
  1269. switch (w)
  1270. {
  1271. case sTagTrackGain:
  1272. tag = GST_TAG_TRACK_GAIN;
  1273. break;
  1274. case sTagTrackPeak:
  1275. tag = GST_TAG_TRACK_PEAK;
  1276. break;
  1277. case sTagAlbumGain:
  1278. tag = GST_TAG_ALBUM_GAIN;
  1279. break;
  1280. case sTagAlbumPeak:
  1281. tag = GST_TAG_ALBUM_PEAK;
  1282. break;
  1283. case sTagReferenceLevel:
  1284. tag = GST_TAG_REFERENCE_LEVEL;
  1285. break;
  1286. case sTagBeatsPerMinute:
  1287. tag = GST_TAG_BEATS_PER_MINUTE;
  1288. break;
  1289. case sTagImage:
  1290. tag = GST_TAG_IMAGE;
  1291. isBuffer = true;
  1292. break;
  1293. case sTagPreviewImage:
  1294. tag = GST_TAG_PREVIEW_IMAGE;
  1295. isBuffer = true;
  1296. break;
  1297. case sTagAttachment:
  1298. tag = GST_TAG_ATTACHMENT;
  1299. isBuffer = true;
  1300. break;
  1301. default:
  1302. break;
  1303. }
  1304. if (m_stream_tags && tag)
  1305. {
  1306. if (isBuffer)
  1307. {
  1308. const GValue *gv_buffer = gst_tag_list_get_value_index(m_stream_tags, tag, 0);
  1309. if ( gv_buffer )
  1310. {
  1311. GstBuffer *buffer;
  1312. buffer = gst_value_get_buffer (gv_buffer);
  1313. container->setBuffer(buffer);
  1314. }
  1315. }
  1316. else
  1317. {
  1318. gdouble value = 0.0;
  1319. gst_tag_list_get_double(m_stream_tags, tag, &value);
  1320. container->setDouble(value);
  1321. }
  1322. }
  1323. return retval;
  1324. }
  1325. RESULT eServiceMP3::audioChannel(ePtr<iAudioChannelSelection> &ptr)
  1326. {
  1327. ptr = this;
  1328. return 0;
  1329. }
  1330. RESULT eServiceMP3::audioTracks(ePtr<iAudioTrackSelection> &ptr)
  1331. {
  1332. ptr = this;
  1333. return 0;
  1334. }
  1335. RESULT eServiceMP3::cueSheet(ePtr<iCueSheet> &ptr)
  1336. {
  1337. ptr = this;
  1338. return 0;
  1339. }
  1340. RESULT eServiceMP3::subtitle(ePtr<iSubtitleOutput> &ptr)
  1341. {
  1342. ptr = this;
  1343. return 0;
  1344. }
  1345. RESULT eServiceMP3::audioDelay(ePtr<iAudioDelay> &ptr)
  1346. {
  1347. ptr = this;
  1348. return 0;
  1349. }
  1350. int eServiceMP3::getNumberOfTracks()
  1351. {
  1352. return m_audioStreams.size();
  1353. }
  1354. int eServiceMP3::getCurrentTrack()
  1355. {
  1356. if (m_currentAudioStream == -1)
  1357. g_object_get (G_OBJECT (m_gst_playbin), "current-audio", &m_currentAudioStream, NULL);
  1358. return m_currentAudioStream;
  1359. }
  1360. RESULT eServiceMP3::selectTrack(unsigned int i)
  1361. {
  1362. bool validposition = false;
  1363. pts_t ppos = 0;
  1364. if (getPlayPosition(ppos) >= 0)
  1365. {
  1366. validposition = true;
  1367. ppos -= 90000;
  1368. if (ppos < 0)
  1369. ppos = 0;
  1370. }
  1371. if (validposition)
  1372. {
  1373. /* flush */
  1374. seekTo(ppos);
  1375. }
  1376. return selectAudioStream(i);
  1377. }
  1378. int eServiceMP3::selectAudioStream(int i)
  1379. {
  1380. int current_audio;
  1381. g_object_set (G_OBJECT (m_gst_playbin), "current-audio", i, NULL);
  1382. g_object_get (G_OBJECT (m_gst_playbin), "current-audio", &current_audio, NULL);
  1383. if ( current_audio == i )
  1384. {
  1385. eDebug ("[eServiceMP3] switched to audio stream %i", current_audio);
  1386. m_currentAudioStream = i;
  1387. return 0;
  1388. }
  1389. return -1;
  1390. }
  1391. int eServiceMP3::getCurrentChannel()
  1392. {
  1393. return STEREO;
  1394. }
  1395. RESULT eServiceMP3::selectChannel(int i)
  1396. {
  1397. eDebug("[eServiceMP3] selectChannel(%i)",i);
  1398. return 0;
  1399. }
  1400. RESULT eServiceMP3::getTrackInfo(struct iAudioTrackInfo &info, unsigned int i)
  1401. {
  1402. if (i >= m_audioStreams.size())
  1403. {
  1404. return -2;
  1405. }
  1406. info.m_description = m_audioStreams[i].codec;
  1407. if (info.m_language.empty())
  1408. {
  1409. info.m_language = m_audioStreams[i].language_code;
  1410. }
  1411. return 0;
  1412. }
  1413. subtype_t getSubtitleType(GstPad* pad, gchar *g_codec=NULL)
  1414. {
  1415. subtype_t type = stUnknown;
  1416. #if GST_VERSION_MAJOR < 1
  1417. GstCaps* caps = gst_pad_get_negotiated_caps(pad);
  1418. #else
  1419. GstCaps* caps = gst_pad_get_current_caps(pad);
  1420. #endif
  1421. if (!caps && !g_codec)
  1422. {
  1423. caps = gst_pad_get_allowed_caps(pad);
  1424. }
  1425. if (caps && !gst_caps_is_empty(caps))
  1426. {
  1427. GstStructure* str = gst_caps_get_structure(caps, 0);
  1428. if (str)
  1429. {
  1430. const gchar *g_type = gst_structure_get_name(str);
  1431. // eDebug("[eServiceMP3] getSubtitleType::subtitle probe caps type=%s", g_type ? g_type : "(null)");
  1432. if (g_type)
  1433. {
  1434. #if GST_VERSION_MAJOR < 1
  1435. if ( !strcmp(g_type, "video/x-dvd-subpicture") )
  1436. #else
  1437. if ( !strcmp(g_type, "subpicture/x-dvd") )
  1438. #endif
  1439. type = stVOB;
  1440. else if ( !strcmp(g_type, "text/x-pango-markup") )
  1441. type = stSRT;
  1442. else if ( !strcmp(g_type, "text/plain") || !strcmp(g_type, "text/x-plain") || !strcmp(g_type, "text/x-raw") )
  1443. type = stPlainText;
  1444. else if ( !strcmp(g_type, "subpicture/x-pgs") )
  1445. type = stPGS;
  1446. else
  1447. eDebug("[eServiceMP3] getSubtitleType::unsupported subtitle caps %s (%s)", g_type, g_codec ? g_codec : "(null)");
  1448. }
  1449. }
  1450. }
  1451. else if ( g_codec )
  1452. {
  1453. // eDebug("[eServiceMP3] getSubtitleType::subtitle probe codec tag=%s", g_codec);
  1454. if ( !strcmp(g_codec, "VOB") )
  1455. type = stVOB;
  1456. else if ( !strcmp(g_codec, "SubStation Alpha") || !strcmp(g_codec, "SSA") )
  1457. type = stSSA;
  1458. else if ( !strcmp(g_codec, "ASS") )
  1459. type = stASS;
  1460. else if ( !strcmp(g_codec, "SRT") )
  1461. type = stSRT;
  1462. else if ( !strcmp(g_codec, "UTF-8 plain text") )
  1463. type = stPlainText;
  1464. else
  1465. eDebug("[eServiceMP3] getSubtitleType::unsupported subtitle codec %s", g_codec);
  1466. }
  1467. else
  1468. eDebug("[eServiceMP3] getSubtitleType::unidentifiable subtitle stream!");
  1469. return type;
  1470. }
  1471. void eServiceMP3::gstBusCall(GstMessage *msg)
  1472. {
  1473. if (!msg)
  1474. return;
  1475. gchar *sourceName;
  1476. GstObject *source;
  1477. GstElement *subsink;
  1478. source = GST_MESSAGE_SRC(msg);
  1479. if (!GST_IS_OBJECT(source))
  1480. return;
  1481. sourceName = gst_object_get_name(source);
  1482. #if 0
  1483. gchar *string;
  1484. if (gst_message_get_structure(msg))
  1485. string = gst_structure_to_string(gst_message_get_structure(msg));
  1486. else
  1487. string = g_strdup(GST_MESSAGE_TYPE_NAME(msg));
  1488. // eDebug("[eServiceMP3] eTsRemoteSource::gst_message from %s: %s", sourceName, string);
  1489. g_free(string);
  1490. #endif
  1491. switch (GST_MESSAGE_TYPE (msg))
  1492. {
  1493. case GST_MESSAGE_EOS:
  1494. m_event((iPlayableService*)this, evEOF);
  1495. break;
  1496. case GST_MESSAGE_STATE_CHANGED:
  1497. {
  1498. if(GST_MESSAGE_SRC(msg) != GST_OBJECT(m_gst_playbin))
  1499. break;
  1500. GstState old_state, new_state;
  1501. gst_message_parse_state_changed(msg, &old_state, &new_state, NULL);
  1502. if(old_state == new_state)
  1503. break;
  1504. //eDebug("[eServiceMP3] state transition %s -> %s", gst_element_state_get_name(old_state), gst_element_state_get_name(new_state));
  1505. GstStateChange transition = (GstStateChange)GST_STATE_TRANSITION(old_state, new_state);
  1506. switch(transition)
  1507. {
  1508. case GST_STATE_CHANGE_NULL_TO_READY:
  1509. {
  1510. m_event(this, evStart);
  1511. } break;
  1512. case GST_STATE_CHANGE_READY_TO_PAUSED:
  1513. {
  1514. m_state = stRunning;
  1515. #if GST_VERSION_MAJOR >= 1
  1516. GValue result = { 0, };
  1517. #endif
  1518. GstIterator *children;
  1519. subsink = gst_bin_get_by_name(GST_BIN(m_gst_playbin), "subtitle_sink");
  1520. if (subsink)
  1521. {
  1522. #ifdef GSTREAMER_SUBTITLE_SYNC_MODE_BUG
  1523. /*
  1524. * HACK: disable sync mode for now, gstreamer suffers from a bug causing sparse streams to loose sync, after pause/resume / skip
  1525. * see: https://bugzilla.gnome.org/show_bug.cgi?id=619434
  1526. * Sideeffect of using sync=false is that we receive subtitle buffers (far) ahead of their
  1527. * display time.
  1528. * Not too far ahead for subtitles contained in the media container.
  1529. * But for external srt files, we could receive all subtitles at once.
  1530. * And not just once, but after each pause/resume / skip.
  1531. * So as soon as gstreamer has been fixed to keep sync in sparse streams, sync needs to be re-enabled.
  1532. */
  1533. g_object_set (G_OBJECT (subsink), "sync", FALSE, NULL);
  1534. #endif
  1535. #if 0
  1536. /* we should not use ts-offset to sync with the decoder time, we have to do our own decoder timekeeping */
  1537. g_object_set (G_OBJECT (subsink), "ts-offset", -2LL * GST_SECOND, NULL);
  1538. /* late buffers probably will not occur very often */
  1539. g_object_set (G_OBJECT (subsink), "max-lateness", 0LL, NULL);
  1540. /* avoid prerolling (it might not be a good idea to preroll a sparse stream) */
  1541. g_object_set (G_OBJECT (subsink), "async", TRUE, NULL);
  1542. #endif
  1543. // eDebug("[eServiceMP3] subsink properties set!");
  1544. gst_object_unref(subsink);
  1545. }
  1546. if (audioSink)
  1547. {
  1548. gst_object_unref(GST_OBJECT(audioSink));
  1549. audioSink = NULL;
  1550. }
  1551. if (videoSink)
  1552. {
  1553. gst_object_unref(GST_OBJECT(videoSink));
  1554. videoSink = NULL;
  1555. }
  1556. children = gst_bin_iterate_recurse(GST_BIN(m_gst_playbin));
  1557. #if GST_VERSION_MAJOR < 1
  1558. audioSink = GST_ELEMENT_CAST(gst_iterator_find_custom(children, (GCompareFunc)match_sinktype, (gpointer)"GstDVBAudioSink"));
  1559. #else
  1560. if (gst_iterator_find_custom(children, (GCompareFunc)match_sinktype, &result, (gpointer)"GstDVBAudioSink"))
  1561. {
  1562. audioSink = GST_ELEMENT_CAST(g_value_dup_object(&result));
  1563. g_value_unset(&result);
  1564. }
  1565. #endif
  1566. gst_iterator_free(children);
  1567. children = gst_bin_iterate_recurse(GST_BIN(m_gst_playbin));
  1568. #if GST_VERSION_MAJOR < 1
  1569. videoSink = GST_ELEMENT_CAST(gst_iterator_find_custom(children, (GCompareFunc)match_sinktype, (gpointer)"GstDVBVideoSink"));
  1570. #else
  1571. if (gst_iterator_find_custom(children, (GCompareFunc)match_sinktype, &result, (gpointer)"GstDVBVideoSink"))
  1572. {
  1573. videoSink = GST_ELEMENT_CAST(g_value_dup_object(&result));
  1574. g_value_unset(&result);
  1575. }
  1576. #endif
  1577. gst_iterator_free(children);
  1578. /* if we are in preroll already do not check again the state */
  1579. if (!m_is_live)
  1580. {
  1581. m_is_live = (gst_element_get_state(m_gst_playbin, NULL, NULL, 0LL) == GST_STATE_CHANGE_NO_PREROLL);
  1582. }
  1583. setAC3Delay(ac3_delay);
  1584. setPCMDelay(pcm_delay);
  1585. if(!m_cuesheet_loaded) /* cuesheet CVR */
  1586. loadCuesheet();
  1587. updateEpgCacheNowNext();
  1588. } break;
  1589. case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
  1590. {
  1591. m_paused = false;
  1592. m_event((iPlayableService*)this, evGstreamerPlayStarted);
  1593. } break;
  1594. case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
  1595. {
  1596. m_paused = true;
  1597. } break;
  1598. case GST_STATE_CHANGE_PAUSED_TO_READY:
  1599. {
  1600. if (audioSink)
  1601. {
  1602. gst_object_unref(GST_OBJECT(audioSink));
  1603. audioSink = NULL;
  1604. }
  1605. if (videoSink)
  1606. {
  1607. gst_object_unref(GST_OBJECT(videoSink));
  1608. videoSink = NULL;
  1609. }
  1610. } break;
  1611. case GST_STATE_CHANGE_READY_TO_NULL:
  1612. {
  1613. } break;
  1614. }
  1615. break;
  1616. }
  1617. case GST_MESSAGE_ERROR:
  1618. {
  1619. gchar *debug;
  1620. GError *err;
  1621. gst_message_parse_error (msg, &err, &debug);
  1622. g_free (debug);
  1623. eWarning("Gstreamer error: %s (%i, %i) from %s", err->message, err->code, err->domain, sourceName );
  1624. if ( err->domain == GST_STREAM_ERROR )
  1625. {
  1626. if ( err->code == GST_STREAM_ERROR_CODEC_NOT_FOUND )
  1627. {
  1628. if ( g_strrstr(sourceName, "videosink") )
  1629. m_event((iPlayableService*)this, evUser+11);
  1630. else if ( g_strrstr(sourceName, "audiosink") )
  1631. m_event((iPlayableService*)this, evUser+10);
  1632. }
  1633. }
  1634. else if ( err->domain == GST_RESOURCE_ERROR )
  1635. {
  1636. if ( err->code == GST_RESOURCE_ERROR_OPEN_READ || err->code == GST_RESOURCE_ERROR_READ )
  1637. {
  1638. stop();
  1639. }
  1640. }
  1641. g_error_free(err);
  1642. break;
  1643. }
  1644. #if GST_VERSION_MAJOR >= 1
  1645. case GST_MESSAGE_WARNING:
  1646. {
  1647. gchar *debug_warn = NULL;
  1648. GError *warn = NULL;
  1649. gst_message_parse_warning (msg, &warn, &debug_warn);
  1650. /* CVR this Warning occurs from time to time with external srt files
  1651. When a new seek is done the problem off to long wait times before subtitles appears,
  1652. after movie was restarted with a resume position is solved. */
  1653. if(!strncmp(warn->message , "Internal data flow problem", 26) && !strncmp(sourceName, "subtitle_sink", 13))
  1654. {
  1655. eWarning("[eServiceMP3] Gstreamer warning : %s (%i) from %s" , warn->message, warn->code, sourceName);
  1656. subsink = gst_bin_get_by_name(GST_BIN(m_gst_playbin), "subtitle_sink");
  1657. if(subsink)
  1658. {
  1659. if (!gst_element_seek (subsink, m_currentTrickRatio, GST_FORMAT_TIME, (GstSeekFlags)(GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT),
  1660. GST_SEEK_TYPE_SET, m_last_seek_pos,
  1661. GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE))
  1662. {
  1663. eDebug("[eServiceMP3] seekToImpl subsink failed");
  1664. }
  1665. gst_object_unref(subsink);
  1666. }
  1667. }
  1668. g_free(debug_warn);
  1669. g_error_free(warn);
  1670. break;
  1671. }
  1672. #endif
  1673. case GST_MESSAGE_INFO:
  1674. {
  1675. gchar *debug;
  1676. GError *inf;
  1677. gst_message_parse_info (msg, &inf, &debug);
  1678. g_free (debug);
  1679. if ( inf->domain == GST_STREAM_ERROR && inf->code == GST_STREAM_ERROR_DECODE )
  1680. {
  1681. if ( g_strrstr(sourceName, "videosink") )
  1682. m_event((iPlayableService*)this, evUser+14);
  1683. }
  1684. g_error_free(inf);
  1685. break;
  1686. }
  1687. case GST_MESSAGE_TAG:
  1688. {
  1689. GstTagList *tags, *result;
  1690. gst_message_parse_tag(msg, &tags);
  1691. result = gst_tag_list_merge(m_stream_tags, tags, GST_TAG_MERGE_REPLACE);
  1692. if (result)
  1693. {
  1694. if (m_stream_tags && gst_tag_list_is_equal(m_stream_tags, result))
  1695. {
  1696. gst_tag_list_free(tags);
  1697. gst_tag_list_free(result);
  1698. break;
  1699. }
  1700. if (m_stream_tags)
  1701. gst_tag_list_free(m_stream_tags);
  1702. m_stream_tags = result;
  1703. }
  1704. const GValue *gv_image = gst_tag_list_get_value_index(tags, GST_TAG_IMAGE, 0);
  1705. if ( gv_image )
  1706. {
  1707. GstBuffer *buf_image;
  1708. #if GST_VERSION_MAJOR < 1
  1709. buf_image = gst_value_get_buffer(gv_image);
  1710. #else
  1711. GstSample *sample;
  1712. sample = (GstSample *)g_value_get_boxed(gv_image);
  1713. buf_image = gst_sample_get_buffer(sample);
  1714. #endif
  1715. int fd = open("/tmp/.id3coverart", O_CREAT|O_WRONLY|O_TRUNC, 0644);
  1716. if (fd >= 0)
  1717. {
  1718. guint8 *data;
  1719. gsize size;
  1720. #if GST_VERSION_MAJOR < 1
  1721. data = GST_BUFFER_DATA(buf_image);
  1722. size = GST_BUFFER_SIZE(buf_image);
  1723. #else
  1724. GstMapInfo map;
  1725. gst_buffer_map(buf_image, &map, GST_MAP_READ);
  1726. data = map.data;
  1727. size = map.size;
  1728. #endif
  1729. int ret = write(fd, data, size);
  1730. #if GST_VERSION_MAJOR >= 1
  1731. gst_buffer_unmap(buf_image, &map);
  1732. #endif
  1733. close(fd);
  1734. // eDebug("[eServiceMP3] /tmp/.id3coverart %d bytes written ", ret);
  1735. }
  1736. m_event((iPlayableService*)this, evUser+13);
  1737. }
  1738. gst_tag_list_free(tags);
  1739. m_event((iPlayableService*)this, evUpdatedInfo);
  1740. break;
  1741. }
  1742. /* TOC entry intercept used for chapter support CVR */
  1743. #if GST_VERSION_MAJOR >= 1
  1744. case GST_MESSAGE_TOC:
  1745. {
  1746. HandleTocEntry(msg);
  1747. break;
  1748. }
  1749. #endif
  1750. case GST_MESSAGE_ASYNC_DONE:
  1751. {
  1752. if(GST_MESSAGE_SRC(msg) != GST_OBJECT(m_gst_playbin))
  1753. break;
  1754. gint i, n_video = 0, n_audio = 0, n_text = 0;
  1755. bool codec_tofix = false;
  1756. g_object_get (m_gst_playbin, "n-video", &n_video, NULL);
  1757. g_object_get (m_gst_playbin, "n-audio", &n_audio, NULL);
  1758. g_object_get (m_gst_playbin, "n-text", &n_text, NULL);
  1759. //eDebug("[eServiceMP3] async-done - %d video, %d audio, %d subtitle", n_video, n_audio, n_text);
  1760. if ( n_video + n_audio <= 0 )
  1761. stop();
  1762. m_audioStreams.clear();
  1763. m_subtitleStreams.clear();
  1764. for (i = 0; i < n_audio; i++)
  1765. {
  1766. audioStream audio;
  1767. gchar *g_codec, *g_lang;
  1768. GstTagList *tags = NULL;
  1769. GstPad* pad = 0;
  1770. g_signal_emit_by_name (m_gst_playbin, "get-audio-pad", i, &pad);
  1771. #if GST_VERSION_MAJOR < 1
  1772. GstCaps* caps = gst_pad_get_negotiated_caps(pad);
  1773. #else
  1774. GstCaps* caps = gst_pad_get_current_caps(pad);
  1775. #endif
  1776. gst_object_unref(pad);
  1777. if (!caps)
  1778. continue;
  1779. GstStructure* str = gst_caps_get_structure(caps, 0);
  1780. const gchar *g_type = gst_structure_get_name(str);
  1781. //eDebug("[eServiceMP3] AUDIO STRUCT=%s", g_type);
  1782. audio.type = gstCheckAudioPad(str);
  1783. audio.language_code = "und";
  1784. audio.codec = g_type;
  1785. g_codec = NULL;
  1786. g_lang = NULL;
  1787. g_signal_emit_by_name (m_gst_playbin, "get-audio-tags", i, &tags);
  1788. #if GST_VERSION_MAJOR < 1
  1789. if (tags && gst_is_tag_list(tags))
  1790. #else
  1791. if (tags && GST_IS_TAG_LIST(tags))
  1792. #endif
  1793. {
  1794. if (gst_tag_list_get_string(tags, GST_TAG_AUDIO_CODEC, &g_codec))
  1795. {
  1796. audio.codec = std::string(g_codec);
  1797. g_free(g_codec);
  1798. }
  1799. if (gst_tag_list_get_string(tags, GST_TAG_LANGUAGE_CODE, &g_lang))
  1800. {
  1801. audio.language_code = std::string(g_lang);
  1802. g_free(g_lang);
  1803. }
  1804. gst_tag_list_free(tags);
  1805. }
  1806. //eDebug("[eServiceMP3] audio stream=%i codec=%s language=%s", i, audio.codec.c_str(), audio.language_code.c_str());
  1807. codec_tofix = (audio.codec.find("MPEG-1 Layer 3 (MP3)") == 0 || audio.codec.find("MPEG-2 AAC") == 0) && n_audio - n_video == 1;
  1808. m_audioStreams.push_back(audio);
  1809. gst_caps_unref(caps);
  1810. }
  1811. for (i = 0; i < n_text; i++)
  1812. {
  1813. gchar *g_codec = NULL, *g_lang = NULL;
  1814. GstTagList *tags = NULL;
  1815. g_signal_emit_by_name (m_gst_playbin, "get-text-tags", i, &tags);
  1816. subtitleStream subs;
  1817. subs.language_code = "und";
  1818. #if GST_VERSION_MAJOR < 1
  1819. if (tags && gst_is_tag_list(tags))
  1820. #else
  1821. if (tags && GST_IS_TAG_LIST(tags))
  1822. #endif
  1823. {
  1824. if (gst_tag_list_get_string(tags, GST_TAG_LANGUAGE_CODE, &g_lang))
  1825. {
  1826. subs.language_code = g_lang;
  1827. g_free(g_lang);
  1828. }
  1829. gst_tag_list_get_string(tags, GST_TAG_SUBTITLE_CODEC, &g_codec);
  1830. gst_tag_list_free(tags);
  1831. }
  1832. //eDebug("[eServiceMP3] subtitle stream=%i language=%s codec=%s", i, subs.language_code.c_str(), g_codec ? g_codec : "(null)");
  1833. GstPad* pad = 0;
  1834. g_signal_emit_by_name (m_gst_playbin, "get-text-pad", i, &pad);
  1835. if ( pad )
  1836. g_signal_connect (G_OBJECT (pad), "notify::caps", G_CALLBACK (gstTextpadHasCAPS), this);
  1837. subs.type = getSubtitleType(pad, g_codec);
  1838. gst_object_unref(pad);
  1839. g_free(g_codec);
  1840. m_subtitleStreams.push_back(subs);
  1841. }
  1842. m_event((iPlayableService*)this, evUpdatedInfo);
  1843. if ( m_errorInfo.missing_codec != "" )
  1844. {
  1845. if (m_errorInfo.missing_codec.find("video/") == 0 || (m_errorInfo.missing_codec.find("audio/") == 0 && m_audioStreams.empty()))
  1846. m_event((iPlayableService*)this, evUser+12);
  1847. }
  1848. /*+++*workaround for mp3 playback problem on some boxes - e.g. xtrend et9200 (if press stop and play or switch to the next track is the state 'playing', but plays not.
  1849. Restart the player-application or paused and then play the track fix this for once.)*/
  1850. if (!m_paused && codec_tofix)
  1851. {
  1852. std::string filename = "/proc/stb/info/boxtype";
  1853. FILE *f = fopen(filename.c_str(), "rb");
  1854. if (f)
  1855. {
  1856. char boxtype[6];
  1857. fread(boxtype, 6, 1, f);
  1858. fclose(f);
  1859. if (!memcmp(boxtype, "et5000", 6) || !memcmp(boxtype, "et6000", 6) || !memcmp(boxtype, "et6500", 6) || !memcmp(boxtype, "et9000", 6) || !memcmp(boxtype, "et9100", 6) || !memcmp(boxtype, "et9200", 6) || !memcmp(boxtype, "et9500", 6))
  1860. {
  1861. eDebug("[eServiceMP3] mp3,aac playback fix for xtrend et5x00,et6x00,et9x00 - set paused and then playing state");
  1862. GstStateChangeReturn ret;
  1863. ret = gst_element_set_state (m_gst_playbin, GST_STATE_PAUSED);
  1864. if (ret != GST_STATE_CHANGE_SUCCESS)
  1865. {
  1866. eDebug("[eServiceMP3] mp3 playback fix - failure set paused state - sleep one second before set playing state");
  1867. sleep(1);
  1868. }
  1869. gst_element_set_state (m_gst_playbin, GST_STATE_PLAYING);
  1870. }
  1871. }
  1872. }
  1873. /*+++*/
  1874. break;
  1875. }
  1876. case GST_MESSAGE_ELEMENT:
  1877. {
  1878. const GstStructure *msgstruct = gst_message_get_structure(msg);
  1879. if (msgstruct)
  1880. {
  1881. if ( gst_is_missing_plugin_message(msg) )
  1882. {
  1883. GstCaps *caps = NULL;
  1884. gst_structure_get (msgstruct, "detail", GST_TYPE_CAPS, &caps, NULL);
  1885. if (caps)
  1886. {
  1887. std::string codec = (const char*) gst_caps_to_string(caps);
  1888. gchar *description = gst_missing_plugin_message_get_description(msg);
  1889. if ( description )
  1890. {
  1891. eDebug("[eServiceMP3] m_errorInfo.missing_codec = %s", codec.c_str());
  1892. m_errorInfo.error_message = "GStreamer plugin " + (std::string)description + " not available!\n";
  1893. m_errorInfo.missing_codec = codec.substr(0,(codec.find_first_of(',')));
  1894. g_free(description);
  1895. }
  1896. gst_caps_unref(caps);
  1897. }
  1898. }
  1899. else
  1900. {
  1901. const gchar *eventname = gst_structure_get_name(msgstruct);
  1902. if ( eventname )
  1903. {
  1904. if (!strcmp(eventname, "eventSizeChanged") || !strcmp(eventname, "eventSizeAvail"))
  1905. {
  1906. gst_structure_get_int (msgstruct, "aspect_ratio", &m_aspect);
  1907. gst_structure_get_int (msgstruct, "width", &m_width);
  1908. gst_structure_get_int (msgstruct, "height", &m_height);
  1909. if (strstr(eventname, "Changed"))
  1910. m_event((iPlayableService*)this, evVideoSizeChanged);
  1911. }
  1912. else if (!strcmp(eventname, "eventFrameRateChanged") || !strcmp(eventname, "eventFrameRateAvail"))
  1913. {
  1914. gst_structure_get_int (msgstruct, "frame_rate", &m_framerate);
  1915. if (strstr(eventname, "Changed"))
  1916. m_event((iPlayableService*)this, evVideoFramerateChanged);
  1917. }
  1918. else if (!strcmp(eventname, "eventProgressiveChanged") || !strcmp(eventname, "eventProgressiveAvail"))
  1919. {
  1920. gst_structure_get_int (msgstruct, "progressive", &m_progressive);
  1921. if (strstr(eventname, "Changed"))
  1922. m_event((iPlayableService*)this, evVideoProgressiveChanged);
  1923. }
  1924. else if (!strcmp(eventname, "redirect"))
  1925. {
  1926. const char *uri = gst_structure_get_string(msgstruct, "new-location");
  1927. // eDebug("[eServiceMP3] redirect to %s", uri);
  1928. gst_element_set_state (m_gst_playbin, GST_STATE_NULL);
  1929. g_object_set(G_OBJECT (m_gst_playbin), "uri", uri, NULL);
  1930. gst_element_set_state (m_gst_playbin, GST_STATE_PLAYING);
  1931. }
  1932. }
  1933. }
  1934. }
  1935. break;
  1936. }
  1937. case GST_MESSAGE_BUFFERING:
  1938. if (m_sourceinfo.is_streaming)
  1939. {
  1940. GstBufferingMode mode;
  1941. gst_message_parse_buffering(msg, &(m_bufferInfo.bufferPercent));
  1942. // eDebug("[eServiceMP3] Buffering %u percent done", m_bufferInfo.bufferPercent);
  1943. gst_message_parse_buffering_stats(msg, &mode, &(m_bufferInfo.avgInRate), &(m_bufferInfo.avgOutRate), &(m_bufferInfo.bufferingLeft));
  1944. m_event((iPlayableService*)this, evBuffering);
  1945. /*
  1946. * we don't react to buffer level messages, unless we are configured to use a prefill buffer
  1947. * (even if we are not configured to, we still use the buffer, but we rely on it to remain at the
  1948. * healthy level at all times, without ever having to pause the stream)
  1949. *
  1950. * Also, it does not make sense to pause the stream if it is a live stream
  1951. * (in which case the sink will not produce data while paused, so we won't
  1952. * recover from an empty buffer)
  1953. */
  1954. if (m_use_prefillbuffer && !m_is_live && --m_ignore_buffering_messages <= 0)
  1955. {
  1956. if (m_bufferInfo.bufferPercent == 100)
  1957. {
  1958. GstState state;
  1959. gst_element_get_state(m_gst_playbin, &state, NULL, 0LL);
  1960. if (state != GST_STATE_PLAYING)
  1961. {
  1962. // eDebug("[eServiceMP3] start playing");
  1963. gst_element_set_state (m_gst_playbin, GST_STATE_PLAYING);
  1964. }
  1965. /*
  1966. * when we start the pipeline, the contents of the buffer will immediately drain
  1967. * into the (hardware buffers of the) sinks, so we will receive low buffer level
  1968. * messages right away.
  1969. * Ignore the first few buffering messages, giving the buffer the chance to recover
  1970. * a bit, before we start handling empty buffer states again.
  1971. */
  1972. m_ignore_buffering_messages = 5;
  1973. }
  1974. else if (m_bufferInfo.bufferPercent == 0)
  1975. {
  1976. // eDebug("[eServiceMP3] start pause");
  1977. gst_element_set_state (m_gst_playbin, GST_STATE_PAUSED);
  1978. m_ignore_buffering_messages = 0;
  1979. }
  1980. else
  1981. {
  1982. m_ignore_buffering_messages = 0;
  1983. }
  1984. }
  1985. }
  1986. break;
  1987. default:
  1988. break;
  1989. }
  1990. g_free (sourceName);
  1991. }
  1992. void eServiceMP3::handleMessage(GstMessage *msg)
  1993. {
  1994. if (GST_MESSAGE_TYPE(msg) == GST_MESSAGE_STATE_CHANGED && GST_MESSAGE_SRC(msg) != GST_OBJECT(m_gst_playbin))
  1995. {
  1996. /*
  1997. * ignore verbose state change messages for all active elements;
  1998. * we only need to handle state-change events for the playbin
  1999. */
  2000. gst_message_unref(msg);
  2001. return;
  2002. }
  2003. m_pump.send(new GstMessageContainer(1, msg, NULL, NULL));
  2004. }
  2005. GstBusSyncReply eServiceMP3::gstBusSyncHandler(GstBus *bus, GstMessage *message, gpointer user_data)
  2006. {
  2007. eServiceMP3 *_this = (eServiceMP3*)user_data;
  2008. if (_this) _this->handleMessage(message);
  2009. return GST_BUS_DROP;
  2010. }
  2011. /*Processing TOC CVR */
  2012. #if GST_VERSION_MAJOR >= 1
  2013. void eServiceMP3::HandleTocEntry(GstMessage *msg)
  2014. {
  2015. /* limit TOC to dvbvideosink cue sheet only works for video media */
  2016. if (!strncmp(GST_MESSAGE_SRC_NAME(msg), "dvbvideosink", 12))
  2017. {
  2018. GstToc *toc;
  2019. gboolean updated;
  2020. gst_message_parse_toc(msg, &toc, &updated);
  2021. for (GList* i = gst_toc_get_entries(toc); i; i = i->next)
  2022. {
  2023. GstTocEntry *entry = static_cast<GstTocEntry*>(i->data);
  2024. if (gst_toc_entry_get_entry_type (entry) == GST_TOC_ENTRY_TYPE_EDITION)
  2025. {
  2026. /* extra debug info for testing purposes should_be_removed later on */
  2027. //eDebug("[eServiceMP3] toc_type %s", gst_toc_entry_type_get_nick(gst_toc_entry_get_entry_type (entry)));
  2028. gint y = 0;
  2029. for (GList* x = gst_toc_entry_get_sub_entries (entry); x; x = x->next)
  2030. {
  2031. GstTocEntry *sub_entry = static_cast<GstTocEntry*>(x->data);
  2032. if (gst_toc_entry_get_entry_type (sub_entry) == GST_TOC_ENTRY_TYPE_CHAPTER)
  2033. {
  2034. if (y == 0)
  2035. {
  2036. m_use_chapter_entries = true;
  2037. if (m_cuesheet_loaded)
  2038. m_cue_entries.clear();
  2039. else
  2040. loadCuesheet();
  2041. }
  2042. /* first chapter is movie start no cut needed */
  2043. else if (y >= 1)
  2044. {
  2045. gint64 start = 0;
  2046. gint64 pts = 0;
  2047. gint type = 0;
  2048. gst_toc_entry_get_start_stop_times(sub_entry, &start, NULL);
  2049. type = 2;
  2050. if(start > 0)
  2051. pts = start / 11111;
  2052. if (pts > 0)
  2053. {
  2054. /* check cue and toc for identical entries */
  2055. bool tocadd = true;
  2056. for (std::multiset<cueEntry>::iterator i(m_cue_entries.begin()); i != m_cue_entries.end(); ++i)
  2057. {
  2058. /* toc not add if cue available */
  2059. if (pts == i->where && type == i->what)
  2060. {
  2061. tocadd = false;
  2062. break;
  2063. }
  2064. }
  2065. if (tocadd)
  2066. {
  2067. m_cue_entries.insert(cueEntry(pts, type));
  2068. }
  2069. m_cuesheet_changed = 1;
  2070. m_event((iPlayableService*)this, evCuesheetChanged);
  2071. /* extra debug info for testing purposes should_be_removed later on */
  2072. /*eDebug("[eServiceMP3] toc_subtype %s,Nr = %d, start= %#"G_GINT64_MODIFIER "x",
  2073. gst_toc_entry_type_get_nick(gst_toc_entry_get_entry_type (sub_entry)), y + 1, pts); */
  2074. }
  2075. }
  2076. y++;
  2077. }
  2078. }
  2079. }
  2080. }
  2081. //eDebug("[eServiceMP3] TOC entry from source %s processed", GST_MESSAGE_SRC_NAME(msg));
  2082. }
  2083. else
  2084. {
  2085. //eDebug("[eServiceMP3] TOC entry from source %s not used", GST_MESSAGE_SRC_NAME(msg));
  2086. ;
  2087. }
  2088. }
  2089. #endif
  2090. void eServiceMP3::playbinNotifySource(GObject *object, GParamSpec *unused, gpointer user_data)
  2091. {
  2092. GstElement *source = NULL;
  2093. eServiceMP3 *_this = (eServiceMP3*)user_data;
  2094. g_object_get(object, "source", &source, NULL);
  2095. if (source)
  2096. {
  2097. if (g_object_class_find_property(G_OBJECT_GET_CLASS(source), "timeout") != 0)
  2098. {
  2099. GstElementFactory *factory = gst_element_get_factory(source);
  2100. if (factory)
  2101. {
  2102. const gchar *sourcename = gst_plugin_feature_get_name(GST_PLUGIN_FEATURE(factory));
  2103. if (!strcmp(sourcename, "souphttpsrc"))
  2104. {
  2105. g_object_set(G_OBJECT(source), "timeout", HTTP_TIMEOUT, NULL);
  2106. }
  2107. }
  2108. }
  2109. if (g_object_class_find_property(G_OBJECT_GET_CLASS(source), "ssl-strict") != 0)
  2110. {
  2111. g_object_set(G_OBJECT(source), "ssl-strict", FALSE, NULL);
  2112. }
  2113. if (g_object_class_find_property(G_OBJECT_GET_CLASS(source), "user-agent") != 0 && !_this->m_useragent.empty())
  2114. {
  2115. g_object_set(G_OBJECT(source), "user-agent", _this->m_useragent.c_str(), NULL);
  2116. }
  2117. if (g_object_class_find_property(G_OBJECT_GET_CLASS(source), "extra-headers") != 0 && !_this->m_extra_headers.empty())
  2118. {
  2119. #if GST_VERSION_MAJOR < 1
  2120. GstStructure *extras = gst_structure_empty_new("extras");
  2121. #else
  2122. GstStructure *extras = gst_structure_new_empty("extras");
  2123. #endif
  2124. size_t pos = 0;
  2125. while (pos != std::string::npos)
  2126. {
  2127. std::string name, value;
  2128. size_t start = pos;
  2129. size_t len = std::string::npos;
  2130. pos = _this->m_extra_headers.find('=', pos);
  2131. if (pos != std::string::npos)
  2132. {
  2133. len = pos - start;
  2134. pos++;
  2135. name = _this->m_extra_headers.substr(start, len);
  2136. start = pos;
  2137. len = std::string::npos;
  2138. pos = _this->m_extra_headers.find('&', pos);
  2139. if (pos != std::string::npos)
  2140. {
  2141. len = pos - start;
  2142. pos++;
  2143. }
  2144. value = _this->m_extra_headers.substr(start, len);
  2145. }
  2146. if (!name.empty() && !value.empty())
  2147. {
  2148. GValue header;
  2149. // eDebug("[eServiceMP3] setting extra-header '%s:%s'", name.c_str(), value.c_str());
  2150. memset(&header, 0, sizeof(GValue));
  2151. g_value_init(&header, G_TYPE_STRING);
  2152. g_value_set_string(&header, value.c_str());
  2153. gst_structure_set_value(extras, name.c_str(), &header);
  2154. }
  2155. else
  2156. {
  2157. eDebug("[eServiceMP3] Invalid header format %s", _this->m_extra_headers.c_str());
  2158. break;
  2159. }
  2160. }
  2161. if (gst_structure_n_fields(extras) > 0)
  2162. {
  2163. g_object_set(G_OBJECT(source), "extra-headers", extras, NULL);
  2164. }
  2165. gst_structure_free(extras);
  2166. }
  2167. gst_object_unref(source);
  2168. }
  2169. }
  2170. void eServiceMP3::handleElementAdded(GstBin *bin, GstElement *element, gpointer user_data)
  2171. {
  2172. eServiceMP3 *_this = (eServiceMP3*)user_data;
  2173. if (_this)
  2174. {
  2175. gchar *elementname = gst_element_get_name(element);
  2176. if (g_str_has_prefix(elementname, "queue2"))
  2177. {
  2178. if (_this->m_download_buffer_path != "")
  2179. {
  2180. g_object_set(G_OBJECT(element), "temp-template", _this->m_download_buffer_path.c_str(), NULL);
  2181. }
  2182. else
  2183. {
  2184. g_object_set(G_OBJECT(element), "temp-template", NULL, NULL);
  2185. }
  2186. }
  2187. else if (g_str_has_prefix(elementname, "uridecodebin")
  2188. #if GST_VERSION_MAJOR < 1
  2189. || g_str_has_prefix(elementname, "decodebin2"))
  2190. #else
  2191. || g_str_has_prefix(elementname, "decodebin"))
  2192. #endif
  2193. {
  2194. /*
  2195. * Listen for queue2 element added to uridecodebin/decodebin2 as well.
  2196. * Ignore other bins since they may have unrelated queues
  2197. */
  2198. g_signal_connect(element, "element-added", G_CALLBACK(handleElementAdded), user_data);
  2199. }
  2200. g_free(elementname);
  2201. }
  2202. }
  2203. audiotype_t eServiceMP3::gstCheckAudioPad(GstStructure* structure)
  2204. {
  2205. if (!structure)
  2206. return atUnknown;
  2207. if ( gst_structure_has_name (structure, "audio/mpeg"))
  2208. {
  2209. gint mpegversion, layer = -1;
  2210. if (!gst_structure_get_int (structure, "mpegversion", &mpegversion))
  2211. return atUnknown;
  2212. switch (mpegversion) {
  2213. case 1:
  2214. {
  2215. gst_structure_get_int (structure, "layer", &layer);
  2216. if ( layer == 3 )
  2217. return atMP3;
  2218. else
  2219. return atMPEG;
  2220. break;
  2221. }
  2222. case 2:
  2223. return atAAC;
  2224. case 4:
  2225. return atAAC;
  2226. default:
  2227. return atUnknown;
  2228. }
  2229. }
  2230. else if ( gst_structure_has_name (structure, "audio/x-ac3") || gst_structure_has_name (structure, "audio/ac3") )
  2231. return atAC3;
  2232. else if ( gst_structure_has_name (structure, "audio/x-dts") || gst_structure_has_name (structure, "audio/dts") )
  2233. return atDTS;
  2234. #if GST_VERSION_MAJOR < 1
  2235. else if ( gst_structure_has_name (structure, "audio/x-raw-int") )
  2236. #else
  2237. else if ( gst_structure_has_name (structure, "audio/x-raw") )
  2238. #endif
  2239. return atPCM;
  2240. return atUnknown;
  2241. }
  2242. void eServiceMP3::gstPoll(ePtr<GstMessageContainer> const &msg)
  2243. {
  2244. switch (msg->getType())
  2245. {
  2246. case 1:
  2247. {
  2248. GstMessage *gstmessage = *((GstMessageContainer*)msg);
  2249. if (gstmessage)
  2250. {
  2251. gstBusCall(gstmessage);
  2252. }
  2253. break;
  2254. }
  2255. case 2:
  2256. {
  2257. GstBuffer *buffer = *((GstMessageContainer*)msg);
  2258. if (buffer)
  2259. {
  2260. pullSubtitle(buffer);
  2261. }
  2262. break;
  2263. }
  2264. case 3:
  2265. {
  2266. GstPad *pad = *((GstMessageContainer*)msg);
  2267. gstTextpadHasCAPS_synced(pad);
  2268. break;
  2269. }
  2270. }
  2271. }
  2272. eAutoInitPtr<eServiceFactoryMP3> init_eServiceFactoryMP3(eAutoInitNumbers::service+1, "eServiceFactoryMP3");
  2273. void eServiceMP3::gstCBsubtitleAvail(GstElement *subsink, GstBuffer *buffer, gpointer user_data)
  2274. {
  2275. eServiceMP3 *_this = (eServiceMP3*)user_data;
  2276. if (_this->m_currentSubtitleStream < 0)
  2277. {
  2278. if (buffer) gst_buffer_unref(buffer);
  2279. return;
  2280. }
  2281. _this->m_pump.send(new GstMessageContainer(2, NULL, NULL, buffer));
  2282. }
  2283. void eServiceMP3::gstTextpadHasCAPS(GstPad *pad, GParamSpec * unused, gpointer user_data)
  2284. {
  2285. eServiceMP3 *_this = (eServiceMP3*)user_data;
  2286. gst_object_ref (pad);
  2287. _this->m_pump.send(new GstMessageContainer(3, NULL, pad, NULL));
  2288. }
  2289. void eServiceMP3::gstTextpadHasCAPS_synced(GstPad *pad)
  2290. {
  2291. GstCaps *caps = NULL;
  2292. g_object_get (G_OBJECT (pad), "caps", &caps, NULL);
  2293. if (caps)
  2294. {
  2295. subtitleStream subs;
  2296. // eDebug("[eServiceMP3] gstTextpadHasCAPS:: signal::caps = %s", gst_caps_to_string(caps));
  2297. // eDebug("[eServiceMP3] gstGhostpadHasCAPS_synced %p %d", pad, m_subtitleStreams.size());
  2298. if (m_currentSubtitleStream >= 0 && m_currentSubtitleStream < (int)m_subtitleStreams.size())
  2299. subs = m_subtitleStreams[m_currentSubtitleStream];
  2300. else {
  2301. subs.type = stUnknown;
  2302. subs.pad = pad;
  2303. }
  2304. if ( subs.type == stUnknown )
  2305. {
  2306. GstTagList *tags = NULL;
  2307. gchar *g_lang = NULL;
  2308. g_signal_emit_by_name (m_gst_playbin, "get-text-tags", m_currentSubtitleStream, &tags);
  2309. subs.language_code = "und";
  2310. subs.type = getSubtitleType(pad);
  2311. #if GST_VERSION_MAJOR < 1
  2312. if (tags && gst_is_tag_list(tags))
  2313. #else
  2314. if (tags && GST_IS_TAG_LIST(tags))
  2315. #endif
  2316. {
  2317. if (gst_tag_list_get_string(tags, GST_TAG_LANGUAGE_CODE, &g_lang))
  2318. {
  2319. subs.language_code = std::string(g_lang);
  2320. g_free(g_lang);
  2321. }
  2322. gst_tag_list_free(tags);
  2323. }
  2324. if (m_currentSubtitleStream >= 0 && m_currentSubtitleStream < (int)m_subtitleStreams.size())
  2325. m_subtitleStreams[m_currentSubtitleStream] = subs;
  2326. else
  2327. m_subtitleStreams.push_back(subs);
  2328. }
  2329. // eDebug("[eServiceMP3] gstGhostpadHasCAPS:: m_gst_prev_subtitle_caps=%s equal=%i",gst_caps_to_string(m_gst_prev_subtitle_caps),gst_caps_is_equal(m_gst_prev_subtitle_caps, caps));
  2330. gst_caps_unref (caps);
  2331. }
  2332. }
  2333. void eServiceMP3::pullSubtitle(GstBuffer *buffer)
  2334. {
  2335. if (buffer && m_currentSubtitleStream >= 0 && m_currentSubtitleStream < (int)m_subtitleStreams.size())
  2336. {
  2337. #if GST_VERSION_MAJOR < 1
  2338. gint64 buf_pos = GST_BUFFER_TIMESTAMP(buffer);
  2339. size_t len = GST_BUFFER_SIZE(buffer);
  2340. #else
  2341. GstMapInfo map;
  2342. if(!gst_buffer_map(buffer, &map, GST_MAP_READ))
  2343. {
  2344. //eDebug("[eServiceMP3] pullSubtitle gst_buffer_map failed");
  2345. return;
  2346. }
  2347. gint64 buf_pos = GST_BUFFER_PTS(buffer);
  2348. size_t len = map.size;
  2349. // eDebug("[eServiceMP3] gst_buffer_get_size %zu map.size %zu", gst_buffer_get_size(buffer), len);
  2350. #endif
  2351. gint64 duration_ns = GST_BUFFER_DURATION(buffer);
  2352. int subType = m_subtitleStreams[m_currentSubtitleStream].type;
  2353. // eDebug("[eServiceMP3] pullSubtitle type=%d size=%zu", subType, len);
  2354. if ( subType )
  2355. {
  2356. if ( subType < stVOB )
  2357. {
  2358. int delay = eConfigManager::getConfigIntValue("config.subtitles.pango_subtitles_delay");
  2359. int subtitle_fps = eConfigManager::getConfigIntValue("config.subtitles.pango_subtitles_fps");
  2360. double convert_fps = 1.0;
  2361. if (subtitle_fps > 1 && m_framerate > 0)
  2362. convert_fps = subtitle_fps / (double)m_framerate;
  2363. #if GST_VERSION_MAJOR < 1
  2364. std::string line((const char*)GST_BUFFER_DATA(buffer), len);
  2365. #else
  2366. std::string line((const char*)map.data, len);
  2367. #endif
  2368. // eDebug("[eServiceMP3] got new text subtitle @ buf_pos = %lld ns (in pts=%lld), dur=%lld: '%s' ", buf_pos, buf_pos/11111, duration_ns, line.c_str());
  2369. uint32_t start_ms = buf_pos / 1000000ULL;
  2370. uint32_t end_ms = start_ms + (duration_ns / 1000000ULL);
  2371. m_subtitle_pages.insert(subtitle_pages_map_pair_t(end_ms, subtitle_page_t(start_ms, end_ms, line)));
  2372. m_subtitle_sync_timer->start(1, true);
  2373. }
  2374. else
  2375. {
  2376. //eDebug("[eServiceMP3] unsupported subpicture... ignoring");
  2377. }
  2378. }
  2379. #if GST_VERSION_MAJOR >= 1
  2380. gst_buffer_unmap(buffer, &map);
  2381. #endif
  2382. }
  2383. }
  2384. void eServiceMP3::pushSubtitles()
  2385. {
  2386. pts_t running_pts = 0;
  2387. int32_t next_timer = 0, decoder_ms, start_ms, end_ms, diff_start_ms, diff_end_ms, delay_ms;
  2388. double convert_fps = 1.0;
  2389. subtitle_pages_map_t::iterator current;
  2390. // wait until clock is stable
  2391. if (getPlayPosition(running_pts) < 0)
  2392. m_decoder_time_valid_state = 0;
  2393. if (m_decoder_time_valid_state < 4)
  2394. {
  2395. m_decoder_time_valid_state++;
  2396. if (m_prev_decoder_time == running_pts)
  2397. m_decoder_time_valid_state = 0;
  2398. if (m_decoder_time_valid_state < 4)
  2399. {
  2400. //eDebug("[eServiceMP3] *** push subtitles, waiting for clock to stabilise");
  2401. m_prev_decoder_time = running_pts;
  2402. next_timer = 50;
  2403. goto exit;
  2404. }
  2405. //eDebug("[eServiceMP3] *** push subtitles, clock stable");
  2406. }
  2407. decoder_ms = running_pts / 90;
  2408. delay_ms = 0;
  2409. #if 0
  2410. // eDebug("\n*** all subs: ");
  2411. for (current = m_subtitle_pages.begin(); current != m_subtitle_pages.end(); current++)
  2412. {
  2413. start_ms = current->second.start_ms;
  2414. end_ms = current->second.end_ms;
  2415. diff_start_ms = start_ms - decoder_ms;
  2416. diff_end_ms = end_ms - decoder_ms;
  2417. // eDebug("[eServiceMP3] start: %d, end: %d, diff_start: %d, diff_end: %d: %s",
  2418. start_ms, end_ms, diff_start_ms, diff_end_ms, current->second.text.c_str());
  2419. }
  2420. // eDebug("\n\n");
  2421. #endif
  2422. if (m_currentSubtitleStream >= 0 && m_currentSubtitleStream < (int)m_subtitleStreams.size() &&
  2423. m_subtitleStreams[m_currentSubtitleStream].type &&
  2424. m_subtitleStreams[m_currentSubtitleStream].type < stVOB)
  2425. {
  2426. delay_ms = eConfigManager::getConfigIntValue("config.subtitles.pango_subtitles_delay") / 90;
  2427. int subtitle_fps = eConfigManager::getConfigIntValue("config.subtitles.pango_subtitles_fps");
  2428. if (subtitle_fps > 1 && m_framerate > 0)
  2429. convert_fps = subtitle_fps / (double)m_framerate;
  2430. }
  2431. for (current = m_subtitle_pages.begin(); current != m_subtitle_pages.end(); current++)
  2432. {
  2433. start_ms = (current->second.start_ms * convert_fps) + delay_ms;
  2434. end_ms = (current->second.end_ms * convert_fps) + delay_ms;
  2435. diff_start_ms = start_ms - decoder_ms;
  2436. diff_end_ms = end_ms - decoder_ms;
  2437. #if 0
  2438. // eDebug("[eServiceMP3] *** next subtitle: decoder: %d, start: %d, end: %d, duration_ms: %d, diff_start: %d, diff_end: %d : %s",
  2439. decoder_ms, start_ms, end_ms, end_ms - start_ms, diff_start_ms, diff_end_ms, current->second.text.c_str());
  2440. #endif
  2441. if (diff_end_ms < 0)
  2442. {
  2443. //eDebug("[eServiceMP3] *** current sub has already ended, skip: %d\n", diff_end_ms);
  2444. continue;
  2445. }
  2446. if (diff_start_ms > 20)
  2447. {
  2448. //eDebug("[eServiceMP3] *** current sub in the future, start timer, %d\n", diff_start_ms);
  2449. next_timer = diff_start_ms;
  2450. goto exit;
  2451. }
  2452. // showtime
  2453. if (m_subtitle_widget && !m_paused)
  2454. {
  2455. //eDebug("[eServiceMP3] *** current sub actual, show!");
  2456. ePangoSubtitlePage pango_page;
  2457. gRGB rgbcol(0xD0,0xD0,0xD0);
  2458. pango_page.m_elements.push_back(ePangoSubtitlePageElement(rgbcol, current->second.text.c_str()));
  2459. pango_page.m_show_pts = start_ms * 90; // actually completely unused by widget!
  2460. if (!m_subtitles_paused)
  2461. pango_page.m_timeout = end_ms - decoder_ms; // take late start into account
  2462. else
  2463. pango_page.m_timeout = 60000; //paused, subs must stay on (60s for now), avoid timeout in lib/gui/esubtitle.cpp: m_hide_subtitles_timer->start(m_pango_page.m_timeout, true);
  2464. m_subtitle_widget->setPage(pango_page);
  2465. }
  2466. //eDebug("[eServiceMP3] *** no next sub scheduled, check NEXT subtitle");
  2467. }
  2468. // no more subs in cache, fall through
  2469. exit:
  2470. if (next_timer == 0)
  2471. {
  2472. //eDebug("[eServiceMP3] *** next timer = 0, set default timer!");
  2473. next_timer = 1000;
  2474. }
  2475. m_subtitle_sync_timer->start(next_timer, true);
  2476. }
  2477. RESULT eServiceMP3::enableSubtitles(iSubtitleUser *user, struct SubtitleTrack &track)
  2478. {
  2479. if (m_currentSubtitleStream != track.pid)
  2480. {
  2481. g_object_set (G_OBJECT (m_gst_playbin), "current-text", -1, NULL);
  2482. m_subtitle_sync_timer->stop();
  2483. m_subtitle_pages.clear();
  2484. m_prev_decoder_time = -1;
  2485. m_decoder_time_valid_state = 0;
  2486. m_currentSubtitleStream = track.pid;
  2487. m_cachedSubtitleStream = m_currentSubtitleStream;
  2488. g_object_set (G_OBJECT (m_gst_playbin), "current-text", m_currentSubtitleStream, NULL);
  2489. m_subtitle_widget = user;
  2490. eDebug ("[eServiceMP3] eServiceMP3::switched to subtitle stream %i", m_currentSubtitleStream);
  2491. #ifdef GSTREAMER_SUBTITLE_SYNC_MODE_BUG
  2492. /*
  2493. * when we're running the subsink in sync=false mode,
  2494. * we have to force a seek, before the new subtitle stream will start
  2495. */
  2496. seekRelative(-1, 90000);
  2497. #endif
  2498. }
  2499. return 0;
  2500. }
  2501. RESULT eServiceMP3::disableSubtitles()
  2502. {
  2503. eDebug("[eServiceMP3] disableSubtitles");
  2504. m_currentSubtitleStream = -1;
  2505. m_cachedSubtitleStream = m_currentSubtitleStream;
  2506. g_object_set (G_OBJECT (m_gst_playbin), "current-text", m_currentSubtitleStream, NULL);
  2507. m_subtitle_sync_timer->stop();
  2508. m_subtitle_pages.clear();
  2509. m_prev_decoder_time = -1;
  2510. m_decoder_time_valid_state = 0;
  2511. if (m_subtitle_widget) m_subtitle_widget->destroy();
  2512. m_subtitle_widget = 0;
  2513. return 0;
  2514. }
  2515. RESULT eServiceMP3::getCachedSubtitle(struct SubtitleTrack &track)
  2516. {
  2517. bool autoturnon = eConfigManager::getConfigBoolValue("config.subtitles.pango_autoturnon", true);
  2518. if (!autoturnon)
  2519. return -1;
  2520. if (m_cachedSubtitleStream >= 0 && m_cachedSubtitleStream < (int)m_subtitleStreams.size())
  2521. {
  2522. track.type = 2;
  2523. track.pid = m_cachedSubtitleStream;
  2524. track.page_number = int(m_subtitleStreams[m_cachedSubtitleStream].type);
  2525. track.magazine_number = 0;
  2526. return 0;
  2527. }
  2528. return -1;
  2529. }
  2530. RESULT eServiceMP3::getSubtitleList(std::vector<struct SubtitleTrack> &subtitlelist)
  2531. {
  2532. // eDebug("[eServiceMP3] getSubtitleList");
  2533. int stream_idx = 0;
  2534. for (std::vector<subtitleStream>::iterator IterSubtitleStream(m_subtitleStreams.begin()); IterSubtitleStream != m_subtitleStreams.end(); ++IterSubtitleStream)
  2535. {
  2536. subtype_t type = IterSubtitleStream->type;
  2537. switch(type)
  2538. {
  2539. case stUnknown:
  2540. case stVOB:
  2541. case stPGS:
  2542. break;
  2543. default:
  2544. {
  2545. struct SubtitleTrack track;
  2546. track.type = 2;
  2547. track.pid = stream_idx;
  2548. track.page_number = int(type);
  2549. track.magazine_number = 0;
  2550. track.language_code = IterSubtitleStream->language_code;
  2551. subtitlelist.push_back(track);
  2552. }
  2553. }
  2554. stream_idx++;
  2555. }
  2556. // eDebug("[eServiceMP3] getSubtitleList finished");
  2557. return 0;
  2558. }
  2559. RESULT eServiceMP3::streamed(ePtr<iStreamedService> &ptr)
  2560. {
  2561. ptr = this;
  2562. return 0;
  2563. }
  2564. ePtr<iStreamBufferInfo> eServiceMP3::getBufferCharge()
  2565. {
  2566. return new eStreamBufferInfo(m_bufferInfo.bufferPercent, m_bufferInfo.avgInRate, m_bufferInfo.avgOutRate, m_bufferInfo.bufferingLeft, m_buffer_size);
  2567. }
  2568. /* cuesheet CVR */
  2569. PyObject *eServiceMP3::getCutList()
  2570. {
  2571. ePyObject list = PyList_New(0);
  2572. for (std::multiset<struct cueEntry>::iterator i(m_cue_entries.begin()); i != m_cue_entries.end(); ++i)
  2573. {
  2574. ePyObject tuple = PyTuple_New(2);
  2575. PyTuple_SET_ITEM(tuple, 0, PyLong_FromLongLong(i->where));
  2576. PyTuple_SET_ITEM(tuple, 1, PyInt_FromLong(i->what));
  2577. PyList_Append(list, tuple);
  2578. Py_DECREF(tuple);
  2579. }
  2580. return list;
  2581. }
  2582. /* cuesheet CVR */
  2583. void eServiceMP3::setCutList(ePyObject list)
  2584. {
  2585. if (!PyList_Check(list))
  2586. return;
  2587. int size = PyList_Size(list);
  2588. int i;
  2589. m_cue_entries.clear();
  2590. for (i=0; i<size; ++i)
  2591. {
  2592. ePyObject tuple = PyList_GET_ITEM(list, i);
  2593. if (!PyTuple_Check(tuple))
  2594. {
  2595. eDebug("[eServiceMP3] non-tuple in cutlist");
  2596. continue;
  2597. }
  2598. if (PyTuple_Size(tuple) != 2)
  2599. {
  2600. eDebug("[eServiceMP3] cutlist entries need to be a 2-tuple");
  2601. continue;
  2602. }
  2603. ePyObject ppts = PyTuple_GET_ITEM(tuple, 0), ptype = PyTuple_GET_ITEM(tuple, 1);
  2604. if (!(PyLong_Check(ppts) && PyInt_Check(ptype)))
  2605. {
  2606. eDebug("[eServiceMP3] cutlist entries need to be (pts, type)-tuples (%d %d)", PyLong_Check(ppts), PyInt_Check(ptype));
  2607. continue;
  2608. }
  2609. pts_t pts = PyLong_AsLongLong(ppts);
  2610. int type = PyInt_AsLong(ptype);
  2611. m_cue_entries.insert(cueEntry(pts, type));
  2612. eDebug("[eServiceMP3] adding %08llx, %d", pts, type);
  2613. }
  2614. m_cuesheet_changed = 1;
  2615. m_event((iPlayableService*)this, evCuesheetChanged);
  2616. }
  2617. void eServiceMP3::setCutListEnable(int enable)
  2618. {
  2619. m_cutlist_enabled = enable;
  2620. }
  2621. int eServiceMP3::setBufferSize(int size)
  2622. {
  2623. m_buffer_size = size;
  2624. g_object_set (G_OBJECT (m_gst_playbin), "buffer-size", m_buffer_size, NULL);
  2625. return 0;
  2626. }
  2627. int eServiceMP3::getAC3Delay()
  2628. {
  2629. return ac3_delay;
  2630. }
  2631. int eServiceMP3::getPCMDelay()
  2632. {
  2633. return pcm_delay;
  2634. }
  2635. void eServiceMP3::setAC3Delay(int delay)
  2636. {
  2637. ac3_delay = delay;
  2638. if (!m_gst_playbin || m_state != stRunning)
  2639. return;
  2640. else
  2641. {
  2642. int config_delay_int = delay;
  2643. /*
  2644. * NOTE: We only look for dvbmediasinks.
  2645. * If either the video or audio sink is of a different type,
  2646. * we have no chance to get them synced anyway.
  2647. */
  2648. if (videoSink)
  2649. {
  2650. config_delay_int += eConfigManager::getConfigIntValue("config.av.generalAC3delay");
  2651. }
  2652. else
  2653. {
  2654. // eDebug("[eServiceMP3]dont apply ac3 delay when no video is running!");
  2655. config_delay_int = 0;
  2656. }
  2657. if (audioSink)
  2658. {
  2659. eTSMPEGDecoder::setHwAC3Delay(config_delay_int);
  2660. }
  2661. }
  2662. }
  2663. void eServiceMP3::setPCMDelay(int delay)
  2664. {
  2665. pcm_delay = delay;
  2666. if (!m_gst_playbin || m_state != stRunning)
  2667. return;
  2668. else
  2669. {
  2670. int config_delay_int = delay;
  2671. /*
  2672. * NOTE: We only look for dvbmediasinks.
  2673. * If either the video or audio sink is of a different type,
  2674. * we have no chance to get them synced anyway.
  2675. */
  2676. if (videoSink)
  2677. {
  2678. config_delay_int += eConfigManager::getConfigIntValue("config.av.generalPCMdelay");
  2679. }
  2680. else
  2681. {
  2682. // eDebug("[eServiceMP3] dont apply pcm delay when no video is running!");
  2683. config_delay_int = 0;
  2684. }
  2685. if (audioSink)
  2686. {
  2687. eTSMPEGDecoder::setHwPCMDelay(config_delay_int);
  2688. }
  2689. }
  2690. }
  2691. /* cuesheet CVR */
  2692. void eServiceMP3::loadCuesheet()
  2693. {
  2694. if (!m_cuesheet_loaded)
  2695. {
  2696. eDebug("[eServiceMP3] loading cuesheet");
  2697. m_cuesheet_loaded = true;
  2698. }
  2699. else
  2700. {
  2701. //eDebug("[eServiceMP3] skip loading cuesheet multiple times");
  2702. return;
  2703. }
  2704. m_cue_entries.clear();
  2705. std::string filename = m_ref.path + ".cuts";
  2706. FILE *f = fopen(filename.c_str(), "rb");
  2707. if (f)
  2708. {
  2709. while (1)
  2710. {
  2711. unsigned long long where;
  2712. unsigned int what;
  2713. if (!fread(&where, sizeof(where), 1, f))
  2714. break;
  2715. if (!fread(&what, sizeof(what), 1, f))
  2716. break;
  2717. where = be64toh(where);
  2718. what = ntohl(what);
  2719. if (what > 3)
  2720. break;
  2721. m_cue_entries.insert(cueEntry(where, what));
  2722. }
  2723. fclose(f);
  2724. eDebug("[eServiceMP3] cuts file has %zd entries", m_cue_entries.size());
  2725. } else
  2726. eDebug("[eServiceMP3] cutfile not found!");
  2727. m_cuesheet_changed = 0;
  2728. m_event((iPlayableService*)this, evCuesheetChanged);
  2729. }
  2730. /* cuesheet */
  2731. void eServiceMP3::saveCuesheet()
  2732. {
  2733. std::string filename = m_ref.path;
  2734. /* save cuesheet only when main file is accessible. */
  2735. if (::access(filename.c_str(), R_OK) < 0)
  2736. return;
  2737. filename.append(".cuts");
  2738. bool removefile = false;
  2739. struct stat s;
  2740. if (stat(filename.c_str(), &s) == 0)
  2741. {
  2742. time_t now;
  2743. time(&now);
  2744. /* check time difference when file was modified - it is possible, the file has been write from another side */
  2745. if (now - s.st_mtime > 1 && m_cue_entries.size() == 0)
  2746. /* no entrys and file was not modified -> delete file */
  2747. removefile = true;
  2748. else
  2749. /* no entrys -> do nothing, have entries -> write file */
  2750. if (m_cue_entries.size() == 0)
  2751. return;
  2752. }
  2753. else
  2754. /* no file and no entries -> do nothing, have entries -> write file */
  2755. if (m_cue_entries.size() == 0)
  2756. return;
  2757. FILE *f = fopen(filename.c_str(), "wb");
  2758. if (f)
  2759. {
  2760. if (removefile)
  2761. {
  2762. fclose(f);
  2763. remove(filename.c_str());
  2764. eDebug("[eServiceMP3] cuts file has been removed");
  2765. return;
  2766. }
  2767. unsigned long long where = 0;
  2768. int what = 0;
  2769. for (std::multiset<cueEntry>::iterator i(m_cue_entries.begin()); i != m_cue_entries.end(); ++i)
  2770. {
  2771. if (where == i->where && what == i->what)
  2772. /* ignore double entries */
  2773. continue;
  2774. else
  2775. {
  2776. where = htobe64(i->where);
  2777. what = htonl(i->what);
  2778. fwrite(&where, sizeof(where), 1, f);
  2779. fwrite(&what, sizeof(what), 1, f);
  2780. /* temorary save for comparing */
  2781. where = i->where;
  2782. what = i->what;
  2783. }
  2784. }
  2785. fclose(f);
  2786. }
  2787. m_cuesheet_changed = 0;
  2788. }