使用libavcodec解码H264视频,C [英] Decode H264 video using libavcodec, C

查看:2361
本文介绍了使用libavcodec解码H264视频,C的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用ffmpeg / libavcodec解码一个原始的h264文件,但无法使其正常工作。输出现在应该是一个原始的YUV文件。可以使用GCC编译代码

I'm trying to decode a raw h264 file with ffmpeg/libavcodec, but can't get it to work properly. Output should be a raw YUV-File for now. It's possible to compile the code with GCC

gcc -o decoder decoder.c -L./lib/ -llibavcodec -llibavutil

avcodec.dll,avutil.dll和swresample.dll必须放在.exe的目录中开始。 CMD中的输出看起来像这样(只是其中的一部分,但总是这样):

avcodec.dll, avutil.dll and swresample.dll must be placed in the directory for the .exe to start. Output in the CMD looks like this (only part of it, but its always like this):

[h264 @ 00a80f20] reference picture missing during reorder
[h264 @ 00a80f20] Missing reference picture, default is 65562
[h264 @ 00a80f20] error while decoding MB 80 54, bytestream -10
[h264 @ 00a80f20] concealing 1649 DC, 1649 AC, 1649 MV errors in B frame
[h264 @ 00a80f20] reference picture missing during reorder
[h264 @ 00a80f20] reference picture missing during reorder
[h264 @ 00a80f20] reference picture missing during reorder
[h264 @ 00a80f20] Missing reference picture, default is 65566
[h264 @ 00a80f20] Missing reference picture, default is 65566
[h264 @ 00a80f20] Missing reference picture, default is 65566
[h264 @ 00a80f20] reference picture missing during reorder
[h264 @ 00a80f20] Missing reference picture, default is 65568
[h264 @ 00a80f20] reference picture missing during reorder
[h264 @ 00a80f20] Missing reference picture, default is 65570
[h264 @ 00a80f20] reference picture missing during reorder

我的代码

#include <stdlib.h>
#include <stdio.h>

#ifdef HAVE_AV_CONFIG_H
#undef HAVE_AV_CONFIG_H
#endif

#include "libavcodec/avcodec.h"
//#include "libavcodec/libavutil/mathematics.h"

#define INBUF_SIZE 4096

void video_decode(char *outfilename, char *filename)
{
    AVCodec *codec;
    AVCodecContext *c= NULL;
    int frame, got_picture, len;
    FILE *f, *outf;
    AVFrame *picture;
    uint8_t inbuf[INBUF_SIZE + FF_INPUT_BUFFER_PADDING_SIZE];
    AVPacket avpkt;
    int i;

    av_init_packet(&avpkt);

    memset(inbuf + INBUF_SIZE, 0, FF_INPUT_BUFFER_PADDING_SIZE);

    codec = avcodec_find_decoder(AV_CODEC_ID_H264);
    if (!codec) {
        fprintf(stderr, "codec not found\n");
        exit(1);
    }

    c = avcodec_alloc_context3(codec);
    picture = av_frame_alloc();

    if((codec->capabilities)&CODEC_CAP_TRUNCATED)
        (c->flags) |= CODEC_FLAG_TRUNCATED;

    c->height = 1080;
    c->width = 1920;

    if (avcodec_open2(c, codec, NULL) < 0) {
        fprintf(stderr, "could not open codec\n");
        exit(1);
    }

    f = fopen(filename, "rb");
    if (!f) {
        fprintf(stderr, "could not open %s\n", filename);
        exit(1);
    }

    outf = fopen(outfilename,"w");
    if(!outf){
        fprintf(stderr, "could not open %s\n", filename);
        exit(1);
    }
    frame = 0;
    for(;;) {
        avpkt.size = fread(inbuf, 1, INBUF_SIZE, f);
        if (avpkt.size == 0)
            break;

        avpkt.data = inbuf;
        while (avpkt.size > 0) {

            len = avcodec_decode_video2(c, picture, &got_picture, &avpkt);

            if (len < 0) {
                fprintf(stderr, "Error while decoding frame %d\n", frame);
                exit(1);
            }
            if (got_picture) {
                printf("saving frame %3d\n", frame);
                fflush(stdout);
                for(i=0; i<c->height; i++)
                    fwrite(picture->data[0] + i * picture->linesize[0], 1, c->width, outf  );
                for(i=0; i<c->height/2; i++)
                    fwrite(picture->data[1] + i * picture->linesize[1], 1, c->width/2, outf );
                for(i=0; i<c->height/2; i++)
                    fwrite(picture->data[2] + i * picture->linesize[2], 1, c->width/2, outf );
                frame++;
            }
            avpkt.size -= len;
            avpkt.data += len;
        }
    }

    avpkt.data = NULL;
    avpkt.size = 0;
    len = avcodec_decode_video2(c,picture, &got_picture, &avpkt);
    if(got_picture) {
        printf("saving last frame %d\n",frame);
        fflush(stdout);
        for(i=0; i<c->height; i++)
            fwrite(picture->data[0] + i * picture->linesize[0], 1, c->width, outf );
        for(i=0; i<c->height/2; i++)
            fwrite(picture->data[1] + i * picture->linesize[1], 1, c->width/2, outf );
        for(i=0; i<c->height/2; i++)
            fwrite(picture->data[2] + i * picture->linesize[2], 1, c->width/2, outf );
        frame++;
    }

    fclose(f);
    fclose(outf);

    avcodec_close(c);
    av_free(c);
    av_frame_free(&picture);
    printf("\n");
}

int main(int argc, char **argv){
    avcodec_register_all();
    video_decode("test", "trailer.264");

    return 0;
}

我也尝试过不同格式的不同视频(当然我改变了在这种情况下的代码)像MPEG1,H263,H265,但没有一个也正常工作。
我希望有人可以帮助我,告诉我在这里做错了什么。谢谢

I also tried different videos in different formats (of course i changed the codec in the code in this case) like MPEG1, H263, H265, but none of those was working properly either. I hope someone can help me with this and tell me what I'm doing wrong here. Thanks

推荐答案

avcodec_decode_video2的每个输入数据包(avpkt)应包含完整的(且仅)数据对于一帧,即不应该在帧NAL的中间被截断。所以你的代码读取和发送数据在4096字节块将不起作用。您需要通过解析附件B数据并查找起始代码并分析NAL类型(在具有多个切片的帧的情况下更多)或使用H.264的libavformat解析器来自己打包。作为H.264的解决方法,您可以尝试使用CODEC_FLAG2_CHUNKS标志,但我不知道它是多么可靠,仍然认为4096字节的块太小。

Every input packet (avpkt) for avcodec_decode_video2 should contain full (and only) data for one frame i.e. it shouldn't be truncated in the middle of the frame NALs. So your code that reads and sends data in 4096 byte chunks wouldn't work. You need to packetize it yourself by parsing Annex B data and finding start codes and analyzing NAL types (even more in case of frame having more than 1 slice) or use libavformat parser for H.264. As workaround for H.264 you can try to use CODEC_FLAG2_CHUNKS flag but I am not sure how reliable it is and still think 4096-byte chunks are too small.

这篇关于使用libavcodec解码H264视频,C的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆