summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/.config18
-rw-r--r--src/Makefile.am11
-rw-r--r--src/Makefile.manual109
-rw-r--r--src/eFilePumpThread.cpp69
-rw-r--r--src/eFilePumpThread.h30
-rw-r--r--src/eNetworkPumpThread.cpp90
-rw-r--r--src/eNetworkPumpThread.h28
-rw-r--r--src/ePreDefine.h24
-rw-r--r--src/eURIDecoder.cpp283
-rw-r--r--src/eURIDecoder.h43
-rw-r--r--src/main.cpp211
-rw-r--r--src/uThread.cpp156
-rw-r--r--src/uThread.h66
13 files changed, 1138 insertions, 0 deletions
diff --git a/src/.config b/src/.config
new file mode 100644
index 0000000..1251fac
--- /dev/null
+++ b/src/.config
@@ -0,0 +1,18 @@
+#############################################
+# BUILD OPTION
+#############################################
+# - BUILD_MODE : debug | release
+# - BUILD_CROSS : y | n
+# - SILENT_BUILD_MODE : y | n
+#############################################
+
+BUILD_MODE=release
+BUILD_CROSS=y
+
+SILENT_BUILD_MODE=y
+
+ifeq ($(BUILD_CROSS),y)
+ARCH=mipsel
+FLATFORM=mipsel-oe-linux
+OE_TOP=/media/840EVO/vuplus/16/vuduo2/build/tmp
+endif
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644
index 0000000..06573d0
--- /dev/null
+++ b/src/Makefile.am
@@ -0,0 +1,11 @@
+## Process this file with automake to produce Makefile.in
+bin_PROGRAMS = filestreamproxy
+filestreamproxy_SOURCES = main.cpp
+filestreamproxy_SOURCES += eFilePumpThread.cpp
+filestreamproxy_SOURCES += eNetworkPumpThread.cpp
+filestreamproxy_SOURCES += eURIDecoder.cpp
+filestreamproxy_SOURCES += uThread.cpp
+
+filestreamproxy_LDADD = $(LIBLTDL) @PTHREAD_LIBS@
+
+
diff --git a/src/Makefile.manual b/src/Makefile.manual
new file mode 100644
index 0000000..5161951
--- /dev/null
+++ b/src/Makefile.manual
@@ -0,0 +1,109 @@
+#============================================================================
+# Name : Makefile
+# Author : oskwon(oskwon@marusys.com)
+# Version :
+# Copyright : Copyright(c)2013 Marusys. All right reserved.
+# Description :
+#============================================================================
+
+include .config
+
+VER = v1.0
+REV = $(shell cat .revision)
+BIN = filestreamproxy
+
+SRC = \
+ main.cpp \
+ uThread.cpp \
+ eURIDecoder.cpp \
+ eFilePumpThread.cpp \
+ eNetworkPumpThread.cpp \
+
+
+CFLAGS ?=
+LDFLAGS ?=
+
+CFLAGS += -DDEBUG_LOG
+
+ifeq ($(SILENT_BUILD_MODE),y)
+Q=@
+endif
+
+ifeq ($(REV),)
+REV = 0
+endif
+
+ifeq ($(ARCH),mipsel)
+BUILD_TOP = $(OE_TOP)/staging/$(FLATFORM)
+CROSS = $(OE_TOP)/cross/mipsel/bin/$(FLATFORM)-
+endif
+
+ifeq ($(BUILD_MODE),debug)
+CFLAGS += -g
+else ifeq ($(BUILD_MODE),release)
+CFLAGS += -O2
+endif
+
+CXX= $(CROSS)g++
+LD= $(CROSS)ld
+STRIP= $(CROSS)strip
+RM= rm -f
+
+CFLAGS += -I$(BUILD_TOP)/usr/include
+LDFLAGS += -L$(BUILD_TOP)/usr/lib -lpthread
+
+OBJ=$(SRC:.cpp=.o)
+
+.SUFFIXES : .cpp .o
+.PHONY : all clean erase .showinfo .version
+
+.cpp.o:
+ $(Q)echo "Compile... "$<
+ $(Q)$(CXX) $(CFLAGS) -c $<
+
+all: .showinfo .version $(BIN)
+
+$(BIN):$(OBJ)
+ $(Q)echo "Linking... "$@
+ $(Q)$(CXX) -o $@ $(OBJ) $(LDFLAGS)
+ $(Q)if [ "$(BUILD_MODE)" == "release" ]; then \
+ echo "Strip... "$@; \
+ $(STRIP) $@; \
+ fi
+ @echo `expr $(REV) + 1` > .revision
+
+clean:
+ $(Q)$(RM) $(BIN) *.o *.log version.h
+
+install:
+ @./upload.sh
+
+erase:clean
+ $(Q)$(RM) .revision
+
+.showinfo:
+ @echo "-----------------------------------------------------"
+ @echo " [ BUILD ENVIRONMENT ] "
+ @echo "-----------------------------------------------------"
+ @echo "OUTPUT : "$(BIN)
+ @echo "VERSION : "$(VER)
+ @echo "REVISION : "$(REV)
+ @echo ""
+ @echo "CXX : "$(CXX)
+ @echo "LD : "$(LD)
+ @echo "STRIP : "$(STRIP)
+ @echo "CFLAGS : "$(CFLAGS)
+ @echo "LDFLAGS : "$(LDFLAGS)
+ @echo "-----------------------------------------------------"
+ @echo
+
+.version:
+ @echo "/*" > version.h
+ @echo " * uVersion.h" >> version.h
+ @echo " * Auto generated code." >> version.h
+ @echo " */" >> version.h
+ @echo "#ifndef UVERSION_H_" >> version.h
+ @echo "#define UVERSION_H_" >> version.h
+ @echo "#define PN \"$(BIN)\"" >> version.h
+ @echo "#define PV \"$(VER)\"" >> version.h
+ @echo "#endif /* UVERSION_H_ */" >> version.h
diff --git a/src/eFilePumpThread.cpp b/src/eFilePumpThread.cpp
new file mode 100644
index 0000000..7659a4d
--- /dev/null
+++ b/src/eFilePumpThread.cpp
@@ -0,0 +1,69 @@
+/*
+ * eFilePumpThread.cpp
+ *
+ * Created on: 2013. 9. 12.
+ * Author: kos
+ */
+
+//#include "uLogger.h"
+
+//#include "uDemux.h"
+
+#include <poll.h>
+#include <stdio.h>
+
+#include "ePreDefine.h"
+#include "eFilePumpThread.h"
+//-------------------------------------------------------------------------------
+
+#ifdef DEBUG_LOG
+//#undef LOG
+//#define LOG(X,...) { do{}while(0); }
+#endif
+
+eFilePumpThread::eFilePumpThread(int aDeviceFd, std::string aFileName)
+ : mDeviceFd(aDeviceFd), mFileName(aFileName), mTermFlag(false), uThread("FilePumpThread", TYPE_DETACHABLE)
+{
+}
+//-------------------------------------------------------------------------------
+
+eFilePumpThread::~eFilePumpThread()
+{
+}
+//-------------------------------------------------------------------------------
+
+void eFilePumpThread::Run()
+{
+ int rc = 0;
+ unsigned char buffer[BUFFER_SIZE];
+ FILE* mediafilefd = fopen(mFileName.c_str(), "rb");
+ struct pollfd pollevt;
+
+ pollevt.fd = mDeviceFd;
+ pollevt.events = POLLOUT;
+ pollevt.revents = 0;
+
+ mTermFlag = true;
+ while(mTermFlag) {
+ rc = poll((struct pollfd*)&pollevt, 1, 1000);
+
+ if (pollevt.revents & POLLOUT) {
+ rc = fread(buffer, 1, BUFFER_SIZE, mediafilefd);
+ if(!rc) break;
+#ifdef DEBUG_LOG
+ LOG("%d byte write.", rc);
+#endif
+ rc = write(mDeviceFd, buffer, rc);
+ }
+ }
+ fclose(mediafilefd);
+ mTermFlag = false;
+}
+//-------------------------------------------------------------------------------
+
+void eFilePumpThread::Terminate()
+{
+ mTermFlag = false;
+}
+//-------------------------------------------------------------------------------
+
diff --git a/src/eFilePumpThread.h b/src/eFilePumpThread.h
new file mode 100644
index 0000000..1e8136d
--- /dev/null
+++ b/src/eFilePumpThread.h
@@ -0,0 +1,30 @@
+/*
+ * eFilePumpThread.h
+ *
+ * Created on: 2013. 9. 12.
+ * Author: kos
+ */
+
+#ifndef EFILEPUMPTHREAD_H_
+#define EFILEPUMPTHREAD_H_
+
+#include "uThread.h"
+//-------------------------------------------------------------------------------
+
+class eFilePumpThread : public uThread
+{
+private:
+ bool mTermFlag;
+ int mDeviceFd;
+ std::string mFileName;
+protected:
+ void Run();
+ void Terminate();
+
+public:
+ eFilePumpThread(int aDeviceFd, std::string aFileName);
+ ~eFilePumpThread();
+};
+//-------------------------------------------------------------------------------
+
+#endif /* EFILEPUMPTHREAD_H_ */
diff --git a/src/eNetworkPumpThread.cpp b/src/eNetworkPumpThread.cpp
new file mode 100644
index 0000000..dc8972e
--- /dev/null
+++ b/src/eNetworkPumpThread.cpp
@@ -0,0 +1,90 @@
+/*
+ * eDemuxPumpThread.cpp
+ *
+ * Created on: 2013. 9. 12.
+ * Author: kos
+ */
+
+//#include "uLogger.h"
+//#include "uDemux.h"
+
+#include <poll.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/ioctl.h>
+
+#include "ePreDefine.h"
+#include "eNetworkPumpThread.h"
+//-------------------------------------------------------------------------------
+
+#ifdef DEBUG_LOG
+//#undef LOG
+//#define LOG(X,...) { do{}while(0); }
+#endif
+
+eNetworkPumpThread::eNetworkPumpThread(int aDeviceFd)
+ : mTermFlag(0), mDeviceFd(aDeviceFd), uThread("eNetworkPumpThread")
+{
+}
+//-------------------------------------------------------------------------------
+
+eNetworkPumpThread::~eNetworkPumpThread()
+{
+}
+//-------------------------------------------------------------------------------
+
+void eNetworkPumpThread::Run()
+{
+ int rc = 0, wc = 0;
+ unsigned char buffer[BUFFER_SIZE];
+ struct pollfd pollevt;
+
+ pollevt.fd = mDeviceFd;
+ pollevt.events = POLLIN | POLLHUP;
+ pollevt.revents = 0;
+
+ mTermFlag = true;
+
+ const char *c = "\
+HTTP/1.0 200 OK\r\n\
+Connection: close\r\n\
+Content-Type: video/mpeg\r\n\
+Server: stream_enigma2\r\n\
+\r\n";
+
+ write(1, c, strlen(c));
+
+ while(mTermFlag) {
+ rc = poll((struct pollfd*)&pollevt, 1, 1000);
+ if (pollevt.revents & POLLIN) {
+ rc = read(mDeviceFd, buffer, BUFFER_SIZE);
+
+ if (errno == EINTR || errno == EAGAIN || errno == EBUSY || errno == EOVERFLOW) {
+#ifdef DEBUG_LOG
+ LOG("(retry... errno : %d)", errno);
+#endif
+ continue;
+ }
+#ifdef DEBUG_LOG
+ LOG("%d byte read", rc);
+#endif
+ wc = write(1, buffer, rc);
+#ifdef DEBUG_LOG
+ LOG("%d byte write", wc);
+#endif
+ } else if (pollevt.revents & POLLHUP) {
+ ioctl(mDeviceFd, 200, 0);
+ break;
+ }
+ }
+ mTermFlag = false;
+}
+//-------------------------------------------------------------------------------
+
+void eNetworkPumpThread::Terminate()
+{
+ mTermFlag = false;
+}
+//-------------------------------------------------------------------------------
+
diff --git a/src/eNetworkPumpThread.h b/src/eNetworkPumpThread.h
new file mode 100644
index 0000000..892c161
--- /dev/null
+++ b/src/eNetworkPumpThread.h
@@ -0,0 +1,28 @@
+/*
+ * eDemuxPumpThread.h
+ *
+ * Created on: 2013. 9. 12.
+ * Author: kos
+ */
+
+#ifndef EDEMUXPUMPTHREAD_H_
+#define EDEMUXPUMPTHREAD_H_
+
+#include "uThread.h"
+//-------------------------------------------------------------------------------
+
+class eNetworkPumpThread : public uThread
+{
+private:
+ int mDeviceFd;
+ bool mTermFlag;
+protected:
+ void Run();
+ void Terminate();
+public:
+ eNetworkPumpThread(int aDeviceFd);
+ virtual ~eNetworkPumpThread();
+};
+//-------------------------------------------------------------------------------
+
+#endif /* EDEMUXPUMPTHREAD_H_ */
diff --git a/src/ePreDefine.h b/src/ePreDefine.h
new file mode 100644
index 0000000..57a8688
--- /dev/null
+++ b/src/ePreDefine.h
@@ -0,0 +1,24 @@
+/*
+ * main.h
+ *
+ * Created on: 2013. 9. 12.
+ * Author: kos
+ */
+
+#ifndef FILESTREAMPROXY_H_
+#define FILESTREAMPROXY_H_
+
+#define BUFFER_SIZE (188*256)
+#define MAX_LINE_LENGTH (1024)
+
+#define RETURN_ERR_400(FMT,...) { printf("HTTP/1.0 400 Bad Request\r\n"FMT"\r\n\r\n", ##__VA_ARGS__); return 1; }
+#define RETURN_ERR_401(FMT,...) { printf("HTTP/1.0 401 Unauthorized\r\n"FMT"\r\n\r\n",##__VA_ARGS__); return 1; }
+#define RETURN_ERR_502(FMT,...) { printf("HTTP/1.0 502 Bad Gateway\r\n"FMT"\r\n\r\n", ##__VA_ARGS__); return 1; }
+//-------------------------------------------------------------------------------
+
+#ifdef DEBUG_LOG
+extern FILE* fpLog;
+#define LOG(X,...) { fprintf(fpLog, "%s:%s(%d) "X"\n",__FILE__,__FUNCTION__,__LINE__,##__VA_ARGS__); fflush(fpLog); }
+#endif
+
+#endif /* FILESTREAMPROXY_H_ */
diff --git a/src/eURIDecoder.cpp b/src/eURIDecoder.cpp
new file mode 100644
index 0000000..e04e60d
--- /dev/null
+++ b/src/eURIDecoder.cpp
@@ -0,0 +1,283 @@
+/*
+ * URIDecoder.cpp
+ *
+ * Created on: 2013. 10. 21.
+ * Author: kos
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include "eURIDecoder.h"
+//-------------------------------------------------------------------------------
+
+eURIDecoder::eURIDecoder()
+{
+}
+//-------------------------------------------------------------------------------
+
+eURIDecoder::~eURIDecoder()
+{
+}
+//-------------------------------------------------------------------------------
+
+unsigned char eURIDecoder::H2I(wchar_t aHexDigit)
+{
+ switch (aHexDigit) {
+ case _UL_('0'):
+ case _UL_('1'):
+ case _UL_('2'):
+ case _UL_('3'):
+ case _UL_('4'):
+ case _UL_('5'):
+ case _UL_('6'):
+ case _UL_('7'):
+ case _UL_('8'):
+ case _UL_('9'):
+ return (unsigned char)(9 + aHexDigit - _UL_('9'));
+ case _UL_('a'):
+ case _UL_('b'):
+ case _UL_('c'):
+ case _UL_('d'):
+ case _UL_('e'):
+ case _UL_('f'):
+ return (unsigned char)(15 + aHexDigit - _UL_('f'));
+ case _UL_('A'):
+ case _UL_('B'):
+ case _UL_('C'):
+ case _UL_('D'):
+ case _UL_('E'):
+ case _UL_('F'):
+ return (unsigned char)(15 + aHexDigit - _UL_('F'));
+ default:
+ return 0;
+ }
+}
+//-------------------------------------------------------------------------------
+
+const wchar_t* eURIDecoder::DecodeURI(wchar_t* aData, int aBreakCond)
+{
+ wchar_t* read = aData;
+ wchar_t* write = aData;
+ bool prevWasCr = false;
+
+ if (aData == NULL) {
+ return NULL;
+ }
+
+ for (;;) {
+ switch (read[0]) {
+ case _UL_('\0'):
+ if (read > write) {
+ write[0] = _UL_('\0');
+ }
+ return write;
+
+ case _UL_('%'):
+ switch (read[1]) {
+ case _UL_('0'):
+ case _UL_('1'):
+ case _UL_('2'):
+ case _UL_('3'):
+ case _UL_('4'):
+ case _UL_('5'):
+ case _UL_('6'):
+ case _UL_('7'):
+ case _UL_('8'):
+ case _UL_('9'):
+ case _UL_('a'):
+ case _UL_('b'):
+ case _UL_('c'):
+ case _UL_('d'):
+ case _UL_('e'):
+ case _UL_('f'):
+ case _UL_('A'):
+ case _UL_('B'):
+ case _UL_('C'):
+ case _UL_('D'):
+ case _UL_('E'):
+ case _UL_('F'):
+ switch (read[2]) {
+ case _UL_('0'):
+ case _UL_('1'):
+ case _UL_('2'):
+ case _UL_('3'):
+ case _UL_('4'):
+ case _UL_('5'):
+ case _UL_('6'):
+ case _UL_('7'):
+ case _UL_('8'):
+ case _UL_('9'):
+ case _UL_('a'):
+ case _UL_('b'):
+ case _UL_('c'):
+ case _UL_('d'):
+ case _UL_('e'):
+ case _UL_('f'):
+ case _UL_('A'):
+ case _UL_('B'):
+ case _UL_('C'):
+ case _UL_('D'):
+ case _UL_('E'):
+ case _UL_('F'): {
+ const unsigned char left = H2I(read[1]);
+ const unsigned char right = H2I(read[2]);
+ const int code = 16 * left + right;
+ switch (code) {
+ case 10:
+ switch (aBreakCond) {
+ case BR_TO_LF:
+ if (!prevWasCr) {
+ write[0] = (wchar_t)10;
+ write++;
+ }
+ break;
+
+ case BR_TO_CRLF:
+ if (!prevWasCr) {
+ write[0] = (wchar_t)13;
+ write[1] = (wchar_t)10;
+ write += 2;
+ }
+ break;
+
+ case BR_TO_CR:
+ if (!prevWasCr) {
+ write[0] = (wchar_t)13;
+ write++;
+ }
+ break;
+
+ case BR_DONT_TOUCH:
+ default:
+ write[0] = (wchar_t)10;
+ write++;
+
+ }
+ prevWasCr = false;
+ break;
+
+ case 13:
+ switch (aBreakCond) {
+ case BR_TO_LF:
+ write[0] = (wchar_t)10;
+ write++;
+ break;
+
+ case BR_TO_CRLF:
+ write[0] = (wchar_t)13;
+ write[1] = (wchar_t)10;
+ write += 2;
+ break;
+
+ case BR_TO_CR:
+ write[0] = (wchar_t)13;
+ write++;
+ break;
+
+ case BR_DONT_TOUCH:
+ default:
+ write[0] = (wchar_t)13;
+ write++;
+
+ }
+ prevWasCr = true;
+ break;
+
+ default:
+ write[0] = (wchar_t)(code);
+ write++;
+
+ prevWasCr = false;
+
+ }
+ read += 3;
+ }
+ break;
+
+ default:
+ if (read > write) {
+ write[0] = read[0];
+ write[1] = read[1];
+ }
+ read += 2;
+ write += 2;
+
+ prevWasCr = false;
+ }
+ break;
+
+ default:
+ if (read > write) {
+ write[0] = read[0];
+ }
+ read++;
+ write++;
+
+ prevWasCr = false;
+ }
+ break;
+
+ case _UL_('+'):
+ if (read > write) {
+ write[0] = _UL_(' ');
+ }
+ read++;
+ write++;
+
+ prevWasCr = false;
+ break;
+
+ default:
+ if (read > write) {
+ write[0] = read[0];
+ }
+ read++;
+ write++;
+
+ prevWasCr = false;
+ }
+ }
+}
+//-------------------------------------------------------------------------------
+
+std::wstring eURIDecoder::Decode(const wchar_t* aInput)
+{
+ wchar_t working[1024] = {0};
+
+ wcscpy(working, aInput);
+ DecodeURI(working, BR_DONT_TOUCH);
+
+ return std::wstring(working);
+}
+//-------------------------------------------------------------------------------
+
+std::string eURIDecoder::Decode(const char* aInput)
+{
+ std::string tmp = aInput;
+ std::wstring in = L"";
+ in.assign(tmp.begin(), tmp.end());
+
+ std::wstring decode = Decode(in.c_str());
+
+ tmp.assign(decode.begin(), decode.end());
+
+ return tmp;
+}
+//-------------------------------------------------------------------------------
+
+#ifdef UNIT_TEST
+#include <iostream>
+int main()
+{
+ std::string in = "/home/kos/work/workspace/tsstreamproxy/test/20130528%201415%20-%20ZDF%20-%20Die%20K%C3%BCchenschlacht.ts";
+ std::string out = URIDecoder().Decode(in.c_str());
+
+ cout << out << endl;
+
+ FILE* fp = fopen(out.c_str(), "rb");
+
+ cout << (fp == NULL) ? "OPEN FAIL!!" : "OPEN OK" << endl;
+}
+
+#endif
diff --git a/src/eURIDecoder.h b/src/eURIDecoder.h
new file mode 100644
index 0000000..e0833b5
--- /dev/null
+++ b/src/eURIDecoder.h
@@ -0,0 +1,43 @@
+/*
+ * URIDecoder.h
+ *
+ * Created on: 2013. 10. 21.
+ * Author: kos
+ */
+
+#ifndef URIDECODER_H_
+#define URIDECODER_H_
+
+#include <memory>
+#include <string>
+
+#include <wchar.h>
+//-------------------------------------------------------------------------------
+
+#define BR_TO_LF 0
+#define BR_TO_CRLF 1
+#define BR_TO_CR 2
+#define BR_TO_UNIX BR_TO_LF
+#define BR_TO_WINDOWS BR_TO_CRLF
+#define BR_TO_MAC BR_TO_CR
+#define BR_DONT_TOUCH 6
+
+#define _UL_(x) L##x
+//-------------------------------------------------------------------------------
+
+class eURIDecoder
+{
+protected:
+ unsigned char H2I(wchar_t aHexDigit);
+ const wchar_t* DecodeURI(wchar_t* aData, int aBreakCond);
+
+public:
+ eURIDecoder();
+ virtual ~eURIDecoder();
+
+ std::string Decode(const char* aInput);
+ std::wstring Decode(const wchar_t* aInput);
+};
+//-------------------------------------------------------------------------------
+
+#endif /* URIDECODER_H_ */
diff --git a/src/main.cpp b/src/main.cpp
new file mode 100644
index 0000000..2baaf4d
--- /dev/null
+++ b/src/main.cpp
@@ -0,0 +1,211 @@
+/*
+ * main.cpp
+ *
+ * Created on: 2013. 9. 12.
+ * Author: kos
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <fcntl.h>
+#include <poll.h>
+#include <stdlib.h>
+#include <sys/ioctl.h>
+
+#include <vector>
+#include <string>
+#include <iterator>
+#include <fstream>
+
+#include "ePreDefine.h"
+#include "eURIDecoder.h"
+#include "eFilePumpThread.h"
+#include "eNetworkPumpThread.h"
+
+#ifdef DEBUG_LOG
+FILE* fpLog = fopen("/tmp/filestreamproxy.log", "w");
+//#undef LOG
+//#define LOG(X,...) { do{}while(0); }
+#endif
+
+using namespace std;
+//-------------------------------------------------------------------------------
+
+int gDeviceFd = 0;
+
+char* ReadRequest(char* aRequest)
+{
+ return fgets(aRequest, MAX_LINE_LENGTH-1, stdin);
+}
+//-------------------------------------------------------------------------------
+
+namespace eParser {
+ int gVideoPid = 0, gAudioPid = 0;
+ std::vector<string> Split(std::string aBuffer, char aDelimiter);
+ void FileName(char* aRequest, char* aHttp, std::string& aOutData);
+ bool MetaData(std::string aMediaFileName);
+};
+using namespace eParser;
+//-------------------------------------------------------------------------------
+
+/* GET /file?file=/home/kos/work/workspace/filestreamproxy/data/20131023%200630%20-%20FASHION%20TV%20-%20instant%20record.ts HTTP/1.0 */
+int main(int argc, char** argv)
+{
+ char request[MAX_LINE_LENGTH] = {0};
+
+ if (!ReadRequest(request)) {
+ RETURN_ERR_400();
+ }
+#ifdef DEBUG_LOG
+ LOG("%s", request);
+#endif
+
+ if (strncmp(request, "GET /", 5)) {
+ RETURN_ERR_400();
+ }
+
+ char* http = strchr(request + 5, ' ');
+ if (!http || strncmp(http, " HTTP/1.", 7)) {
+ RETURN_ERR_400("Not support request (%s).", http);
+ }
+
+ std::string srcfilename = "";
+ eParser::FileName(request, http, srcfilename);
+
+ bool isSuccessMeta = eParser::MetaData(srcfilename);
+
+#ifdef DEBUG_LOG
+ LOG("meta parsing result : %d, video : %d, audio : %d", isSuccessMeta, eParser::gVideoPid, eParser::gAudioPid);
+#endif
+
+ gDeviceFd = open("/dev/bcm_enc0", O_RDWR);
+ if(gDeviceFd < 0 ) {
+ close(gDeviceFd);
+ RETURN_ERR_502("Fail to opne device.");
+ }
+
+ if(isSuccessMeta) {
+ if(ioctl(gDeviceFd, 1, eParser::gVideoPid)) {
+ RETURN_ERR_502("Fail to set video pid");
+ }
+ if(ioctl(gDeviceFd, 2, eParser::gAudioPid)) {
+ RETURN_ERR_502("Fail to set audio pid");
+ }
+ }
+
+ eFilePumpThread filepump(gDeviceFd, srcfilename);
+ filepump.Start();
+
+ sleep(1);
+
+ if(ioctl(gDeviceFd, 100, 0)) {
+ RETURN_ERR_502("Fail to start transcoding.");
+ }
+ eNetworkPumpThread networkpump(gDeviceFd);
+ networkpump.Start();
+
+ networkpump.Join();
+ filepump.Stop();
+ filepump.Join();
+
+ close(gDeviceFd);
+
+#ifdef DEBUG_LOG
+ fclose(fpLog);
+#endif
+ return 0;
+}
+//-------------------------------------------------------------------------------
+
+std::vector<string> eParser::Split(std::string aBuffer, char aDelimiter)
+{
+ int b = 0, i = 0, l = aBuffer.length();
+ std::vector<string> t;
+
+ while (i++ < l) {
+ if (aBuffer[i] == aDelimiter) {
+ t.push_back(aBuffer.substr(b, i-b));
+ b = i + 1;
+ continue;
+ }
+ if (i == (l - 1)) {
+ t.push_back(aBuffer.substr(b, l));
+ }
+ }
+ return t;
+}
+//-------------------------------------------------------------------------------
+
+void eParser::FileName(char* aRequest, char* aHttp, std::string& aOutData)
+{
+ char tmp[256] = {0};
+ char* file = aRequest + 5;
+ if (strncmp(file, "file?file=", strlen("file?file="))) {
+ return;
+ }
+ strncpy(tmp, file+10, aHttp-file-10);
+ aOutData = eURIDecoder().Decode(tmp);
+}
+//-------------------------------------------------------------------------------
+
+/* f:40,c:00007b,c:01008f,c:03007b */
+bool eParser::MetaData(std::string aMediaFileName)
+{
+ std::string metafilename = aMediaFileName;
+ metafilename += ".meta";
+
+ std::ifstream ifs(metafilename.c_str());
+
+ if (!ifs.is_open()) {
+#ifdef DEBUG_LOG
+ LOG("metadata is not exists..");
+#endif
+ return false;
+ }
+
+ size_t rc = 0, i = 0;
+ char buffer[1024] = {0};
+ while (!ifs.eof()) {
+ ifs.getline(buffer, 1024);
+ if (i++ == 7) {
+#ifdef DEBUG_LOG
+ LOG("%d [%s]", i, buffer);
+#endif
+ std::vector<string> tokens = eParser::Split(buffer, ',');
+ if(tokens.size() < 3) {
+#ifdef DEBUG_LOG
+ LOG("pid count size error : %d", tokens.size());
+#endif
+ return false;
+ }
+
+ for (int ii = 0; ii < tokens.size(); ++ii) {
+ std::string token = tokens[ii];
+#ifdef DEBUG_LOG
+ LOG("token : %d [%s]", ii, token.c_str());
+#endif
+ switch(ii) {
+ case(1):
+ gVideoPid = strtol(token.substr(4,8).c_str(), NULL, 16);
+#ifdef DEBUG_LOG
+ LOG("video pid : %d", gVideoPid);
+#endif
+ break;
+ case(2):
+ gAudioPid = strtol(token.substr(4,8).c_str(), NULL, 16);
+#ifdef DEBUG_LOG
+
+ LOG("audio pid : %d", gAudioPid);
+#endif
+ break;
+ }
+ }
+ break;
+ }
+ }
+ ifs.close();
+ return true;
+}
+//-------------------------------------------------------------------------------
+
+
diff --git a/src/uThread.cpp b/src/uThread.cpp
new file mode 100644
index 0000000..6a7a4a5
--- /dev/null
+++ b/src/uThread.cpp
@@ -0,0 +1,156 @@
+/*
+ * uThread.cpp
+ *
+ * Created on: 2013. 9. 10.
+ * Author: kos
+ */
+
+#include "uThread.h"
+
+#include <stdio.h>
+#include <pthread.h>
+
+//#include "uLogger.h"
+
+using namespace std;
+//-------------------------------------------------------------------------------
+
+uThread::uThread(std::string aName, uThread::EXIT_TYPE aExitType)
+ : mTid(0), mState(uThread::STATE_READY), mExitType(aExitType), mName(aName)
+{
+}
+//-------------------------------------------------------------------------------
+
+uThread::~uThread()
+{
+ if(mState == uThread::STATE_ZOMBIE) {
+ Join(mTid);
+ }
+}
+//-------------------------------------------------------------------------------
+
+bool uThread::Start()
+{
+#ifdef SUPPORT_PTHREAD_ATTR
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ if(mExitType == uThread::TYPE_JOINABLE) {
+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
+ } else {
+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+ }
+#endif /* SUPPORT_PTHREAD_ATTR */
+ if(pthread_create(&mTid, NULL, ThreadMain, reinterpret_cast<void *>(this)) == 0) {
+#ifndef SUPPORT_PTHREAD_ATTR
+ if(mExitType == uThread::TYPE_DETACHABLE) {
+ pthread_detach(mTid);
+ }
+#endif /* !SUPPORT_PTHREAD_ATTR */
+ } else {
+ SetState(uThread::STATE_ABORTED);
+#ifdef SUPPORT_PTHREAD_ATTR
+ pthread_attr_destroy(&attr);
+#endif /* SUPPORT_PTHREAD_ATTR */
+ return false;
+ }
+ //cout << mTid << endl;
+#ifdef SUPPORT_PTHREAD_ATTR
+ pthread_attr_destroy(&attr);
+#endif /* SUPPORT_PTHREAD_ATTR */
+ return true;
+}
+//-------------------------------------------------------------------------------
+
+void* uThread::ThreadMain(void* aParam)
+{
+ uThread* thiz = reinterpret_cast<uThread*>(aParam);
+
+ std::string threadName = thiz->GetName();
+ //INFO("start thread...[%s]", threadName.c_str());
+
+ thiz->SetState(uThread::STATE_RUNNING);
+ thiz->Run();
+
+ if(thiz->GetExitType() == uThread::TYPE_DETACHABLE)
+ thiz->SetState(uThread::STATE_TERMINATED);
+ else thiz->SetState(uThread::STATE_ZOMBIE);
+
+ pthread_exit((void*)0);
+
+ //INFO("terminated thread...[%s]", threadName.c_str());
+ return NULL;
+}
+//-------------------------------------------------------------------------------
+
+void uThread::Stop()
+{
+ switch(mState) {
+ case uThread::STATE_RUNNING: {
+ switch(mExitType) {
+ case uThread::TYPE_DETACHABLE: {
+ Terminate();
+ } break;
+ case uThread::TYPE_JOINABLE: {
+ Terminate();
+ Join(mTid);
+ } break;
+ }
+ } break;
+ case uThread::STATE_ZOMBIE: {
+ Join(mTid);
+ } break;
+ }
+}
+//-------------------------------------------------------------------------------
+
+bool uThread::Join(pthread_t aTid)
+{
+ if (!pthread_join(aTid, NULL)) {
+ SetState(uThread::STATE_TERMINATED);
+ return true;
+ }
+ return false;
+}
+//-------------------------------------------------------------------------------
+
+void uThread::SetState(uThread::STATE aState)
+{
+ mState = aState;
+}
+//-------------------------------------------------------------------------------
+
+uThread::STATE uThread::GetState() const
+{
+ return mState;
+}
+//-------------------------------------------------------------------------------
+
+uThread::EXIT_TYPE uThread::GetExitType() const
+{
+ return mExitType;
+}
+//-------------------------------------------------------------------------------
+
+std::string uThread::GetName() const
+{
+ return mName;
+}
+//-------------------------------------------------------------------------------
+
+bool uThread::IsTerminated() const
+{
+ return (mState == uThread::STATE_TERMINATED) ? true : false;
+}
+//-------------------------------------------------------------------------------
+
+bool uThread::IsRunning() const
+{
+ return mState == uThread::STATE_RUNNING ? true : false;
+}
+//-------------------------------------------------------------------------------
+
+bool uThread::Join()
+{
+ return Join(mTid);
+}
+//-------------------------------------------------------------------------------
diff --git a/src/uThread.h b/src/uThread.h
new file mode 100644
index 0000000..a9cc5df
--- /dev/null
+++ b/src/uThread.h
@@ -0,0 +1,66 @@
+/*
+ * uThread.h
+ *
+ * Created on: 2013. 9. 10.
+ * Author: kos
+ */
+
+#ifndef UTHREAD_H_
+#define UTHREAD_H_
+
+#include <string>
+#include <pthread.h>
+//-------------------------------------------------------------------------------
+
+class uThread
+{
+public:
+ enum STATE {
+ STATE_READY = 0,
+ STATE_RUNNING,
+ STATE_TERMINATED,
+ STATE_ZOMBIE,
+ STATE_ABORTED
+ };
+ enum EXIT_TYPE {
+ TYPE_JOINABLE = 0,
+ TYPE_DETACHABLE
+ };
+private:
+ uThread(const uThread&);
+ uThread& operator=(const uThread&);
+
+ uThread::STATE mState;
+ uThread::EXIT_TYPE mExitType;
+protected:
+ pthread_t mTid;
+ std::string mName;
+
+ static void* ThreadMain(void *aParam);
+
+ virtual void Run() = 0;
+ virtual void Terminate() = 0;
+
+ bool Join(pthread_t aTid);
+ void SetState(STATE aState);
+
+ void SetName(std::string aName) { mName = aName; }
+public:
+ uThread(std::string aName="", uThread::EXIT_TYPE aExitType=uThread::TYPE_JOINABLE);
+ virtual ~uThread();
+
+ void Stop();
+ bool Start();
+
+ pthread_t GetTid() { return mTid; }
+ uThread::STATE GetState() const;
+ uThread::EXIT_TYPE GetExitType() const;
+ std::string GetName() const;
+
+ bool IsTerminated() const;
+ bool IsRunning() const;
+ bool Join();
+};
+//-------------------------------------------------------------------------------
+
+#endif /* UTHREAD_H_ */