ffmpeg 编码延迟问题(编码后avcodec_encode_video2要延迟几帧才能got_packet 但要求是要实时编码,即立刻得到pkt)
// gcc temp.c -o 2 -I/root/ffmpeg/include/ -L/root/ffmpeg/lib -lavcodec -lavformat -lavdevice -lavutil -lswscale -lswresample //没有包含x264库
// gcc temp.c -o 2 -I/home/aston/ffmpeg-all/ffmpeg/include/ -L/home/aston/ffmpeg-all/ffmpeg/lib -lavcodec -lavformat -lavdevice -lavutil -lswscale -lswresample
// ./2
/**
* @file
* libavcodec API use example.
*
* Note that libavcodec only handles codecs (mpeg, mpeg4, etc...),
* not file formats (avi, vob, mp4, mov, mkv, mxf, flv, mpegts, mpegps, etc...). See library 'libavformat' for the
* format handling
*/
#include <stdio.h>
#include <math.h>
#include <libavutil/opt.h>
#include <libavcodec/avcodec.h>
#include <libavutil/imgutils.h>
static void video_encode_example(const char *filename, int codec_id)
{
AVCodec *codec;
int i, ret, x, y, got_output;
FILE *f;
AVFrame *picture;
AVPacket pkt;
uint8_t endcode[] = { 0, 0, 1, 0xb7 };
printf("Encode video file %s\n", filename);
printf("codec_id=%d\n",codec_id);
codec = avcodec_find_encoder(codec_id);
if (!codec) { fprintf(stderr, "codec not found\n"); exit(1); }
AVCodecContext *c = avcodec_alloc_context3(codec);
c->bit_rate = 400000;
c->width = 800; //352;
c->height = 500; //288;
c->time_base.den = 1;
c->time_base.num = 25;
c->gop_size = 10; // 一个序列GOP包含几帧
c->max_b_frames=1;
c->pix_fmt = AV_PIX_FMT_YUV420P;
if (avcodec_open2(c, codec, NULL) < 0) { fprintf(stderr, "could not open codec\n"); exit(1); }
f = fopen(filename, "wb");
if (!f) { fprintf(stderr, "could not open %s\n", filename); exit(1); }
picture = av_frame_alloc();
if (!picture) { fprintf(stderr, "Could not allocate video frame\n"); exit(1); }
picture->format = c->pix_fmt;
picture->width = c->width;
picture->height = c->height;
/* the image can be allocated by any means and av_image_alloc() is
* just the most convenient way if av_malloc() is to be used */
ret = av_image_alloc(picture->data, picture->linesize, c->width, c->height, c->pix_fmt, 32);
if (ret < 0) { fprintf(stderr, "could not alloc raw picture buffer\n"); exit(1); }
static int delayedFrame = 0;
/* encode 1 second of video */
for(i=0;i<25;i++) {
av_init_packet(&pkt);
pkt.data = NULL; // packet data will be allocated by the encoder
pkt.size = 0;
fflush(stdout);
/* prepare a dummy image */
/* Y */
for(y=0;y<c->height;y++) {
for(x=0;x<c->width;x++) {
picture->data[0][y * picture->linesize[0] + x] = x + y + i * 3;
}
}
/* Cb and Cr */
for(y=0;y<c->height/2;y++) {
for(x=0;x<c->width/2;x++) {
picture->data[1][y * picture->linesize[1] + x] = 128 + y + i * 2;
picture->data[2][y * picture->linesize[2] + x] = 64 + x + i * 5;
}
}
picture->pts = i;
printf("encoding frame %3d----", i);
/* encode the image */
ret = avcodec_encode_video2(c, &pkt, picture, &got_output);
if (ret < 0) { fprintf(stderr, "error encoding frame\n"); exit(1); }
if (got_output) {
printf("output frame %3d (size=%5d)\n", i-delayedFrame, pkt.size);
fwrite(pkt.data, 1, pkt.size, f);
av_free_packet(&pkt);
}
else {
delayedFrame++;
printf("no output frame\n");
}
}
/* get the delayed frames */
for (got_output = 1; got_output; i++) {
fflush(stdout);
ret = avcodec_encode_video2(c, &pkt, NULL, &got_output);
if (ret < 0) { fprintf(stderr, "error encoding frame\n"); exit(1); }
if (got_output) {
printf("output delayed frame %3d (size=%5d)\n", i-delayedFrame, pkt.size);
fwrite(pkt.data, 1, pkt.size, f);
av_free_packet(&pkt);
}
}
/* add sequence end code to have a real mpeg file */
fwrite(endcode, 1, sizeof(endcode), f);
fclose(f);
avcodec_close(c);
av_free(c);
av_freep(&picture->data[0]);
av_free(picture);
printf("\n");
}
int main(int argc, char **argv)
{
/* register all the codecs */
avcodec_register_all();
avdevice_register_all();
av_register_all();
video_encode_example("test.H264", AV_CODEC_ID_H264);
system("pause");
return 0;
}
avcodec_register_all 注册ffmpeg提供的所有编解码器
注册x264编码器时,有个条件判断CONFIG_LIBX264_ENCODER,我们在ffmpeg工程中查找,发现在它Config.mak中,这个文件是在咱们编译ffmpeg工程时由./configure根据你的选项自动生成的,还记得我们编译时用了--enable-libx264选项吗(我们要使用X264编码器,当然要指定该选项)?所以有CONFIG_LIBX264_ENCODER=yes,因此这里可以成功注册x264编码器,如果当初没有指定该选项,编码器是不会注册进去的。
降延迟–改参数
// 新增语句,设置为编码延迟
av_opt_set(c->priv_data, "preset", "superfast", 0);
// 实时编码关键看这句,上面那条无所谓
av_opt_set(c->priv_data, "tune", "zerolatency", 0);