MythTV  master
Go to the documentation of this file.
1 /*****************************************************************************
2  * httplivestreambuffer.cpp
3  * MythTV
4  *
5  * Created by Jean-Yves Avenard on 6/05/12.
6  * Copyright (c) 2012 Bubblestuff Pty Ltd. All rights reserved.
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
21  *****************************************************************************/
23 #ifndef MythXCode_hlsbuffer_h
24 #define MythXCode_hlsbuffer_h
26 #include "mythcorecontext.h"
27 #include "ringbuffer.h"
29 extern "C" {
30 #include "libavformat/avformat.h"
31 #include "libavformat/url.h"
32 }
35 class HLSStream;
36 class HLSSegment;
37 class StreamWorker;
38 class PlaylistWorker;
41 typedef QList<HLSStream*> StreamsList;
43 class HLSRingBuffer : public RingBuffer
44 {
45 public:
46  explicit HLSRingBuffer(const QString &lfilename);
47  HLSRingBuffer(const QString &lfilename, bool open);
48  ~HLSRingBuffer() override;
50  bool IsOpen(void) const override; // RingBuffer
51  long long GetReadPosition(void) const override; // RingBuffer
52  bool OpenFile(const QString &lfilename,
53  uint retry_ms = kDefaultOpenTimeout) override; // RingBuffer
54  bool IsStreamed(void) override { return false; } // RingBuffer
55  bool IsSeekingAllowed(void) override { return !m_error; } // RingBuffer
56  bool IsBookmarkAllowed(void) override { return true; } // RingBuffer
57  static bool IsHTTPLiveStreaming(QByteArray *s);
58  static bool TestForHTTPLiveStreaming(const QString &filename);
59  bool SaveToDisk(const QString &filename, int segstart = 0, int segend = -1);
60  int NumStreams(void) const;
61  int Read(void *data, uint i_read) { return safe_read(data, i_read); }
62  void Interrupt(void);
63  void Continue(void);
64  int DurationForBytes(uint size);
66 protected:
67  int safe_read(void *data, uint sz) override; // RingBuffer
68  long long GetRealFileSizeInternal(void) const override; // RingBuffer
69  long long SeekInternal(long long pos, int whence) override; // RingBuffer
71 private:
72  void FreeStreamsList(QList<HLSStream*> *streams) const;
73  HLSStream *GetStreamForSegment(int segnum) const;
74  HLSStream *GetStream(int wanted, const StreamsList *streams = nullptr) const;
75  HLSStream *GetFirstStream(const StreamsList *streams = nullptr) const;
76  HLSStream *GetLastStream(const StreamsList *streams = nullptr) const;
77  HLSStream *FindStream(const HLSStream *hls_new, const StreamsList *streams = nullptr) const;
78  HLSStream *GetCurrentStream(void) const;
79  QString ParseAttributes(const QString &line, const char *attr) const;
80  int ParseDecimalValue(const QString &line, int &target) const;
81  int ParseSegmentInformation(const HLSStream *hls, const QString &line,
82  int &duration, QString &title) const;
83  int ParseTargetDuration(HLSStream *hls, const QString &line) const;
84  HLSStream *ParseStreamInformation(const QString &line, const QString &uri) const;
85  int ParseMediaSequence(HLSStream *hls, const QString &line) const;
86  int ParseKey(HLSStream *hls, const QString &line);
87  int ParseProgramDateTime(HLSStream *hls, const QString &line) const;
88  int ParseAllowCache(HLSStream *hls, const QString &line) const;
89  int ParseVersion(const QString &line, int &version) const;
90  int ParseEndList(HLSStream *hls) const;
91  int ParseDiscontinuity(HLSStream *hls, const QString &line) const;
92  int ParseM3U8(const QByteArray *buffer, StreamsList *streams = nullptr);
93  int Prefetch(int count);
94  void SanityCheck(const HLSStream *hls) const;
95  HLSSegment *GetSegment(int segnum, int timeout = 1000);
96  int NumSegments(void) const;
97  int ChooseSegment(int stream) const;
98  int64_t SizeMedia(void) const;
99  void WaitUntilBuffered(void);
100  void SanitizeStreams(StreamsList *streams = nullptr);
102  // private member variables
103  QString m_m3u8; // M3U8 url
104  QByteArray m_peeked;
108  /* state */
109  StreamsList m_streams; // bandwidth adaptation
110  mutable QMutex m_lock; // protect general class members
111  bool m_meta {false}; // meta playlist
112  bool m_error {false}; // parsing error
113  bool m_aesmsg {false}; // only print one time that the media is encrypted
114  int m_startup {0}; // starting segment (where seek start)
120  int64_t m_bitrate {0};
126  bool m_seektoend {false};
128  friend class StreamWorker;
130  friend class PlaylistWorker;
132  FILE *m_fd {nullptr};
133  bool m_interrupted {false};
134  bool m_killed {false};
135 };
137 #endif
static const int kDefaultOpenTimeout
HLSRingBuffer(const QString &lfilename)
StreamWorker * m_streamworker
int ChooseSegment(int stream) const
int NumStreams(void) const
int64_t SizeMedia(void) const
int64_t m_bitrate
assumed bitrate of playback used for the purpose of calculating length and seek position.
bool IsStreamed(void) override
static bool IsHTTPLiveStreaming(QByteArray *s)
int ParseEndList(HLSStream *hls) const
bool OpenFile(const QString &lfilename, uint retry_ms=kDefaultOpenTimeout) override
Opens an HTTP Live Stream for reading.
bool IsOpen(void) const override
Returns true if open for either reading or writing.
int ParseVersion(const QString &line, int &version) const
static bool TestForHTTPLiveStreaming(const QString &filename)
void FreeStreamsList(QList< HLSStream * > *streams) const
HLSSegment * GetSegment(int segnum, int timeout=1000)
Retrieve segment [segnum] from any available streams.
int ParseMediaSequence(HLSStream *hls, const QString &line) const
int DurationForBytes(uint size)
returns an estimated duration in ms for size amount of data returns 0 if we can't estimate the durati...
int ParseProgramDateTime(HLSStream *hls, const QString &line) const
QString ParseAttributes(const QString &line, const char *attr) const
void SanityCheck(const HLSStream *hls) const
unsigned int uint
Definition: compat.h:140
HLSStream * GetStream(int wanted, const StreamsList *streams=nullptr) const
bool m_seektoend
FFmpeg seek to the end of the stream in order to determine the length of the video.
bool SaveToDisk(const QString &filename, int segstart=0, int segend=-1)
int ParseSegmentInformation(const HLSStream *hls, const QString &line, int &duration, QString &title) const
int ParseKey(HLSStream *hls, const QString &line)
long long SeekInternal(long long pos, int whence) override
int Read(void *data, uint i_read)
HLSStream * ParseStreamInformation(const QString &line, const QString &uri) const
int safe_read(void *data, uint sz) override
long long GetRealFileSizeInternal(void) const override
bool IsBookmarkAllowed(void) override
QList< HLSStream * > StreamsList
void WaitUntilBuffered(void)
Wait until we have enough segments buffered to allow smooth playback Do not wait if VOD and at end of...
int ParseAllowCache(HLSStream *hls, const QString &line) const
PlaylistWorker * m_playlistworker
int ParseTargetDuration(HLSStream *hls, const QString &line) const
int ParseDiscontinuity(HLSStream *hls, const QString &line) const
HLSStream * GetFirstStream(const StreamsList *streams=nullptr) const
int FILE
int ParseDecimalValue(const QString &line, int &target) const
Return the decimal argument in a line of type: blah:<decimal> presence of value <decimal> is compulso...
int NumSegments(void) const
bool IsSeekingAllowed(void) override
long long GetReadPosition(void) const override
Returns how far into the file we have read.
int ParseM3U8(const QByteArray *buffer, StreamsList *streams=nullptr)
HLSStream * GetCurrentStream(void) const
return the stream we are currently streaming from
Implements a file/stream reader/writer.
HLSPlayback * m_playback
int Prefetch(int count)
Preferetch the first x segments of the stream.
HLSStream * FindStream(const HLSStream *hls_new, const StreamsList *streams=nullptr) const
HLSStream * GetLastStream(const StreamsList *streams=nullptr) const
void SanitizeStreams(StreamsList *streams=nullptr)
Streams may not be all starting at the same sequence number, so attempt to align their starting seque...
HLSStream * GetStreamForSegment(int segnum) const