/*
* utils for libavcodec
* Copyright (c) 2001 Fabrice Bellard.
+ * Copyright (c) 2003 Michel Bardiaux for the av_log API
+ * Copyright (c) 2002-2004 Michael Niedermayer <michaelni@gmx.at>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
#include "avcodec.h"
#include "dsputil.h"
#include "mpegvideo.h"
+#include "integer.h"
+#include <stdarg.h>
+#include <limits.h>
+
+static void avcodec_default_free_buffers(AVCodecContext *s);
void *av_mallocz(unsigned int size)
{
if(min_size < *size)
return ptr;
- *size= min_size + 10*1024;
+ *size= 17*min_size/16 + 32;
return av_realloc(ptr, *size);
}
-/* allocation of static arrays - do not use for normal allocation */
static unsigned int last_static = 0;
-static char*** array_static = NULL;
-static const unsigned int grow_static = 64; // ^2
-void *__av_mallocz_static(void** location, unsigned int size)
+static unsigned int allocated_static = 0;
+static void** array_static = NULL;
+
+/**
+ * allocation of static arrays - do not use for normal allocation.
+ */
+void *av_mallocz_static(unsigned int size)
{
- unsigned int l = (last_static + grow_static) & ~(grow_static - 1);
void *ptr = av_mallocz(size);
- if (!ptr)
- return NULL;
-
- if (location)
- {
- if (l > last_static)
- array_static = av_realloc(array_static, l);
- array_static[last_static++] = (char**) location;
- *location = ptr;
+
+ if(ptr){
+ array_static =av_fast_realloc(array_static, &allocated_static, sizeof(void*)*(last_static+1));
+ array_static[last_static++] = ptr;
}
+
return ptr;
}
-/* free all static arrays and reset pointers to 0 */
-void av_free_static()
+
+/**
+ * free all static arrays and reset pointers to 0.
+ */
+void av_free_static(void)
{
- if (array_static)
- {
- unsigned i;
- for (i = 0; i < last_static; i++)
- {
- av_free(*array_static[i]);
- *array_static[i] = NULL;
- }
- av_free(array_static);
- array_static = 0;
+ while(last_static){
+ av_freep(&array_static[--last_static]);
}
- last_static = 0;
+ av_freep(&array_static);
}
-/* cannot call it directly because of 'void **' casting is not automatic */
-void __av_freep(void **ptr)
+/**
+ * Frees memory and sets the pointer to NULL.
+ * @param arg pointer to the pointer which should be freed
+ */
+void av_freep(void *arg)
{
+ void **ptr= (void**)arg;
av_free(*ptr);
*ptr = NULL;
}
int last_pic_num;
uint8_t *base[4];
uint8_t *data[4];
+ int linesize[4];
}InternalBuffer;
#define INTERNAL_BUFFER_SIZE 32
+#define ALIGN(x, a) (((x)+(a)-1)&~((a)-1))
+
+void avcodec_align_dimensions(AVCodecContext *s, int *width, int *height){
+ int w_align= 1;
+ int h_align= 1;
+
+ switch(s->pix_fmt){
+ case PIX_FMT_YUV420P:
+ case PIX_FMT_YUV422:
+ case PIX_FMT_UYVY422:
+ case PIX_FMT_YUV422P:
+ case PIX_FMT_YUV444P:
+ case PIX_FMT_GRAY8:
+ case PIX_FMT_YUVJ420P:
+ case PIX_FMT_YUVJ422P:
+ case PIX_FMT_YUVJ444P:
+ w_align= 16; //FIXME check for non mpeg style codecs and use less alignment
+ h_align= 16;
+ break;
+ case PIX_FMT_YUV411P:
+ w_align=32;
+ h_align=8;
+ break;
+ case PIX_FMT_YUV410P:
+ if(s->codec_id == CODEC_ID_SVQ1){
+ w_align=64;
+ h_align=64;
+ }
+ case PIX_FMT_RGB555:
+ if(s->codec_id == CODEC_ID_RPZA){
+ w_align=4;
+ h_align=4;
+ }
+ case PIX_FMT_PAL8:
+ if(s->codec_id == CODEC_ID_SMC){
+ w_align=4;
+ h_align=4;
+ }
+ break;
+ default:
+ w_align= 1;
+ h_align= 1;
+ break;
+ }
+
+ *width = ALIGN(*width , w_align);
+ *height= ALIGN(*height, h_align);
+}
+
int avcodec_default_get_buffer(AVCodecContext *s, AVFrame *pic){
int i;
- const int width = s->width;
- const int height= s->height;
+ int w= s->width;
+ int h= s->height;
InternalBuffer *buf;
+ int *picture_number;
assert(pic->data[0]==NULL);
assert(INTERNAL_BUFFER_SIZE > s->internal_buffer_count);
#endif
buf= &((InternalBuffer*)s->internal_buffer)[s->internal_buffer_count];
-
+ picture_number= &(((InternalBuffer*)s->internal_buffer)[INTERNAL_BUFFER_SIZE-1]).last_pic_num; //FIXME ugly hack
+ (*picture_number)++;
+
if(buf->base[0]){
- pic->age= pic->coded_picture_number - buf->last_pic_num;
- buf->last_pic_num= pic->coded_picture_number;
+ pic->age= *picture_number - buf->last_pic_num;
+ buf->last_pic_num= *picture_number;
}else{
- int align, h_chroma_shift, v_chroma_shift;
- int w, h, pixel_size;
+ int h_chroma_shift, v_chroma_shift;
+ int s_align, pixel_size;
avcodec_get_chroma_sub_sample(s->pix_fmt, &h_chroma_shift, &v_chroma_shift);
switch(s->pix_fmt){
+ case PIX_FMT_RGB555:
+ case PIX_FMT_RGB565:
case PIX_FMT_YUV422:
+ case PIX_FMT_UYVY422:
pixel_size=2;
break;
case PIX_FMT_RGB24:
default:
pixel_size=1;
}
-
- if(s->codec_id==CODEC_ID_SVQ1) align=63;
- else align=15;
-
- w= (width +align)&~align;
- h= (height+align)&~align;
-
+
+ avcodec_align_dimensions(s, &w, &h);
+#if defined(ARCH_POWERPC) || defined(HAVE_MMI) //FIXME some cleaner check
+ s_align= 16;
+#else
+ s_align= 8;
+#endif
+
if(!(s->flags&CODEC_FLAG_EMU_EDGE)){
w+= EDGE_WIDTH*2;
h+= EDGE_WIDTH*2;
const int h_shift= i==0 ? 0 : h_chroma_shift;
const int v_shift= i==0 ? 0 : v_chroma_shift;
- pic->linesize[i]= pixel_size*w>>h_shift;
+ //FIXME next ensures that linesize= 2^x uvlinesize, thats needed because some MC code assumes it
+ buf->linesize[i]= ALIGN(pixel_size*w>>h_shift, s_align<<(h_chroma_shift-h_shift));
- buf->base[i]= av_mallocz((pic->linesize[i]*h>>v_shift)+16); //FIXME 16
+ buf->base[i]= av_mallocz((buf->linesize[i]*h>>v_shift)+16); //FIXME 16
if(buf->base[i]==NULL) return -1;
- memset(buf->base[i], 128, pic->linesize[i]*h>>v_shift);
+ memset(buf->base[i], 128, buf->linesize[i]*h>>v_shift);
if(s->flags&CODEC_FLAG_EMU_EDGE)
buf->data[i] = buf->base[i];
else
- buf->data[i] = buf->base[i] + (pic->linesize[i]*EDGE_WIDTH>>v_shift) + (EDGE_WIDTH>>h_shift);
+ buf->data[i] = buf->base[i] + ALIGN((buf->linesize[i]*EDGE_WIDTH>>v_shift) + (EDGE_WIDTH>>h_shift), s_align);
}
pic->age= 256*256*256*64;
- pic->type= FF_BUFFER_TYPE_INTERNAL;
}
+ pic->type= FF_BUFFER_TYPE_INTERNAL;
for(i=0; i<4; i++){
pic->base[i]= buf->base[i];
pic->data[i]= buf->data[i];
+ pic->linesize[i]= buf->linesize[i];
}
s->internal_buffer_count++;
InternalBuffer *buf, *last, temp;
assert(pic->type==FF_BUFFER_TYPE_INTERNAL);
+ assert(s->internal_buffer_count);
+ buf = NULL; /* avoids warning */
for(i=0; i<s->internal_buffer_count; i++){ //just 3-5 checks so is not worth to optimize
buf= &((InternalBuffer*)s->internal_buffer)[i];
if(buf->data[0] == pic->data[0])
//printf("R%X\n", pic->opaque);
}
-enum PixelFormat avcodec_default_get_format(struct AVCodecContext *s, enum PixelFormat * fmt){
+int avcodec_default_reget_buffer(AVCodecContext *s, AVFrame *pic){
+ AVFrame temp_pic;
+ int i;
+
+ /* If no picture return a new buffer */
+ if(pic->data[0] == NULL) {
+ /* We will copy from buffer, so must be readable */
+ pic->buffer_hints |= FF_BUFFER_HINTS_READABLE;
+ return s->get_buffer(s, pic);
+ }
+
+ /* If internal buffer type return the same buffer */
+ if(pic->type == FF_BUFFER_TYPE_INTERNAL)
+ return 0;
+
+ /*
+ * Not internal type and reget_buffer not overridden, emulate cr buffer
+ */
+ temp_pic = *pic;
+ for(i = 0; i < 4; i++)
+ pic->data[i] = pic->base[i] = NULL;
+ pic->opaque = NULL;
+ /* Allocate new frame */
+ if (s->get_buffer(s, pic))
+ return -1;
+ /* Copy image data from old buffer to new buffer */
+ img_copy((AVPicture*)pic, (AVPicture*)&temp_pic, s->pix_fmt, s->width,
+ s->height);
+ s->release_buffer(s, &temp_pic); // Release old frame
+ return 0;
+}
+
+int avcodec_default_execute(AVCodecContext *c, int (*func)(AVCodecContext *c2, void *arg2),void **arg, int *ret, int count){
+ int i;
+
+ for(i=0; i<count; i++){
+ int r= func(c, arg[i]);
+ if(ret) ret[i]= r;
+ }
+ return 0;
+}
+
+enum PixelFormat avcodec_default_get_format(struct AVCodecContext *s, const enum PixelFormat * fmt){
return fmt[0];
}
+static const char* context_to_name(void* ptr) {
+ AVCodecContext *avc= ptr;
+
+ if(avc && avc->codec && avc->codec->name)
+ return avc->codec->name;
+ else
+ return "NULL";
+}
+
+static AVClass av_codec_context_class = { "AVCodecContext", context_to_name };
+
void avcodec_get_context_defaults(AVCodecContext *s){
+ memset(s, 0, sizeof(AVCodecContext));
+
+ s->av_class= &av_codec_context_class;
s->bit_rate= 800*1000;
s->bit_rate_tolerance= s->bit_rate*10;
s->qmin= 2;
s->get_buffer= avcodec_default_get_buffer;
s->release_buffer= avcodec_default_release_buffer;
s->get_format= avcodec_default_get_format;
+ s->execute= avcodec_default_execute;
+ s->thread_count=1;
s->me_subpel_quality=8;
+ s->lmin= FF_QP2LAMBDA * s->qmin;
+ s->lmax= FF_QP2LAMBDA * s->qmax;
+ s->sample_aspect_ratio= (AVRational){0,1};
+ s->ildct_cmp= FF_CMP_VSAD;
s->intra_quant_bias= FF_DEFAULT_QUANT_BIAS;
s->inter_quant_bias= FF_DEFAULT_QUANT_BIAS;
+ s->palctrl = NULL;
+ s->reget_buffer= avcodec_default_reget_buffer;
}
/**
* this can be deallocated by simply calling free()
*/
AVCodecContext *avcodec_alloc_context(void){
- AVCodecContext *avctx= av_mallocz(sizeof(AVCodecContext));
+ AVCodecContext *avctx= av_malloc(sizeof(AVCodecContext));
if(avctx==NULL) return NULL;
return avctx;
}
+void avcodec_get_frame_defaults(AVFrame *pic){
+ memset(pic, 0, sizeof(AVFrame));
+
+ pic->pts= AV_NOPTS_VALUE;
+}
+
/**
* allocates a AVPFrame and set it to defaults.
* this can be deallocated by simply calling free()
*/
AVFrame *avcodec_alloc_frame(void){
- AVFrame *pic= av_mallocz(sizeof(AVFrame));
+ AVFrame *pic= av_malloc(sizeof(AVFrame));
+
+ if(pic==NULL) return NULL;
+
+ avcodec_get_frame_defaults(pic);
return pic;
}
{
int ret;
+ if(avctx->codec)
+ return -1;
+
avctx->codec = codec;
avctx->codec_id = codec->id;
avctx->frame_number = 0;
int avcodec_encode_audio(AVCodecContext *avctx, uint8_t *buf, int buf_size,
const short *samples)
{
- int ret;
-
- ret = avctx->codec->encode(avctx, buf, buf_size, (void *)samples);
- avctx->frame_number++;
- return ret;
+ if((avctx->codec->capabilities & CODEC_CAP_DELAY) || samples){
+ int ret = avctx->codec->encode(avctx, buf, buf_size, (void *)samples);
+ avctx->frame_number++;
+ return ret;
+ }else
+ return 0;
}
int avcodec_encode_video(AVCodecContext *avctx, uint8_t *buf, int buf_size,
const AVFrame *pict)
{
- int ret;
-
- ret = avctx->codec->encode(avctx, buf, buf_size, (void *)pict);
+ if((avctx->codec->capabilities & CODEC_CAP_DELAY) || pict){
+ int ret = avctx->codec->encode(avctx, buf, buf_size, (void *)pict);
+ avctx->frame_number++;
+ emms_c(); //needed to avoid a emms_c() call before every return;
- emms_c(); //needed to avoid a emms_c() call before every return;
-
- avctx->frame_number++;
- return ret;
+ return ret;
+ }else
+ return 0;
}
/**
{
int ret;
+ *got_picture_ptr= 0;
ret = avctx->codec->decode(avctx, picture, got_picture_ptr,
buf, buf_size);
{
int ret;
+ *frame_size_ptr= 0;
ret = avctx->codec->decode(avctx, samples, frame_size_ptr,
buf, buf_size);
avctx->frame_number++;
{
if (avctx->codec->close)
avctx->codec->close(avctx);
+ avcodec_default_free_buffers(avctx);
av_freep(&avctx->priv_data);
avctx->codec = NULL;
return 0;
return NULL;
}
-AVCodec *avcodec_find(enum CodecID id)
+static AVCodec *avcodec_find(enum CodecID id)
{
AVCodec *p;
p = first_avcodec;
if (p) {
codec_name = p->name;
+ if (!encode && enc->codec_id == CODEC_ID_MP3) {
+ if (enc->sub_id == 2)
+ codec_name = "mp2";
+ else if (enc->sub_id == 1)
+ codec_name = "mp1";
+ }
+ } else if (enc->codec_id == CODEC_ID_MPEG2TS) {
+ /* fake mpeg2 transport stream codec (currently not
+ registered) */
+ codec_name = "mpeg2ts";
} else if (enc->codec_name[0] != '\0') {
codec_name = enc->codec_name;
} else {
case CODEC_TYPE_VIDEO:
snprintf(buf, buf_size,
"Video: %s%s",
- codec_name, enc->flags & CODEC_FLAG_HQ ? " (hq)" : "");
+ codec_name, enc->mb_decision ? " (hq)" : "");
if (enc->codec_id == CODEC_ID_RAWVIDEO) {
snprintf(buf + strlen(buf), buf_size - strlen(buf),
", %s",
break;
}
break;
+ case CODEC_TYPE_DATA:
+ snprintf(buf, buf_size, "Data: %s", codec_name);
+ bitrate = enc->bit_rate;
+ break;
default:
av_abort();
}
dsputil_static_init();
}
-/* this can be called after seeking and before trying to decode the next keyframe */
+/**
+ * Flush buffers, should be called when seeking or when swicthing to a different stream.
+ */
void avcodec_flush_buffers(AVCodecContext *avctx)
{
- int i;
- MpegEncContext *s = avctx->priv_data;
-
- switch(avctx->codec_id){
- case CODEC_ID_MPEG1VIDEO:
- case CODEC_ID_H263:
- case CODEC_ID_RV10:
-// case CODEC_ID_MJPEG:
-// case CODEC_ID_MJPEGB:
- case CODEC_ID_MPEG4:
- case CODEC_ID_MSMPEG4V1:
- case CODEC_ID_MSMPEG4V2:
- case CODEC_ID_MSMPEG4V3:
- case CODEC_ID_WMV1:
- case CODEC_ID_WMV2:
- case CODEC_ID_H263P:
- case CODEC_ID_H263I:
- case CODEC_ID_SVQ1:
- for(i=0; i<MAX_PICTURE_COUNT; i++){
- if(s->picture[i].data[0] && ( s->picture[i].type == FF_BUFFER_TYPE_INTERNAL
- || s->picture[i].type == FF_BUFFER_TYPE_USER))
- avctx->release_buffer(avctx, (AVFrame*)&s->picture[i]);
- }
- s->last_picture_ptr = s->next_picture_ptr = NULL;
- break;
- default:
- //FIXME
- break;
- }
+ if(avctx->codec->flush)
+ avctx->codec->flush(avctx);
}
-void avcodec_default_free_buffers(AVCodecContext *s){
+static void avcodec_default_free_buffers(AVCodecContext *s){
int i, j;
if(s->internal_buffer==NULL) return;
s->internal_buffer_count=0;
}
-int av_reduce(int *dst_nom, int *dst_den, int64_t nom, int64_t den, int64_t max){
- int exact=1, sign=0;
- int64_t gcd, larger;
-
- assert(den != 0);
+char av_get_pict_type_char(int pict_type){
+ switch(pict_type){
+ case I_TYPE: return 'I';
+ case P_TYPE: return 'P';
+ case B_TYPE: return 'B';
+ case S_TYPE: return 'S';
+ case SI_TYPE:return 'i';
+ case SP_TYPE:return 'p';
+ default: return '?';
+ }
+}
- if(den < 0){
- den= -den;
- nom= -nom;
+int av_reduce(int *dst_nom, int *dst_den, int64_t nom, int64_t den, int64_t max){
+ AVRational a0={0,1}, a1={1,0};
+ int sign= (nom<0) ^ (den<0);
+ int64_t gcd= ff_gcd(ABS(nom), ABS(den));
+
+ nom = ABS(nom)/gcd;
+ den = ABS(den)/gcd;
+ if(nom<=max && den<=max){
+ a1= (AVRational){nom, den};
+ den=0;
}
- if(nom < 0){
- nom= -nom;
- sign= 1;
+ while(den){
+ int64_t x = nom / den;
+ int64_t next_den= nom - den*x;
+ int64_t a2n= x*a1.num + a0.num;
+ int64_t a2d= x*a1.den + a0.den;
+
+ if(a2n > max || a2d > max) break;
+
+ a0= a1;
+ a1= (AVRational){a2n, a2d};
+ nom= den;
+ den= next_den;
}
+ assert(ff_gcd(a1.num, a1.den) == 1);
- for(;;){ //note is executed 1 or 2 times
- gcd = ff_gcd(nom, den);
- nom /= gcd;
- den /= gcd;
-
- larger= FFMAX(nom, den);
-
- if(larger > max){
- int64_t div= (larger + max - 1) / max;
- nom = (nom + div/2)/div;
- den = (den + div/2)/div;
- exact=0;
- }else
- break;
- }
+ *dst_nom = sign ? -a1.num : a1.num;
+ *dst_den = a1.den;
- if(sign) nom= -nom;
-
- *dst_nom = nom;
- *dst_den = den;
-
- return exact;
+ return den==0;
}
-int64_t av_rescale(int64_t a, int b, int c){
- uint64_t h, l;
+int64_t av_rescale(int64_t a, int64_t b, int64_t c){
+ AVInteger ai, ci;
assert(c > 0);
assert(b >=0);
if(a<0) return -av_rescale(-a, b, c);
- h= a>>32;
- if(h==0) return a*b/c;
+ if(b<=INT_MAX && c<=INT_MAX){
+ if(a<=INT_MAX)
+ return (a * b + c/2)/c;
+ else
+ return a/c*b + (a%c*b + c/2)/c;
+ }
+
+ ai= av_mul_i(av_int2i(a), av_int2i(b));
+ ci= av_int2i(c);
+ ai= av_add_i(ai, av_shr_i(ci,1));
- l= a&0xFFFFFFFF;
- l *= b;
- h *= b;
+ return av_i2int(av_div_i(ai, ci));
+}
+
+/* av_log API */
+
+static int av_log_level = AV_LOG_DEBUG;
+
+static void av_log_default_callback(void* ptr, int level, const char* fmt, va_list vl)
+{
+ static int print_prefix=1;
+ AVClass* avc= ptr ? *(AVClass**)ptr : NULL;
+ if(level>av_log_level)
+ return;
+#undef fprintf
+ if(print_prefix && avc) {
+ fprintf(stderr, "[%s @ %p]", avc->item_name(ptr), avc);
+ }
+#define fprintf please_use_av_log
+
+ print_prefix= strstr(fmt, "\n") != NULL;
+
+ vfprintf(stderr, fmt, vl);
+}
+
+static void (*av_log_callback)(void*, int, const char*, va_list) = av_log_default_callback;
- l += (h%c)<<32;
+void av_log(void* avcl, int level, const char *fmt, ...)
+{
+ va_list vl;
+ va_start(vl, fmt);
+ av_vlog(avcl, level, fmt, vl);
+ va_end(vl);
+}
+
+void av_vlog(void* avcl, int level, const char *fmt, va_list vl)
+{
+ av_log_callback(avcl, level, fmt, vl);
+}
- return ((h/c)<<32) + l/c;
+int av_log_get_level(void)
+{
+ return av_log_level;
}
+
+void av_log_set_level(int level)
+{
+ av_log_level = level;
+}
+
+void av_log_set_callback(void (*callback)(void*, int, const char*, va_list))
+{
+ av_log_callback = callback;
+}
+
+#if !defined(HAVE_PTHREADS) && !defined(HAVE_W32THREADS)
+int avcodec_thread_init(AVCodecContext *s, int thread_count){
+ return -1;
+}
+#endif