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