博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
OpenCV和FFMpeg图片转换对比
阅读量:6688 次
发布时间:2019-06-25

本文共 4726 字,大约阅读时间需要 15 分钟。

最近一直在处理图片,从H264解码后得到的图片是YUV图片,而且很多都是NV12的,不是YUV420P(它们的差别是NV12格式为YYY...Y UV UV UV ... UV,而420P格式为 YYY...YY UUU..U VVV...V),一张1920x1080的图片大小为3.1M,为了节省空间,我需要存储为jpg,jpeg格式实际上就是压缩后的YUV,别的不说先上代码

/* OpenCV */    cv::Mat srcimg, dstimg;    srcimg.create(height*3/2, width, CV_8UC1);    FILE* fp = fopen(yuvf, "rb");    fread(srcimg.data, 1, height*width*3/2, fp);    // 需要进行一次转化    cv::cvtColor(srcimg, dstimg, cv::COLOR_YUV2BGR_NV12);    // 文件保存,目前已经测试jpg和png文件可行    cv::imwrite(fout, dstimg);
/* libavcodec */   1     AVCodec* codec;  2     AVCodecContext* codecCtx;  3     struct SwsContext* swsCtx;  4     FILE* fp;  5     int inSz, tmpSz;  6     uint8_t *inbuff, *tmpbuff;  7     size_t rd;  8     int got_output = 0;  9     int ret = 0; 10     AVFrame *frame = NULL; 11     AVPacket  pkt; 12     if (width < 1 || height < 1 || !in || !out) 13         return -1; 14  15     // 准备转换环境 16     av_register_all(); // 必须调用,否则 avcodec_find_encoder 会失败 17     codec = avcodec_find_encoder(AV_CODEC_ID_MJPEG); 18     if (NULL == codec) { 19         return -2; 20     } 21     codecCtx = avcodec_alloc_context3(codec); 22     if (NULL == codecCtx) { 23         ret = -3; 24         goto codecctx_errout; 25     } 26     codecCtx->bit_rate = 4000000; 27     codecCtx->width =width; 28     codecCtx->height = height; 29     codecCtx->time_base = (AVRational){ 1, 25 }; 30     codecCtx->pix_fmt = AV_PIX_FMT_YUVJ420P; 31     if (avcodec_open2(codecCtx, codec, NULL) < 0) { 32         ret = -4; 33         goto codecctx_errout; 34     } 35     frame = av_frame_alloc();  36     av_init_packet(&pkt); 37     pkt.data = NULL; 38     pkt.size = 0; 39  40     // 加载源文件 41     fp = fopen(in, "rb"); 42     if (NULL == fp) { 43         ret = -5; 44         goto out; 45     } 46  47     inSz = av_image_get_buffer_size(infmt, width, height, 1); 48     if (inSz <= 0) { 49         ret = -6; 50         goto out; 51     } 52     inbuff = (uint8_t*)malloc(inSz); 53     if (NULL == inbuff) { 54         ret = -7; 55         goto out; 56     } 57     rd = fread(inbuff, 1, inSz, fp); 58     if (rd != (size_t)inSz) { 59         fclose(fp); 60         ret = -8; 61         goto allout; 62     } 63     fclose(fp); 64  65     // 转换格式为YUV420P 66     if (infmt != AV_PIX_FMT_YUVJ420P && infmt != AV_PIX_FMT_YUV420P) { 67         swsCtx = sws_getContext(width, height, infmt, width, height, AV_PIX_FMT_YUV420P, SWS_BILINEAR, 0, 0, 0); 68         if (NULL == swsCtx) { 69             ret = -9; 70             goto allout; 71         } 72         tmpSz = av_image_get_buffer_size(AV_PIX_FMT_YUV420P, width, height, 1); 73         tmpbuff = (uint8_t*)malloc(tmpSz); 74         if (NULL == tmpbuff) { 75             ret = -9; 76             goto allout; 77         } 78  79         AVFrame FrIn, FrOut; 80         av_image_fill_linesizes(FrIn.linesize, infmt, width); 81         av_image_fill_pointers(FrIn.data, infmt, height, inbuff, FrIn.linesize); 82         av_image_fill_linesizes(FrOut.linesize, AV_PIX_FMT_YUV420P, width); 83         av_image_fill_pointers(FrOut.data, AV_PIX_FMT_YUV420P, height, tmpbuff, FrOut.linesize); 84  85         sws_scale(swsCtx, (const uint8_t* const*)FrIn.data, FrIn.linesize, 0, height, FrOut.data, FrOut.linesize); 86         // 使用新的buffer 87         free(inbuff); 88         inbuff = tmpbuff; 89     } 90     // 填充AVFrame 91     frame->format = codecCtx->pix_fmt; 92     frame->width = width; 93     frame->height = height; 94  95     // 转换 96     av_image_fill_linesizes(frame->linesize, codecCtx->pix_fmt, width); 97     av_image_fill_pointers(frame->data, codecCtx->pix_fmt, height, inbuff, frame->linesize); 98     if (avcodec_send_frame(codecCtx, frame) < 0) { 99         ret = -10;100         goto allout;101     }102     if (0 == avcodec_receive_packet(codecCtx, &pkt)) {103         fp = fopen(out, "wb");104         if (fp) {105             fwrite(pkt.data, 1, pkt.size, fp);106             fclose(fp);107         }108         else {109             ret = 12;110         }111         av_packet_unref(&pkt);112     }113 114     // 环境回收115 allout:116     free(inbuff);117 out:118     sws_freeContext(swsCtx);119     av_frame_free(&frame); 120 codecctx_errout:121     avcodec_close(codecCtx);122     av_free(codecCtx);123 errout:124     return ret;

我的电脑配置I7 6700HQ,内存16G,系统Ubuntu 18.04,转换1920x1080图片结果为:OpenCV耗时超过80ms(在84左右浮动),而使用libavcodec版本只需要12ms。

OpevCV是很多做算法的喜欢的工具,可是这个效率,真的是很差 ,它的强项应该就是——代码足够短,FFMpeg使用将近100行的代码它只用了6行就完成了。

现在库包装越来越“豪华”,执行效率却是越来越低,我们真的需要这么高的硬件配置吗?还是我们被这么多工具给忽悠了?

近段在折腾Rockchip的RK3399,在前面被表扬的FFMepg这里就要被打脸了,解码1920x1080的H264视频流,FFMpeg也加入了硬解码,我测试了一下,CPU消耗也是100%,而我直接使用Rockchip提供的MPP借口解码CPU占用率维持在35%左右,没有细看FFMpeg代码,扫了一下,也是一样使用MPP接口,但就不知道为什么差别会这么大了。

转载于:https://www.cnblogs.com/darkise/p/9945699.html

你可能感兴趣的文章
单例模式的那些事
查看>>
Canvas - 时钟绘制
查看>>
linux-vsftp
查看>>
modelsim 中如何加载多个对比波形文件
查看>>
Linux内核抢占与中断返回【转】
查看>>
Linux 文件操作监控inotify功能及实现原理【转】
查看>>
环形缓冲区-模仿linux kfifo【转】
查看>>
linux arm的存储分布那些事之一
查看>>
Spring下redis的配置
查看>>
vs2010在进行数据架构比较时报'text lines should not be null'错误
查看>>
13th_july_scrapy-splash
查看>>
新浪招聘的图片滚动控制JS效果
查看>>
java 汉字转拼音 PinYin4j
查看>>
C# 操作地址 从内存中读取写入数据(初级)
查看>>
栅格那点儿事(四A)---栅格的显示与渲染
查看>>
win下实现Linux的tab自动补全
查看>>
2017 3月22日
查看>>
机器学习笔记(Washington University)- Clustering Specialization-week five
查看>>
单链表的建立/测长/打印/删除/排序/逆序/寻找中间值
查看>>
网页缓存清除
查看>>