Skip to content
Browse files

Add HTTP Live Streaming playback

This add full support for HTTP Live Streaming playback as per http://tools.ietf.org/html/draft-pantos-http-live-streaming-04.
This includes:
- Automatic fallback to lower bandwidth streams if available, the changeover will be detected according to the network bandwidth
- Full support for live streaming
- Seek support for video on demand stream

There are few problems remaining however:
-When switching to a different stream that is of a different resolution, playback will usually fail. Detection for format change should be added to myth player
-When seeking with values over 2 minutes, sometimes the player will fail, detecting an EOF. No idea why.
-For VOD streams, the whole downloaded content is buffered in RAM, this could get huge (as big as the file being streamed). Caching to disk should be implemented

Playback of AES-128 encrypted content hasn't been tested; retrieval of the key will only work from publicly accessible web site defeating the whole purpose of encryption
  • Loading branch information...
1 parent 0a4eb5f commit 099b6cce03f0ba3709b20070bec520d80bf44c6f @jyavenard jyavenard committed
View
2,566 mythtv/libs/libmythtv/httplivestreambuffer.cpp
2,566 additions, 0 deletions not shown because the diff is too large. Please use a local Git client to view these changes.
View
116 mythtv/libs/libmythtv/httplivestreambuffer.h
@@ -0,0 +1,116 @@
+/*****************************************************************************
+ * httplivestreambuffer.cpp
+ * MythTV
+ *
+ * Created by Jean-Yves Avenard on 6/05/12.
+ * Copyright (c) 2012 Bubblestuff Pty Ltd. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+#ifndef MythXCode_hlsbuffer_h
+#define MythXCode_hlsbuffer_h
+
+#include "mythcorecontext.h"
+#include "ringbuffer.h"
+
+extern "C" {
+#include "libavformat/avformat.h"
+#include "libavformat/url.h"
+}
+
+class MythDownloadManager;
+class HLSStream;
+class HLSSegment;
+class StreamWorker;
+class PlaylistWorker;
+class HLSPlayback;
+
+typedef QList<HLSStream*> StreamsList;
+
+class HLSRingBuffer : public RingBuffer
+{
+public:
+ HLSRingBuffer(const QString &lfilename);
+ virtual ~HLSRingBuffer();
+
+ virtual bool IsOpen(void) const;
+ virtual long long GetReadPosition(void) const;
+ virtual bool OpenFile(const QString &lfilename,
+ uint retry_ms = kDefaultOpenTimeout);
+ virtual long long Seek(long long pos, int whence, bool has_lock);
+ virtual long long GetRealFileSize(void) const;
+ virtual bool IsStreamed(void) { return true; }
+ virtual bool IsSeekingAllowed(void);
+ virtual bool IsBookmarkAllowed(void) { return true; }
+ static bool IsHTTPLiveStreaming(QByteArray *s);
+ static bool TestForHTTPLiveStreaming(QString &filename);
+ bool SaveToDisk(QString filename);
+
+protected:
+ virtual int safe_read(void *data, uint i_read);
+
+private:
+ void FreeStreamsList(QList<HLSStream*> *streams);
+ HLSStream *GetStreamForSegment(int segid);
+ HLSStream *GetStream(const int wanted, const StreamsList *streams = NULL) const;
+ HLSStream *GetFirstStream(const StreamsList *streams = NULL);
+ HLSStream *GetLastStream(const StreamsList *streams = NULL);
+ HLSStream *FindStream(const HLSStream *hls_new, const StreamsList *streams = NULL);
+ HLSStream *CurrentStream(void);
+ int BandwidthAdaptation(int progid, uint64_t &bandwidth);
+ QString ParseAttributes(QString &line, const char *attr);
+ int ParseSegmentInformation(HLSStream *hls, QString &line,
+ int &duration, QString &title);
+ int ParseTargetDuration(HLSStream *hls, QString &line);
+ HLSStream *ParseStreamInformation(QString &line, QString &uri);
+ int ParseMediaSequence(HLSStream *hls, QString &line);
+ int ParseKey(HLSStream *hls, QString &line);
+ int ParseProgramDateTime(HLSStream *hls, QString &line);
+ int ParseAllowCache(HLSStream *hls, QString &line);
+ int ParseVersion(QString &line, int &version);
+ int ParseEndList(HLSStream *hls);
+ int ParseDiscontinuity(HLSStream *hls, QString &line);
+ int ParseM3U8(const QByteArray *buffer, StreamsList *streams = NULL);
+ int Prefetch(int count);
+ void SanityCheck(HLSSegment *segment);
+ HLSSegment *GetSegment(int segnum, int timeout = 1000);
+ int NumSegments(void) const;
+ int ChooseSegment(int stream);
+ int64_t SizeMedia(void) const;
+ int64_t CalculateOffset(int count, int64_t *max = NULL, int *segnum = NULL);
+
+ // private member variables
+ QString m_m3u8; // M3U8 url
+ QByteArray m_peeked;
+
+ HLSPlayback *m_playback;
+
+ /* state */
+ StreamsList m_streams; // bandwidth adaptation
+ mutable QMutex m_lock; // protect general class members
+ bool m_cache; // can cache files
+ bool m_meta; // meta playlist
+ bool m_live; // live stream? or vod?
+ bool m_falsevod; // stream was incorrectly detected a VOD
+ bool m_error; // parsing error
+ bool m_aesmsg; // only print one time that the media is encrypted
+ friend class StreamWorker;
+ StreamWorker *m_streamworker;
+ friend class PlaylistWorker;
+ PlaylistWorker *m_playlistworker;
+};
+
+#endif
View
2 mythtv/libs/libmythtv/libmythtv.pro
@@ -166,6 +166,7 @@ HEADERS += avfringbuffer.h ThreadedFileWriter.h
HEADERS += ringbuffer.h fileringbuffer.h
HEADERS += dvdringbuffer.h bdringbuffer.h
HEADERS += streamingringbuffer.h metadataimagehelper.h
+HEADERS += httplivestreambuffer.h
SOURCES += recordinginfo.cpp
SOURCES += dbcheck.cpp
@@ -194,6 +195,7 @@ SOURCES += avfringbuffer.cpp ThreadedFileWriter.cpp
SOURCES += ringbuffer.cpp fileringBuffer.cpp
SOURCES += dvdringbuffer.cpp bdringbuffer.cpp
SOURCES += streamingringbuffer.cpp metadataimagehelper.cpp
+SOURCES += httplivestreambuffer.cpp
# DiSEqC
HEADERS += diseqc.h diseqcsettings.h
View
10 mythtv/libs/libmythtv/ringbuffer.cpp
@@ -19,6 +19,7 @@
#include "dvdringbuffer.h"
#include "bdringbuffer.h"
#include "streamingringbuffer.h"
+#include "httplivestreambuffer.h"
#include "livetvchain.h"
#include "mythcontext.h"
#include "ringbuffer.h"
@@ -107,15 +108,20 @@ RingBuffer *RingBuffer::Create(
bool dvddir = false;
bool bddir = false;
- bool httpurl = lower.startsWith("http://");
+ bool httpurl = lower.startsWith("http://") || lower.startsWith("https://");
bool mythurl = lower.startsWith("myth://");
bool bdurl = lower.startsWith("bd:");
bool dvdurl = lower.startsWith("dvd:");
bool dvdext = lower.endsWith(".img") || lower.endsWith(".iso");
if (httpurl)
+ {
+ if (HLSRingBuffer::TestForHTTPLiveStreaming(lfilename))
+ {
+ return new HLSRingBuffer(lfilename);
+ }
return new StreamingRingBuffer(lfilename);
-
+ }
if (!stream_only && mythurl)
{
struct stat fileInfo;
View
1 mythtv/libs/libmythtv/ringbuffer.h
@@ -38,6 +38,7 @@ enum RingBufferType
kRingBuffer_DVD,
kRingBuffer_BD,
kRingBuffer_HTTP,
+ kRingBuffer_HLS,
};
class MTV_PUBLIC RingBuffer : protected MThread

0 comments on commit 099b6cc

Please sign in to comment.
Something went wrong with that request. Please try again.