在使用ffmpeg的过程中有时候我们自己的数据结构比如yuv数据或者压缩后的H264数据想要转为ffmpeg中的AVFrame或者AVPacket结构体,怎么转呢?
这个在ffmpg的libavcodec的v4l2_buffers.h/.c中有非常好的案例。
下面说说我个人的理解。
1、下面是我的yuv数据结构体
struct Private;
struct MyYUV{
uint8_t *data[8];
int planes[8];
int length;
int width;
int height;
int pix_fmt;
int off_set;
Private *private;
}
1、yuv数据转为AVFrame包数据:
void int MyYUV_2_Avframe(AVFrame *frame, MyYUV *in){
int i , ret;
frame->format = in ->pix_fmt;
for (i = 0; i < in->length; i++) {
ret = buf_to_bufref(in, i, &frame->buf[i]);
if (ret) return ret;
frame->linesize[i] = in->planes[i];
frame->data[i] = frame->buf[i]->data;
}
}
int buf_to_bufref(MyYUV *in, int plane, AVBufferRef **buf){
int ret;
if (plane >= in->num_planes)
return AVERROR(EINVAL);
*buf = av_buffer_create((char *)in->data[plane] + in->off_set,
in->data[plane] * in->height, my_free_buffer, in, 0);
if (!*buf)
return AVERROR(ENOMEM);
return ret;
}
static AVBufferRef *buffer_create(AVBuffer *buf, uint8_t *data, size_t size,
void (*free)(void *opaque, uint8_t *data),
void *opaque, int flags)
{
AVBufferRef *ref = NULL;
buf->data = data;
buf->size = size;
buf->free = free ? free : av_buffer_default_free;
buf->opaque = opaque;
atomic_init(&buf->refcount, 1);
buf->flags = flags;
ref = av_mallocz(sizeof(*ref));
if (!ref)
return NULL;
ref->buffer = buf;
ref->data = data;
ref->size = size;
return ref;
}
AVBufferRef *av_buffer_create(uint8_t *data, size_t size,
void (*free)(void *opaque, uint8_t *data),
void *opaque, int flags)
{
AVBufferRef *ret;
AVBuffer *buf = av_mallocz(sizeof(*buf));
if (!buf)
return NULL;
ret = buffer_create(buf, data, size, free, opaque, flags);
if (!ret) {
av_free(buf);
return NULL;
}
return ret;
}
2、h264数据转为AVPacket包数据:
int mybuf_to_avpkt(AVPacket *pkt, MyYUV *avbuf)
{
int ret;
av_packet_unref(pkt);
ret = buf_to_bufref(avbuf, 0, &pkt->buf);
if (ret)
return ret;
pkt->size = avbuf->planes[0] * height;
pkt->data = pkt->buf->data;
if (avbuf->buf.flags & BUF_FLAG_KEYFRAME)
pkt->flags |= AV_PKT_FLAG_KEY;
if (avbuf->buf.flags & BUF_FLAG_ERROR) {
av_log(logger(avbuf), AV_LOG_ERROR, "%s driver encode error\n", avbuf->context->name);
pkt->flags |= AV_PKT_FLAG_CORRUPT;
}
pkt->dts = pkt->pts = buf_get_pts(avbuf);
return 0;
}
反着来就很简单了简单的数据拷贝。