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