You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

412 lines
9.4 KiB

/************************************************************************/
/* 编解码库使用的帮助和工具函数 */
/************************************************************************/
#include <assert.h>
#include "avcodec.h"
#include "dsputil.h"
#define EDGE_WIDTH 16
#define STRIDE_ALIGN 16
#define INT_MAX 2147483647
#define FFMAX(a,b) ((a) > (b) ? (a) : (b))
void *av_malloc(unsigned int size)
{
void *ptr;
if (size > INT_MAX)
return NULL;
ptr = malloc(size);
return ptr;
}
void *av_realloc(void *ptr, unsigned int size)
{
if (size > INT_MAX)
return NULL;
return realloc(ptr, size);
}
void av_free(void *ptr)
{
if (ptr)
free(ptr);
}
void *av_mallocz(unsigned int size)
{
void *ptr;
ptr = av_malloc(size);
if (!ptr)
return NULL;
memset(ptr, 0, size);
return ptr;
}
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);
}
void av_freep(void *arg)
{
void **ptr = (void **)arg;
av_free(*ptr);
*ptr = NULL;
}
/* 编解码器链表(因为可以支持多个编解码器,因此要把所有的编解码器用链表串起来 )*/
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;
}
typedef struct InternalBuffer
{
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: //FIXME check for non mpeg style codecs and use less alignment
w_align = 16;
h_align = 16;
break;
case PIX_FMT_YUV411P:
case PIX_FMT_UYVY411:
w_align = 32;
h_align = 8;
break;
case PIX_FMT_YUV410P:
case PIX_FMT_RGB555:
case PIX_FMT_PAL8:
break;
case PIX_FMT_BGR24:
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;
return - 1;
}
int avcodec_default_get_buffer(AVCodecContext *s, AVFrame *pic)
{
int i;
int w = s->width;
int h = s->height;
int align_off;
InternalBuffer *buf;
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));
buf = &((InternalBuffer*)s->internal_buffer)[s->internal_buffer_count];
if (buf->base[0])
{}
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);
w+= EDGE_WIDTH*2;
h+= EDGE_WIDTH*2;
avpicture_fill(&picture, NULL, s->pix_fmt, w, h);
pixel_size = picture.linesize[0] * 8 / w;
assert(pixel_size >= 1);
if (pixel_size == 3 *8)
w = ALIGN(w, STRIDE_ALIGN << h_chroma_shift);
else
w = ALIGN(pixel_size *w, STRIDE_ALIGN << (h_chroma_shift + 3)) / pixel_size;
size[1] = avpicture_fill(&picture, NULL, s->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;
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]);
align_off = ALIGN((buf->linesize[i] * EDGE_WIDTH >> v_shift) + ( EDGE_WIDTH >> h_shift), STRIDE_ALIGN);
if ((s->pix_fmt == PIX_FMT_PAL8) || !size[2])
buf->data[i] = buf->base[i];
else
buf->data[i] = buf->base[i] + align_off;
}
}
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(s->internal_buffer_count);
buf = NULL;
for (i = 0; i < s->internal_buffer_count; i++)
{
buf = &((InternalBuffer*)s->internal_buffer)[i]; //just 3-5 checks so is not worth to optimize
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;
}
}
int avcodec_default_reget_buffer(AVCodecContext *s, AVFrame *pic)
{
if (pic->data[0] == NULL) // If no picture return a new buffer
{
return s->get_buffer(s, pic);
}
return 0;
}
void avcodec_default_free_buffers(AVCodecContext *s)
{
int i, j;
if (s->internal_buffer == NULL)
return ;
for (i = 0; i < INTERNAL_BUFFER_SIZE; i++)
{
InternalBuffer *buf = &((InternalBuffer*)s->internal_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;
}
AVCodecContext *avcodec_alloc_context(void)
{
AVCodecContext *s = av_malloc(sizeof(AVCodecContext));
if (s == NULL)
return NULL;
memset(s, 0, sizeof(AVCodecContext));
s->get_buffer = avcodec_default_get_buffer;
s->release_buffer = avcodec_default_release_buffer;
s->pix_fmt = PIX_FMT_NONE;
s->palctrl = NULL;
s->reget_buffer = avcodec_default_reget_buffer;
return s;
}
int avcodec_open(AVCodecContext *avctx, AVCodec *codec)
{
int ret = - 1;
if (avctx->codec)
goto end;
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;
}
avctx->codec = codec;
avctx->codec_id = codec->id;
avctx->frame_number = 0;
ret = avctx->codec->init(avctx);
if (ret < 0)
{
av_freep(&avctx->priv_data);
avctx->codec = NULL;
goto end;
}
ret = 0;
end:
return ret;
}
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 (buf_size)
{
ret = avctx->codec->decode(avctx, picture, got_picture_ptr, buf, buf_size); // 会调用实际的编解码器的编解码函数(例如msrle等编解码器)
if (*got_picture_ptr)
avctx->frame_number++;
}
else
ret = 0;
return ret;
}
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 (buf_size)
{
ret = avctx->codec->decode(avctx, samples, frame_size_ptr, buf, buf_size);
avctx->frame_number++;
}
else
ret = 0;
return ret;
}
int avcodec_close(AVCodecContext *avctx)
{
if (avctx->codec->close)
avctx->codec->close(avctx);
avcodec_default_free_buffers(avctx);
av_freep(&avctx->priv_data);
avctx->codec = NULL;
return 0;
}
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;
}
/* 编解码器初始化 */
void avcodec_init(void)
{
static int inited = 0;
if (inited != 0)
return ;
inited = 1;
dsputil_static_init();
}