1 /*
2  * H.264 Plugin codec for OpenH323/OPAL
3  *
4  * Copyright (C) 2007 Matthias Schneider, All Rights Reserved
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
19  *
20  */
21 
22 #include "plugin-config.h"
23 
24 #include "shared/pipes.h"
25 #include "enc-ctx.h"
26 #include <sys/stat.h>
27 #include <fstream>
28 #include "trace.h"
29 #include <stdlib.h>
30 
31 #ifndef X264_LINK_STATIC
32 #include "x264loader_unix.h"
33 #endif
34 
35 std::ifstream dlStream;
36 std::ofstream ulStream;
37 
38 unsigned msg;
39 unsigned val;
40 
41 unsigned srcLen = 0;
42 unsigned dstLen = 0;
43 unsigned headerLen;
44 unsigned frameBufferSize = 0;
45 unsigned char * src = NULL;
46 unsigned char * dst  = NULL;
47 unsigned flags;
48 int ret;
49 
50 X264EncoderContext* x264;
51 
52 #ifndef X264_LINK_STATIC
53 extern X264Library X264Lib;
54 #endif
55 
closeAndExit()56 void closeAndExit()
57 {
58   dlStream.close();
59   ulStream.close();
60   exit(1);
61 }
62 
writeStream(std::ofstream & stream,const char * data,unsigned bytes)63 void writeStream (std::ofstream & stream, const char* data, unsigned bytes)
64 {
65   stream.write(data, bytes);
66   if (stream.bad())  { TRACE (1, "H264\tIPC\tCP: Bad flag set on writing - terminating"); closeAndExit(); }
67 }
68 
readStream(std::ifstream & stream,char * data,unsigned bytes)69 void readStream (std::ifstream & stream, char* data, unsigned bytes)
70 {
71   stream.read(data, bytes);
72   if (stream.fail()) { TRACE (1, "H264\tIPC\tCP: Terminating");                           closeAndExit(); }
73   if (stream.bad())  { TRACE (1, "H264\tIPC\tCP: Bad flag set on reading - terminating"); closeAndExit(); }
74   if (stream.eof())  { TRACE (1, "H264\tIPC\tCP: Received EOF - terminating");            closeAndExit(); }
75 }
76 
flushStream(std::ofstream & stream)77 void flushStream (std::ofstream & stream)
78 {
79   stream.flush();
80   if (stream.bad())  { TRACE (1, "H264\tIPC\tCP: Bad flag set on flushing - terminating"); closeAndExit(); }
81 }
82 
83 
main(int argc,char * argv[])84 int main(int argc, char *argv[])
85 {
86   unsigned status;
87   if (argc != 3) { fprintf(stderr, "Not to be executed directly - exiting\n"); exit (1); }
88 
89   char * debug_level = getenv ("PTLIB_TRACE_CODECS");
90   if (debug_level!=NULL) {
91       Trace::SetLevel(atoi(debug_level));
92   }
93   else {
94     Trace::SetLevel(0);
95   }
96 
97   debug_level = getenv ("PTLIB_TRACE_CODECS_USER_PLANE");
98   if (debug_level!=NULL) {
99       Trace::SetLevelUserPlane(atoi(debug_level));
100   }
101   else {
102     Trace::SetLevelUserPlane(0);
103   }
104 
105   x264 = NULL;
106   dstLen = 1400;
107   dlStream.open(argv[1], std::ios::binary);
108   if (dlStream.fail()) { TRACE (1, "H264\tIPC\tCP: Error when opening DL named pipe"); exit (1); }
109   ulStream.open(argv[2],std::ios::binary);
110   if (ulStream.fail()) { TRACE (1, "H264\tIPC\tCP: Error when opening UL named pipe"); exit (1); }
111 
112 #ifndef X264_LINK_STATIC
113   if (X264Lib.Load())
114     status = 1;
115   else
116     status = 0;
117 #else
118   status = 1;
119 #endif
120 
121   readStream(dlStream, (char*)&msg, sizeof(msg));
122   writeStream(ulStream,(char*)&msg, sizeof(msg));
123   writeStream(ulStream,(char*)&status, sizeof(status));
124   flushStream(ulStream);
125 
126   if (status == 0) {
127     TRACE (1, "H264\tIPC\tCP: Failed to load dynamic library - exiting");
128     closeAndExit();
129   }
130 
131   while (1) {
132     readStream(dlStream, (char*)&msg, sizeof(msg));
133 
134   switch (msg) {
135     case H264ENCODERCONTEXT_CREATE:
136         x264 = new X264EncoderContext();
137         writeStream(ulStream,(char*)&msg, sizeof(msg));
138         flushStream(ulStream);
139       break;
140     case H264ENCODERCONTEXT_DELETE:
141         delete x264;
142         x264 = NULL;
143         writeStream(ulStream,(char*)&msg, sizeof(msg));
144         flushStream(ulStream);
145       break;
146     case APPLY_OPTIONS:
147         if (x264) {
148           x264->ApplyOptions ();
149           writeStream(ulStream,(char*)&msg, sizeof(msg));
150           flushStream(ulStream);
151         } else {
152           TRACE (1, "H264\tIPC\tCodec not created, yet");
153         }
154       break;
155     case SET_TARGET_BITRATE:
156         readStream(dlStream, (char*)&val, sizeof(val));
157         if (x264) {
158           x264->SetTargetBitrate (val);
159           writeStream(ulStream,(char*)&msg, sizeof(msg));
160           flushStream(ulStream);
161         } else {
162           TRACE (1, "H264\tIPC\tCodec not created, yet");
163         }
164       break;
165     case SET_FRAME_RATE:
166         readStream(dlStream, (char*)&val, sizeof(val));
167         if (x264) {
168           x264->SetFrameRate (val);
169           writeStream(ulStream,(char*)&msg, sizeof(msg));
170           flushStream(ulStream);
171         } else {
172           TRACE (1, "H264\tIPC\tCodec not created, yet");
173         }
174       break;
175     case SET_FRAME_WIDTH:
176         readStream(dlStream, (char*)&val, sizeof(val));
177         if (x264) {
178           x264->SetFrameWidth (val);
179           writeStream(ulStream,(char*)&msg, sizeof(msg));
180           flushStream(ulStream);
181         } else {
182           TRACE (1, "H264\tIPC\tCodec not created, yet");
183         }
184       break;
185     case SET_FRAME_HEIGHT:
186         readStream(dlStream, (char*)&val, sizeof(val));
187         if (x264) {
188           x264->SetFrameHeight (val);
189           writeStream(ulStream,(char*)&msg, sizeof(msg));
190           flushStream(ulStream);
191         } else {
192           TRACE (1, "H264\tIPC\tCodec not created, yet");
193         }
194       break;
195     case SET_MAX_KEY_FRAME_PERIOD:
196         readStream(dlStream, (char*)&val, sizeof(val));
197         if (x264) {
198           x264->SetMaxKeyFramePeriod (val);
199           writeStream(ulStream,(char*)&msg, sizeof(msg));
200           flushStream(ulStream);
201         } else {
202           TRACE (1, "H264\tIPC\tCodec not created, yet");
203         }
204       break;
205     case SET_TSTO:
206         readStream(dlStream, (char*)&val, sizeof(val));
207         if (x264) {
208           x264->SetTSTO (val);
209           writeStream(ulStream,(char*)&msg, sizeof(msg));
210           flushStream(ulStream);
211         } else {
212           TRACE (1, "H264\tIPC\tCodec not created, yet");
213         }
214       break;
215     case SET_PROFILE_LEVEL:
216         readStream(dlStream, (char*)&val, sizeof(val));
217         if (x264) {
218           x264->SetProfileLevel (val);
219           writeStream(ulStream,(char*)&msg, sizeof(msg));
220           flushStream(ulStream);
221         } else {
222           TRACE (1, "H264\tIPC\tCodec not created, yet");
223         }
224       break;
225     case ENCODE_FRAMES:
226         readStream(dlStream, (char*)&srcLen, sizeof(srcLen));
227 		if (srcLen > frameBufferSize) {
228           // only grow, never shrink, memory isn't given back to OS anyway
229           TRACE (1, "H264\tIPC\tGrowing frame buffer to " << srcLen);
230           free(src);
231           free(dst);
232           frameBufferSize = srcLen;
233           src = (unsigned char*)malloc(frameBufferSize);
234           dst = (unsigned char*)malloc(frameBufferSize);
235         }
236         readStream(dlStream, (char*)src, srcLen);
237         readStream(dlStream, (char*)&headerLen, sizeof(headerLen));
238         readStream(dlStream, (char*)dst, headerLen);
239         readStream(dlStream, (char*)&flags, sizeof(flags));
240         // fall through intended
241     case ENCODE_FRAMES_BUFFERED:
242         if (x264) {
243           ret = (x264->EncodeFrames( src,  srcLen, dst, dstLen, flags));
244           writeStream(ulStream,(char*)&msg, sizeof(msg));
245           writeStream(ulStream,(char*)&dstLen, sizeof(dstLen));
246           writeStream(ulStream,(char*)dst, dstLen);
247           writeStream(ulStream,(char*)&flags, sizeof(flags));
248           writeStream(ulStream,(char*)&ret, sizeof(ret));
249           flushStream(ulStream);
250         } else {
251           TRACE (1, "H264\tIPC\tCodec not created, yet");
252         }
253       break;
254     case SET_MAX_FRAME_SIZE:
255         readStream(dlStream, (char*)&val, sizeof(val));
256         if (x264) {
257           x264->SetMaxRTPFrameSize (val);
258           writeStream(ulStream,(char*)&msg, sizeof(msg));
259            flushStream(ulStream);
260         } else {
261           TRACE (1, "H264\tIPC\tCodec not created, yet");
262         }
263       break;
264     case FASTUPDATE_REQUESTED:
265         if (x264) {
266           x264->fastUpdateRequested();
267           writeStream(ulStream,(char*)&msg, sizeof(msg));
268           flushStream(ulStream);
269         } else {
270           TRACE (1, "H264\tIPC\tCodec not created, yet");
271         }
272       break;
273 	case SET_MAX_NALSIZE:
274         readStream(dlStream, (char*)&val, sizeof(val));
275         if (x264) {
276           x264->SetMaxNALSize (val);
277           writeStream(ulStream,(char*)&msg, sizeof(msg));
278           flushStream(ulStream);
279         } else {
280           TRACE (1, "H264\tIPC\tCodec not created, yet");
281         }
282       break;
283 	default:
284       break;
285     }
286   }
287   return 0;
288 }
289