Author: wencoo
Blog:https://wencoo.blog.csdn.net/
Date: 24/04/2023
Details:
文章目录
图片的解码方式和视频解码是一样的,因为视频是由一副一副的图片组成的,只不过视频的帧会前后参考,而图片是单独的一帧的格式封装。
这其中有一个功能点需要注意,不同的图片格式封装算法不同,所以解码使用的解码器也不同,我现在不清楚什么格式对应什么解码器,所以采用通过id的方式来查找解码器,是一种靠谱的行为。
实现功能
将png图片转换为yuv数据,示例代码如下:
#include <iostream>
#include <fstream>
#include <sstream>
#include <jsoncpp/json/json.h>
#include <tuple>
extern "C"
{
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavformat/avio.h>
#include <libavutil/audio_fifo.h>
#include <libavutil/avassert.h>
#include <libavutil/avstring.h>
#include <libavutil/dict.h>
#include <libavutil/frame.h>
#include <libavutil/imgutils.h>
#include <libavutil/opt.h>
#include <libavutil/pixdesc.h>
#include <libavutil/samplefmt.h>
#include <libavutil/time.h>
#include <libavutil/timestamp.h>
#include <libavfilter/buffersink.h>
#include <libavfilter/buffersrc.h>
#include <libavfilter/avfilter.h>
#include <libswresample/swresample.h>
}
int main()
{
std::cout << "Hello World!" << std::endl;
printf("ffmpeg version:%s\n", av_version_info());
int ret = 0;
// input yuv
//打开png图片
// png转换为yuv指令为:ffmpeg -i %4d.png -pix_fmt yuv420p -s 1984x1344 out.yuv
FILE *inFile = NULL;
const char *inFileName = "bg.png";
inFile = fopen(inFileName, "rb+");
if (!inFile)
{
printf("Fail to open file\n");
return -1;
}
int in_width = 48;
int in_height = 48;
// output yuv
FILE *outFile = NULL;
const char *outFileName = "output.yuv";
outFile = fopen( outFileName, "wb");
if (!outFile)
{
printf("Fail to create file for output\n");
return -1;
}
AVFormatContext *pFormatCtx = NULL;
if (avformat_open_input(&pFormatCtx, inFileName, NULL, NULL) != 0)
{
fprintf(stderr, "Couldn't open input filen");
return -1;
}
if (avformat_find_stream_info(pFormatCtx,0) < 0){
fprintf(stderr ,"av_find_stream_info ERRORn");
return -1;
}
int videoStream = -1;
for (int i = 0; i < pFormatCtx->nb_streams; i++)
{
if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)
{
videoStream = i;
fprintf(stderr ,"the first video stream index: videoStream = %d\n", videoStream);
break;
}
}
if (videoStream == -1)
return -1; // Didn't find a video stream
AVCodecContext *codeCtx = pFormatCtx->streams[videoStream]->codec;
if (!codeCtx)
{
fprintf(stderr, "Could not allocate video codec context\n");
exit(1);
}
std::cout << "pix_fmt:" << codeCtx->pix_fmt << std::endl;
//打开mp4文件
const AVCodec *codec = avcodec_find_decoder(codeCtx->codec_id);
if (!codec)
{
fprintf(stderr, "Codec not found\n");
exit(1);
}
if (avcodec_open2(codeCtx, codec, NULL) < 0)
{
fprintf(stderr, "Could not open codec\n");
exit(1);
}
AVFrame *frame = av_frame_alloc();
if (!frame)
{
fprintf(stderr, "Could not allocate video frame\n");
exit(1);
}
AVPacket *pkt = av_packet_alloc();
if (!pkt){
fprintf(stderr, "Could not allocate video packet\n");
exit(1);
}
uint8_t *video_dst_data[4] = {NULL};
int video_dst_linesize[4] = {0};
ret = av_image_alloc(video_dst_data, video_dst_linesize, in_width, in_height, codeCtx->pix_fmt,1);
if (ret < 0){
}
int video_dst_bufsize = ret;
int indexNum = 1;
while (av_read_frame(pFormatCtx, pkt) >= 0)
{
if (pkt->stream_index == videoStream){
ret = avcodec_send_packet(codeCtx,pkt);
while(ret >= 0){
ret = avcodec_receive_frame(codeCtx,frame);
if (ret < 0 || ret == AVERROR_EOF || ret == AVERROR(EAGAIN))
{
break;
}
if (codeCtx->codec->type == AVMEDIA_TYPE_VIDEO){
//获取到了yuv视频帧
av_image_copy(video_dst_data, video_dst_linesize,
(const uint8_t **)(frame->data), frame->linesize,
codeCtx->pix_fmt, in_width, in_height);
char tmpstr[100] = {};
sprintf(tmpstr, "yuv-%d.yuv", indexNum);
FILE *f1;
f1 = fopen(tmpstr, "wb");
fwrite(video_dst_data[0], 1, video_dst_bufsize, f1);
fclose(f1);
indexNum++;
}
}
}
av_packet_unref(pkt);
if (ret < 0)
break;
}
fclose(inFile);
fclose(outFile);
return 0;
}
查看转换结果
使用ffplay进行播放查看,需指定格式
ffplay.exe -f rawvideo -video_size 48x48 -pix_fmt rgba -i .\yuv-1.yuv
参考
由于笔者的水平有限, 加之编写的同时还要参与开发工作,文中难免会出现一些错误或者不准确的地方,恳请读者批评指正。如果读者有任何宝贵意见,可以加我微信 wencoo824。QQ:1419440391。
技术交流
欢迎加微信,搜索"wencoo824",进行技术交流,备注”博客音视频技术交流“
音视频领域其他技术文章的链接
opengl相关文章
- opengl日记7-ubuntu20.04开发环境opengl拓展glfw和glad环境搭建
- opengl日记8-opengl创建三角形
- opengl日记9-opengl使用纹理示例
- opengl日记10-opengl使用多个纹理示例
- opengl日记11-opengl的transformtions变换示例
- opengl日记12-opengl坐标系统
- opengl日记19-opengl文字渲染-教程示例
- opengl日记23-opengl文字渲染-渐变色-教程示例
- opengl日记25-opengl文字渲染-渲染中文渐变色动画-直线线性运动-教程示例
- opengl日记26-opengl文字渲染-渲染中文渐变色动画-贝塞尔运动-教程示例
- opengl日记27-opengl报错ERROR::SHADER::PROGRAM::LINKING_FAILED
- opengl日记28-opengl之c语言版本的glm库cglm编译使用教程
ffmpeg相关文章
ffmpeg原理相关文章
ffmpeg源码分析相关文章
- ffmpeg学习日记501-源码-parse_loglevel()函数
- ffmpeg学习日记502-源码-ffmpeg_parse_options()函数分析
- ffmpeg学习日记503-源码-transcode()函数分析
- ffmpeg学习日记504-源码-readme汉化
- ffmpeg学习日记506-源码-av_image_copy()函数分析及功能
- ffmpeg学习日记508-源码-ffmpeg --help 汉化
- ffmpeg学习日记509-源码-从ffmpeg 源码提取编码的流程分析
- ffmpeg学习日记512-源码-ubuntu20.04下源码编译
- ffmpeg学习日记513-源码-configure_filtergraph()函数分析及功能
ffmpeg指令相关文章
- ffmpeg学习日记601-指令-视频裁剪,添加bgm合成mp4
- ffmpeg学习日记602-指令-转换视频的分辨率
- ffmpeg学习日记603-指令-获取视频分辨率
- ffmpeg学习日记604-指令-将视频格式转为H264格式
- ffmpeg学习日记605-指令-获取视频的总帧数
- ffmpeg学习日记606-指令-将视频转为全I帧
- ffmpeg学习日记607-指令-将mp4视频转yuv
- ffmpeg学习日记612-指令-转换视频格式
- ffmpeg学习日记612-指令-转换视频格式
- ffmpeg学习日记614-指令-获取文件时长
- ffmpeg学习日记619-指令-透明通道视频相关指令
ffmpeg报错相关文章
libass相关文章
- libass分析1-源码分析-起源-源码编译
- libass分析2-源码分析-示例程序test.c的源码分析
- libass分析3-源码分析-libass中的宏定义分析
- libass分析5-源码分析-ASS_Track结构体分析,ass文件数据是如何存放的
- libass分析6-源码分析-ASS_Renderer结构体分析,ass文件数据是如何存放的
- libass分析8-源码分析-libass处理event中{}的逻辑
c/c++相关文章
linux相关文章
后面都是一些废话,不用看,刷分的
推广一个AI学习网站
前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站。
中国软件行业倡议书
精简软件开发,电脑性能越来越好,打出的程序安装包越来越大,磁盘,内存越吃越多,这不是好现象,手机同理,大家觉得呢,欢迎发表看法,各抒己见。
手机app随意读取用户通讯录,就是流氓行为,即使有时候弹窗提示是否授权,选择了否,但是他其实还是悄悄读取你的通讯录,并且随便给你的通讯录好友发推广信息,这一点是非常反感的,并且也触犯了用户的权益,这不仅是流氓行为,更是违法行为,某软件就不说了。
作者有话说
个人简介:多年工作工程经验,擅长linux下软件开发,qt,ffmpeg音视频二次开发。
欢迎各位叨扰作者,如果有什么项目合作,创业合伙需要研发,网站推广,猎头服务,内推等等,尽管来联系,对于能挣钱的事,作者可是很感兴趣的哦。
关于内卷
劝大家一句,不要内卷,内卷只能害了别人,害了自己。