织梦CMS - 轻松建站从此开始!

罗索

从ffmpeg源代码分析如何解决ffmpeg编码的延迟问题

落鹤生 发布于 2013-10-15 18:57 点击:次 
这篇文章记录了我阅读ffmpeg源代码解决问题的各个环节,以备后用,也希望我的这些文字可以给遇到同样问题的人提供一点点帮助。
TAG:

近日在做一个分布式转码服务器,解码器是采用开源的ffmpeg,在开发的过程中遇到一个问题:编码延迟多大5、6秒钟,也就是最初编码的几十帧并不能马上 取出,而我们的要求是实时编码!虽然我对视频编码方面不是很熟悉,但根据开发的经验,我想必定可以通过设置一些参数来改变这些情况。但我本人接触 ffmpeg项目时间并不长,对很多与编解码方面参数的设置并不熟悉,于是google了很久,网上也有相关方面的讨论,说什么的都有,但我试了不行,更 有甚者说修改源代码的,这个可能能够解决问题,但修改源代码毕竟不是解决问题的最佳途径。于是决定分析一下源代码,跟踪源码来找出问题的根源。

    首先我使用的ffmpeg源代码版本是1.0.3,同时给出我的测试代码,项目中的代码就不给出来了,我给个简单的玩具代码:

 

  1. /** 
  2.  * @file 
  3.  * libavcodec API use example. 
  4.  * 
  5.  * Note that libavcodec only handles codecs (mpeg, mpeg4, etc...), 
  6.  * not file formats (avi, vob, mp4, mov, mkv, mxf, flv, mpegts, mpegps, etc...).
  7. * See library 'libavformat' for the 
  8.  * format handling 
  9.  */ 
  10.  
  11. #if _MSC_VER 
  12. #define snprintf _snprintf 
  13. #endif 
  14.  
  15. #include <stdio.h> 
  16. #include <math.h> 
  17.  
  18. extern "C" { 
  19. #include <libavutil/opt.h>        // for av_opt_set 
  20. #include <libavcodec/avcodec.h> 
  21. #include <libavutil/imgutils.h> 
  22. }; 
  23.  
  24. /* 
  25.  * Video encoding example 
  26.  */ 
  27. static void video_encode_example(const char *filename, int codec_id) 
  28.     AVCodec *codec; 
  29.     AVCodecContext *c= NULL; 
  30.     int i, ret, x, y, got_output; 
  31.     FILE *f; 
  32.     AVFrame *picture; 
  33.     AVPacket pkt; 
  34.     uint8_t endcode[] = { 0, 0, 1, 0xb7 }; 
  35.  
  36.     printf("Encode video file %s\n", filename); 
  37.  
  38.     /* find the mpeg1 video encoder */ 
  39.     codec = avcodec_find_encoder((AVCodecID)codec_id); 
  40.     if (!codec) { 
  41.         fprintf(stderr, "codec not found\n"); 
  42.         exit(1); 
  43.     } 
  44.  
  45.     c = avcodec_alloc_context3(codec); 
  46.  
  47.     /* put sample parameters */ 
  48.     c->bit_rate = 400000; 
  49.     /* resolution must be a multiple of two */ 
  50.     c->width = 800/*352*/
  51.     c->height = 500/*288*/
  52.     /* frames per second */ 
  53.     c->time_base.den = 1; 
  54.     c->time_base.num = 25; 
  55.     c->gop_size = 10; /* emit one intra frame every ten frames */ 
  56.     c->max_b_frames=1; 
  57.     c->pix_fmt = PIX_FMT_YUV420P; 
  58.  
  59.     /* open it */ 
  60.     if (avcodec_open2(c, codec, NULL) < 0) { 
  61.         fprintf(stderr, "could not open codec\n"); 
  62.         exit(1); 
  63.     } 
  64.  
  65.     f = fopen(filename, "wb"); 
  66.     if (!f) { 
  67.         fprintf(stderr, "could not open %s\n", filename); 
  68.         exit(1); 
  69.     } 
  70.  
  71.     picture = avcodec_alloc_frame(); 
  72.     if (!picture) { 
  73.         fprintf(stderr, "Could not allocate video frame\n"); 
  74.         exit(1); 
  75.     } 
  76.     picture->format = c->pix_fmt; 
  77.     picture->width  = c->width; 
  78.     picture->height = c->height; 
  79.  
  80.     /* the image can be allocated by any means and av_image_alloc() is 
  81.      * just the most convenient way if av_malloc() is to be used */ 
  82.     ret = av_image_alloc(picture->data, picture->linesize, c->width, c->height, 
  83.                          c->pix_fmt, 32); 
  84.     if (ret < 0) { 
  85.         fprintf(stderr, "could not alloc raw picture buffer\n"); 
  86.         exit(1); 
  87.     } 
  88.  
  89.     static int delayedFrame = 0; 
  90.     /* encode 1 second of video */ 
  91.     for(i=0;i<25;i++) { 
  92.         av_init_packet(&pkt); 
  93.         pkt.data = NULL;    // packet data will be allocated by the encoder 
  94.         pkt.size = 0; 
  95.  
  96.         fflush(stdout); 
  97.         /* prepare a dummy image */ 
  98.         /* Y */ 
  99.         for(y=0;y<c->height;y++) { 
  100.             for(x=0;x<c->width;x++) { 
  101.                 picture->data[0][y * picture->linesize[0] + x] = x + y + i * 3; 
  102.             } 
  103.         } 
  104.  
  105.         /* Cb and Cr */ 
  106.         for(y=0;y<c->height/2;y++) { 
  107.             for(x=0;x<c->width/2;x++) { 
  108.                 picture->data[1][y * picture->linesize[1] + x] = 128 + y + i * 2; 
  109.                 picture->data[2][y * picture->linesize[2] + x] = 64 + x + i * 5; 
  110.             } 
  111.         } 
  112.  
  113.         picture->pts = i; 
  114.  
  115.         printf("encoding frame %3d----", i); 
  116.         /* encode the image */ 
  117.         ret = avcodec_encode_video2(c, &pkt, picture, &got_output); 
  118.         if (ret < 0) { 
  119.             fprintf(stderr, "error encoding frame\n"); 
  120.             exit(1); 
  121.         } 
  122.  
  123.         if (got_output) { 
  124.             printf("output frame %3d (size=%5d)\n", i-delayedFrame, pkt.size); 
  125.             fwrite(pkt.data, 1, pkt.size, f); 
  126.             av_free_packet(&pkt); 
  127.         } 
  128.         else { 
  129.             delayedFrame++; 
  130.             printf("no output frame\n"); 
  131.         } 
  132.     } 
  133.  
  134.     /* get the delayed frames */ 
  135.     for (got_output = 1; got_output; i++) { 
  136.         fflush(stdout); 
  137.  
  138.         ret = avcodec_encode_video2(c, &pkt, NULL, &got_output); 
  139.         if (ret < 0) { 
  140.             fprintf(stderr, "error encoding frame\n"); 
  141.             exit(1); 
  142.         } 
  143.  
  144.         if (got_output) { 
  145.             printf("output delayed frame %3d (size=%5d)\n", i-delayedFrame, pkt.size); 
  146.             fwrite(pkt.data, 1, pkt.size, f); 
  147.             av_free_packet(&pkt); 
  148.         } 
  149.     } 
  150.  
  151.     /* add sequence end code to have a real mpeg file */ 
  152.     fwrite(endcode, 1, sizeof(endcode), f); 
  153.     fclose(f); 
  154.  
  155.     avcodec_close(c); 
  156.     av_free(c); 
  157.     av_freep(&picture->data[0]); 
  158.     av_free(picture); 
  159.     printf("\n"); 
  160. int main(int argc, char **argv) 
  161.     /* register all the codecs */ 
  162.     avcodec_register_all(); 
  163.  
  164.     video_encode_example("test.h264", AV_CODEC_ID_H264); 
  165.  
  166.     system("pause"); 
  167.  
  168.     return 0; 

运行上面的代码,我们编码25帧,发现延迟了多达18帧,如下图所示:

(ymsdu2004)

本站文章除注明转载外,均为本站原创或编译欢迎任何形式的转载,但请务必注明出处,尊重他人劳动,同学习共成长。转载请注明:文章转载自:罗索实验室 [http://www.rosoo.net/a/201310/16766.html]
本文出处:CSDN博客 作者:ymsdu2004
顶一下
(0)
0%
踩一下
(0)
0%
------分隔线----------------------------
发表评论
请自觉遵守互联网相关的政策法规,严禁发布色情、暴力、反动的言论。
评价:
表情:
用户名: 验证码:点击我更换图片
栏目列表
将本文分享到微信
织梦二维码生成器
推荐内容