热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

FFmpeg菜鸡互啄#第5篇#视频帧格式转换

关键步骤intrgbsizeavpicture_get_size(PIX_FMT_RGB24,pVCodecCtx-width,pVCodecCtx-height);算出该格式

关键步骤

int rgbsize = avpicture_get_size(PIX_FMT_RGB24, pVCodecCtx->width, pVCodecCtx->height);//算出该格式和分辨率下一帧图像的数据大小//uint8_t* rgbBuffer = (uint8_t *)av_malloc(rgbsize * sizeof(uint8_t));//分配保存图像的内存//avpicture_fill((AVPicture *)&rgbFrame, rgbBuffer, PIX_FMT_RGB24, pVCodecCtx->width, pVCodecCtx->height);//将自己分配的内存绑定到rgbFrame的data数据区avpicture_alloc((AVPicture *)&rgbFrame, PIX_FMT_RGB24, pVCodecCtx->width, pVCodecCtx->height);//为rgbFrame的data分配内存,不用自己分配SwsContext *img_convert_ctx = sws_getContext(pVCodecCtx->width, pVCodecCtx->height, AV_PIX_FMT_YUV420P, pVCodecCtx->width, pVCodecCtx->height, PIX_FMT_RGB24, SWS_FAST_BILINEAR, NULL, NULL, NULL);//转换上下文sws_scale(img_convert_ctx, (uint8_t const* const *)Frame.data, Frame.linesize, 0, pVCodecCtx->height, rgbFrame.data, rgbFrame.linesize);//转换

avpicture_get_size 算出某格式和分辨率下一帧图像的数据大小
avpicture_fill 将自己分配的内存绑定到AVFrame帧的data数据区
avpicture_alloc 为AVFrame帧的data分配内存,不用自己分配
sws_getContext 创建从一种格式到另一种格式的转换上下文
sws_scale 转换
以上的每一个函数都没有对AFrame的linesize进行有效处理,使用data的内存大小要用avpicture_get_size算出

Code

#define _CRT_SECURE_NO_WARNINGS
#include /*
#define __STDC_CONSTANT_MACROS
#ifndef INT64_C
#define INT64_C(c) (c ## LL)
#define UINT64_C(c) (c ## ULL)
#endif
*/
extern "C"
{
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
#include "libswscale/swscale.h"
#include "libavdevice/avdevice.h"
}#pragma comment(lib, "avcodec.lib")
#pragma comment(lib, "avdevice.lib")
#pragma comment(lib, "avfilter.lib")
#pragma comment(lib, "avformat.lib")
#pragma comment(lib, "avutil.lib")
#pragma comment(lib, "postproc.lib")
#pragma comment(lib, "swresample.lib")
#pragma comment(lib, "swscale.lib")#define INPUT "in.flv"
#define OUTVIDEO "video.yuv"
#define OUTAUDIO "audio.pcm"
#define OUTRGB "video.rgb"int main()
{int res &#61; 0;int videoStream &#61; -1;//标记视频流的编号int audioStream &#61; -1;//标记音频流的编号char errBuf[BUFSIZ] &#61; { 0 };FILE* fp_video &#61; fopen(OUTVIDEO, "wb&#43;");FILE* fp_audio &#61; fopen(OUTAUDIO, "wb&#43;");FILE* fp_rgb &#61; fopen(OUTRGB, "wb&#43;");//初始化FFMPEG 调用了这个才能正常适用编码器和解码器av_register_all();printf("FFmpeg&#39;s version is: %d\n", avcodec_version());//FFMPEG所有的操作都要通过这个AVFormatContext来进行AVFormatContext* pFormatCtx &#61; NULL;//打开输入视频文件//Open an input stream and read the header. The codecs are not opened.if ((res &#61; avformat_open_input(&pFormatCtx, INPUT, NULL, NULL)) <0){av_strerror(res, errBuf, sizeof(errBuf));printf("%s\n", errBuf);return -1;}//Read packets of a media file to get stream information. This is useful for file formats with no headers such as MPEG.//相当于对输入进行 “预处理”avformat_find_stream_info(pFormatCtx, NULL);av_dump_format(pFormatCtx, 0, NULL, 0); //输出视频流的信息//查找流for (int i &#61; 0; i nb_streams; &#43;&#43;i){if (pFormatCtx->streams[i]->codec->codec_type &#61;&#61; AVMEDIA_TYPE_VIDEO)videoStream &#61; i;else if (pFormatCtx->streams[i]->codec->codec_type &#61;&#61; AVMEDIA_TYPE_AUDIO)audioStream &#61; i;}if (videoStream &#61;&#61; -1){printf("Didn&#39;t find a video stream.\n");return -1;}if (audioStream &#61;&#61; -1){printf("Didn&#39;t find a audio stream.\n");return -1;}///查找解码器 AVCodecContext* pVCodecCtx &#61; pFormatCtx->streams[videoStream]->codec;AVCodec* pVCodec &#61; avcodec_find_decoder(pVCodecCtx->codec_id);if (pVCodec &#61;&#61; NULL){printf("Video Codec not found.\n");return -1;}AVCodecContext* pACodecCtx &#61; pFormatCtx->streams[audioStream]->codec;AVCodec* pACodec &#61; avcodec_find_decoder(pACodecCtx->codec_id);if (pACodec &#61;&#61; NULL){printf("Audio Codec not found.\n");return -1;}///打开解码器if (avcodec_open2(pVCodecCtx, pVCodec, NULL) <0){printf("Could not open Video codec.\n");return -1;}if (avcodec_open2(pACodecCtx, pACodec, NULL) <0){printf("Could not open Audio codec.\n");return -1;}AVFrame Frame &#61; { 0 };//不初始化&#xff0c;avcodec_decode_video2会报错AVFrame rgbFrame;AVPacket packet;int got_picture;int rgbsize &#61; avpicture_get_size(PIX_FMT_RGB24, pVCodecCtx->width, pVCodecCtx->height);//算出该格式和分辨率下一帧图像的数据大小//uint8_t* rgbBuffer &#61; (uint8_t *)av_malloc(rgbsize * sizeof(uint8_t));//分配保存图像的内存//avpicture_fill((AVPicture *)&rgbFrame, rgbBuffer, PIX_FMT_RGB24, pVCodecCtx->width, pVCodecCtx->height);//将自己分配的内存绑定到rgbFrame的data数据区avpicture_alloc((AVPicture *)&rgbFrame, PIX_FMT_RGB24, pVCodecCtx->width, pVCodecCtx->height);//为rgbFrame的data分配内存&#xff0c;不用自己分配SwsContext *img_convert_ctx &#61; sws_getContext(pVCodecCtx->width, pVCodecCtx->height, AV_PIX_FMT_YUV420P, pVCodecCtx->width, pVCodecCtx->height, PIX_FMT_RGB24, SWS_FAST_BILINEAR, NULL, NULL, NULL);//转换上下文while (1){//读取视频帧//return 0 if OK, <0 on error or end of fileif (av_read_frame(pFormatCtx, &packet) <0){break; //这里认为视频读取完了}if (packet.stream_index &#61;&#61; videoStream){//解码视频帧if (avcodec_decode_video2(pVCodecCtx, &Frame, &got_picture, &packet) <0){printf("decode Video error.\n");return -1;}if (got_picture){if (Frame.format &#61;&#61; PIX_FMT_YUV420P){//解码后YUV格式的视频像素数据保存在AVFrame的data[0]、data[1]、data[2]中。//但是这些像素值并不是连续存储的&#xff0c;每行有效像素之后存储了一些无效像素。//以亮度Y数据为例&#xff0c;data[0]中一共包含了linesize[0] * height个数据。//但是出于优化等方面的考虑&#xff0c;linesize[0]实际上并不等于宽度width&#xff0c;而是一个比宽度大一些的值。fwrite(Frame.data[0], Frame.linesize[0] * Frame.height, 1, fp_video);fwrite(Frame.data[1], Frame.linesize[1] * Frame.height / 2, 1, fp_video);fwrite(Frame.data[2], Frame.linesize[2] * Frame.height / 2, 1, fp_video);sws_scale(img_convert_ctx, (uint8_t const* const *)Frame.data, Frame.linesize, 0, pVCodecCtx->height, rgbFrame.data, rgbFrame.linesize);//转换fwrite(rgbFrame.data[0], rgbsize, 1, fp_rgb);}}}else if (packet.stream_index &#61;&#61; audioStream){//解码音频帧if (avcodec_decode_audio4(pACodecCtx, &Frame, &got_picture, &packet) <0){printf("decode Audio error.\n");return -1;}if (got_picture){if (Frame.format &#61;&#61; AV_SAMPLE_FMT_S16P)//signed 16 bits, planar 16位 平面数据{//AV_SAMPLE_FMT_S16P//代表每个data[]的数据是连续的&#xff08;planar&#xff09;&#xff0c;每个单位是16bitsfor (int i &#61; 0; i 0]; i &#43;&#61; 2){//如果是多通道的话&#xff0c;保存成c1低位、c1高位、c2低位、c2高位...for (int j &#61; 0; j 2, 1, fp_audio);}}else if (Frame.format &#61;&#61; AV_SAMPLE_FMT_FLTP){for (int i &#61; 0; i 0]; i &#43;&#61; 4){for (int j &#61; 0; j 4, 1, fp_audio);}}}}av_free_packet(&packet);//清除packet里面指向的缓冲区}fclose(fp_video);fclose(fp_audio);fclose(fp_rgb);avpicture_free((AVPicture*)&rgbFrame);//释放avpicture_alloc分配的内存avcodec_close(pVCodecCtx);//关闭解码器avcodec_close(pACodecCtx);avformat_close_input(&pFormatCtx);//关闭输入视频文件。avformat_free_context(pFormatCtx);就不需要了return 0;
}

Github

https://github.com/gongluck/FFmpegTest.git


推荐阅读
  • springmvc学习笔记(十):控制器业务方法中通过注解实现封装Javabean接收表单提交的数据
    本文介绍了在springmvc学习笔记系列的第十篇中,控制器的业务方法中如何通过注解实现封装Javabean来接收表单提交的数据。同时还讨论了当有多个注册表单且字段完全相同时,如何将其交给同一个控制器处理。 ... [详细]
  • 向QTextEdit拖放文件的方法及实现步骤
    本文介绍了在使用QTextEdit时如何实现拖放文件的功能,包括相关的方法和实现步骤。通过重写dragEnterEvent和dropEvent函数,并结合QMimeData和QUrl等类,可以轻松实现向QTextEdit拖放文件的功能。详细的代码实现和说明可以参考本文提供的示例代码。 ... [详细]
  • 本文介绍了南邮ctf-web的writeup,包括签到题和md5 collision。在CTF比赛和渗透测试中,可以通过查看源代码、代码注释、页面隐藏元素、超链接和HTTP响应头部来寻找flag或提示信息。利用PHP弱类型,可以发现md5('QNKCDZO')='0e830400451993494058024219903391'和md5('240610708')='0e462097431906509019562988736854'。 ... [详细]
  • 本文详细介绍了如何使用MySQL来显示SQL语句的执行时间,并通过MySQL Query Profiler获取CPU和内存使用量以及系统锁和表锁的时间。同时介绍了效能分析的三种方法:瓶颈分析、工作负载分析和基于比率的分析。 ... [详细]
  • 本文介绍了在iOS开发中使用UITextField实现字符限制的方法,包括利用代理方法和使用BNTextField-Limit库的实现策略。通过这些方法,开发者可以方便地限制UITextField的字符个数和输入规则。 ... [详细]
  • 本文介绍了在MFC下利用C++和MFC的特性动态创建窗口的方法,包括继承现有的MFC类并加以改造、插入工具栏和状态栏对象的声明等。同时还提到了窗口销毁的处理方法。本文详细介绍了实现方法并给出了相关注意事项。 ... [详细]
  • 本文由编程笔记#小编为大家整理,主要介绍了logistic回归(线性和非线性)相关的知识,包括线性logistic回归的代码和数据集的分布情况。希望对你有一定的参考价值。 ... [详细]
  • 在Android开发中,使用Picasso库可以实现对网络图片的等比例缩放。本文介绍了使用Picasso库进行图片缩放的方法,并提供了具体的代码实现。通过获取图片的宽高,计算目标宽度和高度,并创建新图实现等比例缩放。 ... [详细]
  • 本文分享了一个关于在C#中使用异步代码的问题,作者在控制台中运行时代码正常工作,但在Windows窗体中却无法正常工作。作者尝试搜索局域网上的主机,但在窗体中计数器没有减少。文章提供了相关的代码和解决思路。 ... [详细]
  • CSS3选择器的使用方法详解,提高Web开发效率和精准度
    本文详细介绍了CSS3新增的选择器方法,包括属性选择器的使用。通过CSS3选择器,可以提高Web开发的效率和精准度,使得查找元素更加方便和快捷。同时,本文还对属性选择器的各种用法进行了详细解释,并给出了相应的代码示例。通过学习本文,读者可以更好地掌握CSS3选择器的使用方法,提升自己的Web开发能力。 ... [详细]
  • android listview OnItemClickListener失效原因
    最近在做listview时发现OnItemClickListener失效的问题,经过查找发现是因为button的原因。不仅listitem中存在button会影响OnItemClickListener事件的失效,还会导致单击后listview每个item的背景改变,使得item中的所有有关焦点的事件都失效。本文给出了一个范例来说明这种情况,并提供了解决方法。 ... [详细]
  • 本文主要解析了Open judge C16H问题中涉及到的Magical Balls的快速幂和逆元算法,并给出了问题的解析和解决方法。详细介绍了问题的背景和规则,并给出了相应的算法解析和实现步骤。通过本文的解析,读者可以更好地理解和解决Open judge C16H问题中的Magical Balls部分。 ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • sklearn数据集库中的常用数据集类型介绍
    本文介绍了sklearn数据集库中常用的数据集类型,包括玩具数据集和样本生成器。其中详细介绍了波士顿房价数据集,包含了波士顿506处房屋的13种不同特征以及房屋价格,适用于回归任务。 ... [详细]
  • 本文介绍了一个在线急等问题解决方法,即如何统计数据库中某个字段下的所有数据,并将结果显示在文本框里。作者提到了自己是一个菜鸟,希望能够得到帮助。作者使用的是ACCESS数据库,并且给出了一个例子,希望得到的结果是560。作者还提到自己已经尝试了使用"select sum(字段2) from 表名"的语句,得到的结果是650,但不知道如何得到560。希望能够得到解决方案。 ... [详细]
author-avatar
酷的带_201
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有