FFMPEG 图像拉伸缩放及数据格式转换

本文转载自http://blog.csdn.net/li_wen01/article/details/65445743


在做摄像头数据采集处理的时候,经常会遇到摄像头输入数据格式的不同,导致编码的时候需要再进行一次数据装换。在X264的编码中,是需要将YUV的Y,U,V 三个分量的数据独立出来。遇到一些YUV交叉分布的数据就比较的麻烦,需要自己设计算法对数据进行分离。但是在FFMPEG中,它就已经包含了图像格式转换的接口,同时它还带有图像拉伸缩放的功能。下面代码实现了任意数据格式的转换和任意尺寸的缩放。

[objc]  view plain  copy
 print ?
  1. /*=============================================================================     
  2. #     FileName: scaling_image.c   
  3. #         Desc: an example of ffmpeg scale image 
  4. #       Author: licaibiao     
  5. #   LastChange: 2017-03-23     
  6. =============================================================================*/  
  7.   
  8. #include   
  9. #include   
  10.   
  11. int main(int argc, charchar **argv)  
  12. {  
  13.     enum AVPixelFormat src_pix_fmt = AV_PIX_FMT_YUYV422;  
  14.     enum AVPixelFormat dst_pix_fmt = AV_PIX_FMT_YUV420P;  
  15.     struct SwsContext *sws_ctx;  
  16.       
  17.     const charchar *dst_filename = NULL;  
  18.     const charchar *src_filename = NULL;  
  19.     const charchar *dst_size = NULL;  
  20.     const charchar *src_size = NULL;  
  21.     uint8_t *src_data[4];   
  22.     uint8_t *dst_data[4];  
  23.     int src_linesize[4];  
  24.     int dst_linesize[4];  
  25.     int src_bufsize;  
  26.     int dst_bufsize;  
  27.     int src_w ;  
  28.     int src_h ;  
  29.     int dst_w ;   
  30.     int dst_h ;  
  31.     int i;   
  32.     int ret;  
  33.   
  34.     FILEFILE *src_file;  
  35.     FILEFILE *dst_file;  
  36.   
  37.     if (argc != 5) {  
  38.         fprintf(stderr, "Usage: %s input_file input_size(w x h)  output_file  output_size(w x h)\n"  
  39.                 "API example program to show how to scale an image with libswscale.\n"  
  40.                 "This program generates a  pictures, rescales them to the given "  
  41.                 "output_size and saves them to an output file named output_file\n."  
  42.                 "\n", argv[0]);  
  43.         exit(1);  
  44.     }  
  45.       
  46.     /*source file parse*/  
  47.     src_filename = argv[1];  
  48.     src_size     = argv[2];  
  49.     if (av_parse_video_size(&src_w, &src_h, src_size) < 0) {  
  50.         fprintf(stderr,  
  51.                 "Invalid size '%s', must be in the form WxH or a valid size abbreviation\n",  
  52.                 dst_size);  
  53.         exit(1);  
  54.     }  
  55.     src_file = fopen(src_filename, "rb");  
  56.     if (!src_file) {  
  57.         fprintf(stderr, "Could not open source file %s\n", dst_filename);  
  58.         exit(1);  
  59.     }  
  60.   
  61.     /*destination file parse*/  
  62.     dst_filename = argv[3];  
  63.     dst_size     = argv[4];  
  64.     if (av_parse_video_size(&dst_w, &dst_h, dst_size) < 0) {  
  65.         fprintf(stderr,  
  66.                 "Invalid size '%s', must be in the form WxH or a valid size abbreviation\n",  
  67.                 dst_size);  
  68.         exit(1);  
  69.     }  
  70.     dst_file = fopen(dst_filename, "wb");  
  71.     if (!dst_file) {  
  72.         fprintf(stderr, "Could not open destination file %s\n", dst_filename);  
  73.         exit(1);  
  74.     }  
  75.   
  76.     /* create scaling context */  
  77.     sws_ctx = sws_getContext(src_w, src_h, src_pix_fmt, dst_w, dst_h, dst_pix_fmt,  
  78.                              SWS_BILINEAR, NULLNULLNULL);  
  79.     if (!sws_ctx) {  
  80.         fprintf(stderr,  
  81.                 "Impossible to create scale context for the conversion "  
  82.                 "fmt:%s s:%dx%d -> fmt:%s s:%dx%d\n",  
  83.                 av_get_pix_fmt_name(src_pix_fmt), src_w, src_h,  
  84.                 av_get_pix_fmt_name(dst_pix_fmt), dst_w, dst_h);  
  85.         ret = AVERROR(EINVAL);  
  86.         goto end;  
  87.     }  
  88.   
  89.     /* allocate source and destination image buffers */  
  90.     if ((ret = av_image_alloc(src_data, src_linesize, src_w, src_h, src_pix_fmt, 16)) < 0) {  
  91.         fprintf(stderr, "Could not allocate source image\n");  
  92.         goto end;  
  93.     }  
  94.     src_bufsize = ret;  
  95.   
  96.     /* buffer is going to be written to rawvideo file, no alignment */  
  97.     if ((ret = av_image_alloc(dst_data, dst_linesize, dst_w, dst_h, dst_pix_fmt, 1)) < 0) {  
  98.         fprintf(stderr, "Could not allocate destination image\n");  
  99.         goto end;  
  100.     }  
  101.     dst_bufsize = ret;  
  102.   
  103.     fread(src_data[0], 1, src_bufsize, src_file);  
  104.     sws_scale(sws_ctx, (const uint8_t * const*)src_data,  src_linesize, 0, src_h, dst_data, dst_linesize);  
  105.       
  106.     fprintf(stderr, "Scaling succeeded. Play the output file with the command:\n"  
  107.            "ffplay -f rawvideo -pix_fmt %s -video_size %dx%d %s\n",  
  108.            av_get_pix_fmt_name(dst_pix_fmt), dst_w, dst_h, dst_filename);  
  109.   
  110.     /* write scaled image to file */  
  111.     fwrite(dst_data[0], 1, dst_bufsize, dst_file);  
  112.   
  113. end:  
  114.     fclose(dst_file);  
  115.     fclose(src_file);  
  116.     av_freep(&src_data[0]);  
  117.     av_freep(&dst_data[0]);  
  118.     sws_freeContext(sws_ctx);  
  119.     return ret < 0;  
  120. }  
Mkaefile

[objc]  view plain  copy
 print ?
  1. OUT_APP      = test  
  2. INCLUDE_PATH = /usr/local/include/  
  3. INCLUDE = -I$(INCLUDE_PATH)libavutil/ -I$(INCLUDE_PATH)libavdevice/ \  
  4.             -I$(INCLUDE_PATH)libavcodec/ -I$(INCLUDE_PATH)libswresample \  
  5.             -I$(INCLUDE_PATH)libavfilter/ -I$(INCLUDE_PATH)libavformat \  
  6.             -I$(INCLUDE_PATH)libswscale/  
  7.   
  8. FFMPEG_LIBS = -lavformat -lavutil -lavdevice -lavcodec -lswresample -lavfilter -lswscale  
  9. SDL_LIBS    =   
  10. LIBS        = $(FFMPEG_LIBS)$(SDL_LIBS)  
  11.   
  12. COMPILE_OPTS = $(INCLUDE)  
  13. C            = c  
  14. OBJ          = o  
  15. C_COMPILER   = cc  
  16. C_FLAGS      = $(COMPILE_OPTS) $(CPPFLAGS) $(CFLAGS)  
  17.   
  18. LINK         = cc -o   
  19. LINK_OPTS    = -lz -lm  -lpthread  
  20. LINK_OBJ     = read_device.o   
  21.   
  22. .$(C).$(OBJ):  
  23.     $(C_COMPILER) -c -g $(C_FLAGS) $<  
  24.   
  25.   
  26. $(OUT_APP): $(LINK_OBJ)  
  27.     $(LINK)$@  $(LINK_OBJ)  $(LIBS) $(LINK_OPTS)  
  28.   
  29. clean:  
  30.         -rm -rf *.$(OBJ) $(OUT_APP) core *.core *~  *.jpeg  
运行:

[objc]  view plain  copy
 print ?
  1. licaibiao@ubuntu:~/test/FFMPEG/examples$ ./test yuyv_320_240 320x240 out640_480 640x480  
  2. Scaling succeeded. Play the output file with the command:  
  3. ffplay -f rawvideo -pix_fmt yuv420p -video_size 640x480 out640_480  
  4. licaibiao@ubuntu:~/test/FFMPEG/examples$  


    运行时输入的参数为:输入文件,,输入文件的尺寸,输出文件名,输出文件尺寸


    需要注意的是: 输入文件格式要与程序中src_pix_fmt 设置一致,输出数据格式由dst_pix_fmt 设置

FFMPEG 图像拉伸缩放及数据格式转换_第1张图片

原始输入数据yuyv_320_240


FFMPEG 图像拉伸缩放及数据格式转换_第2张图片

拉伸后的输出数据:out640_480

    博客显示的问题看上去输入与输出图像差不多大,实际图片输入是输出的1/4大小。

你可能感兴趣的:(ffmpeg)