/* * utils for libavcodec * Copyright (c) 2001 Fabrice Bellard. * Copyright (c) 2003 Michel Bardiaux for the av_log API * Copyright (c) 2002-2004 Michael Niedermayer * * This library is CC_free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file utils.c * utils. */ #include "avcodec.h" #include "avformat.h" #include "dsputil.h" #include "mpegvideo.h" #include "integer.h" #include #include #include const uint8_t ff_reverse[256]={ 0x00,0x80,0x40,0xC0,0x20,0xA0,0x60,0xE0,0x10,0x90,0x50,0xD0,0x30,0xB0,0x70,0xF0, 0x08,0x88,0x48,0xC8,0x28,0xA8,0x68,0xE8,0x18,0x98,0x58,0xD8,0x38,0xB8,0x78,0xF8, 0x04,0x84,0x44,0xC4,0x24,0xA4,0x64,0xE4,0x14,0x94,0x54,0xD4,0x34,0xB4,0x74,0xF4, 0x0C,0x8C,0x4C,0xCC,0x2C,0xAC,0x6C,0xEC,0x1C,0x9C,0x5C,0xDC,0x3C,0xBC,0x7C,0xFC, 0x02,0x82,0x42,0xC2,0x22,0xA2,0x62,0xE2,0x12,0x92,0x52,0xD2,0x32,0xB2,0x72,0xF2, 0x0A,0x8A,0x4A,0xCA,0x2A,0xAA,0x6A,0xEA,0x1A,0x9A,0x5A,0xDA,0x3A,0xBA,0x7A,0xFA, 0x06,0x86,0x46,0xC6,0x26,0xA6,0x66,0xE6,0x16,0x96,0x56,0xD6,0x36,0xB6,0x76,0xF6, 0x0E,0x8E,0x4E,0xCE,0x2E,0xAE,0x6E,0xEE,0x1E,0x9E,0x5E,0xDE,0x3E,0xBE,0x7E,0xFE, 0x01,0x81,0x41,0xC1,0x21,0xA1,0x61,0xE1,0x11,0x91,0x51,0xD1,0x31,0xB1,0x71,0xF1, 0x09,0x89,0x49,0xC9,0x29,0xA9,0x69,0xE9,0x19,0x99,0x59,0xD9,0x39,0xB9,0x79,0xF9, 0x05,0x85,0x45,0xC5,0x25,0xA5,0x65,0xE5,0x15,0x95,0x55,0xD5,0x35,0xB5,0x75,0xF5, 0x0D,0x8D,0x4D,0xCD,0x2D,0xAD,0x6D,0xED,0x1D,0x9D,0x5D,0xDD,0x3D,0xBD,0x7D,0xFD, 0x03,0x83,0x43,0xC3,0x23,0xA3,0x63,0xE3,0x13,0x93,0x53,0xD3,0x33,0xB3,0x73,0xF3, 0x0B,0x8B,0x4B,0xCB,0x2B,0xAB,0x6B,0xEB,0x1B,0x9B,0x5B,0xDB,0x3B,0xBB,0x7B,0xFB, 0x07,0x87,0x47,0xC7,0x27,0xA7,0x67,0xE7,0x17,0x97,0x57,0xD7,0x37,0xB7,0x77,0xF7, 0x0F,0x8F,0x4F,0xCF,0x2F,0xAF,0x6F,0xEF,0x1F,0x9F,0x5F,0xDF,0x3F,0xBF,0x7F,0xFF, }; static int volatile entangled_thread_counter=0; void avcodec_default_free_buffers(AVCodecContext *s); void *av_mallocz(unsigned int size) { void *ptr; ptr = av_malloc(size); if (!ptr) return NULL; memset(ptr, 0, size); return ptr; } char *av_strdup(const char *s) { char *ptr; int len; len = strlen(s) + 1; ptr = av_malloc(len); if (!ptr) return NULL; memcpy(ptr, s, len); return ptr; } /** * CC_realloc which does nothing if the block is large enough */ void *av_fast_realloc(void *ptr, unsigned int *size, unsigned int min_size) { if(min_size < *size) return ptr; *size= FFMAX(17*min_size/16 + 32, min_size); return av_realloc(ptr, *size); } static unsigned int last_static = 0; 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) { void *ptr = av_mallocz(size); if(ptr){ array_static =av_fast_realloc(array_static, &allocated_static, sizeof(void*)*(last_static+1)); if(!array_static) return NULL; array_static[last_static++] = ptr; } return ptr; } /** * same as above, but does CC_realloc */ void *av_realloc_static(void *ptr, unsigned int size) { int i; if(!ptr) return av_mallocz_static(size); /* Look for the old ptr */ for(i = 0; i < last_static; i++) { if(array_static[i] == ptr) { array_static[i] = av_realloc(array_static[i], size); return array_static[i]; } } return NULL; } /** * CC_free all static arrays and reset pointers to 0. */ void av_free_static(void) { while(last_static){ av_freep(&array_static[--last_static]); } av_freep(&array_static); } /** * 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; } /* encoder management */ AVCodec *first_avcodec = NULL; void register_avcodec(AVCodec *format) { AVCodec **p; p = &first_avcodec; while (*p != NULL) p = &(*p)->next; *p = format; format->next = NULL; } void avcodec_set_dimensions(AVCodecContext *s, int width, int height){ s->coded_width = width; s->coded_height= height; s->width = -((-width )>>s->lowres); s->height= -((-height)>>s->lowres); } typedef struct InternalBuffer{ 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: case PIX_FMT_UYVY411: 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; case PIX_FMT_BGR24: if((s->codec_id == CODEC_ID_MSZH) || (s->codec_id == CODEC_ID_ZLIB)){ 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_check_dimensions(void *av_log_ctx, unsigned int w, unsigned int h){ if((int)w>0 && (int)h>0 && (w+128)*(uint64_t)(h+128) < INT_MAX/4) return 0; av_log(av_log_ctx, AV_LOG_ERROR, "picture size invalid (%ux%u)\n", w, h); return -1; } int avcodec_default_get_buffer(AVCodecContext *s, AVFrame *pic){ int i; 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); if(avcodec_check_dimensions(s,w,h)) return -1; if(s->internal_buffer==NULL){ s->internal_buffer= av_mallocz(INTERNAL_BUFFER_SIZE*sizeof(InternalBuffer)); } #if 0 s->internal_buffer= av_fast_realloc( s->internal_buffer, &s->internal_buffer_size, sizeof(InternalBuffer)*FFMAX(99, s->internal_buffer_count+1)/*FIXME*/ ); #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= *picture_number - buf->last_pic_num; buf->last_pic_num= *picture_number; }else{ int h_chroma_shift, v_chroma_shift; int pixel_size, size[3]; AVPicture picture; avcodec_get_chroma_sub_sample(s->pix_fmt, &h_chroma_shift, &v_chroma_shift); avcodec_align_dimensions(s, &w, &h); if(!(s->flags&CODEC_FLAG_EMU_EDGE)){ w+= EDGE_WIDTH*2; h+= EDGE_WIDTH*2; } avpicture_fill(&picture, NULL, s->pix_fmt, w, h); pixel_size= picture.linesize[0]*8 / w; //av_log(NULL, AV_LOG_ERROR, "%d %d %d %d\n", (int)picture.data[1], w, h, s->pix_fmt); assert(pixel_size>=1); //FIXME next ensures that linesize= 2^x uvlinesize, thats needed because some MC code assumes it if(pixel_size == 3*8) w= ALIGN(w, STRIDE_ALIGN<pix_fmt, w, h); size[0] = picture.linesize[0] * h; size[1] -= size[0]; if(picture.data[2]) size[1]= size[2]= size[1]/2; else size[2]= 0; buf->last_pic_num= -256*256*256*64; memset(buf->base, 0, sizeof(buf->base)); memset(buf->data, 0, sizeof(buf->data)); for(i=0; i<3 && size[i]; i++){ const int h_shift= i==0 ? 0 : h_chroma_shift; const int v_shift= i==0 ? 0 : v_chroma_shift; buf->linesize[i]= picture.linesize[i]; buf->base[i]= av_malloc(size[i]+16); //FIXME 16 if(buf->base[i]==NULL) return -1; memset(buf->base[i], 128, size[i]); // no edge if EDEG EMU or not planar YUV, we check for PAL8 redundantly to protect against a exploitable bug regression ... if((s->flags&CODEC_FLAG_EMU_EDGE) || (s->pix_fmt == PIX_FMT_PAL8) || !size[2]) buf->data[i] = buf->base[i]; else buf->data[i] = buf->base[i] + ALIGN((buf->linesize[i]*EDGE_WIDTH>>v_shift) + (EDGE_WIDTH>>h_shift), STRIDE_ALIGN); } pic->age= 256*256*256*64; } 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++; return 0; } void avcodec_default_release_buffer(AVCodecContext *s, AVFrame *pic){ int i; InternalBuffer *buf, *last, temp; assert(pic->type==FF_BUFFER_TYPE_INTERNAL); assert(s->internal_buffer_count); buf = NULL; /* avoids warning */ for(i=0; iinternal_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]) break; } assert(i < s->internal_buffer_count); s->internal_buffer_count--; last = &((InternalBuffer*)s->internal_buffer)[s->internal_buffer_count]; temp= *buf; *buf= *last; *last= temp; for(i=0; i<3; i++){ pic->data[i]=NULL; // pic->base[i]=NULL; } //printf("R%X\n", pic->opaque); } 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; icodec && 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->qmax= 31; s->mb_lmin= FF_QP2LAMBDA * 2; s->mb_lmax= FF_QP2LAMBDA * 31; s->rc_eq= "tex^qComp"; s->qcompress= 0.5; s->max_qdiff= 3; s->b_quant_factor=1.25; s->b_quant_offset=1.25; s->i_quant_factor=-0.8; s->i_quant_offset=0.0; s->error_concealment= 3; s->error_resilience= 1; s->workaround_bugs= FF_BUG_AUTODETECT; s->time_base.num=0;s->time_base.den=1;// (AVRational){0,1}; s->gop_size= 50; s->me_method= ME_EPZS; 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.num=0;s->sample_aspect_ratio.den=1;// = (AVRational){0,1}; s->ildct_cmp= FF_CMP_VSAD; s->profile= FF_PROFILE_UNKNOWN; s->level= FF_LEVEL_UNKNOWN; s->me_penalty_compensation= 256; s->pix_fmt= PIX_FMT_NONE; s->frame_skip_cmp= FF_CMP_DCTMAX; s->nsse_weight= 8; 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; } /** * allocates a AVCodecContext and set it to defaults. * this can be deallocated by simply calling CC_free() */ AVCodecContext *avcodec_alloc_context(void){ AVCodecContext *avctx= av_malloc(sizeof(AVCodecContext)); if(avctx==NULL) return NULL; avcodec_get_context_defaults(avctx); return avctx; } void avcodec_get_frame_defaults(AVFrame *pic){ memset(pic, 0, sizeof(AVFrame)); pic->pts= AV_NOPTS_VALUE; pic->key_frame= 1; } /** * allocates a AVPFrame and set it to defaults. * this can be deallocated by simply calling CC_free() */ AVFrame *avcodec_alloc_frame(void){ AVFrame *pic= av_malloc(sizeof(AVFrame)); if(pic==NULL) return NULL; avcodec_get_frame_defaults(pic); return pic; } int avcodec_open(AVCodecContext *avctx, AVCodec *codec) { int ret= -1; entangled_thread_counter++; if(entangled_thread_counter != 1){ av_log(avctx, AV_LOG_ERROR, "insufficient thread locking around avcodec_open/close()\n"); goto end; } if(avctx->codec) goto end; avctx->codec = codec; avctx->codec_id = codec->id; avctx->frame_number = 0; if (codec->priv_data_size > 0) { avctx->priv_data = av_mallocz(codec->priv_data_size); if (!avctx->priv_data) goto end; } else { avctx->priv_data = NULL; } if(avctx->coded_width && avctx->coded_height) avcodec_set_dimensions(avctx, avctx->coded_width, avctx->coded_height); else if(avctx->width && avctx->height) avcodec_set_dimensions(avctx, avctx->width, avctx->height); if((avctx->coded_width||avctx->coded_height) && avcodec_check_dimensions(avctx,avctx->coded_width,avctx->coded_height)){ av_freep(&avctx->priv_data); goto end; } ret = avctx->codec->init(avctx); if (ret < 0) { av_freep(&avctx->priv_data); goto end; } ret=0; end: entangled_thread_counter--; return ret; } int avcodec_encode_audio(AVCodecContext *avctx, uint8_t *buf, int buf_size, const short *samples) { if(buf_size < FF_MIN_BUFFER_SIZE && 0){ av_log(avctx, AV_LOG_ERROR, "buffer smaller then minimum size\n"); return -1; } 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) { if(buf_size < FF_MIN_BUFFER_SIZE){ av_log(avctx, AV_LOG_ERROR, "buffer smaller then minimum size\n"); return -1; } if(avcodec_check_dimensions(avctx,avctx->width,avctx->height)) return -1; 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 an emms_c() call before every return; return ret; }else return 0; } int avcodec_encode_subtitle(AVCodecContext *avctx, uint8_t *buf, int buf_size, const AVSubtitle *sub) { int ret; ret = avctx->codec->encode(avctx, buf, buf_size, (void *)sub); avctx->frame_number++; return ret; } /** * decode a frame. * @param buf bitstream buffer, must be FF_INPUT_BUFFER_PADDING_SIZE larger then the actual read bytes * because some optimized bitstream readers read 32 or 64 bit at once and could read over the end * @param buf_size the size of the buffer in bytes * @param got_picture_ptr zero if no frame could be decompressed, Otherwise, it is non zero * @return -1 if error, otherwise return the number of * bytes used. */ int avcodec_decode_video(AVCodecContext *avctx, AVFrame *picture, int *got_picture_ptr, uint8_t *buf, int buf_size) { int ret; *got_picture_ptr= 0; if((avctx->coded_width||avctx->coded_height) && avcodec_check_dimensions(avctx,avctx->coded_width,avctx->coded_height)) return -1; if((avctx->codec->capabilities & CODEC_CAP_DELAY) || buf_size) { ret = avctx->codec->decode(avctx, picture, got_picture_ptr, buf, buf_size); emms_c(); //needed to avoid an emms_c() call before every return; if (*got_picture_ptr) avctx->frame_number++; } else ret= 0; return ret; } /* decode an audio frame. return -1 if error, otherwise return the *number of bytes used. If no frame could be decompressed, *frame_size_ptr is zero. Otherwise, it is the decompressed frame *size in BYTES. */ int avcodec_decode_audio(AVCodecContext *avctx, int16_t *samples, int *frame_size_ptr, uint8_t *buf, int buf_size) { int ret; *frame_size_ptr= 0; if((avctx->codec->capabilities & CODEC_CAP_DELAY) || buf_size){ ret = avctx->codec->decode(avctx, samples, frame_size_ptr, buf, buf_size); avctx->frame_number++; }else ret= 0; return ret; } /* decode a subtitle message. return -1 if error, otherwise return the *number of bytes used. If no subtitle could be decompressed, *got_sub_ptr is zero. Otherwise, the subtitle is stored in *sub. */ int avcodec_decode_subtitle(AVCodecContext *avctx, AVSubtitle *sub, int *got_sub_ptr, const uint8_t *buf, int buf_size) { int ret; *got_sub_ptr = 0; ret = avctx->codec->decode(avctx, sub, got_sub_ptr, (uint8_t *)buf, buf_size); if (*got_sub_ptr) avctx->frame_number++; return ret; } int avcodec_close(AVCodecContext *avctx) { entangled_thread_counter++; if(entangled_thread_counter != 1){ av_log(avctx, AV_LOG_ERROR, "insufficient thread locking around avcodec_open/close()\n"); entangled_thread_counter--; return -1; } if (avctx->codec && avctx->codec->close) avctx->codec->close(avctx); avcodec_default_free_buffers(avctx); av_freep(&avctx->priv_data); avctx->codec = NULL; entangled_thread_counter--; return 0; } AVCodec *avcodec_find_encoder(enum CodecID id) { AVCodec *p; p = first_avcodec; while (p) { if (p->encode != NULL && p->id == id) return p; p = p->next; } return NULL; } AVCodec *avcodec_find_encoder_by_name(const char *name) { AVCodec *p; p = first_avcodec; while (p) { if (p->encode != NULL && strcmp(name,p->name) == 0) return p; p = p->next; } return NULL; } AVCodec *avcodec_find_decoder(enum CodecID id) { AVCodec *p; p = first_avcodec; while (p) { if (p->decode != NULL && p->id == id) return p; p = p->next; } return NULL; } AVCodec *avcodec_find_decoder_by_name(const char *name) { AVCodec *p; p = first_avcodec; while (p) { if (p->decode != NULL && strcmp(name,p->name) == 0) return p; p = p->next; } return NULL; } unsigned avcodec_version( void ) { return LIBAVCODEC_VERSION_INT; } unsigned avcodec_build( void ) { return LIBAVCODEC_BUILD; } /* must be called before any other functions */ void avcodec_init(void) { static int inited = 0; if (inited != 0) return; inited = 1; #if __STDC_VERSION__ < 199901L { extern void avpicture_init_pixfmtinfo(void); avpicture_init_pixfmtinfo(); } #endif dsputil_static_init(); } void dump_format(AVFormatContext *ic, int index, const char *url, int is_output) { int i, flags; char buf[256]; av_log(NULL, AV_LOG_INFO, "%s #%d, %s, %s '%s':\n", is_output ? "Output" : "Input", index, is_output ? ic->oformat->name : ic->iformat->name, is_output ? "to" : "from", url); if (!is_output) { av_log(NULL, AV_LOG_INFO, " Duration: "); if (ic->duration != AV_NOPTS_VALUE) { int hours, mins, secs, us; secs = ic->duration / AV_TIME_BASE; us = ic->duration % AV_TIME_BASE; mins = secs / 60; secs %= 60; hours = mins / 60; mins %= 60; av_log(NULL, AV_LOG_INFO, "%02d:%02d:%02d.%01d", hours, mins, secs, (10 * us) / AV_TIME_BASE); } else { av_log(NULL, AV_LOG_INFO, "N/A"); } if (ic->start_time != AV_NOPTS_VALUE) { int secs, us; av_log(NULL, AV_LOG_INFO, ", start: "); secs = ic->start_time / AV_TIME_BASE; us = ic->start_time % AV_TIME_BASE; av_log(NULL, AV_LOG_INFO, "%d.%06d", secs, (int)av_rescale(us, 1000000, AV_TIME_BASE)); } av_log(NULL, AV_LOG_INFO, ", bitrate: "); if (ic->bit_rate) { av_log(NULL, AV_LOG_INFO,"%d kb/s", ic->bit_rate / 1000); } else { av_log(NULL, AV_LOG_INFO, "N/A"); } av_log(NULL, AV_LOG_INFO, "\n"); } for(i=0;inb_streams;i++) { AVStream *st = ic->streams[i]; int g= ff_gcd(st->time_base.num, st->time_base.den); //avcodec_string(buf, sizeof(buf), st->codec, is_output); av_log(NULL, AV_LOG_INFO, " Stream #%d.%d", index, i); /* the pid is an important information, so we display it */ /* XXX: add a generic system */ if (is_output) flags = ic->oformat->flags; else flags = ic->iformat->flags; if (flags & AVFMT_SHOW_IDS) { av_log(NULL, AV_LOG_INFO, "[0x%x]", st->id); } if (strlen(st->language) > 0) { av_log(NULL, AV_LOG_INFO, "(%s)", st->language); } av_log(NULL, AV_LOG_DEBUG, ", %d/%d", st->time_base.num/g, st->time_base.den/g); if(st->codec->codec_type == CODEC_TYPE_VIDEO){ if(st->r_frame_rate.den && st->r_frame_rate.num) av_log(NULL, AV_LOG_INFO, ", %5.2f fps(r)", av_q2d(st->r_frame_rate)); /* else if(st->time_base.den && st->time_base.num) av_log(NULL, AV_LOG_INFO, ", %5.2f fps(m)", 1/av_q2d(st->time_base));*/ else av_log(NULL, AV_LOG_INFO, ", %5.2f fps(c)", 1/av_q2d(st->codec->time_base)); } av_log(NULL, AV_LOG_INFO, ": %s\n", buf); } } /** * Flush buffers, should be called when seeking or when swicthing to a different stream. */ void avcodec_flush_buffers(AVCodecContext *avctx) { if(avctx->codec->flush) avctx->codec->flush(avctx); } void avcodec_default_free_buffers(AVCodecContext *s){ int i, j; if(s->internal_buffer==NULL) return; for(i=0; iinternal_buffer)[i]; for(j=0; j<4; j++){ av_freep(&buf->base[j]); buf->data[j]= NULL; } } av_freep(&s->internal_buffer); s->internal_buffer_count=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 '?'; } } /* av_log API */ static int av_log_level = AV_LOG_INFO; 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; 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); } 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_THREADS) int avcodec_thread_init(AVCodecContext *s, int thread_count){ return -1; } #endif unsigned int av_xiphlacing(unsigned char *s, unsigned int v) { unsigned int n = 0; while(v >= 0xff) { *s++ = 0xff; v -= 0xff; n++; } *s = v; n++; return n; } /* absolute maximum size we read until we abort */ #define MAX_READ_SIZE 5000000 /* maximum duration until we stop analysing the stream */ #define MAX_STREAM_DURATION ((int)(AV_TIME_BASE * 2.0)) /** * Read the beginning of a media file to get stream information. This * is useful for file formats with no headers such as MPEG. This * function also compute the real frame rate in case of mpeg2 repeat * frame mode. * * @param ic media file handle * @return >=0 if OK. AVERROR_xxx if error. * @todo let user decide somehow what information is needed so we dont waste time geting stuff the user doesnt need */ extern int av_read_frame_internal(AVFormatContext *s, AVPacket *pkt); int av_find_stream_info(AVFormatContext *ic) { int i, count, ret, read_size; AVStream *st; AVPacket pkt1, *pkt; AVPacketList *pktl=NULL, **ppktl; int64_t last_dts[MAX_STREAMS]; int64_t duration_sum[MAX_STREAMS]; int duration_count[MAX_STREAMS]={0}; for(i=0;inb_streams;i++) { st = ic->streams[i]; if(st->codec->codec_type == CODEC_TYPE_VIDEO){ /* if(!st->time_base.num) st->time_base= */ if(!st->codec->time_base.num) st->codec->time_base= st->time_base; } //only for the split stuff if (!st->parser) { st->parser = av_parser_init(st->codec->codec_id); if(st->need_parsing == 2 && st->parser){ st->parser->flags |= PARSER_FLAG_COMPLETE_FRAMES; } } } for(i=0;ipacket_buffer; for(;;) { /* check if one codec still needs to be handled */ for(i=0;inb_streams;i++) { st = ic->streams[i]; /* if (!has_codec_parameters(st->codec)) break; / /* variable fps and no guess at the real fps */ if( st->codec->time_base.den >= 1000LL*st->codec->time_base.num && duration_count[i]<20 && st->codec->codec_type == CODEC_TYPE_VIDEO) break; if(st->parser && st->parser->parser->split && !st->codec->extradata) break; } if (i == ic->nb_streams) { /* NOTE: if the format has no header, then we need to read some packets to get most of the streams, so we cannot stop here */ if (!(ic->ctx_flags & AVFMTCTX_NOHEADER)) { /* if we found the info for all the codecs, we can stop */ ret = count; break; } } else { /* we did not get all the codec info, but we read too much data */ if (read_size >= MAX_READ_SIZE) { ret = count; break; } } /* NOTE: a new stream can be added there if no header in file (AVFMTCTX_NOHEADER) */ ret = av_read_frame_internal(ic, &pkt1); if (ret < 0) { /* EOF or error */ ret = -1; /* we could not have all the codec parameters before EOF */ for(i=0;inb_streams;i++) { st = ic->streams[i]; /*if (!has_codec_parameters(st->codec)) break;*/ } if (i == ic->nb_streams) ret = 0; break; } pktl = av_mallocz(sizeof(AVPacketList)); if (!pktl) { ret = AVERROR_NOMEM; break; } /* add the packet in the buffered packet list */ *ppktl = pktl; ppktl = &pktl->next; pkt = &pktl->pkt; *pkt = pkt1; /* duplicate the packet */ if (av_dup_packet(pkt) < 0) { ret = AVERROR_NOMEM; break; } read_size += pkt->size; st = ic->streams[pkt->stream_index]; st->codec_info_duration += pkt->duration; if (pkt->duration != 0) st->codec_info_nb_frames++; { int index= pkt->stream_index; int64_t last= last_dts[index]; int64_t duration= pkt->dts - last; if(pkt->dts != AV_NOPTS_VALUE && last != AV_NOPTS_VALUE && duration>0){ if(duration*duration_count[index]*10/9 < duration_sum[index]){ duration_sum[index]= duration; duration_count[index]=1; }else{ int factor= av_rescale(duration, duration_count[index], duration_sum[index]); duration_sum[index] += duration; duration_count[index]+= factor; } if(st->codec_info_nb_frames == 0 && 0) st->codec_info_duration += duration; } last_dts[pkt->stream_index]= pkt->dts; } if(st->parser && st->parser->parser->split && !st->codec->extradata){ int i= st->parser->parser->split(st->codec, pkt->data, pkt->size); if(i){ st->codec->extradata_size= i; st->codec->extradata= av_malloc(st->codec->extradata_size); memcpy(st->codec->extradata, pkt->data, st->codec->extradata_size); } } /* if still no information, we try to open the codec and to decompress the frame. We try to avoid that in most cases as it takes longer and uses more memory. For MPEG4, we need to decompress for Quicktime. */ #if 0 if (!has_codec_parameters(st->codec) /*&& (st->codec->codec_id == CODEC_ID_FLV1 || st->codec->codec_id == CODEC_ID_H264 || st->codec->codec_id == CODEC_ID_H263 || st->codec->codec_id == CODEC_ID_H261 || st->codec->codec_id == CODEC_ID_VORBIS || st->codec->codec_id == CODEC_ID_MJPEG || st->codec->codec_id == CODEC_ID_PNG || st->codec->codec_id == CODEC_ID_PAM || st->codec->codec_id == CODEC_ID_PGM || st->codec->codec_id == CODEC_ID_PGMYUV || st->codec->codec_id == CODEC_ID_PBM || st->codec->codec_id == CODEC_ID_PPM || st->codec->codec_id == CODEC_ID_SHORTEN || (st->codec->codec_id == CODEC_ID_MPEG4 && !st->need_parsing))*/) try_decode_frame(st, pkt->data, pkt->size); #endif if (av_rescale_q(st->codec_info_duration, st->time_base, AV_TIME_BASE_Q) >= MAX_STREAM_DURATION) { break; } count++; } // close codecs which where opened in try_decode_frame() for(i=0;inb_streams;i++) { st = ic->streams[i]; if(st->codec->codec) avcodec_close(st->codec); } for(i=0;inb_streams;i++) { st = ic->streams[i]; if (st->codec->codec_type == CODEC_TYPE_VIDEO) { //if(st->codec->codec_id == CODEC_ID_RAWVIDEO && !st->codec->codec_tag && !st->codec->bits_per_sample) // st->codec->codec_tag= avcodec_pix_fmt_to_codec_tag(st->codec->pix_fmt); if(duration_count[i] && st->codec->time_base.num*1000LL <= st->codec->time_base.den && st->time_base.num*duration_sum[i]/duration_count[i]*1000LL > st->time_base.den){ AVRational fps1; int64_t num, den; num= st->time_base.den*duration_count[i]; den= st->time_base.num*duration_sum[i]; av_reduce(&fps1.num, &fps1.den, num*1001, den*1000, FFMAX(st->time_base.den, st->time_base.num)/4); av_reduce(&st->r_frame_rate.num, &st->r_frame_rate.den, num, den, FFMAX(st->time_base.den, st->time_base.num)/4); if(fps1.num < st->r_frame_rate.num && fps1.den == 1 && (fps1.num==24 || fps1.num==30)){ //FIXME better decission st->r_frame_rate.num= fps1.num*1000; st->r_frame_rate.den= fps1.den*1001; } } /* set real frame rate info */ /* compute the real frame rate for telecine */ if ((st->codec->codec_id == CODEC_ID_MPEG1VIDEO || st->codec->codec_id == CODEC_ID_MPEG2VIDEO) && st->codec->sub_id == 2) { if (st->codec_info_nb_frames >= 20) { float coded_frame_rate, est_frame_rate; est_frame_rate = ((double)st->codec_info_nb_frames * AV_TIME_BASE) / (double)st->codec_info_duration ; coded_frame_rate = 1.0/av_q2d(st->codec->time_base); #if 0 printf("telecine: coded_frame_rate=%0.3f est_frame_rate=%0.3f\n", coded_frame_rate, est_frame_rate); #endif /* if we detect that it could be a telecine, we signal it. It would be better to do it at a higher level as it can change in a film */ /* if (coded_frame_rate >= 24.97 && (est_frame_rate >= 23.5 && est_frame_rate < 24.5)) { st->r_frame_rate = (AVRational){24000, 1001}; } */ } } /* if no real frame rate, use the codec one */ if (!st->r_frame_rate.num){ st->r_frame_rate.num = st->codec->time_base.den; st->r_frame_rate.den = st->codec->time_base.num; } } } //av_estimate_timings(ic); #if 0 /* correct DTS for b frame streams with no timestamps */ for(i=0;inb_streams;i++) { st = ic->streams[i]; if (st->codec->codec_type == CODEC_TYPE_VIDEO) { if(b-frames){ ppktl = &ic->packet_buffer; while(ppkt1){ if(ppkt1->stream_index != i) continue; if(ppkt1->pkt->dts < 0) break; if(ppkt1->pkt->pts != AV_NOPTS_VALUE) break; ppkt1->pkt->dts -= delta; ppkt1= ppkt1->next; } if(ppkt1) continue; st->cur_dts -= delta; } } } #endif return ret; }