近日在做一个分布式转码服务器,解码器是采用开源的ffmpeg,在开发的过程中遇到一个问题:编码延迟多大5、6秒钟,也就是最初编码的几十帧并不能马上 取出,而我们的要求是实时编码!虽然我对视频编码方面不是很熟悉,但根据开发的经验,我想必定可以通过设置一些参数来改变这些情况。但我本人接触 ffmpeg项目时间并不长,对很多与编解码方面参数的设置并不熟悉,于是google了很久,网上也有相关方面的讨论,说什么的都有,但我试了不行,更 有甚者说修改源代码的,这个可能能够解决问题,但修改源代码毕竟不是解决问题的最佳途径。于是决定分析一下源代码,跟踪源码来找出问题的根源。
首先我使用的ffmpeg源代码版本是1.0.3,同时给出我的测试代码,项目中的代码就不给出来了,我给个简单的玩具代码:
-
-
-
-
-
- *
-
-
-
- #if _MSC_VER
- #define snprintf _snprintf
- #endif
-
- #include <stdio.h>
- #include <math.h>
-
- extern "C" {
- #include <libavutil/opt.h> // for av_opt_set
- #include <libavcodec/avcodec.h>
- #include <libavutil/imgutils.h>
- };
-
-
-
-
- static void video_encode_example(const char *filename, int codec_id)
- {
- AVCodec *codec;
- AVCodecContext *c= NULL;
- 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);
-
-
- codec = avcodec_find_encoder((AVCodecID)codec_id);
- if (!codec) {
- fprintf(stderr, "codec not found\n");
- exit(1);
- }
-
- c = avcodec_alloc_context3(codec);
-
-
- c->bit_rate = 400000;
-
- c->width = 800;
- c->height = 500;
-
- c->time_base.den = 1;
- c->time_base.num = 25;
- c->gop_size = 10;
- c->max_b_frames=1;
- c->pix_fmt = 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 = avcodec_alloc_frame();
- 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;
-
-
-
- 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;
-
- for(i=0;i<25;i++) {
- av_init_packet(&pkt);
- pkt.data = NULL;
- pkt.size = 0;
-
- fflush(stdout);
-
-
- 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;
- }
- }
-
-
- 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);
-
- 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");
- }
- }
-
-
- 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);
- }
- }
-
-
- 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)
- {
-
- avcodec_register_all();
-
- video_encode_example("test.h264", AV_CODEC_ID_H264);
-
- system("pause");
-
- return 0;
- }
运行上面的代码,我们编码25帧,发现延迟了多达18帧,如下图所示:
(ymsdu2004) |