/* libfame - Fast Assembly MPEG Encoder Library Copyright (C) 2000-2001 Vivien Chappelier This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include #include #include "fame.h" #include "fame_malloc.h" #include "cpuflags.h" #include "fame_profile_mpeg1.h" #include "fame_profile_mpeg4_simple.h" #include "fame_profile_mpeg4_shape.h" #include "fame_profile_stats.h" #include "fame_syntax.h" #include "fame_syntax_mpeg1.h" #include "fame_syntax_mpeg4.h" #include "fame_shape.h" #include "fame_motion.h" #include "fame_motion_none.h" #include "fame_motion_fourstep.h" #include "fame_motion_pmvfast.h" #include "fame_encoder_mpeg.h" #include "fame_decoder_mpeg.h" #include "fame_rate.h" #include "fame_rate_simple.h" #include "fame_rate_1param.h" #include "fame_monitor.h" #if defined(HAS_MMX) #include "table_mmx_const.h" #endif /* version information */ const unsigned int libfame_major_version = LIBFAME_MAJOR_VERSION, libfame_minor_version = LIBFAME_MINOR_VERSION, libfame_micro_version = LIBFAME_MICRO_VERSION; const char libfame_version[] = LIBFAME_VERSION; struct _fame_private_t_ { /* built-in objects */ fame_profile_mpeg1_t *profile_mpeg1; fame_profile_mpeg4_simple_t *profile_mpeg4_simple; fame_profile_mpeg4_shape_t *profile_mpeg4_shape; fame_profile_stats_t *profile_stats; fame_encoder_mpeg_t *encoder_mpeg; fame_decoder_mpeg_t *decoder_mpeg; fame_motion_none_t *motion_none; fame_motion_pmvfast_t *motion_pmvfast; fame_motion_fourstep_t *motion_fourstep; fame_syntax_mpeg1_t *syntax_mpeg1; fame_syntax_mpeg4_t *syntax_mpeg4; fame_shape_t *shape; fame_rate_t *rate; fame_rate_simple_t *rate_simple; fame_rate_1param_t *rate_1param; fame_monitor_t *monitor; /* for DEPRECATED fame_encode_frame */ int fame_encode_frame_first_call; int slices_per_frame; fame_frame_statistics_t stats; }; /* fame_open */ /* */ /* Description: */ /* Create a new context to use the library. */ /* */ /* Arguments: */ /* None. */ /* */ /* Return value: */ /* fame_context_t * : a handle needed by all other library functions */ fame_context_t * fame_open() { fame_context_t *context; /* Initialize context */ context = (fame_context_t *) fame_malloc(sizeof(fame_context_t)); /* Build built_in object list */ context->type_list = NULL; context->priv = (struct _fame_private_t_ *) fame_malloc(sizeof(struct _fame_private_t_)); context->priv->profile_mpeg1 = FAME_NEW(fame_profile_mpeg1_t); context->priv->profile_mpeg4_simple = FAME_NEW(fame_profile_mpeg4_simple_t); context->priv->profile_mpeg4_shape = FAME_NEW(fame_profile_mpeg4_shape_t); context->priv->profile_stats = FAME_NEW(fame_profile_stats_t); context->priv->encoder_mpeg = FAME_NEW(fame_encoder_mpeg_t); context->priv->decoder_mpeg = FAME_NEW(fame_decoder_mpeg_t); context->priv->motion_none = FAME_NEW(fame_motion_none_t); context->priv->motion_pmvfast = FAME_NEW(fame_motion_pmvfast_t); context->priv->motion_fourstep = FAME_NEW(fame_motion_fourstep_t); context->priv->syntax_mpeg1 = FAME_NEW(fame_syntax_mpeg1_t); context->priv->syntax_mpeg4 = FAME_NEW(fame_syntax_mpeg4_t); context->priv->shape = FAME_NEW(fame_shape_t); context->priv->rate = FAME_NEW(fame_rate_t); context->priv->rate_simple = FAME_NEW(fame_rate_simple_t); context->priv->rate_1param = FAME_NEW(fame_rate_1param_t); context->priv->monitor = FAME_NEW(fame_monitor_t); /* built-in profiles */ fame_register(context, "profile", FAME_OBJECT(context->priv->profile_mpeg1)); fame_register(context, "profile/mpeg1", FAME_OBJECT(context->priv->profile_mpeg1)); fame_register(context, "profile/mpeg4", FAME_OBJECT(context->priv->profile_mpeg4_simple)); fame_register(context, "profile/mpeg4/simple", FAME_OBJECT(context->priv->profile_mpeg4_simple)); fame_register(context, "profile/mpeg4/shape", FAME_OBJECT(context->priv->profile_mpeg4_shape)); fame_register(context, "profile/stats", FAME_OBJECT(context->priv->profile_stats)); /* built-in encoders */ fame_register(context, "encoder", FAME_OBJECT(context->priv->encoder_mpeg)); fame_register(context, "encoder/mpeg", FAME_OBJECT(context->priv->encoder_mpeg)); /* built-in decoders */ fame_register(context, "decoder", FAME_OBJECT(context->priv->decoder_mpeg)); fame_register(context, "decoder/mpeg", FAME_OBJECT(context->priv->decoder_mpeg)); /* built-in motion estimators */ fame_register(context, "motion", FAME_OBJECT(context->priv->motion_pmvfast)); fame_register(context, "motion/none", FAME_OBJECT(context->priv->motion_none)); fame_register(context, "motion/pmvfast", FAME_OBJECT(context->priv->motion_pmvfast)); fame_register(context, "motion/fourstep", FAME_OBJECT(context->priv->motion_fourstep)); /* built-in bitstream syntax writers */ fame_register(context, "syntax", FAME_OBJECT(context->priv->syntax_mpeg1)); fame_register(context, "syntax/mpeg1", FAME_OBJECT(context->priv->syntax_mpeg1)); fame_register(context, "syntax/mpeg4", FAME_OBJECT(context->priv->syntax_mpeg4)); /* built-in shape coders */ fame_register(context, "shape", FAME_OBJECT(context->priv->shape)); /* built-in rate controllers */ fame_register(context, "rate", FAME_OBJECT(context->priv->rate_1param)); fame_register(context, "rate/simple", FAME_OBJECT(context->priv->rate_simple)); fame_register(context, "rate/1param", FAME_OBJECT(context->priv->rate_1param)); fame_register(context, "monitor", FAME_OBJECT(context->priv->monitor)); return(context); } /* fame_register */ /* */ /* Description: */ /* Register a type to the library and associate an object with it. */ /* */ /* Arguments: */ /* fame_context_t * context: the context handle returned by fame_open */ /* char const *type: the type to register */ /* fame_object_t * object: the object to be associated with this type */ /* */ /* Return value: */ /* None. */ void fame_register(fame_context_t *context, char const *type, fame_object_t *object) { fame_list_t * next = context->type_list; if(fame_get_object(context, type)) fame_unregister(context, type); context->type_list = (fame_list_t *) fame_malloc(sizeof(fame_list_t)); context->type_list->next = next; context->type_list->type = type; context->type_list->item = object; } /* fame_unregister */ /* */ /* Description: */ /* Remove a type from the library. */ /* */ /* Arguments: */ /* fame_context_t * context: the context handle returned by fame_open */ /* char const *type: the type to be unregistered */ /* */ /* Return value: */ /* None. */ void fame_unregister(fame_context_t * context, char const *type) { fame_list_t *list, *last; for(last = list = context->type_list; list; list = list->next) { if(!strcmp(list->type, type)) { if(last == list) context->type_list = list->next; else last->next = list->next; fame_free(list); return; } last = list; } } /* fame_get_object */ /* */ /* Description: */ /* Retrieve the object associated to the given type from the library. */ /* */ /* Arguments: */ /* fame_context_t * context: the context handle returned by fame_open */ /* char const *type: the type of the object to be retrieved */ /* */ /* Return value: */ /* fame_object_t *: the object associated with type or NULL if not found. */ fame_object_t *fame_get_object(fame_context_t * context, char const *type) { fame_list_t *list; for(list = context->type_list; list; list = list->next) { if(!strcmp(list->type, type)) return(list->item); } return(NULL); } /* fame_init */ /* */ /* Description: */ /* Initialize the library */ /* */ /* Arguments: */ /* fame_context_t * context: the context handle returned by fame_open */ /* fame_parameters_t *p: the parameters used to initialize (see fame.h) */ /* unsigned char * buffer: the output buffer */ /* int size: the size of the output buffer */ /* */ /* Notes: */ /* The output buffer must be large enough to contain an encoded frame. */ /* There is no check to detect buffer overflow. */ /* */ /* Return value: */ /* None. */ void fame_init(fame_context_t * context, fame_parameters_t *p, unsigned char *buffer, unsigned int size) { unsigned long arch_flags; /* Print information message */ if(p->verbose) { FAME_INFO("libfame %s Copyright (C) 2000-2002 Vivien Chappelier\n", LIBFAME_VERSION); FAME_INFO("This library is provided under the terms of the LGPL. " "See COPYING for details\n"); } /* Choose profile */ context->profile = fame_get_object(context, "profile"); if(context->profile == NULL) FAME_FATAL("could not find 'profile'\n"); if(p->verbose) { FAME_INFO("%s %dx%d @ %.2f fps %d%% quality ", context->profile->name, p->width, p->height, (float)p->frame_rate_num/(float)p->frame_rate_den, p->quality); if(p->search_range) FAME_INFO("%d pixel search range\n", p->search_range); else FAME_INFO("adaptive search range\n"); FAME_INFO("%s coding sequence\n", p->coding); } FAME_PROFILE(context->profile)->init(FAME_PROFILE(context->profile), context, p, buffer, size); arch_flags = cpuflags(); #if defined(HAS_MMX) if(arch_flags & X86_HAS_MMX) { if(p->verbose) FAME_INFO("Using MMX arithmetic\n"); } else { FAME_FATAL("MMX not detected!\n" "Consider recompiling without --enable-mmx in configure\n"); } #else if(p->verbose) FAME_INFO("Using floating point arithmetic\n"); #endif /* for DEPRECATED fame_encode_frame */ context->priv->fame_encode_frame_first_call = 1; context->priv->slices_per_frame = p->slices_per_frame; } /* fame_start_frame */ /* */ /* Description: */ /* Start encoding a frame. */ /* */ /* Arguments: */ /* fame_context_t * context: the context handle returned by fame_open */ /* fame_yuv_t * yuv: the input frame in raw YUV format (YV12 planar) */ /* unsigned char * mask: the input mask (0 = transparent, 255 = opaque) */ /* */ /* Return value: */ /* None. */ void fame_start_frame(fame_context_t *context, fame_yuv_t *yuv, unsigned char *mask) { FAME_PROFILE(context->profile)->enter(FAME_PROFILE(context->profile), yuv, mask); } /* fame_encode_slice */ /* */ /* Description: */ /* Encode a slice of a frame. */ /* */ /* Arguments: */ /* fame_context_t * context: the context handle returned by fame_open */ /* */ /* Return value: */ /* int : the number of bytes written to buffer */ int fame_encode_slice(fame_context_t *context) { return(FAME_PROFILE(context->profile)->encode(FAME_PROFILE(context->profile))); } /* fame_end_frame */ /* */ /* Description: */ /* Finish encoding of a frame. */ /* */ /* Arguments: */ /* fame_context_t * context: the context handle returned by fame_open */ /* fame_frame_statistics_t * stats: information about the encoding */ /* */ /* Return value: */ /* None. */ void fame_end_frame(fame_context_t *context, fame_frame_statistics_t *stats) { FAME_PROFILE(context->profile)->leave(FAME_PROFILE(context->profile), stats); } /* fame_close */ /* */ /* Description: */ /* Flush remaining encoded data and cleanup everything. */ /* */ /* Arguments: */ /* fame_context_t * context: the context handle returned by fame_open */ /* */ /* Return value: */ /* int : the number of bytes written to buffer */ int fame_close(fame_context_t *context) { int bytes_written = 0; fame_list_t *l, *p; if(context->profile && FAME_PROFILE(context->profile)->close) bytes_written = FAME_PROFILE(context->profile)->close(FAME_PROFILE(context->profile)); if(context->type_list != NULL) { l = context->type_list; while(l->next != NULL) { p = l; l = l->next; fame_free(p); } fame_free(l); } FAME_DELETE(context->priv->profile_mpeg1); FAME_DELETE(context->priv->profile_mpeg4_simple); FAME_DELETE(context->priv->profile_mpeg4_shape); FAME_DELETE(context->priv->profile_stats); FAME_DELETE(context->priv->encoder_mpeg); FAME_DELETE(context->priv->decoder_mpeg); FAME_DELETE(context->priv->motion_none); FAME_DELETE(context->priv->motion_pmvfast); FAME_DELETE(context->priv->motion_fourstep); FAME_DELETE(context->priv->syntax_mpeg1); FAME_DELETE(context->priv->syntax_mpeg4); FAME_DELETE(context->priv->shape); FAME_DELETE(context->priv->rate); FAME_DELETE(context->priv->rate_simple); FAME_DELETE(context->priv->rate_1param); FAME_DELETE(context->priv->monitor); fame_free(context->priv); fame_free(context); return(bytes_written); } /* DEPRECATED */ int fame_encode_frame(fame_context_t *context, fame_yuv_t *yuv, unsigned char *mask) { if(context->priv->fame_encode_frame_first_call) { context->priv->fame_encode_frame_first_call = 0; fprintf(stderr, "usage of fame_encode_frame is deprecated\n" "please use fame_start_frame, fame_encode_slice\n" "and fame_end_frame functions instead\n"); } if(context->priv->slices_per_frame != 1) { fprintf(stderr, "fame_encode_frame doesn't work when slices_per_frame != 1\n"); memset(&context->priv->stats, 0, sizeof(context->priv->stats)); return(context->priv->stats.actual_bits/8); } fame_start_frame(context, yuv, mask); fame_encode_slice(context); fame_end_frame(context, &context->priv->stats); return(context->priv->stats.actual_bits/8); } #if !defined(__GNUC__) #include /* va_* based error management by Petter Reinholdtsen */ int FAME_INFO(const char *format, ...) { va_list va; va_start(va, format); vfprintf(stderr, format, va); va_end(va); } int FAME_WARNING(const char *format, ...) { va_list va; fprintf(stderr, "Warning: "); va_start(va, format); vfprintf(stderr, format, va); va_end(va); } int FAME_ERROR(const char *format, ...) { va_list va; fprintf(stderr, "Error: "); va_start(va, format); vfprintf(stderr, format, va); va_end(va); } int FAME_FATAL(const char *format, ...) { va_list va; fprintf(stderr, "Fatal: "); va_start(va, format); vfprintf(stderr, format, va); va_end(va); exit(-1); } #endif /* not __GNUC__ */ #if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ <= 95 && __GNUC_PATCHLEVEL__ <= 3) /* gcc bug?? workaround */ void __fame_dummy_call(int q) { } #endif