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

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6
Author: wencoo
Bloghttps://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

参考

在这里插入图片描述

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6