假设我在内存中有一个完整的视频文件,我想使用 libav 来解码整个帧。我该怎么做?关键是我可以使用 avformat_open_input() 函数直接从文件中读取,但我确实需要从存储在内存中的文件中读取。
我的 AVIOContext 实现:
class AVIOMemContext
{
public:
    AVIOMemContext(char* videoData, const int videoLen)
    {
        // Output buffer
        bufferSize = 32768;
        buffer = static_cast<char*>(av_malloc(bufferSize));
        // Internal buffer
        pos = 0;
        this->videoData = videoData;
        this->videoLen = videoLen;
        ctx_ = avio_alloc_context((unsigned char*) buffer, bufferSize, AVIO_FLAG_READ, this, &AVIOMemContext::read, &AVIOMemContext::write, &AVIOMemContext::seek);
    }
    ~AVIOMemContext()
    {
        av_free(videoData);
    }
    static int read(void *opaque, unsigned char *buf, int buf_size)
    {
        AVIOMemContext* This = static_cast<AVIOMemContext*>(opaque);
        // Read from pos to pos + buf_size
        if (This->pos + buf_size > This->videoLen)
        {
            int len = This->videoLen - This->pos;
            memcpy(buf, This->videoData + This->pos, len);
            return len;
        }
        else
        {
            memcpy(buf, This->videoData + This->pos, buf_size);
            return buf_size;
        }
    }
    static int write(void *opaque, unsigned char *buf, int buf_size)
    {
        /*
        AVIOMemContext* This = static_cast<AVIOMemContext*>(opaque);
        return fwrite(buf, 1, buf_size, This->f_);
        */
        return 0;
    }
    static int64_t seek(void *opaque, int64_t offset, int whence)
    {
        AVIOMemContext* This = static_cast<AVIOMemContext*>(opaque);
        if (offset + whence > This->videoLen)
        {
            This->pos = This->videoLen;
            return -1;
        }
        else
        {
            This->pos = offset + whence;
            return 0;
        }
    }
    AVIOContext *get_avio()
    {
        return ctx_;
    }
private:
    // Output buffer
    int bufferSize;
    char* buffer;
    // Internal buffer
    int pos;
    char* videoData;
    int videoLen;
    AVIOContext* ctx_;
};
我当前的代码:
[...]
av_register_all();
avcodec_register_all();
AVFormatContext* context;
AVCodec* pCodec;
AVPacket packet;
AVCodecContext* pCodecCtx;
int video_stream_index;
int res;
int got_picture;
// Init variables and objects
context = avformat_alloc_context();
AVIOMemContext priv_ctx(videoData, videoLen); 
context->pb = priv_ctx.get_avio();
res = avformat_find_stream_info(context, NULL);
if (res < 0)
{
    // Error
    avformat_free_context(context);
    return 0;
}
// Obtain the video stream of the total set of streams
for (unsigned int k = 0; k < context->nb_streams; ++k)
{
    if (context->streams[k]->codec->codec_type == AVMEDIA_TYPE_VIDEO)
        video_stream_index = k;
    context->streams[k]->codec->time_base.den = 90000;
}
pCodecCtx = context->streams[video_stream_index]->codec;
pCodec = avcodec_find_decoder(pCodecCtx->codec_id);
avcodec_open(pCodecCtx, pCodec);
//allocate video frame
AVFrame *pFrame = avcodec_alloc_frame();
unsigned int nFrame = 0;
while (av_read_frame(context, &packet) >= 0)
[...]
提前致谢,
迪达克·佩雷斯