From d36def84f92bb9206c792356954e62c533297af4 Mon Sep 17 00:00:00 2001 From: andy Date: Thu, 30 Oct 2008 18:24:06 +0100 Subject: fix execute string for tasks --- lib/python/Components/Task.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'lib/python/Components') diff --git a/lib/python/Components/Task.py b/lib/python/Components/Task.py index 7ea64f1a..c152e9a2 100644 --- a/lib/python/Components/Task.py +++ b/lib/python/Components/Task.py @@ -136,7 +136,6 @@ class Task(object): def setTool(self, tool): self.cmd = tool - self.args = [tool] self.global_preconditions.append(ToolExistsPrecondition()) self.postconditions.append(ReturncodePostcondition()) @@ -172,7 +171,7 @@ class Task(object): if self.cwd is not None: self.container.setCWD(self.cwd) - execstr = self.cmd + " ".join(self.args) + #execstr = " ".join([self.cmd]+self.args) print "execute:", self.container.execute(execstr), execstr if self.initial_input: self.writeInput(self.initial_input) -- cgit v1.2.3 From f69b4f8dbed8ff96260b951cf8cecd76fa85423b Mon Sep 17 00:00:00 2001 From: Fraxinas Date: Fri, 31 Oct 2008 11:18:40 +0100 Subject: uncomment necessary line --- lib/python/Components/Task.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib/python/Components') diff --git a/lib/python/Components/Task.py b/lib/python/Components/Task.py index c152e9a2..47acc87e 100644 --- a/lib/python/Components/Task.py +++ b/lib/python/Components/Task.py @@ -171,7 +171,7 @@ class Task(object): if self.cwd is not None: self.container.setCWD(self.cwd) - #execstr = " ".join([self.cmd]+self.args) + execstr = " ".join([self.cmd]+self.args) print "execute:", self.container.execute(execstr), execstr if self.initial_input: self.writeInput(self.initial_input) -- cgit v1.2.3 From 19ce1123c780a9475e2f158712da6e73fa543e9c Mon Sep 17 00:00:00 2001 From: ghost Date: Fri, 31 Oct 2008 13:07:01 +0100 Subject: add possibility to call eConsoleAppContainer execute with unlimited count of arguments when its called with single argument, then /bin/sh is started else not --- lib/base/console.cpp | 36 +++++++++++++++++++++++++++++++----- lib/python/Components/Task.py | 4 ++-- 2 files changed, 33 insertions(+), 7 deletions(-) (limited to 'lib/python/Components') diff --git a/lib/base/console.cpp b/lib/base/console.cpp index a12cb5e2..25318cc9 100644 --- a/lib/base/console.cpp +++ b/lib/base/console.cpp @@ -476,11 +476,37 @@ eConsolePy_running(eConsolePy* self) static PyObject * eConsolePy_execute(eConsolePy* self, PyObject *argt) { - const char *str; - if (PyArg_ParseTuple(argt, "s", &str)) - return PyInt_FromLong(self->cont->execute(str)); - PyErr_SetString(PyExc_TypeError, - "argument is not a string"); + Py_ssize_t argc = PyTuple_Size(argt); + if (argc > 1) + { + const char *argv[argc + 1]; + int argpos=0; + while(argpos < argc) + { + PyObject *arg = PyTuple_GET_ITEM(argt, argpos); + if (!PyString_Check(arg)) + { + char err[255]; + if (argpos) + snprintf(err, 255, "arg %d is not a string", argpos); + else + snprintf(err, 255, "cmd is not a string!"); + PyErr_SetString(PyExc_TypeError, err); + return NULL; + } + argv[argpos++] = PyString_AsString(arg); + } + argv[argpos] = 0; + return PyInt_FromLong(self->cont->execute(argv[0], argv)); + } + else + { + const char *str; + if (PyArg_ParseTuple(argt, "s", &str)) + return PyInt_FromLong(self->cont->execute(str)); + PyErr_SetString(PyExc_TypeError, + "cmd is not a string!"); + } return NULL; } diff --git a/lib/python/Components/Task.py b/lib/python/Components/Task.py index 47acc87e..ab85c667 100644 --- a/lib/python/Components/Task.py +++ b/lib/python/Components/Task.py @@ -136,6 +136,7 @@ class Task(object): def setTool(self, tool): self.cmd = tool + self.args = [tool] self.global_preconditions.append(ToolExistsPrecondition()) self.postconditions.append(ReturncodePostcondition()) @@ -171,8 +172,7 @@ class Task(object): if self.cwd is not None: self.container.setCWD(self.cwd) - execstr = " ".join([self.cmd]+self.args) - print "execute:", self.container.execute(execstr), execstr + print "execute:", self.container.execute(self.cmd, *self.args), self.cmd, *self.args if self.initial_input: self.writeInput(self.initial_input) -- cgit v1.2.3 From de868496fdbc0dc65d961d7404bfd7af827e045f Mon Sep 17 00:00:00 2001 From: ghost Date: Fri, 31 Oct 2008 14:04:12 +0100 Subject: fix syntax error --- lib/python/Components/Task.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib/python/Components') diff --git a/lib/python/Components/Task.py b/lib/python/Components/Task.py index ab85c667..f249f711 100644 --- a/lib/python/Components/Task.py +++ b/lib/python/Components/Task.py @@ -172,7 +172,7 @@ class Task(object): if self.cwd is not None: self.container.setCWD(self.cwd) - print "execute:", self.container.execute(self.cmd, *self.args), self.cmd, *self.args + print "execute:", self.container.execute(self.cmd, *self.args), self.cmd, self.args if self.initial_input: self.writeInput(self.initial_input) -- cgit v1.2.3 From 28c7b76bc72da019f3c3bf3aca88c3636062a618 Mon Sep 17 00:00:00 2001 From: ghost Date: Fri, 31 Oct 2008 16:43:41 +0100 Subject: needed update for avahi stuff --- lib/python/Components/Network.py | 102 +++++++++++++++++++++++++-------------- 1 file changed, 65 insertions(+), 37 deletions(-) (limited to 'lib/python/Components') diff --git a/lib/python/Components/Network.py b/lib/python/Components/Network.py index 9b0898e0..5c9e06b7 100644 --- a/lib/python/Components/Network.py +++ b/lib/python/Components/Network.py @@ -14,10 +14,11 @@ class Network: self.Console = Console() self.getInterfaces() - def getInterfaces(self): + def getInterfaces(self, callback = None): devicesPattern = re_compile('[a-z]+[0-9]+') self.configuredInterfaces = [] fp = file('/proc/net/dev', 'r') + system("cat /proc/net/dev") result = fp.readlines() fp.close() for line in result: @@ -25,19 +26,10 @@ class Network: device = devicesPattern.search(line).group() if device == 'wifi0': continue - self.getDataForInterface(device) - # Show only UP Interfaces in E2 - #if self.getAdapterAttribute(device, 'up') is False: - # del self.ifaces[device] + self.getDataForInterface(device, callback) except AttributeError: pass - #print "self.ifaces:", self.ifaces - #self.writeNetworkConfig() - #print ord(' ') - #for line in result: - # print ord(line[0]) - # helper function def regExpMatch(self, pattern, string): if string is None: @@ -55,12 +47,37 @@ class Network: ip.append(int(x)) return ip - def getDataForInterface(self, iface): - cmd = "ifconfig " + iface - self.Console.ePopen(cmd, self.ifconfigFinished, iface) - - def ifconfigFinished(self, result, retval, iface): + def IPaddrFinished(self, result, retval, extra_args): + (iface, callback ) = extra_args data = { 'up': False, 'dhcp': False, 'preup' : False, 'postdown' : False } + globalIPpattern = re_compile("scope global") + ipRegexp = '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' + ipLinePattern = re_compile('inet ' + ipRegexp +'/') + ipPattern = re_compile(ipRegexp) + + for line in result.splitlines(): + split = line.strip().split(' ',2) + if (split[1] == iface): + if re_search(globalIPpattern, split[2]): + ip = self.regExpMatch(ipPattern, self.regExpMatch(ipLinePattern, split[2])) + if ip is not None: + data['ip'] = self.convertIP(ip) + if not data.has_key('ip'): + data['dhcp'] = True + data['ip'] = [0, 0, 0, 0] + data['netmask'] = [0, 0, 0, 0] + data['gateway'] = [0, 0, 0, 0] + + cmd = "ifconfig " + iface + self.Console.ePopen(cmd, self.ifconfigFinished, [iface, data, callback]) + + def getDataForInterface(self, iface,callback): + #get ip out of ip addr, as avahi sometimes overrides it in ifconfig. + cmd = "ip -o addr" + self.Console.ePopen(cmd, self.IPaddrFinished, [iface,callback]) + + def ifconfigFinished(self, result, retval, extra_args ): + (iface, data, callback ) = extra_args ipRegexp = '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' ipLinePattern = re_compile('inet addr:' + ipRegexp) netmaskLinePattern = re_compile('Mask:' + ipRegexp) @@ -68,15 +85,15 @@ class Network: ipPattern = re_compile(ipRegexp) upPattern = re_compile('UP ') macPattern = re_compile('[0-9]{2}\:[0-9]{2}\:[0-9]{2}\:[0-9]{2}\:[0-9]{2}\:[0-9]{2}') - + for line in result.splitlines(): - ip = self.regExpMatch(ipPattern, self.regExpMatch(ipLinePattern, line)) + #ip = self.regExpMatch(ipPattern, self.regExpMatch(ipLinePattern, line)) netmask = self.regExpMatch(ipPattern, self.regExpMatch(netmaskLinePattern, line)) bcast = self.regExpMatch(ipPattern, self.regExpMatch(bcastLinePattern, line)) up = self.regExpMatch(upPattern, line) mac = self.regExpMatch(macPattern, line) - if ip is not None: - data['ip'] = self.convertIP(ip) + #if ip is not None: + # data['ip'] = self.convertIP(ip) if netmask is not None: data['netmask'] = self.convertIP(netmask) if bcast is not None: @@ -87,27 +104,34 @@ class Network: self.configuredInterfaces.append(iface) if mac is not None: data['mac'] = mac - if not data.has_key('ip'): - data['dhcp'] = True - data['ip'] = [0, 0, 0, 0] - data['netmask'] = [0, 0, 0, 0] - data['gateway'] = [0, 0, 0, 0] - + cmd = "route -n | grep " + iface - self.Console.ePopen(cmd,self.routeFinished,[iface,data,ipPattern]) + self.Console.ePopen(cmd,self.routeFinished,[iface,data,callback]) def routeFinished(self, result, retval, extra_args): - (iface, data, ipPattern) = extra_args - + (iface, data, callback) = extra_args + ipRegexp = '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' + ipPattern = re_compile(ipRegexp) + ipLinePattern = re_compile(ipRegexp) + for line in result.splitlines(): print line[0:7] if line[0:7] == "0.0.0.0": gateway = self.regExpMatch(ipPattern, line[16:31]) if gateway is not None: data['gateway'] = self.convertIP(gateway) + + for line in result.splitlines(): #get real netmask in case avahi has overridden ifconfig netmask + split = line.strip().split(' ') + if re_search(ipPattern, split[0]): + foundip = self.convertIP(split[0]) + if (foundip[0] == data['ip'][0] and foundip[1] == data['ip'][1]): + if re_search(ipPattern, split[4]): + mask = self.regExpMatch(ipPattern, self.regExpMatch(ipLinePattern, split[4])) + if mask is not None: + data['netmask'] = self.convertIP(mask) self.ifaces[iface] = data - if len(self.Console.appContainers) == 0: - self.loadNetworkConfig() + self.loadNetworkConfig(iface,callback) def writeNetworkConfig(self): self.configuredInterfaces = [] @@ -144,8 +168,7 @@ class Network: fp.write("nameserver %d.%d.%d.%d\n" % tuple(nameserver)) fp.close() - def loadNetworkConfig(self): - self.loadNameserverConfig() + def loadNetworkConfig(self,iface,callback = None): interfaces = [] # parse the interfaces-file try: @@ -166,7 +189,7 @@ class Network: ifaces[currif]["dhcp"] = True else: ifaces[currif]["dhcp"] = False - if (currif != ""): + if (currif == iface): #read information only for available interfaces if (split[0] == "address"): ifaces[currif]["address"] = map(int, split[1].split('.')) if self.ifaces[currif].has_key("ip"): @@ -181,7 +204,7 @@ class Network: ifaces[currif]["gateway"] = map(int, split[1].split('.')) if self.ifaces[currif].has_key("gateway"): if self.ifaces[currif]["gateway"] != ifaces[currif]["gateway"] and ifaces[currif]["dhcp"] == False: - self.ifaces[currif]["gateway"] = map(int, split[1].split('.')) + self.ifaces[currif]["gateway"] = map(int, split[1].split('.')) if (split[0] == "pre-up"): if self.ifaces[currif].has_key("preup"): self.ifaces[currif]["preup"] = i @@ -189,11 +212,16 @@ class Network: if self.ifaces[currif].has_key("postdown"): self.ifaces[currif]["postdown"] = i - print "read interfaces:", ifaces for ifacename, iface in ifaces.items(): if self.ifaces.has_key(ifacename): self.ifaces[ifacename]["dhcp"] = iface["dhcp"] - print "self.ifaces after loading:", self.ifaces + if len(self.Console.appContainers) == 0: + # load ns only once + self.loadNameserverConfig() + print "read configured interfac:", ifaces + print "self.ifaces after loading:", self.ifaces + if callback is not None: + callback(True) def loadNameserverConfig(self): ipRegexp = "[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}" -- cgit v1.2.3 From 340ec4b3727cb61e1038ca97b006471b5568e8a3 Mon Sep 17 00:00:00 2001 From: ghost Date: Fri, 31 Oct 2008 17:16:10 +0100 Subject: remove debug output --- lib/python/Components/Network.py | 1 - 1 file changed, 1 deletion(-) (limited to 'lib/python/Components') diff --git a/lib/python/Components/Network.py b/lib/python/Components/Network.py index 5c9e06b7..cf21c6d0 100644 --- a/lib/python/Components/Network.py +++ b/lib/python/Components/Network.py @@ -18,7 +18,6 @@ class Network: devicesPattern = re_compile('[a-z]+[0-9]+') self.configuredInterfaces = [] fp = file('/proc/net/dev', 'r') - system("cat /proc/net/dev") result = fp.readlines() fp.close() for line in result: -- cgit v1.2.3 From 7d90a93493f1dc9ab9d3a5694aa96501a9b25b89 Mon Sep 17 00:00:00 2001 From: ghost Date: Fri, 31 Oct 2008 19:36:58 +0100 Subject: add missing import --- lib/python/Components/Network.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib/python/Components') diff --git a/lib/python/Components/Network.py b/lib/python/Components/Network.py index cf21c6d0..bed9d95f 100644 --- a/lib/python/Components/Network.py +++ b/lib/python/Components/Network.py @@ -1,5 +1,5 @@ from os import system, popen, path as os_path, listdir -from re import compile as re_compile +from re import compile as re_compile, search as re_search from socket import * from enigma import eConsoleAppContainer from Components.Console import Console -- cgit v1.2.3 From bd9c23676ae20d70488f7a539574b2ec75886940 Mon Sep 17 00:00:00 2001 From: ghost Date: Sun, 2 Nov 2008 11:14:33 +0100 Subject: add .mp2 as supported filetype --- lib/python/Components/FileList.py | 1 + lib/python/Plugins/Extensions/MediaPlayer/plugin.py | 6 +++--- lib/service/servicemp3.cpp | 1 + 3 files changed, 5 insertions(+), 3 deletions(-) (limited to 'lib/python/Components') diff --git a/lib/python/Components/FileList.py b/lib/python/Components/FileList.py index 7801c556..e028ec3a 100644 --- a/lib/python/Components/FileList.py +++ b/lib/python/Components/FileList.py @@ -10,6 +10,7 @@ from enigma import RT_HALIGN_LEFT, eListboxPythonMultiContent, \ from Tools.LoadPixmap import LoadPixmap EXTENSIONS = { + "mp2": "music", "mp3": "music", "wav": "music", "ogg": "music", diff --git a/lib/python/Plugins/Extensions/MediaPlayer/plugin.py b/lib/python/Plugins/Extensions/MediaPlayer/plugin.py index a144f2cd..841ad614 100644 --- a/lib/python/Plugins/Extensions/MediaPlayer/plugin.py +++ b/lib/python/Plugins/Extensions/MediaPlayer/plugin.py @@ -66,7 +66,7 @@ class MediaPlayer(Screen, InfoBarBase, InfoBarSeek, InfoBarAudioSelection, InfoB self.addPlaylistParser(PlaylistIOInternal, "e2pls") # 'None' is magic to start at the list of mountpoints - self.filelist = FileList(None, matchingPattern = "(?i)^.*\.(mp3|ogg|ts|wav|wave|m3u|pls|e2pls|mpg|vob|avi|mkv|mp4|dat|flac)", useServiceRef = True, additionalExtensions = "4098:m3u 4098:e2pls 4098:pls") + self.filelist = FileList(None, matchingPattern = "(?i)^.*\.(mp2|mp3|ogg|ts|wav|wave|m3u|pls|e2pls|mpg|vob|avi|mkv|mp4|dat|flac)", useServiceRef = True, additionalExtensions = "4098:m3u 4098:e2pls 4098:pls") self["filelist"] = self.filelist self.playlist = MyPlayList() @@ -727,7 +727,7 @@ class MediaPlayer(Screen, InfoBarBase, InfoBarSeek, InfoBarAudioSelection, InfoB ext = text[-4:].lower() # FIXME: the information if the service contains video (and we should hide our window) should com from the service instead - if ext not in [".mp3", ".wav", ".ogg", "flac"] and not self.isAudioCD: + if ext not in [".mp2", ".mp3", ".wav", ".ogg", "flac"] and not self.isAudioCD: self.hide() else: needsInfoUpdate = True @@ -754,7 +754,7 @@ class MediaPlayer(Screen, InfoBarBase, InfoBarSeek, InfoBarAudioSelection, InfoB currref = self.playlist.getServiceRefList()[idx] text = currref.getPath() ext = text[-4:].lower() - if ext not in [".mp3", ".wav", ".ogg", "flac"] and not self.isAudioCD: + if ext not in [".mp2", ".mp3", ".wav", ".ogg", "flac"] and not self.isAudioCD: self.hide() else: needsInfoUpdate = True diff --git a/lib/service/servicemp3.cpp b/lib/service/servicemp3.cpp index 5c982aa1..c76e346e 100644 --- a/lib/service/servicemp3.cpp +++ b/lib/service/servicemp3.cpp @@ -27,6 +27,7 @@ eServiceFactoryMP3::eServiceFactoryMP3() if (sc) { std::list extensions; + extensions.push_back("mp2"); extensions.push_back("mp3"); extensions.push_back("ogg"); extensions.push_back("mpg"); -- cgit v1.2.3 From 6d9bdc5e7ee8990b74da7e18f0b641b39250a827 Mon Sep 17 00:00:00 2001 From: Fraxinas Date: Mon, 3 Nov 2008 13:47:04 +0100 Subject: fix streaming playback (webradio) --- lib/python/Components/Playlist.py | 2 ++ lib/service/servicemp3.cpp | 35 +++++++++++++++++++---------------- 2 files changed, 21 insertions(+), 16 deletions(-) (limited to 'lib/python/Components') diff --git a/lib/python/Components/Playlist.py b/lib/python/Components/Playlist.py index 22799692..744ee3af 100644 --- a/lib/python/Components/Playlist.py +++ b/lib/python/Components/Playlist.py @@ -70,6 +70,8 @@ class PlaylistIOM3U(PlaylistIO): # TODO: use e2 facilities to create a service ref from file if entry[0] == "/": self.addService(ServiceReference("4097:0:0:0:0:0:0:0:0:0:" + entry)) + elif entry.startswith("http"): + self.addService(ServiceReference("4097:0:0:0:0:0:0:0:0:0:" + entry.replace(':',"%3a"))) else: self.addService(ServiceReference("4097:0:0:0:0:0:0:0:0:0:" + os.path.dirname(filename) + "/" + entry)) file.close() diff --git a/lib/service/servicemp3.cpp b/lib/service/servicemp3.cpp index c76e346e..19b7735b 100644 --- a/lib/service/servicemp3.cpp +++ b/lib/service/servicemp3.cpp @@ -227,11 +227,29 @@ eServiceMP3::eServiceMP3(const char *filename): m_filename(filename), m_pump(eAp if (!m_gst_pipeline) m_error_message = "failed to create GStreamer pipeline!\n"; - if ( sourceinfo.containertype == ctCDA ) + if ( sourceinfo.is_streaming ) + { + eDebug("play webradio!"); + source = gst_element_factory_make ("neonhttpsrc", "http-source"); + if (source) + { + g_object_set (G_OBJECT (source), "location", filename, NULL); + g_object_set (G_OBJECT (source), "automatic-redirect", TRUE, NULL); + } + else + m_error_message = "GStreamer plugin neonhttpsrc not available!\n"; + } + else if ( sourceinfo.containertype == ctCDA ) { source = gst_element_factory_make ("cdiocddasrc", "cda-source"); if (source) + { g_object_set (G_OBJECT (source), "device", "/dev/cdroms/cdrom0", NULL); + int track = atoi(filename+18); + eDebug("play audio CD track #%i",track); + if (track > 0) + g_object_set (G_OBJECT (source), "track", track, NULL); + } else sourceinfo.containertype = ctNone; } @@ -243,21 +261,6 @@ eServiceMP3::eServiceMP3(const char *filename): m_filename(filename), m_pump(eAp else m_error_message = "GStreamer can't open filesrc " + (std::string)filename + "!\n"; } - else if ( sourceinfo.is_streaming ) - { - source = gst_element_factory_make ("neonhttpsrc", "http-source"); - if (source) - g_object_set (G_OBJECT (source), "automatic-redirect", TRUE, NULL); - else - m_error_message = "GStreamer plugin neonhttpsrc not available!\n"; - } - else - { - int track = atoi(filename+18); - eDebug("play audio CD track #%i",track); - if (track > 0) - g_object_set (G_OBJECT (source), "track", track, NULL); - } if ( sourceinfo.is_video ) { /* filesrc -> mpegdemux -> | queue_audio -> dvbaudiosink -- cgit v1.2.3 From a1404d58d60d5dc369e89cb98f239a83d447a986 Mon Sep 17 00:00:00 2001 From: Fraxinas Date: Wed, 5 Nov 2008 09:00:27 +0100 Subject: don't crash when background jobs fail and user presses red key --- lib/python/Components/Task.py | 1 + 1 file changed, 1 insertion(+) (limited to 'lib/python/Components') diff --git a/lib/python/Components/Task.py b/lib/python/Components/Task.py index f249f711..b276438f 100644 --- a/lib/python/Components/Task.py +++ b/lib/python/Components/Task.py @@ -265,6 +265,7 @@ class JobManager: from Tools import Notifications if self.in_background: from Screens.TaskView import JobView + self.in_background = False Notifications.AddNotification(JobView, self.active_job) if problems: from Screens.MessageBox import MessageBox -- cgit v1.2.3 From be092c47edfd4babfd3b4c5ea511710e6458343f Mon Sep 17 00:00:00 2001 From: Fraxinas Date: Wed, 5 Nov 2008 17:25:52 +0100 Subject: allow setting progress for current task from within resident task, implement rudimentary progress for mplextask in dvdburn (requires dvdauthor patch) --- lib/python/Components/Task.py | 12 ++++--- lib/python/Plugins/Extensions/DVDBurn/Process.py | 45 ++++++++++++++---------- 2 files changed, 33 insertions(+), 24 deletions(-) (limited to 'lib/python/Components') diff --git a/lib/python/Components/Task.py b/lib/python/Components/Task.py index b276438f..9a768425 100644 --- a/lib/python/Components/Task.py +++ b/lib/python/Components/Task.py @@ -45,6 +45,7 @@ class Job(object): def addTask(self, task): task.job = self + task.task_progress_changed = self.task_progress_changed_CB self.tasks.append(task) def start(self, callback): @@ -70,7 +71,7 @@ class Job(object): else: print "still waiting for %d resident task(s) %s to finish" % (len(self.resident_tasks), str(self.resident_tasks)) else: - self.tasks[self.current_task].run(self.taskCallback, self.task_progress_changed_CB) + self.tasks[self.current_task].run(self.taskCallback) self.state_changed() def taskCallback(self, task, res, stay_resident = False): @@ -151,7 +152,7 @@ class Task(object): not_met.append(precondition) return not_met - def run(self, callback, task_progress_changed): + def run(self, callback): failed_preconditions = self.checkPreconditions(True) + self.checkPreconditions(False) if len(failed_preconditions): callback(self, failed_preconditions) @@ -159,7 +160,6 @@ class Task(object): self.prepare() self.callback = callback - self.task_progress_changed = task_progress_changed from enigma import eConsoleAppContainer self.container = eConsoleAppContainer() self.container.appClosed.append(self.processFinished) @@ -235,7 +235,8 @@ class Task(object): if progress < 0: progress = 0 self.__progress = progress - self.task_progress_changed() + if self.task_progress_changed: + self.task_progress_changed() progress = property(getProgress, setProgress) @@ -372,7 +373,8 @@ class ToolExistsPrecondition(Condition): return _("A required tool (%s) was not found.") % (self.realpath) class AbortedPostcondition(Condition): - pass + def getErrorMessage(self, task): + return "Cancelled upon user request" class ReturncodePostcondition(Condition): def check(self, task): diff --git a/lib/python/Plugins/Extensions/DVDBurn/Process.py b/lib/python/Plugins/Extensions/DVDBurn/Process.py index 9cca8f70..49054596 100644 --- a/lib/python/Plugins/Extensions/DVDBurn/Process.py +++ b/lib/python/Plugins/Extensions/DVDBurn/Process.py @@ -10,8 +10,8 @@ class png2yuvTask(Task): self.dumpFile = outputfile self.weighting = 15 - def run(self, callback, task_progress_changed): - Task.run(self, callback, task_progress_changed) + def run(self, callback): + Task.run(self, callback) self.container.stdoutAvail.remove(self.processStdout) self.container.dumpToFile(self.dumpFile) @@ -26,8 +26,8 @@ class mpeg2encTask(Task): self.inputFile = inputfile self.weighting = 25 - def run(self, callback, task_progress_changed): - Task.run(self, callback, task_progress_changed) + def run(self, callback): + Task.run(self, callback) self.container.readFromFile(self.inputFile) def processOutputLine(self, line): @@ -42,8 +42,8 @@ class spumuxTask(Task): self.dumpFile = outputfile self.weighting = 15 - def run(self, callback, task_progress_changed): - Task.run(self, callback, task_progress_changed) + def run(self, callback): + Task.run(self, callback) self.container.stdoutAvail.remove(self.processStdout) self.container.dumpToFile(self.dumpFile) self.container.readFromFile(self.inputFile) @@ -212,7 +212,7 @@ class RemoveESFiles(Task): class DVDAuthorTask(Task): def __init__(self, job): Task.__init__(self, job, "Authoring DVD") - self.weighting = 300 + self.weighting = 20 self.setTool("/usr/bin/dvdauthor") self.CWD = self.job.workspace self.args += ["-x", self.job.workspace+"/dvdauthor.xml"] @@ -222,6 +222,14 @@ class DVDAuthorTask(Task): print "[DVDAuthorTask] ", line[:-1] if not self.menupreview and line.startswith("STAT: Processing"): self.callback(self, [], stay_resident=True) + elif line.startswith("STAT: VOBU"): + try: + progress = int(line.split("MB")[0].split(" ")[-1]) + if progress: + self.job.mplextask.progress = progress + print "[DVDAuthorTask] update mplextask progress:", self.job.mplextask.progress, "of", self.job.mplextask.end + except: + print "couldn't set mux progress" class DVDAuthorFinalTask(Task): def __init__(self, job): @@ -233,7 +241,7 @@ class WaitForResidentTasks(Task): def __init__(self, job): Task.__init__(self, job, "waiting for dvdauthor to finalize") - def run(self, callback, task_progress_changed): + def run(self, callback): print "waiting for %d resident task(s) %s to finish..." % (len(self.job.resident_tasks),str(self.job.resident_tasks)) if self.job.resident_tasks == 0: callback(self, []) @@ -334,23 +342,24 @@ class RemoveDVDFolder(Task): class CheckDiskspaceTask(Task): def __init__(self, job): Task.__init__(self, job, "Checking free space") - totalsize = 50*1024*1024 # require an extra safety 50 MB + totalsize = 0 # require an extra safety 50 MB maxsize = 0 for title in job.project.titles: titlesize = title.estimatedDiskspace if titlesize > maxsize: maxsize = titlesize totalsize += titlesize diskSpaceNeeded = totalsize + maxsize + job.estimateddvdsize = totalsize / 1024 / 1024 + totalsize += 50*1024*1024 # require an extra safety 50 MB self.global_preconditions.append(DiskspacePrecondition(diskSpaceNeeded)) self.weighting = 5 - def run(self, callback, task_progress_changed): + def run(self, callback): failed_preconditions = self.checkPreconditions(True) + self.checkPreconditions(False) if len(failed_preconditions): callback(self, failed_preconditions) return self.callback = callback - self.task_progress_changed = task_progress_changed Task.processFinished(self, 0) class PreviewTask(Task): @@ -361,9 +370,8 @@ class PreviewTask(Task): self.path = path self.weighting = 10 - def run(self, callback, task_progress_changed): + def run(self, callback): self.callback = callback - self.task_progress_changed = task_progress_changed if self.job.menupreview: self.previewProject() else: @@ -439,9 +447,8 @@ class ImagePrepareTask(Task): self.job = job self.Menus = job.Menus - def run(self, callback, task_progress_changed): + def run(self, callback): self.callback = callback - self.task_progress_changed = task_progress_changed # we are doing it this weird way so that the TaskView Screen actually pops up before the spinner comes from enigma import eTimer self.delayTimer = eTimer() @@ -451,7 +458,7 @@ class ImagePrepareTask(Task): def conduct(self): try: from ImageFont import truetype - from Image import open as Image_open + from Image import open as Image_open s = self.job.project.settings self.Menus.im_bg_orig = Image_open(s.menubg.getValue()) if self.Menus.im_bg_orig.size != (self.Menus.imgwidth, self.Menus.imgheight): @@ -475,9 +482,8 @@ class MenuImageTask(Task): self.menubgpngfilename = menubgpngfilename self.highlightpngfilename = highlightpngfilename - def run(self, callback, task_progress_changed): + def run(self, callback): self.callback = callback - self.task_progress_changed = task_progress_changed try: import ImageDraw, Image, os s = self.job.project.settings @@ -712,7 +718,8 @@ class DVDJob(Job): title_filename = self.workspace + "/dvd_title_%d.mpg" % (self.i+1) LinkTS(self, title.inputfile, link_name) demux = DemuxTask(self, link_name) - MplexTask(self, outputfile=title_filename, demux_task=demux) + self.mplextask = MplexTask(self, outputfile=title_filename, demux_task=demux) + self.mplextask.end = self.estimateddvdsize RemoveESFiles(self, demux) WaitForResidentTasks(self) PreviewTask(self, self.workspace + "/dvd/VIDEO_TS/") -- cgit v1.2.3 From 67a09e962e20c1a2becd8b8699b542779941b6e7 Mon Sep 17 00:00:00 2001 From: Felix Domke Date: Mon, 17 Nov 2008 17:19:39 +0100 Subject: performance fix: don't redraw if in/out list is the same --- lib/python/Components/Renderer/PositionGauge.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'lib/python/Components') diff --git a/lib/python/Components/Renderer/PositionGauge.py b/lib/python/Components/Renderer/PositionGauge.py index 5fa8c356..3f93d82e 100644 --- a/lib/python/Components/Renderer/PositionGauge.py +++ b/lib/python/Components/Renderer/PositionGauge.py @@ -50,9 +50,10 @@ class PositionGauge(Renderer): return self.__cutlist def setCutlist(self, cutlist): - self.__cutlist = cutlist - if self.instance is not None: - self.instance.setInOutList(cutlist) + if self.__cutlist != cutlist: + self.__cutlist = cutlist + if self.instance is not None: + self.instance.setInOutList(cutlist) cutlist = property(getCutlist, setCutlist) -- cgit v1.2.3 From 3aedbe22cf74b72ad0c3e2bc1869e914701e6574 Mon Sep 17 00:00:00 2001 From: Felix Domke Date: Tue, 18 Nov 2008 00:39:59 +0100 Subject: experimental dm8000 recording fix, doesn't belong here --- lib/python/Components/Renderer/FrontpanelLed.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'lib/python/Components') diff --git a/lib/python/Components/Renderer/FrontpanelLed.py b/lib/python/Components/Renderer/FrontpanelLed.py index 7bb584e5..cd329b56 100644 --- a/lib/python/Components/Renderer/FrontpanelLed.py +++ b/lib/python/Components/Renderer/FrontpanelLed.py @@ -6,15 +6,24 @@ class FrontpanelLed(Element): Element.__init__(self) def changed(self, *args, **kwargs): - if self.source.value: + if self.source.value or 1: pattern = 0x55555555 + pattern_4bit = 0x84fc8c04 speed = 20 else: pattern = 0 + pattern_4bit = 0xffffffff speed = 1 try: open("/proc/stb/fp/led0_pattern", "w").write("%08x" % pattern) + except IOError: + pass + try: + open("/proc/stb/fp/led_pattern", "w").write("%08x" % pattern_4bit) + except IOError: + pass + try: open("/proc/stb/fp/led_pattern_speed", "w").write("%d" % speed) except IOError: pass -- cgit v1.2.3 From dce87891f204f8e1f7151c4a3ba00b9dd048e795 Mon Sep 17 00:00:00 2001 From: Felix Domke Date: Fri, 13 Feb 2009 03:41:57 +0100 Subject: - While recording, collect startcodes and save them into ".sc"-files - this allows finding iframes for fast forward/reverse more easily - when in fast forward, strictly just output good (=complete iframes) data (this might break dm7025, we will fix this later) - draw smaller, fixed-size bar in position gauge --- lib/dvb/decoder.cpp | 4 +- lib/dvb/demux.cpp | 28 ++- lib/dvb/demux.h | 2 +- lib/dvb/dvb.cpp | 56 +++-- lib/dvb/idemux.h | 2 +- lib/dvb/pvrparse.cpp | 302 ++++++++++++++++++++------ lib/dvb/pvrparse.h | 26 ++- lib/dvb/tstools.cpp | 70 +++++- lib/dvb/tstools.h | 2 + lib/gui/epositiongauge.cpp | 2 +- lib/python/Components/Converter/StringList.py | 6 + lib/python/Components/Renderer/Listbox.py | 4 + lib/service/servicedvb.cpp | 18 +- lib/service/servicedvbrecord.cpp | 10 +- 14 files changed, 416 insertions(+), 116 deletions(-) (limited to 'lib/python/Components') diff --git a/lib/dvb/decoder.cpp b/lib/dvb/decoder.cpp index 6f0ead65..a4cffb77 100644 --- a/lib/dvb/decoder.cpp +++ b/lib/dvb/decoder.cpp @@ -1071,7 +1071,9 @@ RESULT eTSMPEGDecoder::setAC3Delay(int delay) } eTSMPEGDecoder::eTSMPEGDecoder(eDVBDemux *demux, int decoder) - :m_demux(demux), m_changed(0), m_decoder(decoder), m_video_clip_fd(-1), m_showSinglePicTimer(eTimer::create(eApp)) + : m_demux(demux), + m_vpid(-1), m_vtype(-1), m_apid(-1), m_atype(-1), m_pcrpid(-1), m_textpid(-1), + m_changed(0), m_decoder(decoder), m_video_clip_fd(-1), m_showSinglePicTimer(eTimer::create(eApp)) { demux->connectEvent(slot(*this, &eTSMPEGDecoder::demux_event), m_demux_event_conn); CONNECT(m_showSinglePicTimer->timeout, eTSMPEGDecoder::finishShowSinglePic); diff --git a/lib/dvb/demux.cpp b/lib/dvb/demux.cpp index 810b10a5..918ecec6 100644 --- a/lib/dvb/demux.cpp +++ b/lib/dvb/demux.cpp @@ -402,9 +402,10 @@ class eDVBRecordFileThread: public eFilePushThread { public: eDVBRecordFileThread(); - void setTimingPID(int pid); + void setTimingPID(int pid, int type); - void saveTimingInformation(const std::string &filename); + void startSaveMetaInformation(const std::string &filename); + void stopSaveMetaInformation(); int getLastPTS(pts_t &pts); protected: int filterRecordData(const unsigned char *data, int len, size_t ¤t_span_remaining); @@ -422,14 +423,19 @@ eDVBRecordFileThread::eDVBRecordFileThread() m_current_offset = 0; } -void eDVBRecordFileThread::setTimingPID(int pid) +void eDVBRecordFileThread::setTimingPID(int pid, int type) { - m_ts_parser.setPid(pid); + m_ts_parser.setPid(pid, type); } -void eDVBRecordFileThread::saveTimingInformation(const std::string &filename) +void eDVBRecordFileThread::startSaveMetaInformation(const std::string &filename) { - m_stream_info.save(filename.c_str()); + m_stream_info.startSave(filename.c_str()); +} + +void eDVBRecordFileThread::stopSaveMetaInformation() +{ + m_stream_info.stopSave(); } int eDVBRecordFileThread::getLastPTS(pts_t &pts) @@ -520,6 +526,9 @@ RESULT eDVBTSRecorder::start() ::ioctl(m_source_fd, DMX_START); #endif + + if (m_target_filename != "") + m_thread->startSaveMetaInformation(m_target_filename); m_thread->start(m_source_fd, m_target_fd); m_running = 1; @@ -553,11 +562,11 @@ RESULT eDVBTSRecorder::removePID(int pid) return 0; } -RESULT eDVBTSRecorder::setTimingPID(int pid) +RESULT eDVBTSRecorder::setTimingPID(int pid, int type) { if (m_running) return -1; - m_thread->setTimingPID(pid); + m_thread->setTimingPID(pid, type); return 0; } @@ -590,8 +599,7 @@ RESULT eDVBTSRecorder::stop() close(m_source_fd); m_source_fd = -1; - if (m_target_filename != "") - m_thread->saveTimingInformation(m_target_filename + ".ap"); + m_thread->stopSaveMetaInformation(); return 0; } diff --git a/lib/dvb/demux.h b/lib/dvb/demux.h index 14501b98..7a697d49 100644 --- a/lib/dvb/demux.h +++ b/lib/dvb/demux.h @@ -94,7 +94,7 @@ public: RESULT addPID(int pid); RESULT removePID(int pid); - RESULT setTimingPID(int pid); + RESULT setTimingPID(int pid, int type); RESULT setTargetFD(int fd); RESULT setTargetFilename(const char *filename); diff --git a/lib/dvb/dvb.cpp b/lib/dvb/dvb.cpp index c320fc78..4bbed519 100644 --- a/lib/dvb/dvb.cpp +++ b/lib/dvb/dvb.cpp @@ -974,7 +974,7 @@ int eDVBChannelFilePush::filterRecordData(const unsigned char *_data, int len, s } #endif -#if 1 /* This codepath is required on Broadcom-based Dreamboxes (DM800, DM8000) and strips away non-I-frames. */ +#if 0 if (!m_iframe_search) return len; @@ -1272,6 +1272,21 @@ void eDVBChannel::getNextSourceSpan(off_t current_offset, size_t bytes_read, off eDebug("getNextSourceSpan, current offset is %08llx, m_skipmode_m = %d!", current_offset, m_skipmode_m); current_offset += align(m_skipmode_m, blocksize); + + if (m_skipmode_m) + { + eDebug("we are at %llx, and we try to find the iframe here:", current_offset); + size_t iframe_len; + off_t iframe_start = current_offset; + + if (m_tstools.findIFrame(iframe_start, iframe_len, (m_skipmode_m < 0) ? -1 : +1)) + eDebug("failed"); + else + { + current_offset = align(iframe_start, blocksize); + max = align(iframe_len, blocksize); + } + } while (!m_cue->m_seek_requests.empty()) { @@ -1348,6 +1363,10 @@ void eDVBChannel::getNextSourceSpan(off_t current_offset, size_t bytes_read, off eDebug("get offset for pts=%lld failed!", pts); continue; } + + size_t iframe_len; + /* try to align to iframe */ + m_tstools.findIFrame(offset, iframe_len, pts < 0 ? -1 : 1); eDebug("ok, resolved skip (rel: %d, diff %lld), now at %08llx", relative, pts, offset); current_offset = align(offset, blocksize); /* in case tstools return non-aligned offset */ @@ -1417,30 +1436,23 @@ void eDVBChannel::getNextSourceSpan(off_t current_offset, size_t bytes_read, off } } - if (m_source_span.empty()) { - if ((current_offset < -m_skipmode_m) && (m_skipmode_m < 0)) - { - eDebug("reached SOF"); - m_skipmode_m = 0; - m_pvr_thread->sendEvent(eFilePushThread::evtUser); - } + if ((current_offset < -m_skipmode_m) && (m_skipmode_m < 0)) + { + eDebug("reached SOF"); + m_skipmode_m = 0; + m_pvr_thread->sendEvent(eFilePushThread::evtUser); + } + + if (m_source_span.empty()) + { start = current_offset; size = max; - } else { - off_t tmp2, tmp = align(m_source_span.rbegin()->second, blocksize); - pts_t len; - getLength(len); - m_tstools.getOffset(tmp2, len, 1); - if (current_offset == tmp || current_offset == tmp2) { - start = tmp2; - size = max; - } else { - start = tmp - align(512*1024, blocksize); - size = align(512*1024, blocksize); - } + eDebug("NO CUESHEET. (%08llx, %d)", start, size); + } else + { + start = current_offset; + size = 0; } - - eDebug("END OF CUESHEET. (%08llx, %d)", start, size); return; } diff --git a/lib/dvb/idemux.h b/lib/dvb/idemux.h index 9432afb6..e92b1e75 100644 --- a/lib/dvb/idemux.h +++ b/lib/dvb/idemux.h @@ -30,7 +30,7 @@ public: virtual RESULT addPID(int pid) = 0; virtual RESULT removePID(int pid) = 0; - virtual RESULT setTimingPID(int pid) = 0; + virtual RESULT setTimingPID(int pid, int type) = 0; virtual RESULT setTargetFD(int fd) = 0; /* for saving additional meta data. */ diff --git a/lib/dvb/pvrparse.cpp b/lib/dvb/pvrparse.cpp index 71cbd602..1393bf77 100644 --- a/lib/dvb/pvrparse.cpp +++ b/lib/dvb/pvrparse.cpp @@ -6,9 +6,36 @@ #error no byte order defined! #endif -int eMPEGStreamInformation::save(const char *filename) +eMPEGStreamInformation::eMPEGStreamInformation() + : m_structure_cache_valid(0), m_structure_read(0), m_structure_write(0) { - FILE *f = fopen(filename, "wb"); +} + +eMPEGStreamInformation::~eMPEGStreamInformation() +{ + if (m_structure_read) + fclose(m_structure_read); + if (m_structure_write) + fclose(m_structure_write); +} + +int eMPEGStreamInformation::startSave(const char *filename) +{ + m_filename = filename; + m_structure_write = fopen((m_filename + ".sc").c_str(), "wb"); + return 0; +} + +int eMPEGStreamInformation::stopSave(void) +{ + if (m_structure_write) + { + fclose(m_structure_write); + m_structure_write = 0; + } + if (m_filename == "") + return -1; + FILE *f = fopen((m_filename + ".ap").c_str(), "wb"); if (!f) return -1; @@ -31,7 +58,11 @@ int eMPEGStreamInformation::save(const char *filename) int eMPEGStreamInformation::load(const char *filename) { - FILE *f = fopen(filename, "rb"); + m_filename = filename; + if (m_structure_read) + fclose(m_structure_read); + m_structure_read = fopen((std::string(m_filename) + ".sc").c_str(), "rb"); + FILE *f = fopen((std::string(m_filename) + ".ap").c_str(), "rb"); if (!f) return -1; m_access_points.clear(); @@ -284,6 +315,117 @@ int eMPEGStreamInformation::getNextAccessPoint(pts_t &ts, const pts_t &start, in return 0; } +void eMPEGStreamInformation::writeStructureEntry(off_t offset, structure_data data) +{ + unsigned long long d[2]; +#if BYTE_ORDER == BIG_ENDIAN + d[0] = offset; + d[1] = data; +#else + d[0] = bswap_64(offset); + d[1] = bswap_64(data); +#endif + if (m_structure_write) + fwrite(d, sizeof(d), 1, m_structure_write); +} + +int eMPEGStreamInformation::getStructureEntry(off_t &offset, unsigned long long &data, int get_next) +{ + if (!m_structure_read) + { + eDebug("getStructureEntry failed because of no m_structure_read"); + return -1; + } + + const int struture_cache_entries = sizeof(m_structure_cache) / 16; + if ((!m_structure_cache_valid) || ((off_t)m_structure_cache[0] > offset) || ((off_t)m_structure_cache[(struture_cache_entries - (get_next ? 2 : 1)) * 2] <= offset)) + { + fseek(m_structure_read, 0, SEEK_END); + int l = ftell(m_structure_read); + unsigned long long d[2]; + const int entry_size = sizeof d; + + /* do a binary search */ + int count = l / entry_size; + int i = 0; + + while (count) + { + int step = count >> 1; + + fseek(m_structure_read, (i + step) * entry_size, SEEK_SET); + if (!fread(d, 1, entry_size, m_structure_read)) + { + eDebug("read error at entry %d", i); + return -1; + } + +#if BYTE_ORDER != BIG_ENDIAN + d[0] = bswap_64(d[0]); + d[1] = bswap_64(d[1]); +#endif +// eDebug("%d: %08llx > %llx", i, d[0], d[1]); + + if (d[0] < (unsigned long long)offset) + { + i += step + 1; + count -= step + 1; + } else + count = step; + } + + eDebug("found %d", i); + + /* put that in the middle */ + i -= struture_cache_entries / 2; + if (i < 0) + i = 0; + eDebug("cache starts at %d", i); + fseek(m_structure_read, i * entry_size, SEEK_SET); + int num = fread(m_structure_cache, entry_size, struture_cache_entries, m_structure_read); + eDebug("%d entries", num); + for (i = 0; i < struture_cache_entries; ++i) + { + if (i < num) + { +#if BYTE_ORDER != BIG_ENDIAN + m_structure_cache[i * 2] = bswap_64(m_structure_cache[i * 2]); + m_structure_cache[i * 2 + 1] = bswap_64(m_structure_cache[i * 2 + 1]); +#endif + } else + { + m_structure_cache[i * 2] = 0x7fffffffffffffffULL; /* fill with harmless content */ + m_structure_cache[i * 2 + 1] = 0; + } + } + m_structure_cache_valid = 1; + } + + int i = 0; + while ((off_t)m_structure_cache[i * 2] <= offset) + { + ++i; + if (i == struture_cache_entries) + { + eDebug("structure data consistency fail!, we are looking for %llx, but last entry is %llx", offset, m_structure_cache[i*2-2]); + return -1; + } + } + if (!i) + { + eDebug("structure data (first entry) consistency fail!"); + return -1; + } + + if (!get_next) + --i; + +// eDebug("[%d] looked for %llx, found %llx=%llx", sizeof offset, offset, m_structure_cache[i * 2], m_structure_cache[i * 2 + 1]); + offset = m_structure_cache[i * 2]; + data = m_structure_cache[i * 2 + 1]; + return 0; +} + eMPEGStreamParserTS::eMPEGStreamParserTS(eMPEGStreamInformation &streaminfo): m_streaminfo(streaminfo), m_pktptr(0), m_pid(-1), m_need_next_packet(0), m_skip(0), m_last_pts_valid(0) { } @@ -293,16 +435,15 @@ int eMPEGStreamParserTS::processPacket(const unsigned char *pkt, off_t offset) if (!wantPacket(pkt)) eWarning("something's wrong."); - const unsigned char *end = pkt + 188; + const unsigned char *end = pkt + 188, *begin = pkt; - if (!(pkt[3] & 0x10)) - { - eWarning("[TSPARSE] PUSI set but no payload."); - return 0; - } + int pusi = !!(pkt[1] & 0x40); - if (pkt[3] & 0x20) // adaption field present? - pkt += pkt[4] + 4 + 1; /* skip adaption field and header */ + if (!(pkt[3] & 0x10)) /* no payload? */ + return 0; + + if (pkt[3] & 0x20) // adaptation field present? + pkt += pkt[4] + 4 + 1; /* skip adaptation field and header */ else pkt += 4; /* skip header */ @@ -311,78 +452,96 @@ int eMPEGStreamParserTS::processPacket(const unsigned char *pkt, off_t offset) eWarning("[TSPARSE] dropping huge adaption field"); return 0; } - - // ok, we now have the start of the payload, aligned with the PES packet start. - if (pkt[0] || pkt[1] || (pkt[2] != 1)) - { - eWarning("broken startcode"); - return 0; - } - - + pts_t pts = 0; int ptsvalid = 0; - if (pkt[7] & 0x80) // PTS present? + if (pusi) { - pts = ((unsigned long long)(pkt[ 9]&0xE)) << 29; - pts |= ((unsigned long long)(pkt[10]&0xFF)) << 22; - pts |= ((unsigned long long)(pkt[11]&0xFE)) << 14; - pts |= ((unsigned long long)(pkt[12]&0xFF)) << 7; - pts |= ((unsigned long long)(pkt[13]&0xFE)) >> 1; - ptsvalid = 1; - - m_last_pts = pts; - m_last_pts_valid = 1; - -#if 0 - int sec = pts / 90000; - int frm = pts % 90000; - int min = sec / 60; - sec %= 60; - int hr = min / 60; - min %= 60; - int d = hr / 24; - hr %= 24; + // ok, we now have the start of the payload, aligned with the PES packet start. + if (pkt[0] || pkt[1] || (pkt[2] != 1)) + { + eWarning("broken startcode"); + return 0; + } + + if (pkt[7] & 0x80) // PTS present? + { + pts = ((unsigned long long)(pkt[ 9]&0xE)) << 29; + pts |= ((unsigned long long)(pkt[10]&0xFF)) << 22; + pts |= ((unsigned long long)(pkt[11]&0xFE)) << 14; + pts |= ((unsigned long long)(pkt[12]&0xFF)) << 7; + pts |= ((unsigned long long)(pkt[13]&0xFE)) >> 1; + ptsvalid = 1; + + m_last_pts = pts; + m_last_pts_valid = 1; + + #if 0 + int sec = pts / 90000; + int frm = pts % 90000; + int min = sec / 60; + sec %= 60; + int hr = min / 60; + min %= 60; + int d = hr / 24; + hr %= 24; + + eDebug("pts: %016llx %d:%02d:%02d:%02d:%05d", pts, d, hr, min, sec, frm); + #endif + } - eDebug("pts: %016llx %d:%02d:%02d:%02d:%05d", pts, d, hr, min, sec, frm); -#endif + /* advance to payload */ + pkt += pkt[8] + 9; } - - /* advance to payload */ - pkt += pkt[8] + 9; - /* sometimes, there are zeros before the startcode. */ while (pkt < (end-4)) - if (pkt[0] || pkt[1] || pkt[2]) - break; - else - pkt++; - - /* if startcode found */ -// eDebug("%02x %02x %02x %02x", pkt[0], pkt[1], pkt[2], pkt[3]); - if (!(pkt[0] || pkt[1] || (pkt[2] != 1))) { - if (pkt[3] == 0xb3) /* sequence header */ + int pkt_offset = pkt - begin; + if (!(pkt[0] || pkt[1] || (pkt[2] != 1))) { - if (ptsvalid) +// eDebug("SC %02x %02x %02x %02x, %02x", pkt[0], pkt[1], pkt[2], pkt[3], pkt[4]); + int sc = pkt[3]; + + if (m_streamtype == 0) /* mpeg2 */ { - m_streaminfo.m_access_points[offset] = pts; -// eDebug("Sequence header at %llx, pts %llx", offset, pts); - } else - /*eDebug("Sequence header but no valid PTS value.")*/; - } + if ((sc == 0x00) || (sc == 0xb3) || (sc == 0xb8)) /* picture, sequence, group start code */ + { + unsigned long long data = sc | (pkt[4] << 8) | (pkt[5] << 16) | (pkt[6] << 24); + m_streaminfo.writeStructureEntry(offset + pkt_offset, data & 0xFFFFFFFFULL); + } + if (pkt[3] == 0xb3) /* sequence header */ + { + if (ptsvalid) + { + m_streaminfo.m_access_points[offset] = pts; + // eDebug("Sequence header at %llx, pts %llx", offset, pts); + } else + /*eDebug("Sequence header but no valid PTS value.")*/; + } + } - if (pkt[3] == 0x09 && /* MPEG4 AVC unit access delimiter */ - (pkt[4] >> 5) == 0) /* and I-frame */ - { - if (ptsvalid) + if (m_streamtype == 1) /* H.264 */ { - m_streaminfo.m_access_points[offset] = pts; -// eDebug("MPEG4 AVC UAD at %llx, pts %llx", offset, pts); - } else - /*eDebug("MPEG4 AVC UAD but no valid PTS value.")*/; + if (sc == 0x09) + { + /* store image type */ + unsigned long long data = sc | (pkt[4] << 8); + m_streaminfo.writeStructureEntry(offset + pkt_offset, data); + } + if (pkt[3] == 0x09 && /* MPEG4 AVC NAL unit access delimiter */ + (pkt[4] >> 5) == 0) /* and I-frame */ + { + if (ptsvalid) + { + m_streaminfo.m_access_points[offset] = pts; + // eDebug("MPEG4 AVC UAD at %llx, pts %llx", offset, pts); + } else + /*eDebug("MPEG4 AVC UAD but no valid PTS value.")*/; + } + } } + ++pkt; } return 0; } @@ -405,7 +564,7 @@ inline int eMPEGStreamParserTS::wantPacket(const unsigned char *hdr) const if (hdr[1] & 0x40) /* pusi set: yes. */ return 1; - return 0; + return m_streamtype == 0; /* we need all packets for MPEG2, but only PUSI packets for H.264 */ } void eMPEGStreamParserTS::parseData(off_t offset, const void *data, unsigned int len) @@ -520,10 +679,11 @@ void eMPEGStreamParserTS::parseData(off_t offset, const void *data, unsigned int } } -void eMPEGStreamParserTS::setPid(int _pid) +void eMPEGStreamParserTS::setPid(int _pid, int type) { m_pktptr = 0; m_pid = _pid; + m_streamtype = type; } int eMPEGStreamParserTS::getLastPTS(pts_t &last_pts) diff --git a/lib/dvb/pvrparse.h b/lib/dvb/pvrparse.h index 20d33470..28c0314a 100644 --- a/lib/dvb/pvrparse.h +++ b/lib/dvb/pvrparse.h @@ -12,6 +12,8 @@ class eMPEGStreamInformation { public: + eMPEGStreamInformation(); + ~eMPEGStreamInformation(); /* we order by off_t here, since the timestamp may */ /* wrap around. */ /* we only record sequence start's pts values here. */ @@ -23,7 +25,8 @@ public: /* these are non-fixed up pts value (like m_access_points), just used to accelerate stuff. */ std::multimap m_pts_to_offset; - int save(const char *filename); + int startSave(const char *filename); + int stopSave(void); int load(const char *filename); /* recalculates timestampDeltas */ @@ -46,6 +49,23 @@ public: int getNextAccessPoint(pts_t &ts, const pts_t &start, int direction); bool empty(); + + typedef unsigned long long structure_data; + /* this is usually: + sc | (other_information << 8) + but is really specific to the used video encoder. + */ + void writeStructureEntry(off_t offset, structure_data data); + + /* get a structure entry at given offset (or previous one, if no exact match was found). + optionall, return next element. Offset will be returned. this allows you to easily + get previous and next structure elements. */ + int getStructureEntry(off_t &offset, unsigned long long &data, int get_next); + + std::string m_filename; + int m_structure_cache_valid; + unsigned long long m_structure_cache[1024]; + FILE *m_structure_read, *m_structure_write; }; /* Now we define the parser's state: */ @@ -54,7 +74,7 @@ class eMPEGStreamParserTS public: eMPEGStreamParserTS(eMPEGStreamInformation &streaminfo); void parseData(off_t offset, const void *data, unsigned int len); - void setPid(int pid); + void setPid(int pid, int streamtype); int getLastPTS(pts_t &last_pts); private: eMPEGStreamInformation &m_streaminfo; @@ -62,7 +82,7 @@ private: int m_pktptr; int processPacket(const unsigned char *pkt, off_t offset); inline int wantPacket(const unsigned char *hdr) const; - int m_pid; + int m_pid, m_streamtype; int m_need_next_packet; int m_skip; int m_last_pts_valid; diff --git a/lib/dvb/tstools.cpp b/lib/dvb/tstools.cpp index bd7ebce2..7ac86f08 100644 --- a/lib/dvb/tstools.cpp +++ b/lib/dvb/tstools.cpp @@ -32,7 +32,10 @@ int eDVBTSTools::openFile(const char *filename, int nostreaminfo) closeFile(); if (!nostreaminfo) - m_streaminfo.load((std::string(filename) + ".ap").c_str()); + { + eDebug("loading streaminfo for %s", filename); + m_streaminfo.load(filename); + } if (!m_streaminfo.empty()) m_use_streaminfo = 1; @@ -562,3 +565,68 @@ int eDVBTSTools::findPMT(int &pmt_pid, int &service_id) return -1; } + +int eDVBTSTools::findIFrame(off_t &_offset, size_t &len, int direction) +{ + off_t offset = _offset; +// eDebug("trying to find iFrame at %llx", offset); + + if (!m_use_streaminfo) + { + eDebug("can't get next iframe without streaminfo"); + return -1; + } + + /* let's find the iframe before the given offset */ + unsigned long long data; + while (1) + { + if (m_streaminfo.getStructureEntry(offset, data, (direction == 0) ? 1 : 0)) + { + eDebug("getting structure info for origin offset failed."); + return -1; + } + if (offset == 0x7fffffffffffffffLL) /* eof */ + { + eDebug("reached eof"); + return -1; + } + /* data is usually the start code in the lower 8 bit, and the next byte <<8. we extract the picture type from there */ + /* we know that we aren't recording startcode 0x09 for mpeg2, so this is safe */ + int is_start = (data & 0xE0FF) == 0x0009; /* H.264 NAL unit access delimiter with I-frame*/ + is_start |= (data & 0x3800FF) == 0x080000; /* MPEG2 picture start code with I-frame */ +// eDebug("%08llx@%llx -> %d", data, offset, is_start); + if (is_start) + break; + + if (direction == -1) + --offset; /* move to previous entry */ + else if (direction == +1) + direction = 0; + } + /* let's find the next frame after the given offset */ + off_t start = offset; + + do { + if (m_streaminfo.getStructureEntry(offset, data, 1)) + { + eDebug("get next failed"); + return -1; + } + if (offset == 0x7fffffffffffffffLL) /* eof */ + { + eDebug("reached eof (while looking for end of iframe)"); + return -1; + } +// eDebug("%08llx@%llx", data, offset); + } while (((data & 0xFF) != 9) && ((data & 0xFF) != 0x00)); /* next frame */ + + /* align to TS pkt start */ + start = start - (start % 188); + offset = offset - (offset % 188); + + len = offset - start; + _offset = start; +// eDebug("result: offset=%llx, len: %ld", offset, (int)len); + return 0; +} diff --git a/lib/dvb/tstools.h b/lib/dvb/tstools.h index 4bc04729..a8e0751e 100644 --- a/lib/dvb/tstools.h +++ b/lib/dvb/tstools.h @@ -55,6 +55,8 @@ public: int takeSample(off_t off, pts_t &p); int findPMT(int &pmt_pid, int &service_id); + + int findIFrame(off_t &offset, size_t &len, int direction); private: int m_pid; int m_maxrange; diff --git a/lib/gui/epositiongauge.cpp b/lib/gui/epositiongauge.cpp index b3ee5111..ff98c080 100644 --- a/lib/gui/epositiongauge.cpp +++ b/lib/gui/epositiongauge.cpp @@ -144,7 +144,7 @@ int ePositionGauge::event(int event, void *data, void *data2) { painter.setForegroundColor(gRGB(m_foreground_color)); int xi = scale(in), xo = scale(out); - painter.fill(eRect(xi, 10, xo-xi, s.height()-14)); + painter.fill(eRect(xi, (s.height()-4) / 2, xo-xi, 4)); } in = m_length; diff --git a/lib/python/Components/Converter/StringList.py b/lib/python/Components/Converter/StringList.py index c9488db0..08794b34 100644 --- a/lib/python/Components/Converter/StringList.py +++ b/lib/python/Components/Converter/StringList.py @@ -19,8 +19,11 @@ class StringList(Converter): def selectionChanged(self, index): self.source.selectionChanged(index) # update all non-master targets + print "changed selection in listbox!" for x in self.downstream_elements: + print "downstream element", x if x is not self.master: + print "is not master, so update to index", index x.index = index @cached @@ -43,3 +46,6 @@ class StringList(Converter): self.master.index = index index = property(getIndex, setIndex) + + def entry_changed(self, index): + self.downstream_elements.entry_changed(index) \ No newline at end of file diff --git a/lib/python/Components/Renderer/Listbox.py b/lib/python/Components/Renderer/Listbox.py index 8e510b4c..7a895330 100644 --- a/lib/python/Components/Renderer/Listbox.py +++ b/lib/python/Components/Renderer/Listbox.py @@ -78,3 +78,7 @@ class Listbox(Renderer, object): def changed(self, what): self.content = self.source.content + + def entry_changed(self, index): + if self.instance is not None: + self.instance.entryChanged(index) diff --git a/lib/service/servicedvb.cpp b/lib/service/servicedvb.cpp index 33cd865e..e3d960d4 100644 --- a/lib/service/servicedvb.cpp +++ b/lib/service/servicedvb.cpp @@ -370,13 +370,17 @@ int eStaticServiceDVBPVRInformation::getLength(const eServiceReference &ref) struct stat s; stat(ref.path.c_str(), &s); - if (tstools.openFile(ref.path.c_str())) + if (tstools.openFile(ref.path.c_str(), 1)) return 0; /* check if cached data is still valid */ if (m_parser.m_data_ok && (s.st_size == m_parser.m_filesize) && (m_parser.m_length)) return m_parser.m_length / 90000; + /* open again, this time with stream info */ + if (tstools.openFile(ref.path.c_str())) + return 0; + /* otherwise, re-calc length and update meta file */ pts_t len; if (tstools.calcLen(len)) @@ -502,6 +506,7 @@ RESULT eDVBPVRServiceOfflineOperations::getListOfFilenames(std::list= 0)) + { + eDebug("timeshift EOF, so let's go live"); switchToLive(); + } break; } } @@ -1173,9 +1181,9 @@ RESULT eDVBServicePlay::setFastForward_internal(int ratio) if (!m_decoder) return -1; - + if (ffratio == 0) - return 0; + return m_decoder->play(); else if (ffratio != 1) return m_decoder->setFastForward(ffratio); else @@ -1211,6 +1219,7 @@ RESULT eDVBServicePlay::pause() setFastForward_internal(0); if (m_decoder) { + m_is_paused = 1; return m_decoder->pause(); } else return -1; @@ -1222,6 +1231,7 @@ RESULT eDVBServicePlay::unpause() setFastForward_internal(0); if (m_decoder) { + m_is_paused = 0; return m_decoder->play(); } else return -1; @@ -2136,6 +2146,8 @@ void eDVBServicePlay::switchToLive() if (!m_timeshift_active) return; + eDebug("SwitchToLive"); + m_cue = 0; m_decoder = 0; m_decode_demux = 0; diff --git a/lib/service/servicedvbrecord.cpp b/lib/service/servicedvbrecord.cpp index c2767e8d..5b7b5d8c 100644 --- a/lib/service/servicedvbrecord.cpp +++ b/lib/service/servicedvbrecord.cpp @@ -270,7 +270,7 @@ int eDVBServiceRecord::doRecord() if (program.pmtPid != -1) pids_to_record.insert(program.pmtPid); // PMT - int timing_pid = -1; + int timing_pid = -1, timing_pid_type = -1; eDebugNoNewLine("RECORD: have %d video stream(s)", program.videoStreams.size()); if (!program.videoStreams.empty()) @@ -283,7 +283,10 @@ int eDVBServiceRecord::doRecord() pids_to_record.insert(i->pid); if (timing_pid == -1) + { timing_pid = i->pid; + timing_pid_type = i->type; + } if (i != program.videoStreams.begin()) eDebugNoNewLine(", "); @@ -302,7 +305,10 @@ int eDVBServiceRecord::doRecord() pids_to_record.insert(i->pid); if (timing_pid == -1) + { timing_pid = i->pid; + timing_pid_type = -1; + } if (i != program.audioStreams.begin()) eDebugNoNewLine(", "); @@ -358,7 +364,7 @@ int eDVBServiceRecord::doRecord() } if (timing_pid != -1) - m_record->setTimingPID(timing_pid); + m_record->setTimingPID(timing_pid, timing_pid_type); m_pids_active = pids_to_record; -- cgit v1.2.3