【问题标题】:FFmpeg c++ H264 decoding errorFFmpeg c++ H264解码错误
【发布时间】:2015-06-07 01:12:17
【问题描述】:

我有一个程序,它从网络摄像头捕获视频,用 ffmpeg 编码,编码数据包然后写入缓冲区。在接收端,使用 ffmpeg 从缓冲区解码并播放。

现在我将发送者和接收者合并到一个程序中进行测试。它适用于 AV_CODEC_ID_MPEG1VIDEO,但是当我将 ffmpeg 编解码器更改为 AV_CODEC_ID_H264 时,在解码过程中,它显示错误:

整个程序在这里仅供参考,我做了一个循环让整个进度运行两次。

错误的原因是什么,H264有什么特别的吗?提前致谢!

#include <math.h>

extern "C" {

#include <libavutil/opt.h>
#include <libavcodec/avcodec.h>
#include <libavutil/channel_layout.h>
#include <libavutil/common.h>
#include <libavutil/imgutils.h>
#include <libavutil/mathematics.h>
#include <libavutil/samplefmt.h>
#include <libswscale/swscale.h>
#include "v4l2.h"
}
#include "opencv2/highgui/highgui.hpp"
#include <iostream>

using namespace cv;
using namespace std;
#define INBUF_SIZE 4096
static uint8_t inbuf[INBUF_SIZE + FF_INPUT_BUFFER_PADDING_SIZE];



static AVCodec *codec;
static AVCodecContext *c= NULL;
static int  ret,   got_output;
static int frame_count;
static FILE *f;

static AVPacket pkt;
static AVFrame *frame;
static AVFrame *frameDecode;
static AVFrame *framergb;
static uint8_t endcode[] = { 0, 0, 1, 0xb7 };
static AVPacket avpkt;
int totalSize=0;

#define SUBSITY     3



static int decode_write_frame(AVCodecContext *avctx,
                          AVFrame *frame, int *frame_count, AVPacket *pkt, int last)
{
int len, got_frame;
char buf[1024];
struct SwsContext *convert_ctx;
Mat m;
AVFrame dst;

len = avcodec_decode_video2(avctx, frame, &got_frame, pkt);
if (len < 0) {
    fprintf(stderr, "Error while decoding frame %d\n", *frame_count);
    return len;
}
if (got_frame) {
    printf("Saving %s frame %3d\n", last ? "last " : "", *frame_count);
    fflush(stdout);

int w = avctx->width;
int h = avctx->height;

/*convert AVFrame to opencv Mat frame*/

m = cv::Mat(h, w, CV_8UC3);
dst.data[0] = (uint8_t *)m.data;
avpicture_fill( (AVPicture *)&dst, dst.data[0], PIX_FMT_BGR24, w, h);

enum PixelFormat src_pixfmt = (enum PixelFormat)frame->format;
enum PixelFormat dst_pixfmt = PIX_FMT_BGR24;
convert_ctx = sws_getContext(w, h, src_pixfmt, w, h, dst_pixfmt,
                    SWS_FAST_BILINEAR, NULL, NULL, NULL);

if(convert_ctx == NULL) {
    fprintf(stderr, "Cannot initialize the conversion context!\n");
    exit(1);
}

sws_scale(convert_ctx, frame->data, frame->linesize, 0, h,
                    dst.data, dst.linesize);


    imshow("MyVideo", m);
    //video.write(m);
    waitKey(10); //wait next frame time


    (*frame_count)++;
}
if (pkt->data) {
    pkt->size -= len;
    pkt->data += len;
}
return 0;
}


static void video_decode_example(char *inbufout)
{
int bytes;
uint8_t *buffer;

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);
if (!c) {
    fprintf(stderr, "Could not allocate video codec context\n");
    exit(1);
}

if(codec->capabilities&CODEC_CAP_TRUNCATED)
    c->flags|= CODEC_FLAG_TRUNCATED; /* we do not send complete frames */


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


frameDecode = avcodec_alloc_frame();
if (!frameDecode) {
    fprintf(stderr, "Could not allocate video frame\n");
    exit(1);
}


bytes=avpicture_get_size(PIX_FMT_RGB24, CAMER_WIDTH, CAMER_HEIGHT);
buffer=(uint8_t *)av_malloc(bytes*sizeof(uint8_t));
avpicture_fill((AVPicture *)framergb, buffer, PIX_FMT_RGB24,
                CAMER_WIDTH, CAMER_HEIGHT);*/

frame_count = 0;

namedWindow("MyVideo",CV_WINDOW_AUTOSIZE); //create a window called "MyVideo"


int size1=0;
for(;;) {

    memcpy(inbuf,inbufout+size1,INBUF_SIZE);
    size1+=INBUF_SIZE;
    if (size1>(totalSize-INBUF_SIZE))
        break;
    avpkt.size=INBUF_SIZE;


    avpkt.data = inbuf;

    /*frame by frame process*/

    while (avpkt.size > 0)
        if (decode_write_frame(c, frameDecode, &frame_count, &avpkt, 0) < 0)
            exit(1);
}
avpkt.data = NULL;
avpkt.size = 0;
decode_write_frame(c, frameDecode, &frame_count, &avpkt, 1);
}
static void init_video_encode(const char *filename, AVCodecID codec_id, int max_f)
{

printf("Encode video file %s\n", filename);

/* find the mpeg1 video encoder */
codec = avcodec_find_encoder(codec_id);
if (!codec) {
    fprintf(stderr, "Codec not found\n");
    exit(1);
}

c = avcodec_alloc_context3(codec);
if (!c) {
    fprintf(stderr, "Could not allocate video codec context\n");
    exit(1);
}

/* put sample parameters */
c->bit_rate = 400000;
/* resolution must be a multiple of two */
c->width = 640;
c->height = 480;
/* frames per second */
c->time_base= (AVRational){1,25};
c->gop_size = 10; /* emit one intra frame every ten frames */
c->max_b_frames=max_f;
c->pix_fmt = AV_PIX_FMT_YUV420P;

if(codec_id == AV_CODEC_ID_H264)
    av_opt_set(c->priv_data, "preset", "slow", 0);

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

frame = avcodec_alloc_frame();
if (!frame) {
    fprintf(stderr, "Could not allocate video frame\n");
    exit(1);
}
frame->format = c->pix_fmt;
frame->width  = c->width;
frame->height = c->height;


ret = av_image_alloc(frame->data, frame->linesize, c->width, c->height,
                     c->pix_fmt, 32);

/* get the delayed frames */
if (ret < 0) {
    fprintf(stderr, "Could not allocate raw picture buffer\n");
    exit(1);
}

printf("\n");
}

int video_encode(int frameNo,char *inbufout)
{
static int count = 0;
static int i = 0;

/* encode 1 frame of video */
av_init_packet(&pkt);
pkt.data = NULL;    // packet data will be allocated by the encoder
pkt.size = 0;
//cout<<"\nBefore YUV\n";
if(count == 0)
read_yuv420(frame->data[0]);
count ++;

if(count == SUBSITY) {
count = 0;
}

frame->pts = i++;

/* encode the image */
ret = avcodec_encode_video2(c, &pkt, frame, &got_output);
if (ret < 0) {
     fprintf(stderr, "Error encoding frame\n");
     return -1;
}

if (got_output) {
     printf("Write frame %3d (size=%5d)\n", i, pkt.size);
     memcpy(inbufout+totalSize,pkt.data,pkt.size);
     totalSize+=pkt.size;
     fwrite(pkt.data, 1, pkt.size, f);

     av_free_packet(&pkt);
}
return 0;
}

void cancle_encode(void)
{
fclose(f);
avcodec_close(c);
av_free(c);
av_freep(&frame->data[0]);
avcodec_free_frame(&frame);
}


int main(int argc, char **argv)
{
int i;


char inbufout[25*50*(INBUF_SIZE + FF_INPUT_BUFFER_PADDING_SIZE)];
if(init_v4l2() < 0) {
printf("can't open camera\n");
return 0;
}

/* register all the codecs */
avcodec_register_all();



for(int j=0;j<2;j++){
    //init_video_encode("test.mpg", AV_CODEC_ID_MPEG1VIDEO, 15);
    init_video_encode("test.mpg", AV_CODEC_ID_H264, 15);
    //for(i = 0;i< 10*15;i++ ) {
    for(i = 0;i< 25*10;i++ ) {
    if(video_encode(i,inbufout) < 0)
        return 0;
    }
    cout<<"\n"<<totalSize<<"\n"<<endl;
    video_decode_example(inbufout);
    cancle_encode();
    totalSize=0;
}
exit_v4l2();


return 0;
}

【问题讨论】:

    标签: c++ video ffmpeg video-streaming h.264


    【解决方案1】:

    您需要包含parser。 ffmpeg mpeg1/2 解码器碰巧在没有解析器的情况下也能正常工作,但 h264/mp​​eg4/vp9 需要解析器,否则会出现上述错误。

    请注意,如果您使用 libavformat 进行解复用并调用 avformat_read_frame(),它会自动为您解析,但由于您自己进行缓冲区管理,因此您也需要自己包含解析器。

    【讨论】:

    • 我认为您正在链接到 0.6 分支 doxygen 而不是主干。
    • 感谢您的回答,我尝试包含“parser.h”,但没有显示此类文件和目录。 #include "libavutil/avassert.h" #include "libavutil/atomic.h" #include "libavutil/mem.h" #include "internal.h" #include "parser.h"
    • 嗨 Yoohoo,包括解析器不是源文件,它是 ffmpeg 的 API 中公开的对象。例如,在调用 avcodec_decode_video2() 之前查看 129.97.134.72:8888/h264dec.c 以及它如何使用 av_parser_parse2()。
    • 亲爱的 Bultje,非常感谢您到目前为止的帮助,当我尝试运行您提供的程序时,它给出了很多错误,似乎是由于 C 和 C++ 不兼容的问题,我正在使用 C++ ,在新问题stackoverflow.com/questions/30345495/ffmpeg-h264-parsing中查看问题
    猜你喜欢
    • 2015-08-11
    • 2012-02-24
    • 2011-11-24
    • 2011-08-26
    • 2016-11-10
    • 2020-10-06
    • 2020-06-13
    • 2012-08-03
    • 2016-04-09
    相关资源
    最近更新 更多