学无先后,达者为师

网站首页 编程语言 正文

ffmpeg中AVFrame\AVPacket与自己的数据交互

作者:泰勒朗斯 更新时间: 2022-07-16 编程语言

在使用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;
    }
}

//该函数主要创建AVBufferRef ,并将相关数据指向其内部指针
int buf_to_bufref(MyYUV *in, int plane, AVBufferRef **buf){
   int ret;
   if (plane >= in->num_planes)
        return AVERROR(EINVAL);

    /* even though most encoders return 0 in data_offset encoding vp8 does require this value */
    //其中my_free_buffer是个回调函数,用来释放yuv数据。
    *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;
}
//下面两个函数是ffmpeg内部函数buffer.c文件中
//通过观察可以发现,其内部并没有申请数据的存储空间,只是创建了一个AVBufferRef 和一个AVBuffer ,然后让数据指针直接浅拷贝过去。
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);
    //特别注意的是ffmpeg中引用的使用,这里跟上一个案例是一样的。
    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;
}

反着来就很简单了简单的数据拷贝。

原文链接:https://blog.csdn.net/weixin_43360707/article/details/125782672

栏目分类
最近更新