1 /*
2 libfame - Fast Assembly MPEG Encoder Library
3 Copyright (C) 2000-2001 Vivien Chappelier
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public
16 License along with this library; if not, write to the Free
17 Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19
20 #include <stdlib.h>
21 #include <stdio.h>
22 #include <string.h>
23
24 #include "fame.h"
25 #include "fame_malloc.h"
26 #include "cpuflags.h"
27 #include "fame_profile_mpeg1.h"
28 #include "fame_profile_mpeg4_simple.h"
29 #include "fame_profile_mpeg4_shape.h"
30 #include "fame_profile_stats.h"
31 #include "fame_syntax.h"
32 #include "fame_syntax_mpeg1.h"
33 #include "fame_syntax_mpeg4.h"
34 #include "fame_shape.h"
35 #include "fame_motion.h"
36 #include "fame_motion_none.h"
37 #include "fame_motion_fourstep.h"
38 #include "fame_motion_pmvfast.h"
39 #include "fame_encoder_mpeg.h"
40 #include "fame_decoder_mpeg.h"
41 #include "fame_rate.h"
42 #include "fame_rate_simple.h"
43 #include "fame_rate_1param.h"
44 #include "fame_monitor.h"
45
46 #if defined(HAS_MMX)
47 #include "table_mmx_const.h"
48 #endif
49
50 /* version information */
51 const unsigned int libfame_major_version = LIBFAME_MAJOR_VERSION,
52 libfame_minor_version = LIBFAME_MINOR_VERSION,
53 libfame_micro_version = LIBFAME_MICRO_VERSION;
54 const char libfame_version[] = LIBFAME_VERSION;
55
56 struct _fame_private_t_ {
57 /* built-in objects */
58 fame_profile_mpeg1_t *profile_mpeg1;
59 fame_profile_mpeg4_simple_t *profile_mpeg4_simple;
60 fame_profile_mpeg4_shape_t *profile_mpeg4_shape;
61 fame_profile_stats_t *profile_stats;
62 fame_encoder_mpeg_t *encoder_mpeg;
63 fame_decoder_mpeg_t *decoder_mpeg;
64 fame_motion_none_t *motion_none;
65 fame_motion_pmvfast_t *motion_pmvfast;
66 fame_motion_fourstep_t *motion_fourstep;
67 fame_syntax_mpeg1_t *syntax_mpeg1;
68 fame_syntax_mpeg4_t *syntax_mpeg4;
69 fame_shape_t *shape;
70 fame_rate_t *rate;
71 fame_rate_simple_t *rate_simple;
72 fame_rate_1param_t *rate_1param;
73 fame_monitor_t *monitor;
74 /* for DEPRECATED fame_encode_frame */
75 int fame_encode_frame_first_call;
76 int slices_per_frame;
77 fame_frame_statistics_t stats;
78 };
79
80 /* fame_open */
81 /* */
82 /* Description: */
83 /* Create a new context to use the library. */
84 /* */
85 /* Arguments: */
86 /* None. */
87 /* */
88 /* Return value: */
89 /* fame_context_t * : a handle needed by all other library functions */
90
fame_open()91 fame_context_t * fame_open()
92 {
93 fame_context_t *context;
94
95 /* Initialize context */
96 context = (fame_context_t *) fame_malloc(sizeof(fame_context_t));
97
98 /* Build built_in object list */
99 context->type_list = NULL;
100 context->priv = (struct _fame_private_t_ *) fame_malloc(sizeof(struct _fame_private_t_));
101 context->priv->profile_mpeg1 = FAME_NEW(fame_profile_mpeg1_t);
102 context->priv->profile_mpeg4_simple = FAME_NEW(fame_profile_mpeg4_simple_t);
103 context->priv->profile_mpeg4_shape = FAME_NEW(fame_profile_mpeg4_shape_t);
104 context->priv->profile_stats = FAME_NEW(fame_profile_stats_t);
105 context->priv->encoder_mpeg = FAME_NEW(fame_encoder_mpeg_t);
106 context->priv->decoder_mpeg = FAME_NEW(fame_decoder_mpeg_t);
107 context->priv->motion_none = FAME_NEW(fame_motion_none_t);
108 context->priv->motion_pmvfast = FAME_NEW(fame_motion_pmvfast_t);
109 context->priv->motion_fourstep = FAME_NEW(fame_motion_fourstep_t);
110 context->priv->syntax_mpeg1 = FAME_NEW(fame_syntax_mpeg1_t);
111 context->priv->syntax_mpeg4 = FAME_NEW(fame_syntax_mpeg4_t);
112 context->priv->shape = FAME_NEW(fame_shape_t);
113 context->priv->rate = FAME_NEW(fame_rate_t);
114 context->priv->rate_simple = FAME_NEW(fame_rate_simple_t);
115 context->priv->rate_1param = FAME_NEW(fame_rate_1param_t);
116 context->priv->monitor = FAME_NEW(fame_monitor_t);
117
118 /* built-in profiles */
119 fame_register(context, "profile", FAME_OBJECT(context->priv->profile_mpeg1));
120 fame_register(context, "profile/mpeg1", FAME_OBJECT(context->priv->profile_mpeg1));
121 fame_register(context, "profile/mpeg4", FAME_OBJECT(context->priv->profile_mpeg4_simple));
122 fame_register(context, "profile/mpeg4/simple", FAME_OBJECT(context->priv->profile_mpeg4_simple));
123 fame_register(context, "profile/mpeg4/shape", FAME_OBJECT(context->priv->profile_mpeg4_shape));
124 fame_register(context, "profile/stats", FAME_OBJECT(context->priv->profile_stats));
125 /* built-in encoders */
126 fame_register(context, "encoder", FAME_OBJECT(context->priv->encoder_mpeg));
127 fame_register(context, "encoder/mpeg", FAME_OBJECT(context->priv->encoder_mpeg));
128 /* built-in decoders */
129 fame_register(context, "decoder", FAME_OBJECT(context->priv->decoder_mpeg));
130 fame_register(context, "decoder/mpeg", FAME_OBJECT(context->priv->decoder_mpeg));
131 /* built-in motion estimators */
132 fame_register(context, "motion", FAME_OBJECT(context->priv->motion_pmvfast));
133 fame_register(context, "motion/none", FAME_OBJECT(context->priv->motion_none));
134 fame_register(context, "motion/pmvfast", FAME_OBJECT(context->priv->motion_pmvfast));
135 fame_register(context, "motion/fourstep", FAME_OBJECT(context->priv->motion_fourstep));
136 /* built-in bitstream syntax writers */
137 fame_register(context, "syntax", FAME_OBJECT(context->priv->syntax_mpeg1));
138 fame_register(context, "syntax/mpeg1", FAME_OBJECT(context->priv->syntax_mpeg1));
139 fame_register(context, "syntax/mpeg4", FAME_OBJECT(context->priv->syntax_mpeg4));
140 /* built-in shape coders */
141 fame_register(context, "shape", FAME_OBJECT(context->priv->shape));
142 /* built-in rate controllers */
143 fame_register(context, "rate", FAME_OBJECT(context->priv->rate_1param));
144 fame_register(context, "rate/simple", FAME_OBJECT(context->priv->rate_simple));
145 fame_register(context, "rate/1param", FAME_OBJECT(context->priv->rate_1param));
146 fame_register(context, "monitor", FAME_OBJECT(context->priv->monitor));
147 return(context);
148 }
149
150 /* fame_register */
151 /* */
152 /* Description: */
153 /* Register a type to the library and associate an object with it. */
154 /* */
155 /* Arguments: */
156 /* fame_context_t * context: the context handle returned by fame_open */
157 /* char const *type: the type to register */
158 /* fame_object_t * object: the object to be associated with this type */
159 /* */
160 /* Return value: */
161 /* None. */
162
fame_register(fame_context_t * context,char const * type,fame_object_t * object)163 void fame_register(fame_context_t *context,
164 char const *type,
165 fame_object_t *object)
166 {
167 fame_list_t * next = context->type_list;
168
169 if(fame_get_object(context, type))
170 fame_unregister(context, type);
171 context->type_list = (fame_list_t *) fame_malloc(sizeof(fame_list_t));
172 context->type_list->next = next;
173 context->type_list->type = type;
174 context->type_list->item = object;
175 }
176
177 /* fame_unregister */
178 /* */
179 /* Description: */
180 /* Remove a type from the library. */
181 /* */
182 /* Arguments: */
183 /* fame_context_t * context: the context handle returned by fame_open */
184 /* char const *type: the type to be unregistered */
185 /* */
186 /* Return value: */
187 /* None. */
188
fame_unregister(fame_context_t * context,char const * type)189 void fame_unregister(fame_context_t * context, char const *type)
190 {
191 fame_list_t *list, *last;
192
193 for(last = list = context->type_list; list; list = list->next) {
194 if(!strcmp(list->type, type)) {
195 if(last == list)
196 context->type_list = list->next;
197 else
198 last->next = list->next;
199 fame_free(list);
200 return;
201 }
202 last = list;
203 }
204 }
205
206 /* fame_get_object */
207 /* */
208 /* Description: */
209 /* Retrieve the object associated to the given type from the library. */
210 /* */
211 /* Arguments: */
212 /* fame_context_t * context: the context handle returned by fame_open */
213 /* char const *type: the type of the object to be retrieved */
214 /* */
215 /* Return value: */
216 /* fame_object_t *: the object associated with type or NULL if not found. */
217
fame_get_object(fame_context_t * context,char const * type)218 fame_object_t *fame_get_object(fame_context_t * context, char const *type)
219 {
220 fame_list_t *list;
221
222 for(list = context->type_list; list; list = list->next) {
223 if(!strcmp(list->type, type))
224 return(list->item);
225 }
226 return(NULL);
227 }
228
229 /* fame_init */
230 /* */
231 /* Description: */
232 /* Initialize the library */
233 /* */
234 /* Arguments: */
235 /* fame_context_t * context: the context handle returned by fame_open */
236 /* fame_parameters_t *p: the parameters used to initialize (see fame.h) */
237 /* unsigned char * buffer: the output buffer */
238 /* int size: the size of the output buffer */
239 /* */
240 /* Notes: */
241 /* The output buffer must be large enough to contain an encoded frame. */
242 /* There is no check to detect buffer overflow. */
243 /* */
244 /* Return value: */
245 /* None. */
246
fame_init(fame_context_t * context,fame_parameters_t * p,unsigned char * buffer,unsigned int size)247 void fame_init(fame_context_t * context,
248 fame_parameters_t *p,
249 unsigned char *buffer,
250 unsigned int size)
251 {
252 unsigned long arch_flags;
253
254 /* Print information message */
255 if(p->verbose) {
256 FAME_INFO("libfame %s Copyright (C) 2000-2002 Vivien Chappelier\n",
257 LIBFAME_VERSION);
258 FAME_INFO("This library is provided under the terms of the LGPL. "
259 "See COPYING for details\n");
260 }
261
262 /* Choose profile */
263 context->profile = fame_get_object(context, "profile");
264
265 if(context->profile == NULL)
266 FAME_FATAL("could not find 'profile'\n");
267
268 if(p->verbose) {
269 FAME_INFO("%s %dx%d @ %.2f fps %d%% quality ",
270 context->profile->name,
271 p->width, p->height,
272 (float)p->frame_rate_num/(float)p->frame_rate_den,
273 p->quality);
274 if(p->search_range)
275 FAME_INFO("%d pixel search range\n", p->search_range);
276 else
277 FAME_INFO("adaptive search range\n");
278
279 FAME_INFO("%s coding sequence\n", p->coding);
280 }
281
282 FAME_PROFILE(context->profile)->init(FAME_PROFILE(context->profile), context, p, buffer, size);
283
284 arch_flags = cpuflags();
285
286 #if defined(HAS_MMX)
287 if(arch_flags & X86_HAS_MMX) {
288 if(p->verbose)
289 FAME_INFO("Using MMX arithmetic\n");
290 } else {
291 FAME_FATAL("MMX not detected!\n"
292 "Consider recompiling without --enable-mmx in configure\n");
293 }
294 #else
295 if(p->verbose)
296 FAME_INFO("Using floating point arithmetic\n");
297 #endif
298
299 /* for DEPRECATED fame_encode_frame */
300 context->priv->fame_encode_frame_first_call = 1;
301 context->priv->slices_per_frame = p->slices_per_frame;
302 }
303
304 /* fame_start_frame */
305 /* */
306 /* Description: */
307 /* Start encoding a frame. */
308 /* */
309 /* Arguments: */
310 /* fame_context_t * context: the context handle returned by fame_open */
311 /* fame_yuv_t * yuv: the input frame in raw YUV format (YV12 planar) */
312 /* unsigned char * mask: the input mask (0 = transparent, 255 = opaque) */
313 /* */
314 /* Return value: */
315 /* None. */
316
fame_start_frame(fame_context_t * context,fame_yuv_t * yuv,unsigned char * mask)317 void fame_start_frame(fame_context_t *context,
318 fame_yuv_t *yuv,
319 unsigned char *mask)
320 {
321 FAME_PROFILE(context->profile)->enter(FAME_PROFILE(context->profile), yuv, mask);
322 }
323
324 /* fame_encode_slice */
325 /* */
326 /* Description: */
327 /* Encode a slice of a frame. */
328 /* */
329 /* Arguments: */
330 /* fame_context_t * context: the context handle returned by fame_open */
331 /* */
332 /* Return value: */
333 /* int : the number of bytes written to buffer */
334
fame_encode_slice(fame_context_t * context)335 int fame_encode_slice(fame_context_t *context)
336 {
337 return(FAME_PROFILE(context->profile)->encode(FAME_PROFILE(context->profile)));
338 }
339
340 /* fame_end_frame */
341 /* */
342 /* Description: */
343 /* Finish encoding of a frame. */
344 /* */
345 /* Arguments: */
346 /* fame_context_t * context: the context handle returned by fame_open */
347 /* fame_frame_statistics_t * stats: information about the encoding */
348 /* */
349 /* Return value: */
350 /* None. */
351
fame_end_frame(fame_context_t * context,fame_frame_statistics_t * stats)352 void fame_end_frame(fame_context_t *context,
353 fame_frame_statistics_t *stats)
354 {
355 FAME_PROFILE(context->profile)->leave(FAME_PROFILE(context->profile), stats);
356 }
357
358 /* fame_close */
359 /* */
360 /* Description: */
361 /* Flush remaining encoded data and cleanup everything. */
362 /* */
363 /* Arguments: */
364 /* fame_context_t * context: the context handle returned by fame_open */
365 /* */
366 /* Return value: */
367 /* int : the number of bytes written to buffer */
368
fame_close(fame_context_t * context)369 int fame_close(fame_context_t *context)
370 {
371 int bytes_written = 0;
372 fame_list_t *l, *p;
373
374 if(context->profile && FAME_PROFILE(context->profile)->close)
375 bytes_written = FAME_PROFILE(context->profile)->close(FAME_PROFILE(context->profile));
376
377 if(context->type_list != NULL) {
378 l = context->type_list;
379 while(l->next != NULL) {
380 p = l;
381 l = l->next;
382 fame_free(p);
383 }
384 fame_free(l);
385 }
386
387 FAME_DELETE(context->priv->profile_mpeg1);
388 FAME_DELETE(context->priv->profile_mpeg4_simple);
389 FAME_DELETE(context->priv->profile_mpeg4_shape);
390 FAME_DELETE(context->priv->profile_stats);
391 FAME_DELETE(context->priv->encoder_mpeg);
392 FAME_DELETE(context->priv->decoder_mpeg);
393 FAME_DELETE(context->priv->motion_none);
394 FAME_DELETE(context->priv->motion_pmvfast);
395 FAME_DELETE(context->priv->motion_fourstep);
396 FAME_DELETE(context->priv->syntax_mpeg1);
397 FAME_DELETE(context->priv->syntax_mpeg4);
398 FAME_DELETE(context->priv->shape);
399 FAME_DELETE(context->priv->rate);
400 FAME_DELETE(context->priv->rate_simple);
401 FAME_DELETE(context->priv->rate_1param);
402 FAME_DELETE(context->priv->monitor);
403
404 fame_free(context->priv);
405 fame_free(context);
406
407 return(bytes_written);
408 }
409
410 /* DEPRECATED */
fame_encode_frame(fame_context_t * context,fame_yuv_t * yuv,unsigned char * mask)411 int fame_encode_frame(fame_context_t *context,
412 fame_yuv_t *yuv,
413 unsigned char *mask)
414 {
415 if(context->priv->fame_encode_frame_first_call) {
416 context->priv->fame_encode_frame_first_call = 0;
417 fprintf(stderr,
418 "usage of fame_encode_frame is deprecated\n"
419 "please use fame_start_frame, fame_encode_slice\n"
420 "and fame_end_frame functions instead\n");
421 }
422 if(context->priv->slices_per_frame != 1) {
423 fprintf(stderr,
424 "fame_encode_frame doesn't work when slices_per_frame != 1\n");
425 memset(&context->priv->stats, 0, sizeof(context->priv->stats));
426 return(context->priv->stats.actual_bits/8);
427 }
428
429 fame_start_frame(context, yuv, mask);
430 fame_encode_slice(context);
431 fame_end_frame(context, &context->priv->stats);
432
433 return(context->priv->stats.actual_bits/8);
434 }
435
436 #if !defined(__GNUC__)
437
438 #include <stdarg.h>
439
440 /* va_* based error management by Petter Reinholdtsen */
441 int
FAME_INFO(const char * format,...)442 FAME_INFO(const char *format, ...)
443 {
444 va_list va;
445 va_start(va, format);
446 vfprintf(stderr, format, va);
447 va_end(va);
448 }
449
FAME_WARNING(const char * format,...)450 int FAME_WARNING(const char *format, ...)
451 {
452 va_list va;
453 fprintf(stderr, "Warning: ");
454 va_start(va, format);
455 vfprintf(stderr, format, va);
456 va_end(va);
457 }
458
FAME_ERROR(const char * format,...)459 int FAME_ERROR(const char *format, ...)
460 {
461 va_list va;
462 fprintf(stderr, "Error: ");
463 va_start(va, format);
464 vfprintf(stderr, format, va);
465 va_end(va);
466 }
467
FAME_FATAL(const char * format,...)468 int FAME_FATAL(const char *format, ...)
469 {
470 va_list va;
471 fprintf(stderr, "Fatal: ");
472 va_start(va, format);
473 vfprintf(stderr, format, va);
474 va_end(va);
475 exit(-1);
476 }
477
478 #endif /* not __GNUC__ */
479
480
481 #if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ <= 95 && __GNUC_PATCHLEVEL__ <= 3)
482 /* gcc bug?? workaround */
__fame_dummy_call(int q)483 void __fame_dummy_call(int q)
484 {
485 }
486 #endif
487