From 70c7e21335c4a9f5aeea8b6078a5c42a1bc2925c Mon Sep 17 00:00:00 2001 From: deathbybandaid Date: Thu, 21 Jan 2021 09:35:13 -0500 Subject: [PATCH] test --- fHDHR/device/tuners/__init__.py | 84 ++++++++++++++++++- .../tuners/stream/direct_m3u8_stream.py | 29 ++++--- fHDHR/device/tuners/stream/direct_stream.py | 5 +- fHDHR/device/tuners/stream/ffmpeg_stream.py | 34 +++++--- fHDHR/device/tuners/stream/vlc_stream.py | 25 +++--- 5 files changed, 140 insertions(+), 37 deletions(-) diff --git a/fHDHR/device/tuners/__init__.py b/fHDHR/device/tuners/__init__.py index 6dafb2f..7d47015 100644 --- a/fHDHR/device/tuners/__init__.py +++ b/fHDHR/device/tuners/__init__.py @@ -1,3 +1,4 @@ +import m3u8 from fHDHR.exceptions import TunerError @@ -96,12 +97,15 @@ class Tuners(): raise TunerError("806 - Tune Failed") if isinstance(stream_info, str): - stream_info = {"url": stream_info} + stream_info = {"url": stream_info, "headers": None} stream_args["stream_info"] = stream_info if not stream_args["stream_info"]["url"]: raise TunerError("806 - Tune Failed") + if "headers" not in list(stream_args["stream_info"].keys()): + stream_args["stream_info"]["headers"] = None + if stream_args["stream_info"]["url"].startswith("udp://"): stream_args["true_content_type"] = "video/mpeg" stream_args["content_type"] = "video/mpeg" @@ -112,7 +116,85 @@ class Tuners(): if stream_args["true_content_type"].startswith(tuple(["application/", "text/"])): stream_args["content_type"] = "video/mpeg" + if stream_args["origin_quality"] != -1: + stream_args["stream_info"]["url"] = self.m3u8_quality(stream_args) else: stream_args["content_type"] = stream_args["true_content_type"] return stream_args + + def m3u8_quality(self, stream_args): + + m3u8_url = stream_args["stream_info"]["url"] + quality_profile = stream_args["origin_quality"] + + if not quality_profile: + if stream_args["method"] == "direct": + quality_profile = "high" + self.fhdhr.logger.info("Origin Quality not set in config. Direct Method set and will default to Highest Quality") + else: + self.fhdhr.logger.info("Origin Quality not set in config. %s Method will select the Quality Automatically" % stream_args["method"]) + return m3u8_url + else: + quality_profile = quality_profile.lower() + self.fhdhr.logger.info("Origin Quality set in config to %s" % (quality_profile)) + + while True: + self.fhdhr.logger.info("Opening m3u8 for reading %s" % m3u8_url) + + if stream_args["stream_info"]["headers"]: + videoUrlM3u = m3u8.load(m3u8_url, headers=stream_args["stream_info"]["headers"]) + else: + videoUrlM3u = m3u8.load(m3u8_url) + + if len(videoUrlM3u.playlists): + self.fhdhr.logger.info("%s m3u8 varients found" % len(videoUrlM3u.playlists)) + + # Create list of dicts + playlists, playlist_index = {}, 0 + for playlist_item in videoUrlM3u.playlists: + playlist_index += 1 + playlist_dict = { + "url": playlist_item.absolute_uri, + "bandwidth": playlist_item.stream_info.bandwidth, + } + + if not playlist_item.stream_info.resolution: + playlist_dict["width"] = None + playlist_dict["height"] = None + else: + try: + playlist_dict["width"] = playlist_item.stream_info.resolution[0] + playlist_dict["height"] = playlist_item.stream_info.resolution[1] + except TypeError: + playlist_dict["width"] = None + playlist_dict["height"] = None + + playlists[playlist_index] = playlist_dict + + sorted_playlists = sorted(playlists, key=lambda i: ( + int(playlists[i]['bandwidth']), + int(playlists[i]['width'] or 0), + int(playlists[i]['height'] or 0) + )) + sorted_playlists = [playlists[x] for x in sorted_playlists] + + if not quality_profile or quality_profile == "high": + selected_index = -1 + elif quality_profile == "medium": + selected_index = int((len(sorted_playlists) - 1)/2) + elif quality_profile == "low": + selected_index = 0 + + m3u8_stats = ",".join( + ["%s %s" % (x, sorted_playlists[selected_index][x]) + for x in list(sorted_playlists[selected_index].keys()) + if x != "url" and sorted_playlists[selected_index][x]]) + self.fhdhr.logger.info("Selected m3u8 details: %s" % m3u8_stats) + m3u8_url = sorted_playlists[selected_index]["url"] + + else: + self.fhdhr.logger.info("No m3u8 varients found") + break + + return m3u8_url diff --git a/fHDHR/device/tuners/stream/direct_m3u8_stream.py b/fHDHR/device/tuners/stream/direct_m3u8_stream.py index 7a3d8ac..4e6bd32 100644 --- a/fHDHR/device/tuners/stream/direct_m3u8_stream.py +++ b/fHDHR/device/tuners/stream/direct_m3u8_stream.py @@ -21,18 +21,7 @@ class Direct_M3U8_Stream(): if not self.stream_args["duration"] == 0: self.stream_args["time_end"] = self.stream_args["duration"] + time.time() - self.fhdhr.logger.info("Detected stream URL is m3u8: %s" % self.stream_args["true_content_type"]) - - channel_stream_url = self.stream_args["stream_info"]["url"] - while True: - - self.fhdhr.logger.info("Opening m3u8 for reading %s" % channel_stream_url) - videoUrlM3u = m3u8.load(channel_stream_url) - if len(videoUrlM3u.playlists): - self.fhdhr.logger.info("%s m3u8 varients found" % len(videoUrlM3u.playlists)) - channel_stream_url = videoUrlM3u.playlists[0].absolute_uri - else: - break + self.fhdhr.logger.info("Detected stream of m3u8 URL: %s" % self.stream_args["stream_info"]["url"]) def generate(): @@ -42,7 +31,11 @@ class Direct_M3U8_Stream(): while self.tuner.tuner_lock.locked(): - playlist = m3u8.load(channel_stream_url) + if self.stream_args["stream_info"]["headers"]: + playlist = m3u8.load(self.stream_args["stream_info"]["url"], headers=self.stream_args["stream_info"]["headers"]) + else: + playlist = m3u8.load(self.stream_args["stream_info"]["url"]) + segments = playlist.segments if len(played_chunk_urls): @@ -70,13 +63,19 @@ class Direct_M3U8_Stream(): self.fhdhr.logger.info("Requested Duration Expired.") self.tuner.close() - chunk = self.fhdhr.web.session.get(chunkurl).content + if self.stream_args["stream_info"]["headers"]: + chunk = self.fhdhr.web.session.get(chunkurl, headers=self.stream_args["stream_info"]["headers"]).content + else: + chunk = self.fhdhr.web.session.get(chunkurl).content if not chunk: break # raise TunerError("807 - No Video Data") if key: if key["url"]: - keyfile = self.fhdhr.web.session.get(key["url"]).content + if self.stream_args["stream_info"]["headers"]: + keyfile = self.fhdhr.web.session.get(key["url"], headers=self.stream_args["stream_info"]["headers"]).content + else: + keyfile = self.fhdhr.web.session.get(key["url"]).content cryptor = AES.new(keyfile, AES.MODE_CBC, keyfile) self.fhdhr.logger.info("Decrypting Chunk #%s with key: %s" % (len(played_chunk_urls), key["url"])) chunk = cryptor.decrypt(chunk) diff --git a/fHDHR/device/tuners/stream/direct_stream.py b/fHDHR/device/tuners/stream/direct_stream.py index 23dfd9a..fdc78e9 100644 --- a/fHDHR/device/tuners/stream/direct_stream.py +++ b/fHDHR/device/tuners/stream/direct_stream.py @@ -20,7 +20,10 @@ class Direct_Stream(): self.fhdhr.logger.info("Direct Stream of %s URL: %s" % (self.stream_args["true_content_type"], self.stream_args["stream_info"]["url"])) - req = self.fhdhr.web.session.get(self.stream_args["stream_info"]["url"], stream=True) + if self.stream_args["stream_info"]["headers"]: + req = self.fhdhr.web.session.get(self.stream_args["stream_info"]["url"], stream=True, headers=self.stream_args["stream_info"]["headers"]) + else: + req = self.fhdhr.web.session.get(self.stream_args["stream_info"]["url"], stream=True) def generate(): diff --git a/fHDHR/device/tuners/stream/ffmpeg_stream.py b/fHDHR/device/tuners/stream/ffmpeg_stream.py index 4daf52c..834031a 100644 --- a/fHDHR/device/tuners/stream/ffmpeg_stream.py +++ b/fHDHR/device/tuners/stream/ffmpeg_stream.py @@ -50,12 +50,26 @@ class FFMPEG_Stream(): self.fhdhr.config.dict["ffmpeg"]["path"], "-i", stream_args["stream_info"]["url"], ] + ffmpeg_command.extend(self.ffmpeg_headers(stream_args)) ffmpeg_command.extend(self.ffmpeg_duration(stream_args)) ffmpeg_command.extend(self.transcode_profiles(stream_args)) ffmpeg_command.extend(self.ffmpeg_loglevel()) ffmpeg_command.extend(["pipe:stdout"]) return ffmpeg_command + def ffmpeg_headers(self, stream_args): + ffmpeg_command = [] + if stream_args["stream_info"]["headers"]: + headers_string = "" + if len(list(stream_args["stream_info"]["headers"].keys())) > 1: + for x in list(stream_args["stream_info"]["headers"].keys()): + headers_string += "%s: %s\r\n" % (x, stream_args["stream_info"]["headers"][x]) + else: + for x in list(stream_args["stream_info"]["headers"].keys()): + headers_string += "%s: %s" % (x, stream_args["stream_info"]["headers"][x]) + ffmpeg_command.extend(["-headers", '\"%s\"' % headers_string]) + return ffmpeg_command + def ffmpeg_duration(self, stream_args): ffmpeg_command = [] if stream_args["duration"]: @@ -103,30 +117,30 @@ class FFMPEG_Stream(): 16:9 content, not exceeding 320x240 30fps for 4:3 content """ - if stream_args["transcode"]: - self.fhdhr.logger.info("Client requested a %s transcode for stream." % stream_args["transcode"]) - stream_args["transcode"] = None + if stream_args["transcode_quality"]: + self.fhdhr.logger.info("Client requested a %s transcode for stream." % stream_args["transcode_quality"]) + stream_args["transcode_quality"] = None ffmpeg_command = [] - if not stream_args["transcode"]: + if not stream_args["transcode_quality"]: ffmpeg_command.extend( [ "-c", "copy", "-f", "mpegts", ] ) - elif stream_args["transcode"] == "heavy": + elif stream_args["transcode_quality"] == "heavy": ffmpeg_command.extend([]) - elif stream_args["transcode"] == "mobile": + elif stream_args["transcode_quality"] == "mobile": ffmpeg_command.extend([]) - elif stream_args["transcode"] == "internet720": + elif stream_args["transcode_quality"] == "internet720": ffmpeg_command.extend([]) - elif stream_args["transcode"] == "internet480": + elif stream_args["transcode_quality"] == "internet480": ffmpeg_command.extend([]) - elif stream_args["transcode"] == "internet360": + elif stream_args["transcode_quality"] == "internet360": ffmpeg_command.extend([]) - elif stream_args["transcode"] == "internet240": + elif stream_args["transcode_quality"] == "internet240": ffmpeg_command.extend([]) return ffmpeg_command diff --git a/fHDHR/device/tuners/stream/vlc_stream.py b/fHDHR/device/tuners/stream/vlc_stream.py index 0c586e9..702ba08 100644 --- a/fHDHR/device/tuners/stream/vlc_stream.py +++ b/fHDHR/device/tuners/stream/vlc_stream.py @@ -51,12 +51,17 @@ class VLC_Stream(): self.fhdhr.config.dict["vlc"]["path"], "-I", "dummy", stream_args["stream_info"]["url"], ] + # vlc_command.extend(self.vlc_headers(stream_args)) vlc_command.extend(self.vlc_duration(stream_args)) vlc_command.extend(self.vlc_loglevel()) vlc_command.extend(["--sout"]) vlc_command.extend(self.transcode_profiles(stream_args)) return vlc_command + def vlc_headers(self, stream_args): + vlc_command = [] + return vlc_command + def vlc_duration(self, stream_args): vlc_command = [] if stream_args["duration"]: @@ -95,28 +100,28 @@ class VLC_Stream(): """ vlc_command = [] - if stream_args["transcode"]: - self.fhdhr.logger.info("Client requested a %s transcode for stream." % stream_args["transcode"]) - stream_args["transcode"] = None + if stream_args["transcode_quality"]: + self.fhdhr.logger.info("Client requested a %s transcode for stream." % stream_args["transcode_quality"]) + stream_args["transcode_quality"] = None vlc_transcode_string = "#std{mux=ts,access=file,dst=-}" return [vlc_transcode_string] '#transcode{vcodec=mp2v,vb=4096,acodec=mp2a,ab=192,scale=1,channels=2,deinterlace}:std{access=file,mux=ts,dst=-"}' - if not stream_args["transcode"]: + if not stream_args["transcode_quality"]: vlc_command.extend([]) - elif stream_args["transcode"] == "heavy": + elif stream_args["transcode_quality"] == "heavy": vlc_command.extend([]) - elif stream_args["transcode"] == "mobile": + elif stream_args["transcode_quality"] == "mobile": vlc_command.extend([]) - elif stream_args["transcode"] == "internet720": + elif stream_args["transcode_quality"] == "internet720": vlc_command.extend([]) - elif stream_args["transcode"] == "internet480": + elif stream_args["transcode_quality"] == "internet480": vlc_command.extend([]) - elif stream_args["transcode"] == "internet360": + elif stream_args["transcode_quality"] == "internet360": vlc_command.extend([]) - elif stream_args["transcode"] == "internet240": + elif stream_args["transcode_quality"] == "internet240": vlc_command.extend([]) return vlc_command