ffmpeg学习日记121-视频-各种图片转yuv

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相关文章

ffmpeg相关文章

ffmpeg原理相关文章

ffmpeg源码分析相关文章

ffmpeg指令相关文章

ffmpeg报错相关文章

libass相关文章

c/c++相关文章

linux相关文章

后面都是一些废话,不用看,刷分的

推广一个AI学习网站

前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站

中国软件行业倡议书

精简软件开发,电脑性能越来越好,打出的程序安装包越来越大,磁盘,内存越吃越多,这不是好现象,手机同理,大家觉得呢,欢迎发表看法,各抒己见。

手机app随意读取用户通讯录,就是流氓行为,即使有时候弹窗提示是否授权,选择了否,但是他其实还是悄悄读取你的通讯录,并且随便给你的通讯录好友发推广信息,这一点是非常反感的,并且也触犯了用户的权益,这不仅是流氓行为,更是违法行为,某软件就不说了。

作者有话说

个人简介:多年工作工程经验,擅长linux下软件开发,qt,ffmpeg音视频二次开发。

欢迎各位叨扰作者,如果有什么项目合作,创业合伙需要研发,网站推广,猎头服务,内推等等,尽管来联系,对于能挣钱的事,作者可是很感兴趣的哦。

关于内卷

劝大家一句,不要内卷,内卷只能害了别人,害了自己。

一句话伤害3次

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

WenCoo

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值