1 /*
2 * Copyright (C) 2004 Nathan Lutchansky <lutchann@litech.org>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software Foundation,
16 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 */
18
19 #include <sys/types.h>
20 #include <stdlib.h>
21 #include <stdio.h>
22 #include <unistd.h>
23 #include <string.h>
24 #include <fcntl.h>
25 #include <pthread.h>
26
27 #include <xvid.h>
28
29 #include <event.h>
30 #include <log.h>
31 #include <frame.h>
32 #include <stream.h>
33 #include <encoders.h>
34 #include <conf_parse.h>
35
36 struct mpeg4_encoder {
37 struct stream *output;
38 struct stream_destination *input;
39 struct frame_exchanger *ex;
40 pthread_t encoding_thread;
41 int running; /* only used by the main thread */
42
43 /* parameters from the config file */
44 int bitrate;
45
46 /* reset_pending is used to indicate that there may have been a long
47 * break since the last frame, presumably because nobody was listening
48 * and the source stopped sending us frames, so the encoding thread
49 * should reset the encoder. It doesn't really need synchronization
50 * because if we reset in the middle of a bunch of contiguous frames
51 * it's not the end of the world. */
52 int reset_pending;
53
54 /* All the parameters after the handle indicate the settings used
55 * to set up the current encoder. Therefore, they are invalid
56 * when xvid_handle == NULL. */
57 void *xvid_handle;
58 int width;
59 int height;
60 };
61
mpeg4_start(struct mpeg4_encoder * en,struct frame * f)62 static void mpeg4_start( struct mpeg4_encoder *en, struct frame *f )
63 {
64 xvid_enc_create_t xvid_enc_create;
65 xvid_enc_plugin_t plugins[1];
66 xvid_plugin_single_t single;
67
68 en->reset_pending = 0;
69 en->width = f->width;
70 en->height = f->height;
71
72 memset( &xvid_enc_create, 0, sizeof( xvid_enc_create ) );
73 xvid_enc_create.version = XVID_VERSION;
74 xvid_enc_create.width = en->width;
75 xvid_enc_create.height = en->height;
76 xvid_enc_create.profile = XVID_PROFILE_ARTS_L4;
77 en->input->stream->get_framerate( en->input->stream,
78 &xvid_enc_create.fincr,
79 &xvid_enc_create.fbase );
80 spook_log( SL_DEBUG, "creating mpeg4 encoder with fincr=%d fbase=%d",
81 xvid_enc_create.fincr, xvid_enc_create.fbase );
82 xvid_enc_create.zones = NULL;
83 xvid_enc_create.num_zones = 0;
84 xvid_enc_create.plugins = plugins;
85 xvid_enc_create.num_plugins = 1;
86 xvid_enc_create.num_threads = 0;
87 xvid_enc_create.max_key_interval = 300;
88 xvid_enc_create.max_bframes = 0;
89 xvid_enc_create.bquant_ratio = 150;
90 xvid_enc_create.bquant_offset = 100;
91 xvid_enc_create.frame_drop_ratio = 0;
92 xvid_enc_create.global = 0;
93
94 memset( &single, 0, sizeof( single ) );
95 single.version = XVID_VERSION;
96 single.bitrate = en->bitrate * 1000;
97 plugins[0].func = xvid_plugin_single;
98 plugins[0].param = &single;
99
100 if( xvid_encore( NULL, XVID_ENC_CREATE,
101 &xvid_enc_create, NULL ) )
102 {
103 spook_log( SL_ERR, "mpeg4: unable to start XviD!" );
104 return;
105 }
106
107 en->xvid_handle = xvid_enc_create.handle;
108 }
109
mpeg4_stop(struct mpeg4_encoder * en)110 static void mpeg4_stop( struct mpeg4_encoder *en )
111 {
112 spook_log( SL_DEBUG, "mpeg4: destroying mpeg4 encoder" );
113
114 xvid_encore( en->xvid_handle, XVID_ENC_DESTROY, NULL, NULL );
115 en->xvid_handle = NULL;
116 }
117
mpeg4_loop(void * d)118 static void *mpeg4_loop( void *d )
119 {
120 struct mpeg4_encoder *en = (struct mpeg4_encoder *)d;
121 xvid_enc_frame_t xvid_enc_frame;
122 struct frame *mpeg, *input;
123
124 for(;;)
125 {
126 input = get_next_frame( en->ex, 1 );
127
128 if( en->reset_pending && en->xvid_handle ) mpeg4_stop( en );
129 if( ! en->xvid_handle ) mpeg4_start( en, input );
130
131 if( input->width != en->width || input->height != en->height )
132 {
133 spook_log( SL_WARN,
134 "mpeg4: image size changed midstream!" );
135 unref_frame( input );
136 continue;
137 }
138
139 mpeg = new_frame();
140
141 memset( &xvid_enc_frame, 0, sizeof( xvid_enc_frame ) );
142 xvid_enc_frame.version = XVID_VERSION;
143 xvid_enc_frame.bitstream = mpeg->d;
144 xvid_enc_frame.length = -1;
145 xvid_enc_frame.input.plane[0] = input->d;
146 switch( input->format )
147 {
148 case FORMAT_RAW_BGR24:
149 xvid_enc_frame.input.csp = XVID_CSP_BGR;
150 xvid_enc_frame.input.stride[0] = en->width * 3;
151 break;
152 case FORMAT_RAW_UYVY:
153 xvid_enc_frame.input.csp = XVID_CSP_UYVY;
154 xvid_enc_frame.input.stride[0] = en->width * 2;
155 break;
156 }
157 xvid_enc_frame.vol_flags = 0;
158 xvid_enc_frame.vop_flags = 0;
159 xvid_enc_frame.type = XVID_TYPE_AUTO;
160 xvid_enc_frame.quant = 0;
161 xvid_enc_frame.motion = XVID_ME_ADVANCEDDIAMOND16;
162 xvid_enc_frame.quant_intra_matrix = NULL;
163 xvid_enc_frame.quant_inter_matrix = NULL;
164
165 mpeg->length = xvid_encore( en->xvid_handle, XVID_ENC_ENCODE,
166 &xvid_enc_frame, NULL );
167 if( mpeg->length < 0 )
168 {
169 mpeg->length = 0;
170 spook_log( SL_WARN, "mpeg4: XviD encoding failed!" );
171 }
172
173 mpeg->format = FORMAT_MPEG4;
174 mpeg->width = en->width;
175 mpeg->height = en->height;
176 mpeg->key = xvid_enc_frame.out_flags & XVID_KEYFRAME;
177
178 deliver_frame( en->ex, mpeg );
179
180 unref_frame( input );
181 }
182
183 return NULL;
184 }
185
mpeg4_encode(struct frame * input,void * d)186 static void mpeg4_encode( struct frame *input, void *d )
187 {
188 struct mpeg4_encoder *en = (struct mpeg4_encoder *)d;
189
190 exchange_frame( en->ex, input );
191 }
192
get_framerate(struct stream * s,int * fincr,int * fbase)193 static void get_framerate( struct stream *s, int *fincr, int *fbase )
194 {
195 struct mpeg4_encoder *en = (struct mpeg4_encoder *)s->private;
196
197 en->input->stream->get_framerate( en->input->stream, fincr, fbase );
198 }
199
set_running(struct stream * s,int running)200 static void set_running( struct stream *s, int running )
201 {
202 struct mpeg4_encoder *en = (struct mpeg4_encoder *)s->private;
203
204 spook_log( SL_DEBUG,
205 "mpeg4 encoder is told to set running to %d", running );
206
207 if( ! en->running && running ) en->reset_pending = 1;
208 set_waiting( en->input, running );
209 en->running = running;
210 }
211
212 /************************ CONFIGURATION DIRECTIVES ************************/
213
start_block(void)214 static void *start_block(void)
215 {
216 struct mpeg4_encoder *en;
217
218 en = (struct mpeg4_encoder *)malloc( sizeof( struct mpeg4_encoder ) );
219 en->output = NULL;
220 en->xvid_handle = NULL;
221 en->bitrate = -1;
222
223 return en;
224 }
225
end_block(void * d)226 static int end_block( void *d )
227 {
228 struct mpeg4_encoder *en = (struct mpeg4_encoder *)d;
229
230 if( ! en->output )
231 {
232 spook_log( SL_ERR, "mpeg4: missing output stream name" );
233 return -1;
234 }
235 if( ! en->input )
236 {
237 spook_log( SL_ERR, "mpeg4: missing input stream name" );
238 return -1;
239 }
240 if( en->bitrate < 0 )
241 {
242 spook_log( SL_ERR, "mpeg4: bitrate must be specified" );
243 return -1;
244 }
245
246 en->ex = new_exchanger( 8, deliver_frame_to_stream, en->output );
247 pthread_create( &en->encoding_thread, NULL, mpeg4_loop, en );
248
249 return 0;
250 }
251
set_input(int num_tokens,struct token * tokens,void * d)252 static int set_input( int num_tokens, struct token *tokens, void *d )
253 {
254 struct mpeg4_encoder *en = (struct mpeg4_encoder *)d;
255 int formats[2] = { FORMAT_RAW_UYVY, FORMAT_RAW_BGR24 };
256
257 if( ! ( en->input = connect_to_stream( tokens[1].v.str, mpeg4_encode,
258 en, formats, 2 ) ) )
259 {
260 spook_log( SL_ERR, "mpeg4: unable to connect to stream \"%s\"",
261 tokens[1].v.str );
262 return -1;
263 }
264 return 0;
265 }
266
set_output(int num_tokens,struct token * tokens,void * d)267 static int set_output( int num_tokens, struct token *tokens, void *d )
268 {
269 struct mpeg4_encoder *en = (struct mpeg4_encoder *)d;
270
271 en->output = new_stream( tokens[1].v.str, FORMAT_MPEG4, en );
272 if( ! en->output )
273 {
274 spook_log( SL_ERR, "mpeg4: unable to create stream \"%s\"",
275 tokens[1].v.str );
276 return -1;
277 }
278 en->output->get_framerate = get_framerate;
279 en->output->set_running = set_running;
280 return 0;
281 }
282
set_bitrate(int num_tokens,struct token * tokens,void * d)283 static int set_bitrate( int num_tokens, struct token *tokens, void *d )
284 {
285 struct mpeg4_encoder *en = (struct mpeg4_encoder *)d;
286
287 if( tokens[1].v.num < 10 || tokens[1].v.num > 4000 )
288 {
289 spook_log( SL_ERR,
290 "mpeg4: bitrate must be between 10 and 4000" );
291 return -1;
292 }
293 en->bitrate = tokens[1].v.num;
294 return 0;
295 }
296
297 static struct statement config_statements[] = {
298 /* directive name, process function, min args, max args, arg types */
299 { "input", set_input, 1, 1, { TOKEN_STR } },
300 { "output", set_output, 1, 1, { TOKEN_STR } },
301 { "bitrate", set_bitrate, 1, 1, { TOKEN_NUM } },
302
303 /* empty terminator -- do not remove */
304 { NULL, NULL, 0, 0, {} }
305 };
306
mpeg4_init(void)307 int mpeg4_init(void)
308 {
309 xvid_gbl_init_t xvid_gbl_init;
310
311 memset( &xvid_gbl_init, 0, sizeof( xvid_gbl_init ) );
312 xvid_gbl_init.version = XVID_VERSION;
313 xvid_global( NULL, XVID_GBL_INIT, &xvid_gbl_init, NULL );
314 register_config_context( "encoder", "mpeg4", start_block, end_block,
315 config_statements );
316 return 0;
317 }
318