File: stream_data.ecpp

package info (click to toggle)
vdr-plugin-live 3.5.2-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 6,116 kB
  • sloc: cpp: 12,988; javascript: 3,220; makefile: 241; sh: 40
file content (118 lines) | stat: -rw-r--r-- 3,110 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
<%pre>

#include <setup.h>
#include <filecache.h>
#include <tntfeatures.h>
#include <ffmpeg.h>
#include <fstream>
#include <tnt/mimedb.h>
#include <tnt/sessionunlocker.h>

#include <vdr/tools.h>
#include <unistd.h>

using namespace vdrlive;

</%pre>
<%session scope="global">
bool logged_in(false);
FFmpegThread *f_worker = nullptr;
</%session>
<%cpp>
if(f_worker) f_worker->Touch();
tnt::SessionUnlocker unlck = tnt::SessionUnlocker(request, true);

reply.setHeader("Expires", "Mon, 26 Jul 1997 05:00:00 GMT");

// assign Mime type to repply
tnt::MimeDb mimeDb("/etc/mime.types");
std::string mime = mimeDb.getMimetype(request.getPathInfo());
reply.setContentType(mime);

// check for session cookie. TODO: handle secure cookie for ssl
std::string session;
if (request.hasCookie("tntnet")) {
  session = request.getCookie("tntnet");
}

// forge target path from requested path.
std::string path(request.getPathInfo());
if (path.substr(0, 7) == "/media/") {
  path.replace(0, 7, tmpHlsBufferDir);
}
else return DECLINED;

// try to open the target file
uint8_t retry;
if (path.rfind(".m3u8") != std::string::npos && path.find("master_") != std::string::npos) retry = 100;
else retry = 5;
std::ifstream f;
do {
  f.open ( path.c_str(), std::ios::binary );
  if (!f.is_open()) {
    usleep(200e3);
  }
} while (!f.is_open() && --retry);

// fail if file did not appear
if (!f.is_open()) {
  dsyslog("vdrlive::stream_data: %s - DECLINED", path.c_str());
  return DECLINED;
}

// wait until TARGETDURATION in playlist is != 0
if (path.rfind(".m3u8") != std::string::npos && path.find("ffmpeg_") != std::string::npos) {
  std::string line;
  int count = 20;
  while(getline(f, line) && count) {
    if (line.find("#EXT-X-TARGETDURATION:") != std::string::npos) {
      if (! (atoi(line.erase(0, 22).c_str()))) {
        count--;
        f.close();
        usleep(100e3);
        f.open( path.c_str(), std::ios::binary );
      }
    }
  }
  f.clear(); // unset eof flag
}

usleep(100e3);
f.seekg( 0, std::ios::end );
std::streamsize size = f.tellg();
f.seekg( 0, std::ios::beg );

unsigned httpReturn = HTTP_OK;
std::string range = request.getHeader(tnt::httpheader::range);
off_t offset = 0, stop = size-1;
if (!range.empty()) {
  range.erase(0,6);
  std::stringstream ss(range);
  char tmp;
  ss >> offset >> tmp >> stop;
  dsyslog("vdrlive::stream_data::range(%jd to %jd)", (intmax_t)offset, (intmax_t)stop);
  if (offset > size) return HTTP_RANGE_NOT_SATISFIABLE;
  if ((stop+1) > size) stop = size - 1;
  httpReturn = HTTP_PARTIAL_CONTENT;
  std::stringstream contentRange;
  contentRange << offset << ('-') << stop << ('/') << size;
  reply.setHeader(tnt::httpheader::contentRange, contentRange.str());
  f.seekg( offset, std::ios::beg );
}

char buffer[KILOBYTE(64)];
size_t r, c = stop - offset+ 1;
while (r = f.readsome(buffer, (c < (long int) sizeof(buffer))?c:sizeof(buffer))) {
  reply.out().write(buffer, r);
  c -= r;
  if (!reply.out()) {
    return HTTP_GONE;
  }
#if TNT_WATCHDOG_SILENCE
  request.touch(); // retrigger the watchdog.
#endif
}

reply.out() << std::flush;
return httpReturn;
</%cpp>