FFMPEG 对MP4视频解码转成YUV格式文件,Y格式文件,U格式文件,V格式文件的详细流程

1 视频解码

视频解码是将压缩后的视频(压缩格式如H264)通过对应解码算法还原为YUV视频流的过程;在计算机看来,首先输入一段01串(压缩的视频),然后进行大量的浮点运算,最后再输出更长的一段01串(还原的非压缩视频)。计算机内部可以进行浮点数计算的部件是CPU,目前市场上涌现了一批GPU和类GPU芯片,如Nvidia、海思芯片甚至Intel自家的核显。利用前者进行解码一般称为“软解码”,后者被称为“硬解码”,如果没有特殊指定,FFMPEG是用CPU进行解码的,即软解。

在这里插入图片描述

源代码

// testYuv.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>

extern "C"
{

#include "libavcodec\avcodec.h" 
#include "libavformat\avformat.h"
#include "libswscale/swscale.h" //像素处理

}


void yuv420(const char* path, int width, int height)
{
	FILE* fp = fopen(path, "rb+");
	FILE* f1 = fopen("yuv420_y.y", "wb+");
	FILE* f2 = fopen("yuv420_u.y", "wb+");
	FILE* f3 = fopen("yuv420_v.y", "wb+");
	unsigned char*p = (unsigned char*)malloc(width*height * 3 / 2);

	int i = 0;
	while (i<750)
	{
		fread(p, 1, width*height * 3 / 2, fp);
		fwrite(p, 1, width*height, f1);
		fwrite(p+ width * height, 1, width*height/4, f2);
		fwrite(p + width * height*(1+1/4), 1, width*height/4, f3);

		i++;
	}
	fclose(fp);
	fclose(f1);
	fclose(f2);
	fclose(f3);
	
}

int main()
{

	//yuv420("11.yuv", 720, 480);

	//注册所有组件
	av_register_all();
	const char* path = "11.mp4";
	const char * output = "test.yuv";

	//封装格式上下文,统领全局的结构体,保存了视频文件封装格式的相关信息
	AVFormatContext *pFormat = NULL;

	// 打开输入视频文件文件
	int ret = avformat_open_input(&pFormat, path, NULL, NULL);
	if (ret)
	{
		printf("%s", "无法打开输入视频文件\n");
		return -1;
	}

	// 3 获取视频文件信息
	ret = avformat_find_stream_info(pFormat, NULL);
	if (ret)
	{
		printf("%s", "avformat_find_stream_info failed\n");
		return -1;
	}

	int time = pFormat->duration;
	int maxtime = time / AV_TIME_BASE / 60;
	int mintime = time / AV_TIME_BASE % 60;
	printf("时长 %d分 %d秒 ", maxtime, mintime);
	av_dump_format(pFormat, NULL, path, 0);

	//获取视频流的索引位置
	//遍历所有类型的流(音频流、视频流、字幕流),找到视频流
	int VideoStream = -1, AudioStream = -1;
	VideoStream = av_find_best_stream(pFormat, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, NULL);

	/* 以下方式可以用 同av_find_best_stream
	for (int i=0; i < pFormat->nb_streams; i++)
	{
		//流的类型
		if (pFormat->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)
		{
			VideoStream = i;
			break;
		}
	}*/


	// 只有知道视频的编码方式,才能够根据编码方式去找到解码器
	//获取视频流中的编解码上下文
	AVCodecContext *pCodecCtx = pFormat->streams[VideoStream]->codec;
	if (pCodecCtx == NULL)
	{
		printf("%s", "找不到解码器\n");
		return -1;
	}

	//4.根据编解码上下文中的编码id查找对应的解码
	AVCodec* pAvCode = avcodec_find_decoder(pCodecCtx->codec_id);
	if (!pAvCode)
	{
		printf(" avcodec_find_decoder failed\n");
		return -1;
	}

	//5. 打开解码器 注意新库和老库都用avcodec_open2
	if (avcodec_open2(pCodecCtx, pAvCode, NULL) < 0)
	{
		printf("%s", "解码器无法打开\n");
		return -1;
	}

	//输出视频信息
	printf("视频的文件格式:%s\n", pFormat->iformat->name);
	printf("视频时长:%d秒\n", (pFormat->duration) / 1000000);
	printf("视频的宽高:%d,%d\n", pCodecCtx->width, pCodecCtx->height);
	printf("解码器的名称:%s\n", pAvCode->name);

	//准备读取
	//AVPacket用于存储一帧一帧的压缩数据(H264)
	//缓冲区,开辟空间

	AVPacket* packet = (AVPacket*)av_malloc(sizeof(AVPacket));
	//AVFrame用于存储解码后的像素数据(YUV)
	//内存分配
	AVFrame* pFrame = av_frame_alloc();

	//YUV 420
	AVFrame* pFrameYUV = av_frame_alloc();

	//缓冲区分配内存
	uint8_t *out_buffer = (uint8_t*)av_malloc(avpicture_get_size(
		AV_PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height));

	//初始化缓冲区 一帧图像
	avpicture_fill((AVPicture *)pFrameYUV, out_buffer, AV_PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height);

	//用于转码(缩放)的参数,转之前的宽高,转之后的宽高,格式等
	struct SwsContext *sws_ctx =
		sws_getContext(pCodecCtx->width, pCodecCtx->height,
		pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height, AV_PIX_FMT_YUV420P,
			SWS_BICUBIC, NULL, NULL, NULL);
	int got_picture;


	int width = pCodecCtx->width;
	int height = pCodecCtx->height;

	

	int frame_count = 0;

	FILE *fp_yuv = fopen(output, "wb+");
	FILE* fy = fopen("11_yuv_y.y", "wb+");
	FILE* fu = fopen("11_yuv_u.y", "wb+");
	FILE* fv = fopen("11_yuv_v.y", "wb+");
	// 6.一帧一帧的读取压缩数据
	while (av_read_frame(pFormat, packet) >= 0)
	{
		if (packet->stream_index == AVMEDIA_TYPE_VIDEO)
		{
			//7.解码一帧视频压缩数据,得到视频像素数据
			ret = avcodec_decode_video2(pFormat->streams[VideoStream]->codec, pFrame, &got_picture, packet);
			if (ret < 0)
			{
				printf(" avcodec_decode_video2 failed\n");
				return -1;
			}
			//为0说明解码完成,非0正在解码
			if (got_picture)
			{
				//AVFrame转为像素格式YUV420,宽高
			   //2 6输入、输出数据
			   //3 7输入、输出画面一行的数据的大小 AVFrame 转换是一行一行转换的
			   //4 输入数据第一列要转码的位置 从0开始
			   //5 输入画面的高度
				sws_scale(sws_ctx,(const uint8_t**)pFrame->data,
					pFrame->linesize,0,	pCodecCtx->height, pFrameYUV->data, pFrameYUV->linesize);

				//输出到YUV文件
			   //AVFrame像素帧写入文件
			   //data解码后的图像像素数据(音频采样数据)
			   //Y 亮度 UV 色度(压缩了) 人对亮度更加敏感
			   //U V 个数是Y的1/4
				fwrite(pFrameYUV->data[0], 1, width*height, fp_yuv);
				fwrite(pFrameYUV->data[1], 1, width*height / 4, fp_yuv);
				fwrite(pFrameYUV->data[2], 1, width*height / 4, fp_yuv);

				fwrite(pFrameYUV->data[0], 1, width*height, fy);
				fwrite(pFrameYUV->data[1], 1, width*height / 4, fu);
				fwrite(pFrameYUV->data[2], 1, width*height / 4, fv);
				frame_count++;
				printf("解码第%d帧\n", frame_count);

			}

		}
	}


	fclose(fp_yuv);
	fclose(fy);
	fclose(fu);
	fclose(fv);
	sws_freeContext(sws_ctx);
	av_frame_free(&pFrame);
	av_frame_free(&pFrameYUV);
	avformat_close_input(&pFormat);
	return 0;
}

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: ffmpeg是一个广泛使用的开源多媒体处理库,支持多种音视频解码格式。在使用ffmpeg进行JPG解码时,它会将JPG图像换为YUV格式。YUV是一种用于存储和传输彩色图像的格式,它将亮度(Y)和色度(U和V)分离开来。 首先,ffmpeg会读取JPG图像文件,并将其解析为像素数据。然后,它会根据JPG中的颜色信息,将像素数据换为YUV格式。Y分量表示图像的亮度信息,U和V分量表示图像的色度信息。 在进行YUV换时,ffmpeg会根据JPG图像的色彩空间信息进行自适应处理。常见的色彩空间包括RGB和YCbCr,其中YCbCr就是一种YUV的变体。通过将RGB图像换为YCbCr,可以更有效地压缩图像数据,并减少存储或传输所需的空间和带宽。 因此,当使用ffmpeg解码JPG图像时,它会将输入的JPG换为YUV格式,并提供Y,U和V三个分量的像素数据。这些像素数据可以根据需要进行进一步的处理或者用于其他操作,如视频编码、图像处理等。 总之,使用ffmpeg解码JPG图像时,它会将图像换为YUV格式,将亮度和色度信息分离开来,以便于后续的处理和应用。 ### 回答2: FFmpeg是一个开源的多媒体处理工具集,可以实现音视频的编解码码、处理等功能。在FFmpeg中,可以通过使用libjpeg库来实现JPG格式的解码。 JPG是一种常见的图片压缩格式,其编码方式使用了基于离散余弦变换(DCT)的算法。要解码JPG图片到YUV格式,需要以下几个步骤: 1. 打开JPG文件:通过FFmpeg提供的接口,可以打开并读取JPG文件。 2. 解码JPG图像:使用libjpeg库提供的函数,可以将JPG图像解码为RGB(红绿蓝)格式。 3. 换为YUV格式:在FFmpeg中,可以使用swscale库提供的函数将RGB图像换为YUV格式。YUV是一种常用的视频颜色空间,其中包括亮度(Y)和色度(U、V)分量。 4. 保存YUV图像:将换后的YUV图像保存到文件中,或者用于后续的视频处理。 需要注意的是,解码JPG到YUV格式是一个比较复杂的过程,需要对图像编码和颜色空间换等进行处理。在使用FFmpeg进行解码时,可以针对具体的需求选择不同的设置和参数,以获得所需的解码效果。 总之,使用FFmpeg可以方便地实现JPG图像解码YUV格式的功能,通过调用FFmpeg提供的接口和库函数,可以完成文件的打开、图像的解码和颜色空间的换等操作。这为后续的视频处理提供了基础。 ### 回答3: ffmpeg是一个开源的多媒体处理工具,可以在命令行中使用。jpg是一种常见的图片格式,而yuv则是一种常见的视频像素格式。 使用ffmpeg解码jpg图片到yuv像素格式的过程可以分为以下几步: 1. 安装ffmpeg:在电脑上安装ffmpeg软件,可以从官方网站或其他途径下载并安装。 2. 打开命令行界面:在电脑上打开命令行界面,可以通过搜索或者运行cmd命令打开。 3. 编写解码命令:在命令行中输入ffmpeg解码命令。命令的基本格式如下所示: `ffmpeg -i input.jpg -pix_fmt yuv420p output.yuv` 这条命令中,`-i input.jpg`表示输入的jpg图片文件,`-pix_fmt yuv420p`表示输出的像素格式为yuv420p,`output.yuv`表示输出的yuv文件名。 4. 执行命令:在命令行中按下回车键执行解码命令。此时,ffmpeg会加载输入的jpg文件,将其解码yuv420p格式,并输出到指定的文件中。 通过以上步骤,我们可以使用ffmpeg将jpg图片解码yuv像素格式。这样的操作对于一些视频处理任务或者需要将图片换为视频的应用场景非常有用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

程序员心得

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

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

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

打赏作者

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

抵扣说明:

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

余额充值