yuv数据生成器

1.YUV格式说明

上一篇yuv文章说明
从存储格式以及像素采样对yuv进行了简要说明,更为详细的阐述可参考 : https://blog.csdn.net/byhook/article/details/84037338
以下是重点:
YUV420P,Y,U,V三个分量都是平面格式,分为I420和YV12。I420格式和YV12格式的不同处在U平面和V平面的位置不同。在I420格式中,U平面紧跟在Y平面之后,然后才是V平面(即:YUV);但YV12则是相反(即:YVU)。
YUV420SP, Y分量平面格式,UV打包格式, 即NV12。 NV12与NV21类似,U 和 V 交错排列,不同在于UV顺序。
I420: YYYYYYYY UU VV =>YUV420P
YV12: YYYYYYYY VV UU =>YUV420P
NV12: YYYYYYYY UVUV =>YUV420SP
NV21: YYYYYYYY VUVU =>YUV420SP

2.YUV生成器
参考JM8.6相关configure配置,模拟出基于配置参数的动态yuv生成器,并通过JM8.6中encode_extended.cfg验证了生成yuv数据的正确性。
2.1构造配置参数
typedef struct
{
   char Inputfilenme[128];
   int FrameDecoder;
   char OutputFileName[128];
   int clCount;
   int YUVSWSCALE;
   int YUVOUTPUT;
public:
   void parser(int argc,char*argv[]);
   char *GetConfigFileContent (const char*filename);
   void ParseContent (char *buf, int bufsize);
}InputParameters;

使用vs2010环境编写,Inputfilenme表示输入视频文件名称,OutputFileName为输出yuv文件,FrameDecoder表示输出的帧数,YUVTYPE表示的是输出类型,YUVOUTPUT表示是否进行yuv文件输出(默认为1)

ConfigMapping cinfigMap[] = {
	{"InputFileName", &configinput.Inputfilenme,  1},
	{"OutputFileName", &configinput.OutputFileName,1},
	{"FrameDecoder",  &configinput.FrameDecoder,  0},
	{"YUVTYPE",  &configinput.YUVSWSCALE,  0},
	{"YUVOUTPUT",  &configinput.YUVOUTPUT,  0},
};

解析文件参数调用逻辑如下:

	memset (&configinput, 0, sizeof (InputParameters));
	configinput.parser(argc,argv);
	AV_Pareser *pParser=new AV_Pareser(configinput.Inputfilenme);

具体的音视频解析类为如下定义

AV_Pareser::AV_Pareser(const char* filename)
{
	g_filename = filename;
	av_register_all();
	avformat_network_init();
	pFormatCtx = avformat_alloc_context();
	avformat_open_input(&pFormatCtx,g_filename,NULL,NULL);
	if(avformat_find_stream_info(pFormatCtx,NULL)<0){
		printf("Couldn't find stream information.\n");
	}
	m_pVideoId = 0;
}


AV_Pareser::~AV_Pareser(void)
{
}

void AV_Pareser::Set_FormatCtx(struct AVFormatContext*ForamtCtx)
{
   pFormatCtx = ForamtCtx;
}

AVCodec*AV_Pareser::Get_Video_Codec()
{
	int videoindex=-1;
	AVCodec * pCodec = NULL;
	for(int i=0; i<pFormatCtx->nb_streams; i++) 
	if(pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_VIDEO){
		videoindex=i;
		break;
    }
	m_pVideoId = videoindex;
	pCodec = avcodec_find_decoder(pFormatCtx->streams[videoindex]->codec->codec_id);
    return pCodec;
}

AVCodec*AV_Pareser::Get_Audio_Codec()
{
	int audioindex=-1;
	AVCodec * pCodec = NULL;
	for(int i=0; i<pFormatCtx->nb_streams; i++) 
	if(pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_AUDIO){
		audioindex=i;
		break;
	}
	//m_pVideoId = videoindex;
	pCodec = avcodec_find_decoder(pFormatCtx->streams[audioindex]->codec->codec_id);
	return pCodec;
}

encoder_extended.cfg文件如下配置

# New Input File Format is as follows
# <ParameterName> = <ParameterValue> # Comment
#
# See configfile.h for a list of supported ParameterNames


##########################################################################################
# Files
##########################################################################################
InputFileName             = "bigbuckbunny_480x272.h264"       # Input sequence h264 file
OutputFileName             = "bigbuckbunny_480x272.yuv"    # output yuv
FrameDecoder             = 1      # output frame . (0-N)
YUVTYPE             = 0     # YUV format 422P==4 420P==0 YUYV=1 NV21=26 NV12=25
YUVOUTPUT           = 1      # output yuv

需要根据h264文件的帧数,修改FrameDecoder的帧数,注意FrameDecoder的值小于文件帧数

sws_scale(img_convert_ctx, (const uint8_t* const*)pFrame->data, pFrame->linesize, 0, pCodecCtx->height, 
	pFrameYUV->data, pFrameYUV->linesize);
if(configinput.YUVSWSCALE == 4) 
{
	fwrite(pFrameYUV->data[0],1,y_size,fp_out);     //Y    //422P
	fwrite(pFrameYUV->data[1],1,y_size/2,fp_out);   //U
	fwrite(pFrameYUV->data[2],1,y_size/2,fp_out);   //V
} else if(configinput.YUVSWSCALE == 0) {
	fwrite(pFrameYUV->data[0],1,y_size,fp_out);     //Y  					//420P
	fwrite(pFrameYUV->data[1],1,y_size/4,fp_out);   //U
	fwrite(pFrameYUV->data[2],1,y_size/4,fp_out);   //V
} else if(configinput.YUVSWSCALE == 1)
{
	fwrite(pFrameYUV->data[0],1,y_size*2,fp_out);     //Y      //YUYV
} else if(configinput.YUVSWSCALE == 26 || configinput.YUVSWSCALE == 25)
{
	fwrite(pFrameYUV->data[0],1,y_size,fp_out);     //Y    two-plane 420P
	fwrite(pFrameYUV->data[1],1,y_size/2,fp_out);   //U
} else
{
	printf("not support!\n");
}

资源链接
https://download.csdn.net/download/zhiyanzhai563/12020326

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
要将内存中的YUV数据混合成一个视频,可以使用FFmpeg库进行处理。以下是一个基本的示例代码: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <stdint.h> #include <math.h> #include <libavcodec/avcodec.h> #include <libavutil/imgutils.h> #include <libavutil/opt.h> #include <libavutil/mathematics.h> #define WIDTH 640 #define HEIGHT 480 #define FPS 25 int main(int argc, char *argv[]) { int ret; AVCodec *codec; AVCodecContext *codec_context; AVFrame *frame; AVPacket packet; uint8_t *buffer; int buffer_size; int frame_count = 0; /* Allocate frame */ frame = av_frame_alloc(); if (!frame) { fprintf(stderr, "Error allocating frame\n"); exit(1); } /* Set frame properties */ frame->format = AV_PIX_FMT_YUV420P; frame->width = WIDTH; frame->height = HEIGHT; /* Allocate buffer for frame */ buffer_size = av_image_get_buffer_size(frame->format, frame->width, frame->height, 1); buffer = av_malloc(buffer_size); av_image_fill_arrays(frame->data, frame->linesize, buffer, frame->format, frame->width, frame->height, 1); /* Open codec */ codec = avcodec_find_encoder(AV_CODEC_ID_H264); if (!codec) { fprintf(stderr, "Codec not found\n"); exit(1); } codec_context = avcodec_alloc_context3(codec); if (!codec_context) { fprintf(stderr, "Error allocating codec context\n"); exit(1); } /* Set codec properties */ codec_context->width = WIDTH; codec_context->height = HEIGHT; codec_context->pix_fmt = AV_PIX_FMT_YUV420P; codec_context->time_base = (AVRational){1, FPS}; codec_context->bit_rate = 400000; /* Open codec */ ret = avcodec_open2(codec_context, codec, NULL); if (ret < 0) { fprintf(stderr, "Error opening codec: %s\n", av_err2str(ret)); exit(1); } /* Encode frames */ while (frame_count < FPS * 10) { /* Generate YUV data */ uint8_t *y_data = malloc(WIDTH * HEIGHT); uint8_t *u_data = malloc(WIDTH * HEIGHT / 4); uint8_t *v_data = malloc(WIDTH * HEIGHT / 4); // fill y_data, u_data, v_data with your desired YUV data /* Convert YUV data to frame */ int y_size = WIDTH * HEIGHT; int u_size = y_size / 4; int v_size = y_size / 4; memcpy(frame->data[0], y_data, y_size); memcpy(frame->data[1], u_data, u_size); memcpy(frame->data[2], v_data, v_size); /* Set frame properties */ frame->pts = frame_count++; /* Encode frame */ ret = avcodec_send_frame(codec_context, frame); if (ret < 0) { fprintf(stderr, "Error sending frame to codec: %s\n", av_err2str(ret)); exit(1); } while (ret >= 0) { ret = avcodec_receive_packet(codec_context, &packet); if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) break; else if (ret < 0) { fprintf(stderr, "Error receiving packet from codec: %s\n", av_err2str(ret)); exit(1); } /* Write packet to file or stream */ // fwrite(packet.data, 1, packet.size, outfile); av_packet_unref(&packet); } free(y_data); free(u_data); free(v_data); } /* Flush encoder */ ret = avcodec_send_frame(codec_context, NULL); if (ret < 0) { fprintf(stderr, "Error sending flush frame to codec: %s\n", av_err2str(ret)); exit(1); } while (ret >= 0) { ret = avcodec_receive_packet(codec_context, &packet); if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) break; else if (ret < 0) { fprintf(stderr, "Error receiving packet from codec: %s\n", av_err2str(ret)); exit(1); } /* Write packet to file or stream */ // fwrite(packet.data, 1, packet.size, outfile); av_packet_unref(&packet); } /* Free resources */ avcodec_free_context(&codec_context); av_frame_free(&frame); av_free(buffer); return 0; } ``` 在此示例中,我们使用`av_image_fill_arrays()`函数分配了一个YUV420P格式的AVFrame,并将其用作编码器的输入。我们使用`avcodec_send_frame()`函数将帧发送到编码器进行编码,然后使用`avcodec_receive_packet()`函数从编码器接收编码数据包。最后,我们使用`av_packet_unref()`函数释放数据包并清除任何剩余的缓存数据。 要生成要混合的YUV数据,您可以从文件中读取数据,也可以在内存中生成数据。无论哪种方法,您都需要将其复制到AVFrame的data数组中。请注意,AVFrame中的YUV数据顺序是YUV420P,即先是所有的Y分量,然后是U和V分量交错。因此,在将YUV数据复制到AVFrame之前,请确保按正确的顺序复制它们。 希望这可以帮助您开始使用FFmpeg处理内存中的YUV数据

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值