MythTV master
remoteavformatcontext.h
Go to the documentation of this file.
1// Wrapper for AVFormatContext (av_open_input_file/stream)
2// supporting myth remote files
3#ifndef REMOTEAVFORMATCONTEXT_H
4#define REMOTEAVFORMATCONTEXT_H
5
6// C++
7#include <iostream>
8
9// Qt
10#include <QString>
11
12// MythTV
15
16extern "C" {
17#include <libavformat/avformat.h>
18#include <libavformat/avio.h>
19#include <libavutil/opt.h>
20}
21
23{
24 public:
25 explicit RemoteAVFormatContext(const QString &filename = "")
26 { if (!filename.isEmpty()) Open(filename); }
27
29 {
30 Close();
31 if (m_buffer)
32 av_free(m_buffer);
33 }
34
35 AVFormatContext *getContext(void) { return m_inputFC; }
36
37 bool Open(const QString &filename)
38 {
39 LOG(VB_PLAYBACK, LOG_ERR, QString("RemoteAVFormatContext::Open: Opening %1").arg(filename));
40 if (isOpen())
41 return false;
42
43 if (m_inputFC)
44 avformat_free_context(m_inputFC);
45 m_inputFC = avformat_alloc_context();
46
47 delete m_rf;
48
49 m_inputIsRemote = filename.startsWith("myth://");
51 {
53
54 if (!m_rf->isOpen())
55 return false;
56
57 const int BUFFER_SIZE = 0x20000;
58 if (!m_buffer)
59 {
60 m_buffer = (unsigned char*)av_malloc(BUFFER_SIZE + AV_INPUT_BUFFER_PADDING_SIZE);
61 if (!m_buffer)
62 return false;
63 }
64 m_byteIOContext = avio_alloc_context(m_buffer, BUFFER_SIZE, 0,
66
67 m_byteIOContext->seekable = 1;
68
69 // probe the stream
70 AVProbeData probe_data;
71 memset(&probe_data, 0, sizeof(AVProbeData));
72 probe_data.filename = "stream";
73 probe_data.buf_size = m_rf->Read(m_buffer, BUFFER_SIZE);
74 probe_data.buf = m_buffer;
75
76 const AVInputFormat *fmt = av_probe_input_format(&probe_data, 1);
77 if (!fmt)
78 {
79 LOG(VB_GENERAL, LOG_ERR, QString("RemoteAVFormatContext::Open: Failed to probe file: %1").arg(filename));
80 return false;
81 }
82 LOG(VB_PLAYBACK, LOG_INFO, QString("RemoteAVFormatContext::Open: probed file as %1").arg(fmt->name));
83
84 m_rf->Seek(0, SEEK_SET);
85
87
88 int ret = avformat_open_input(&m_inputFC, "stream", fmt, nullptr);
89 if (ret)
90 {
91 LOG(VB_GENERAL, LOG_ERR, QString("RemoteAVFormatContext::Open: Failed to open input: %1").arg(filename));
92 return false;
93 }
94 }
95 else
96 {
97 // if this is a ice/shoutcast stream setup grabbing the inline metadata
98 AVDictionary *options = nullptr;
99
100 if (filename.startsWith("http://"))
101 av_dict_set(&options, "icy", "1", 0);
102
103 int ret = avformat_open_input(&m_inputFC, qPrintable(filename), nullptr, &options);
104 if (ret)
105 {
106 LOG(VB_GENERAL, LOG_ERR, QString("RemoteAVFormatContext::Open: Failed to open input: %1").arg(filename));
107 return false;
108 }
109 }
110
111 m_isOpen = true;
112 return m_isOpen;
113 }
114
115 void Close()
116 {
117 if (m_inputFC)
118 {
119 avformat_close_input(&m_inputFC);
120 m_inputFC = nullptr;
121 }
122
123 delete m_rf;
124 m_rf = nullptr;
125
126 m_isOpen = false;
127 }
128
129 bool isOpen() const { return m_isOpen; }
130
131 operator AVFormatContext * () const { return m_inputFC; }
132 //operator AVFormatContext & () const { return m_inputFC; }
133 AVFormatContext * operator -> () const { return m_inputFC; }
134
135 private:
136 static int ReadFunc(void *opaque, uint8_t *buf, int buf_size)
137 {
138 auto *rf = reinterpret_cast< RemoteFile* >(opaque);
139 int len = rf->Read(buf, buf_size);
140 int ret = ((len == 0) && (buf_size > 0)) ? AVERROR_EOF : len;
141 return ret;
142 }
143
144 static int WriteFunc(void */*opaque*/, const uint8_t */*buf*/, int/*buf_size*/)
145 { return -1; }
146
147 static int64_t SeekFunc(void *opaque, int64_t offset, int whence)
148 {
149 auto *rf = reinterpret_cast< RemoteFile* >(opaque);
150 if (whence == AVSEEK_SIZE)
151 return rf->GetFileSize();
152
153 return rf->Seek(offset, whence);
154 }
155
156 private:
157 AVFormatContext *m_inputFC { nullptr };
158 bool m_inputIsRemote { false };
159 bool m_isOpen { false };
160 RemoteFile *m_rf { nullptr };
161 AVIOContext *m_byteIOContext { nullptr };
162 unsigned char *m_buffer { nullptr };
163};
164#endif // REMOTEAVFORMATCONTEXT_H
static int ReadFunc(void *opaque, uint8_t *buf, int buf_size)
RemoteAVFormatContext(const QString &filename="")
static int64_t SeekFunc(void *opaque, int64_t offset, int whence)
AVFormatContext * getContext(void)
bool Open(const QString &filename)
AVFormatContext * operator->() const
static int WriteFunc(void *, const uint8_t *, int)
int Read(void *data, int size)
Definition: remotefile.cpp:938
long long Seek(long long pos, int whence, long long curpos=-1)
Definition: remotefile.cpp:759
bool isOpen(void) const
Definition: remotefile.cpp:245
long long GetFileSize(void) const
GetFileSize: returns the remote file's size at the time it was first opened Will query the server in ...
static constexpr qint64 BUFFER_SIZE
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39