Open MSzturc opened 4 years ago
Do you mean if you disable timeshift you are not able to seek?
No i try to describe my problem a bit better.
When i use the following configuration:
#KODIPROP:inputstream=inputstream.ffmpegdirect
#KODIPROP:inputstream.ffmpegdirect.manifest_type=hls
#EXTINF:-1,MyChannel
http://127.0.0.1:3002/mystream.m3u8
The stream starts and im able to seek inside the stream. The problem i get there is that about every 2-3 minutes, i get shutters. It looks like a package segment got dropped and the player jumps to the next segment. To fix this problem i have to enable timeshift. With timeshift enabled i can watch my m3u8 perfectly without any drops, but i lost the ability to seek since ffmpegdirect than handles the m3u8 as livestream and doesnt allow me to seek into the future.
So what i want is an mode where i get the buffering from timeshift for streams that a not livestreams
I understand.
For those streams it might be better to let kodi handle it instead of the addon.
What happens if you replace the prop you have with this one property?
#KODIPROP:inputstream=inputstream.ffmpeg
Did you mean inputstream.adaptive? Never heared of inputstream.ffmpeg. With inputstream adaptive I face the same problems as with your inputstream addon. I think because both dont cache hls streams. I've done a bit of research to get a better understanding of the szenario. The hls stream is a 1080p stream, has a bitrate of 8-12mbit and is splitted into 1mb segments. In my opinion the problem occurs when the new segment is provided too late ( by to slow dns lookup or other isp related problems )
inputstream.ffmpeg is kodi’s internal inputstream based on ffmpeg. Please try it.
Tried it and got the same error as with the other inputstream plugins
2020-07-08 23:26:25.737 T:327514 INFO <general>: Creating InputStream
2020-07-08 23:26:25.900 T:327514 INFO <general>: Creating Demuxer
2020-07-08 23:26:29.830 T:327514 INFO <general>: Opening stream: 4 source: 256
2020-07-08 23:26:29.831 T:327514 INFO <general>: Creating video codec with codec id: 27
2020-07-08 23:26:29.831 T:327514 INFO <general>: CDVDVideoCodecFFmpeg::Open() Using codec: H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10
2020-07-08 23:26:29.831 T:327514 INFO <general>: Creating video thread
2020-07-08 23:26:29.831 T:327594 INFO <general>: running thread: video_thread
2020-07-08 23:26:29.933 T:327514 INFO <general>: Opening stream: 5 source: 256
2020-07-08 23:26:29.933 T:327514 INFO <general>: Finding audio codec for: 86018
2020-07-08 23:26:29.933 T:327514 INFO <general>: CDVDAudioCodecFFmpeg::Open() Successful opened audio decoder aac
2020-07-08 23:26:29.934 T:327514 INFO <general>: Creating audio thread
2020-07-08 23:26:29.934 T:327602 INFO <general>: running thread: CVideoPlayerAudio::Process()
2020-07-08 23:26:29.935 T:327594 INFO <general>: CVideoPlayerVideo - Stillframe left, switching to normal playback
2020-07-08 23:26:29.945 T:327602 INFO <general>: CDVDAudioCodecFFmpeg::Open() Successful opened audio decoder aac
2020-07-08 23:26:29.945 T:327602 INFO <general>: Creating audio stream (codec id: 86018, channels: 2, sample rate: 44100, no pass-through)
2020-07-08 23:26:29.957 T:327287 INFO <general>: CActiveAESink::OpenSink - initialize sink
2020-07-08 23:26:30.141 T:327287 INFO <general>: virtual bool CAESinkDARWINOSX::Initialize(AEAudioFormat &, std::string &): Opening default device Built-in Output
2020-07-08 23:26:30.207 T:327237 INFO <general>: GL: Using CVBREF render method
2020-07-08 23:26:30.212 T:327237 INFO <general>: GL: Selecting YUV 2 RGB shader
2020-07-08 23:26:30.216 T:327237 INFO <general>: Using GL_TEXTURE_RECTANGLE
2020-07-08 23:26:30.219 T:327237 INFO <general>: GL: Using CVBREF render method
2020-07-08 23:26:30.221 T:327237 INFO <general>: GL: Selecting YUV 2 RGB shader
2020-07-08 23:26:30.247 T:327237 INFO <general>: Loading skin file: VideoFullScreen.xml, load type: KEEP_IN_MEMORY
2020-07-08 23:26:30.771 T:327594 WARNING <general>: CRenderManager::WaitForBuffer - timeout waiting for buffer
2020-07-08 23:26:31.195 T:327594 INFO <general>: CDVDVideoCodecFFmpeg::CDropControl: calculated diff time: 41708
2020-07-08 23:26:32.785 T:327237 INFO <general>: Loading skin file: DialogPlayerProcessInfo.xml, load type: KEEP_IN_MEMORY
2020-07-08 23:26:45.606 T:327594 INFO <general>: CVideoPlayerVideo - Stillframe left, switching to normal playback
2020-07-08 23:26:46.223 T:327594 WARNING <general>: CRenderManager::WaitForBuffer - timeout waiting for buffer
2020-07-08 23:26:47.913 T:327594 INFO <general>: CVideoPlayerVideo - Stillframe left, switching to normal playback
2020-07-08 23:26:48.538 T:327594 WARNING <general>: CRenderManager::WaitForBuffer - timeout waiting for buffer
2020-07-08 23:27:11.731 T:327237 INFO <general>: CVideoPlayer::CloseFile()
2020-07-08 23:27:11.733 T:327514 INFO <general>: CVideoPlayer::OnExit()
What quality is the stream? Is it a very high quality stream?
1080p with 8-12mbit
That seems a reasonable quality. Any way I can get access to a test stream? I can try a few things but need something to work on.
I have two sources where this problem occurs:
In Kodi v18 i use script.module.livestreamer (https://kodi.wiki/view/Add-on:Livestreamer) as hls cache
with the following code:
serverPath = os.path.join(xbmc.translatePath(addon.getAddonInfo("path")), "livestreamerXBMCLocalProxy.py")
runs = 0
while not runs > 10:
try:
requests.get("http://127.0.0.1:19001/version")
break
except Exception:
logger.info(str(Exception))
xbmc.executebuiltin("RunScript(" + serverPath + ")")
runs += 1
xbmc.sleep(600)
livestreamer_url = "http://127.0.0.1:19001/livestreamer/" + urlsafe_b64encode("hlsvariant://" + data['link'])
import xbmc
import base64
import urlparse
import sys
import socket
from SocketServer import ThreadingMixIn
from BaseHTTPServer import HTTPServer, BaseHTTPRequestHandler
from livestreamer import Livestreamer
class MyHandler(BaseHTTPRequestHandler):
def log_message(self, format, *args):
pass
"""
Serves a HEAD request
"""
def do_HEAD(self):
self.answer_request(0)
"""
Serves a GET request.
"""
def do_GET(self):
self.answer_request(1)
def answer_request(self, sendData):
try:
request_path = self.path[1:]
if request_path == "stop":
sys.exit()
elif request_path == "version":
self.send_response(200)
self.end_headers()
self.wfile.write("Proxy: Running\r\n")
self.wfile.write("Version: 0.1\r\n")
elif request_path[0:13] == "livestreamer/":
realpath = request_path[13:]
fURL = base64.urlsafe_b64decode(realpath)
self.serveFile(fURL, sendData)
else:
self.send_response(403)
self.end_headers()
finally:
return
"""
Sends the requested file and add additional headers.
"""
def serveFile(self, fURL, sendData):
session = Livestreamer()
if '|' in fURL:
sp = fURL.split('|')
fURL = sp[0]
headers = dict(urlparse.parse_qsl(sp[1]))
session.set_option("http-headers", headers)
session.set_option("http-ssl-verify", False)
session.set_option("hls-segment-threads", 2)
try:
streams = session.streams(fURL)
self.send_response(200)
except:
self.send_response(403)
finally:
self.end_headers()
if (sendData):
with streams["best"].open() as stream:
buf = 'INIT'
while (len(buf) > 0):
buf = stream.read(500 * 1024)
self.wfile.write(buf)
class Server(HTTPServer):
"""HTTPServer class with timeout."""
def get_request(self):
"""Get the request and client address from the socket."""
self.socket.settimeout(5.0)
result = None
while result is None:
try:
result = self.socket.accept()
except socket.timeout:
pass
result[0].settimeout(1000)
return result
class ThreadedHTTPServer(ThreadingMixIn, Server):
"""Handle requests in a separate thread."""
HOST_NAME = '127.0.0.1'
PORT_NUMBER = 19001
if __name__ == '__main__':
sys.stderr = sys.stdout
server_class = ThreadedHTTPServer
httpd = server_class((HOST_NAME, PORT_NUMBER), MyHandler)
while not xbmc.abortRequested:
httpd.handle_request()
httpd.server_close()
My plan was to migrate this to ffmpegdirect since it's a more cleaner solution to have this code inside inputstream addon and outside of video addon
Ok, but then this should be in a new addon called inputstream.livestreamer as the stream is no longer being read by ffmpeg. It could be quite a simple addon that doesn’t need a demuxer. So more like inputstream.rtmp.
Before developing a new inputstream plugin, i thought that it might be smarter to ask if you enhance your plugin since almost everything you need for this is already developed in your inputstream, the hls player, the cache for timeshift, the http server, the only think that is missing is seeking support inside timeshift mode
Timeshift supports seeking but only backwards. This is accomplished by buffering the stream and then handling all seek requests via the addons own data structure.
When you play a VOD HLS stream all seeking is handled by ffmpeg, I.e. the video stream is not handled or stored in any way in the addon. It’s not possible to mix the two, I.e. use the data structure for backwards and leave ffmpeg handle forwards.
I’m trying to think of a simple way there could be small delay buffer but I don’t see how that is possible without a delay of X seconds on any seek (where X is the buffer size). And even then I’m not sure how to make that work with a VOD stream.
When i play non livestream m3u8 streams every 2-3 minutes i notice a shutter in playback. It seams that the hls segment that should be play is still downloading. If I enable timeshift the problem is gone but im not able to seek. I would like to have a buffer for non timeshift based hls streams.