ffmpeg 库yuv420转jpeg(内存)

2024-04-08 11:38
文章标签 内存 ffmpeg jpeg yuv420

本文主要是介绍ffmpeg 库yuv420转jpeg(内存),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

ffmpeg 库yuv420转jpeg(内存)

近来实现mjpeg的http实时流,需要yuv420转jpeg。了解了一下主要可以通过ffmpeg或者libjpeg(terbo)实现。
现想用ffmpeg,网上搜了一下,资料不多。比较热门的是雷神的博客:
http://blog.csdn.net/leixiaohua1020/article/details/25346147
但有个问题,例子是写文件的,使用到AVFormatContext,封装好的读写,没法从内存里搞出来。
自己对ffmpeg也是小白一个,只能慢慢查找资料研究。解决方法是自己定义AVCodecContext。

pCodecCtx = avcodec_alloc_context3(pCodec);

这样总算能拿到编码后的buff了。但还有一个问题,在调试雷神的demo的时候发现编码后的图片明显有颜色的差别。
编码前编码后

一开始以为是质量的问题,找了很久也没发现哪里可以调质量(有人知道请告诉我一声)
后来一想不太对,ffmpeg中jpeg编码输入要求YUVJ420P。但YUVJ420PYUV420P是不一样的,他们的range有大有小。参考https://en.wikipedia.org/wiki/YUV
雷神的例子中直接把YUV420P当成YUVJ420P编码可能存在颜色出错。所以解决方法就是
1.YUV420P to YUVJ420P
2.YUVJ420P to jpeg

最终加上YUV420P 转 YUVJ420P的代码就可以了。
完整的代码如下,可下载雷神的demo修改:

extern "C"
{
#include "libavutil/imgutils.h"
#include "libswscale/swscale.h"  
};
int main(int argc, char* argv[])
{AVCodec *pCodec;AVCodecContext *pCodecCtx = NULL;int i, ret, got_output;FILE *fp_in;FILE *fp_out;AVFrame *pFrame;AVPacket pkt;int y_size;int framecnt = 0;struct SwsContext *img_convert_ctx;AVFrame *pFrame2;char filename_in[] = "cuc_view_480x272.yuv";AVCodecID codec_id = AV_CODEC_ID_MJPEG;char filename_out[] = "mytest.jpg";int in_w = 480, in_h = 272;int framenum = 1;avcodec_register_all();pCodec = avcodec_find_encoder(codec_id);if (!pCodec) {printf("Codec not found\n");return -1;}pCodecCtx = avcodec_alloc_context3(pCodec);if (!pCodecCtx) {printf("Could not allocate video codec context\n");return -1;}pCodecCtx->bit_rate = 4000000;pCodecCtx->width = in_w;pCodecCtx->height = in_h;pCodecCtx->time_base.num = 1;pCodecCtx->time_base.den = 11;pCodecCtx->gop_size = 75;//pCodecCtx->max_b_frames = 0;//pCodecCtx->global_quality = 1;pCodecCtx->pix_fmt = AV_PIX_FMT_YUVJ420P;//if (codec_id == AV_CODEC_ID_H264)//  av_opt_set(pCodecCtx->priv_data, "preset", "slow", 0);if (avcodec_open2(pCodecCtx, pCodec, NULL) < 0) {printf("Could not open codec\n");return -1;}pFrame = av_frame_alloc();if (!pFrame) {printf("Could not allocate video frame\n");return -1;}pFrame->format = pCodecCtx->pix_fmt;pFrame->width = pCodecCtx->width;pFrame->height = pCodecCtx->height;ret = av_image_alloc(pFrame->data, pFrame->linesize, pCodecCtx->width, pCodecCtx->height,pCodecCtx->pix_fmt, 16);if (ret < 0) {printf("Could not allocate raw picture buffer\n");return -1;}pFrame2 = av_frame_alloc();if (!pFrame) {printf("Could not allocate video frame\n");return -1;}pFrame2->format = AV_PIX_FMT_YUV420P;pFrame2->width = pCodecCtx->width;pFrame2->height = pCodecCtx->height;ret = av_image_alloc(pFrame2->data, pFrame2->linesize, pCodecCtx->width, pCodecCtx->height,AV_PIX_FMT_YUV420P, 16);if (ret < 0) {printf("Could not allocate raw picture buffer\n");return -1;}img_convert_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height, AV_PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height, AV_PIX_FMT_YUVJ420P, SWS_BICUBIC, NULL, NULL, NULL);//Input raw datafp_in = fopen(filename_in, "rb");if (!fp_in) {printf("Could not open %s\n", filename_in);return -1;}//Output bitstreamfp_out = fopen(filename_out, "wb");if (!fp_out) {printf("Could not open %s\n", filename_out);return -1;}y_size = pCodecCtx->width * pCodecCtx->height;//Encodefor (i = 0; i < framenum; i++) {av_init_packet(&pkt);pkt.data = NULL;    // packet data will be allocated by the encoderpkt.size = 0;//Read raw YUV dataif (fread(pFrame2->data[0], 1, y_size, fp_in) <= 0 ||       // Yfread(pFrame2->data[1], 1, y_size / 4, fp_in) <= 0 ||   // Ufread(pFrame2->data[2], 1, y_size / 4, fp_in) <= 0) {   // Vreturn -1;}else if (feof(fp_in)) {break;}sws_scale(img_convert_ctx, (const uint8_t* const*)pFrame2->data, pFrame2->linesize, 0, pCodecCtx->height, pFrame->data, pFrame->linesize);pFrame->pts = i;/* encode the image */ret = avcodec_encode_video2(pCodecCtx, &pkt, pFrame, &got_output);if (ret < 0) {printf("Error encoding frame\n");return -1;}if (got_output) {printf("Succeed to encode frame: %5d\tsize:%5d\n", framecnt, pkt.size);framecnt++;fwrite(pkt.data, 1, pkt.size, fp_out);av_free_packet(&pkt);}}//Flush Encoderfor (got_output = 1; got_output; i++) {ret = avcodec_encode_video2(pCodecCtx, &pkt, NULL, &got_output);if (ret < 0) {printf("Error encoding frame\n");return -1;}if (got_output) {printf("Flush Encoder: Succeed to encode 1 frame!\tsize:%5d\n", pkt.size);fwrite(pkt.data, 1, pkt.size, fp_out);av_free_packet(&pkt);}}fclose(fp_out);avcodec_close(pCodecCtx);av_free(pCodecCtx);av_freep(&pFrame->data[0]);av_frame_free(&pFrame);av_frame_free(&pFrame2);return 0;
}

附:yuv颜色range转换原理

一开始我是想自己查查怎么转换range的。找了很久没找到什么例子,最后使用ffmpeg转换了。有时间得补补图像基础。
实际上我猜想是等比变换的,应该不会太复杂,我看了一下内存里面几个值对比了一下也比较符合。有时间看看ffmpeg的源码验证一下。
y的range是 [16,235] to [0,255]
u、v的range是 [16,240] to [0,255]

所以y的等式如下:
y420-16 / 235-16 = yj420 / 255
uv的如下:
uv420-16 / 240-16 = uvj420 / 255
根据以上求解转换。

从来没这么认真写过博客,感觉耗时甚多。不知道那些写很多博客的大神,还写的很好的是怎么做到的。

这篇关于ffmpeg 库yuv420转jpeg(内存)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/885488

相关文章

NameNode内存生产配置

Hadoop2.x 系列,配置 NameNode 内存 NameNode 内存默认 2000m ,如果服务器内存 4G , NameNode 内存可以配置 3g 。在 hadoop-env.sh 文件中配置如下。 HADOOP_NAMENODE_OPTS=-Xmx3072m Hadoop3.x 系列,配置 Nam

音视频入门基础:WAV专题(10)——FFmpeg源码中计算WAV音频文件每个packet的pts、dts的实现

一、引言 从文章《音视频入门基础:WAV专题(6)——通过FFprobe显示WAV音频文件每个数据包的信息》中我们可以知道,通过FFprobe命令可以打印WAV音频文件每个packet(也称为数据包或多媒体包)的信息,这些信息包含该packet的pts、dts: 打印出来的“pts”实际是AVPacket结构体中的成员变量pts,是以AVStream->time_base为单位的显

JVM内存调优原则及几种JVM内存调优方法

JVM内存调优原则及几种JVM内存调优方法 1、堆大小设置。 2、回收器选择。   1、在对JVM内存调优的时候不能只看操作系统级别Java进程所占用的内存,这个数值不能准确的反应堆内存的真实占用情况,因为GC过后这个值是不会变化的,因此内存调优的时候要更多地使用JDK提供的内存查看工具,比如JConsole和Java VisualVM。   2、对JVM内存的系统级的调优主要的目的是减少

JVM 常见异常及内存诊断

栈内存溢出 栈内存大小设置:-Xss size 默认除了window以外的所有操作系统默认情况大小为 1MB,window 的默认大小依赖于虚拟机内存。 栈帧过多导致栈内存溢出 下述示例代码,由于递归深度没有限制且没有设置出口,每次方法的调用都会产生一个栈帧导致了创建的栈帧过多,而导致内存溢出(StackOverflowError)。 示例代码: 运行结果: 栈帧过大导致栈内存

理解java虚拟机内存收集

学习《深入理解Java虚拟机》时个人的理解笔记 1、为什么要去了解垃圾收集和内存回收技术? 当需要排查各种内存溢出、内存泄漏问题时,当垃圾收集成为系统达到更高并发量的瓶颈时,我们就必须对这些“自动化”的技术实施必要的监控和调节。 2、“哲学三问”内存收集 what?when?how? 那些内存需要回收?什么时候回收?如何回收? 这是一个整体的问题,确定了什么状态的内存可以

NGINX轻松管理10万长连接 --- 基于2GB内存的CentOS 6.5 x86-64

转自:http://blog.chinaunix.net/xmlrpc.php?r=blog/article&uid=190176&id=4234854 一 前言 当管理大量连接时,特别是只有少量活跃连接,NGINX有比较好的CPU和RAM利用率,如今是多终端保持在线的时代,更能让NGINX发挥这个优点。本文做一个简单测试,NGINX在一个普通PC虚拟机上维护100k的HTTP

研究人员在RSA大会上演示利用恶意JPEG图片入侵企业内网

安全研究人员Marcus Murray在正在旧金山举行的RSA大会上公布了一种利用恶意JPEG图片入侵企业网络内部Windows服务器的新方法。  攻击流程及漏洞分析 最近,安全专家兼渗透测试员Marcus Murray发现了一种利用恶意JPEG图片来攻击Windows服务器的新方法,利用该方法还可以在目标网络中进行特权提升。几天前,在旧金山举行的RSA大会上,该Marcus现场展示了攻击流程,

PHP原理之内存管理中难懂的几个点

PHP的内存管理, 分为俩大部分, 第一部分是PHP自身的内存管理, 这部分主要的内容就是引用计数, 写时复制, 等等面向应用的层面的管理. 而第二部分就是今天我要介绍的, zend_alloc中描写的关于PHP自身的内存管理, 包括它是如何管理可用内存, 如何分配内存等. 另外, 为什么要写这个呢, 因为之前并没有任何资料来介绍PHP内存管理中使用的策略, 数据结构, 或者算法. 而在我们

string字符会调用new分配堆内存吗

gcc的string默认大小是32个字节,字符串小于等于15直接保存在栈上,超过之后才会使用new分配。

PHP内存泄漏问题解析

内存泄漏 内存泄漏指的是在程序运行过程中申请了内存,但是在使用完成后没有及时释放的现象, 对于普通运行时间较短的程序来说可能问题不会那么明显,但是对于长时间运行的程序, 比如Web服务器,后台进程等就比较明显了,随着系统运行占用的内存会持续上升, 可能会因为占用内存过高而崩溃,或被系统杀掉 PHP的内存泄漏 PHP属于高级语言,语言级别并没有内存的概念,在使用过程中完全不需要主动申请或释放内