avtools: move buffer management code from avconv to cmdutils.

It will be used by avplay.
This commit is contained in:
Anton Khirnov 2012-05-30 07:57:59 +02:00
parent 3ffa233595
commit d55c2e05b5
3 changed files with 172 additions and 142 deletions

142
avconv.c
View File

@ -171,19 +171,6 @@ typedef struct FilterGraph {
int nb_outputs;
} FilterGraph;
typedef struct FrameBuffer {
uint8_t *base[4];
uint8_t *data[4];
int linesize[4];
int h, w;
enum PixelFormat pix_fmt;
int refcount;
struct FrameBuffer **pool; ///< head of the buffer pool
struct FrameBuffer *next;
} FrameBuffer;
typedef struct InputStream {
int file_index;
AVStream *st;
@ -449,135 +436,6 @@ static void reset_options(OptionsContext *o)
init_opts();
}
static int alloc_buffer(FrameBuffer **pool, AVCodecContext *s, FrameBuffer **pbuf)
{
FrameBuffer *buf = av_mallocz(sizeof(*buf));
int i, ret;
const int pixel_size = av_pix_fmt_descriptors[s->pix_fmt].comp[0].step_minus1+1;
int h_chroma_shift, v_chroma_shift;
int edge = 32; // XXX should be avcodec_get_edge_width(), but that fails on svq1
int w = s->width, h = s->height;
if (!buf)
return AVERROR(ENOMEM);
if (!(s->flags & CODEC_FLAG_EMU_EDGE)) {
w += 2*edge;
h += 2*edge;
}
avcodec_align_dimensions(s, &w, &h);
if ((ret = av_image_alloc(buf->base, buf->linesize, w, h,
s->pix_fmt, 32)) < 0) {
av_freep(&buf);
return ret;
}
/* XXX this shouldn't be needed, but some tests break without this line
* those decoders are buggy and need to be fixed.
* the following tests fail:
* cdgraphics, ansi, aasc, fraps-v1, qtrle-1bit
*/
memset(buf->base[0], 128, ret);
avcodec_get_chroma_sub_sample(s->pix_fmt, &h_chroma_shift, &v_chroma_shift);
for (i = 0; i < FF_ARRAY_ELEMS(buf->data); i++) {
const int h_shift = i==0 ? 0 : h_chroma_shift;
const int v_shift = i==0 ? 0 : v_chroma_shift;
if (s->flags & CODEC_FLAG_EMU_EDGE)
buf->data[i] = buf->base[i];
else
buf->data[i] = buf->base[i] +
FFALIGN((buf->linesize[i]*edge >> v_shift) +
(pixel_size*edge >> h_shift), 32);
}
buf->w = s->width;
buf->h = s->height;
buf->pix_fmt = s->pix_fmt;
buf->pool = pool;
*pbuf = buf;
return 0;
}
static void free_buffer_pool(FrameBuffer **pool)
{
FrameBuffer *buf = *pool;
while (buf) {
*pool = buf->next;
av_freep(&buf->base[0]);
av_free(buf);
buf = *pool;
}
}
static void unref_buffer(FrameBuffer *buf)
{
FrameBuffer **pool = buf->pool;
av_assert0(buf->refcount);
buf->refcount--;
if (!buf->refcount) {
buf->next = *pool;
*pool = buf;
}
}
static int codec_get_buffer(AVCodecContext *s, AVFrame *frame)
{
FrameBuffer **pool = s->opaque;
FrameBuffer *buf;
int ret, i;
if (!*pool && (ret = alloc_buffer(pool, s, pool)) < 0)
return ret;
buf = *pool;
*pool = buf->next;
buf->next = NULL;
if (buf->w != s->width || buf->h != s->height || buf->pix_fmt != s->pix_fmt) {
av_freep(&buf->base[0]);
av_free(buf);
if ((ret = alloc_buffer(pool, s, &buf)) < 0)
return ret;
}
buf->refcount++;
frame->opaque = buf;
frame->type = FF_BUFFER_TYPE_USER;
frame->extended_data = frame->data;
frame->pkt_pts = s->pkt ? s->pkt->pts : AV_NOPTS_VALUE;
frame->width = buf->w;
frame->height = buf->h;
frame->format = buf->pix_fmt;
frame->sample_aspect_ratio = s->sample_aspect_ratio;
for (i = 0; i < FF_ARRAY_ELEMS(buf->data); i++) {
frame->base[i] = buf->base[i]; // XXX h264.c uses base though it shouldn't
frame->data[i] = buf->data[i];
frame->linesize[i] = buf->linesize[i];
}
return 0;
}
static void codec_release_buffer(AVCodecContext *s, AVFrame *frame)
{
FrameBuffer *buf = frame->opaque;
int i;
for (i = 0; i < FF_ARRAY_ELEMS(frame->data); i++)
frame->data[i] = NULL;
unref_buffer(buf);
}
static void filter_release_buffer(AVFilterBuffer *fb)
{
FrameBuffer *buf = fb->priv;
av_free(fb);
unref_buffer(buf);
}
/**
* Define a function for building a string containing a list of
* allowed formats,

View File

@ -37,6 +37,7 @@
#include "libavutil/avassert.h"
#include "libavutil/avstring.h"
#include "libavutil/mathematics.h"
#include "libavutil/imgutils.h"
#include "libavutil/parseutils.h"
#include "libavutil/pixdesc.h"
#include "libavutil/eval.h"
@ -1041,3 +1042,132 @@ void *grow_array(void *array, int elem_size, int *size, int new_size)
}
return array;
}
static int alloc_buffer(FrameBuffer **pool, AVCodecContext *s, FrameBuffer **pbuf)
{
FrameBuffer *buf = av_mallocz(sizeof(*buf));
int i, ret;
const int pixel_size = av_pix_fmt_descriptors[s->pix_fmt].comp[0].step_minus1+1;
int h_chroma_shift, v_chroma_shift;
int edge = 32; // XXX should be avcodec_get_edge_width(), but that fails on svq1
int w = s->width, h = s->height;
if (!buf)
return AVERROR(ENOMEM);
if (!(s->flags & CODEC_FLAG_EMU_EDGE)) {
w += 2*edge;
h += 2*edge;
}
avcodec_align_dimensions(s, &w, &h);
if ((ret = av_image_alloc(buf->base, buf->linesize, w, h,
s->pix_fmt, 32)) < 0) {
av_freep(&buf);
return ret;
}
/* XXX this shouldn't be needed, but some tests break without this line
* those decoders are buggy and need to be fixed.
* the following tests fail:
* cdgraphics, ansi, aasc, fraps-v1, qtrle-1bit
*/
memset(buf->base[0], 128, ret);
avcodec_get_chroma_sub_sample(s->pix_fmt, &h_chroma_shift, &v_chroma_shift);
for (i = 0; i < FF_ARRAY_ELEMS(buf->data); i++) {
const int h_shift = i==0 ? 0 : h_chroma_shift;
const int v_shift = i==0 ? 0 : v_chroma_shift;
if (s->flags & CODEC_FLAG_EMU_EDGE)
buf->data[i] = buf->base[i];
else
buf->data[i] = buf->base[i] +
FFALIGN((buf->linesize[i]*edge >> v_shift) +
(pixel_size*edge >> h_shift), 32);
}
buf->w = s->width;
buf->h = s->height;
buf->pix_fmt = s->pix_fmt;
buf->pool = pool;
*pbuf = buf;
return 0;
}
int codec_get_buffer(AVCodecContext *s, AVFrame *frame)
{
FrameBuffer **pool = s->opaque;
FrameBuffer *buf;
int ret, i;
if (!*pool && (ret = alloc_buffer(pool, s, pool)) < 0)
return ret;
buf = *pool;
*pool = buf->next;
buf->next = NULL;
if (buf->w != s->width || buf->h != s->height || buf->pix_fmt != s->pix_fmt) {
av_freep(&buf->base[0]);
av_free(buf);
if ((ret = alloc_buffer(pool, s, &buf)) < 0)
return ret;
}
buf->refcount++;
frame->opaque = buf;
frame->type = FF_BUFFER_TYPE_USER;
frame->extended_data = frame->data;
frame->pkt_pts = s->pkt ? s->pkt->pts : AV_NOPTS_VALUE;
frame->width = buf->w;
frame->height = buf->h;
frame->format = buf->pix_fmt;
frame->sample_aspect_ratio = s->sample_aspect_ratio;
for (i = 0; i < FF_ARRAY_ELEMS(buf->data); i++) {
frame->base[i] = buf->base[i]; // XXX h264.c uses base though it shouldn't
frame->data[i] = buf->data[i];
frame->linesize[i] = buf->linesize[i];
}
return 0;
}
static void unref_buffer(FrameBuffer *buf)
{
FrameBuffer **pool = buf->pool;
av_assert0(buf->refcount);
buf->refcount--;
if (!buf->refcount) {
buf->next = *pool;
*pool = buf;
}
}
void codec_release_buffer(AVCodecContext *s, AVFrame *frame)
{
FrameBuffer *buf = frame->opaque;
int i;
for (i = 0; i < FF_ARRAY_ELEMS(frame->data); i++)
frame->data[i] = NULL;
unref_buffer(buf);
}
void filter_release_buffer(AVFilterBuffer *fb)
{
FrameBuffer *buf = fb->priv;
av_free(fb);
unref_buffer(buf);
}
void free_buffer_pool(FrameBuffer **pool)
{
FrameBuffer *buf = *pool;
while (buf) {
*pool = buf->next;
av_freep(&buf->base[0]);
av_free(buf);
buf = *pool;
}
}

View File

@ -383,4 +383,46 @@ void exit_program(int ret);
*/
void *grow_array(void *array, int elem_size, int *size, int new_size);
typedef struct FrameBuffer {
uint8_t *base[4];
uint8_t *data[4];
int linesize[4];
int h, w;
enum PixelFormat pix_fmt;
int refcount;
struct FrameBuffer **pool; ///< head of the buffer pool
struct FrameBuffer *next;
} FrameBuffer;
/**
* Get a frame from the pool. This is intended to be used as a callback for
* AVCodecContext.get_buffer.
*
* @param s codec context. s->opaque must be a pointer to the head of the
* buffer pool.
* @param frame frame->opaque will be set to point to the FrameBuffer
* containing the frame data.
*/
int codec_get_buffer(AVCodecContext *s, AVFrame *frame);
/**
* A callback to be used for AVCodecContext.release_buffer along with
* codec_get_buffer().
*/
void codec_release_buffer(AVCodecContext *s, AVFrame *frame);
/**
* A callback to be used for AVFilterBuffer.free.
* @param fb buffer to free. fb->priv must be a pointer to the FrameBuffer
* containing the buffer data.
*/
void filter_release_buffer(AVFilterBuffer *fb);
/**
* Free all the buffers in the pool. This must be called after all the
* buffers have been released.
*/
void free_buffer_pool(FrameBuffer **pool);
#endif /* LIBAV_CMDUTILS_H */