1 /*****************************************************************
2 |
3 | Platinum - Frame Streamer
4 |
5 | Copyright (c) 2004-2010, Plutinosoft, LLC.
6 | All rights reserved.
7 | http://www.plutinosoft.com
8 |
9 | This program is free software; you can redistribute it and/or
10 | modify it under the terms of the GNU General Public License
11 | as published by the Free Software Foundation; either version 2
12 | of the License, or (at your option) any later version.
13 |
14 | OEMs, ISVs, VARs and other distributors that combine and
15 | distribute commercially licensed software with Platinum software
16 | and do not wish to distribute the source code for the commercially
17 | licensed software under version 2, or (at your option) any later
18 | version, of the GNU General Public License (the "GPL") must enter
19 | into a commercial license agreement with Plutinosoft, LLC.
20 | licensing@plutinosoft.com
21 |
22 | This program is distributed in the hope that it will be useful,
23 | but WITHOUT ANY WARRANTY; without even the implied warranty of
24 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 | GNU General Public License for more details.
26 |
27 | You should have received a copy of the GNU General Public License
28 | along with this program; see the file LICENSE.txt. If not, write to
29 | the Free Software Foundation, Inc.,
30 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
31 | http://www.gnu.org/licenses/gpl-2.0.html
32 |
33 ****************************************************************/
34
35 /*----------------------------------------------------------------------
36 | includes
37 +---------------------------------------------------------------------*/
38 #include "Platinum.h"
39 #include "PltFrameBuffer.h"
40 #include "PltFrameStream.h"
41 #include "PltFrameServer.h"
42
43 #include <stdlib.h>
44
45 NPT_SET_LOCAL_LOGGER("platinum.core.framestreamer")
46
47 /*----------------------------------------------------------------------
48 | globals
49 +---------------------------------------------------------------------*/
50 struct Options {
51 const char* path;
52 } Options;
53
54 /*----------------------------------------------------------------------
55 | StreamValidator:
56 +---------------------------------------------------------------------*/
57 class StreamValidator : public PLT_StreamValidator
58 {
59 public:
StreamValidator(NPT_Reference<PLT_FrameBuffer> & buffer)60 StreamValidator(NPT_Reference<PLT_FrameBuffer>& buffer) : m_Buffer(buffer) {}
~StreamValidator()61 virtual ~StreamValidator() {}
62
63 // PLT_StreamValidator methods
OnNewRequestAccept(const NPT_HttpRequest & request,const NPT_HttpRequestContext & context,NPT_HttpResponse & response,NPT_Reference<PLT_FrameBuffer> & buffer)64 bool OnNewRequestAccept(const NPT_HttpRequest& request,
65 const NPT_HttpRequestContext& context,
66 NPT_HttpResponse& response,
67 NPT_Reference<PLT_FrameBuffer>& buffer) {
68 NPT_COMPILER_UNUSED(request);
69 NPT_COMPILER_UNUSED(response);
70 NPT_COMPILER_UNUSED(context);
71 // TODO: should compare HTTP Header Accept and buffer mimetype
72 buffer = m_Buffer;
73 return true;
74 }
75
76 NPT_Reference<PLT_FrameBuffer> m_Buffer;
77 };
78
79 /*----------------------------------------------------------------------
80 | FrameWriter
81 +---------------------------------------------------------------------*/
82 class FrameWriter : public NPT_Thread
83 {
84 public:
FrameWriter(NPT_Reference<PLT_FrameBuffer> & frame_buffer,const char * frame_folder)85 FrameWriter(NPT_Reference<PLT_FrameBuffer>& frame_buffer,
86 const char* frame_folder) :
87 m_FrameBuffer(frame_buffer),
88 m_Aborted(false),
89 m_Folder(frame_folder)
90 {}
91
GetPath(NPT_List<NPT_String>::Iterator & entry)92 const char* GetPath(NPT_List<NPT_String>::Iterator& entry) {
93 if (!entry) return NULL;
94
95 if (!entry->EndsWith(".jpg", true)) {
96 return GetPath(++entry);
97 }
98
99 return *entry;
100 }
101
Run()102 void Run() {
103 NPT_List<NPT_String> entries;
104 const char* frame_path = NULL;
105 NPT_DataBuffer frame;
106 NPT_List<NPT_String>::Iterator entry;
107
108 while (!m_Aborted) {
109 // has number of images changed since last time?
110 NPT_LargeSize count;
111 NPT_File::GetSize(m_Folder, count);
112
113 if (entries.GetItemCount() == 0 || entries.GetItemCount() != count) {
114 NPT_File::ListDir(m_Folder, entries);
115 entry = entries.GetFirstItem();
116 if (!entry) {
117 // Wait a bit before continuing
118 NPT_System::Sleep(NPT_TimeInterval(0.2f));
119 continue;
120 }
121
122 // set delay based on number of files if necessary
123 m_Delay = NPT_TimeInterval((float)1.f/entries.GetItemCount());
124 }
125
126 // look for path to next image
127 if (!(frame_path = GetPath(entry))) {
128 // loop back if necessary
129 entry = entries.GetFirstItem();
130 continue;
131 }
132
133 if (NPT_FAILED(NPT_File::Load(NPT_FilePath::Create(m_Folder, frame_path), frame))) {
134 NPT_LOG_SEVERE_1("Image \"%s\" not found!", frame_path?frame_path:"none");
135 // clear previously loaded names so we reload entire set
136 entries.Clear();
137 continue;
138 }
139
140 if (NPT_FAILED(m_FrameBuffer->SetNextFrame(frame.GetData(),
141 frame.GetDataSize()))) {
142 NPT_LOG_SEVERE_1("Failed to set next frame %s", frame_path);
143 goto failure;
144 }
145
146 // Wait before loading next frame
147 NPT_System::Sleep(m_Delay);
148
149 // look for next entry
150 ++entry;
151 }
152
153 failure:
154 // one more time to unblock any pending readers
155 m_FrameBuffer->Abort();
156 }
157
158 NPT_Reference<PLT_FrameBuffer> m_FrameBuffer;
159 bool m_Aborted;
160 NPT_String m_Folder;
161 NPT_TimeInterval m_Delay;
162 };
163
164 /*----------------------------------------------------------------------
165 | PrintUsageAndExit
166 +---------------------------------------------------------------------*/
167 static void
PrintUsageAndExit(char ** args)168 PrintUsageAndExit(char** args)
169 {
170 fprintf(stderr, "usage: %s <images path>\n", args[0]);
171 fprintf(stderr, "<path> : local path to serve images from\n");
172 exit(1);
173 }
174
175 /*----------------------------------------------------------------------
176 | ParseCommandLine
177 +---------------------------------------------------------------------*/
178 static void
ParseCommandLine(char ** args)179 ParseCommandLine(char** args)
180 {
181 char** _args = args++;
182 const char* arg;
183
184 /* default values */
185 Options.path = NULL;
186
187 while ((arg = *args++)) {
188 if (Options.path == NULL) {
189 Options.path = arg;
190 } else {
191 fprintf(stderr, "ERROR: too many arguments\n");
192 PrintUsageAndExit(_args);
193 }
194 }
195
196 /* check args */
197 if (Options.path == NULL) {
198 fprintf(stderr, "ERROR: path missing\n");
199 PrintUsageAndExit(_args);
200 }
201 }
202
203 /*----------------------------------------------------------------------
204 | main
205 +---------------------------------------------------------------------*/
206 int
main(int argc,char ** argv)207 main(int argc, char** argv)
208 {
209 NPT_COMPILER_UNUSED(argc);
210
211 /* parse command line */
212 ParseCommandLine(argv);
213
214 // frame buffer
215 NPT_Reference<PLT_FrameBuffer> frame_buffer(new PLT_FrameBuffer("image/jpeg"));
216
217 // A Framewriter reading images from a folder and writing them
218 // into frame buffer in a loop
219 FrameWriter writer(frame_buffer, Options.path);
220 writer.Start();
221
222 // stream request validation
223 StreamValidator validator(frame_buffer);
224
225 // frame server receiving requests and serving frames
226 // read from frame buffer
227 NPT_Reference<PLT_FrameServer> device(
228 new PLT_FrameServer(
229 "frame",
230 validator,
231 NPT_IpAddress::Any,
232 8099));
233
234 if (NPT_FAILED(device->Start()))
235 return 1;
236
237 char buf[256];
238 while (true) {
239 fgets(buf, 256, stdin);
240 if (*buf == 'q')
241 break;
242 }
243
244 writer.m_Aborted = true;
245
246 return 0;
247 }
248