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>
|