ffmpeg学习日记122-视频-获取视频的解码器,yuv格式名称,理解编码格式,封装格式,yuv格式的关系

news2024/12/29 11:38:28
Author: wencoo
Blog:https://wencoo.blog.csdn.net/
Date: 25/05/2023
Email: jianwen056@aliyun.com
Wechat:wencoo824
QQ:1419440391
Details:

在这里插入图片描述

文章目录

  • 正文 或 背景
  • 获取像素格式,也就是yuv排列格式
  • 获取解码器id
  • 获取输出文件的封装格式
    • 在设置输出时,需要手动设置编码参数
  • 理解编码格式,封装格式,yuv格式的关系
  • 总结
  • 代码
  • 报错:Specified pixel format rgba is invalid or not supported
  • 参考
  • 技术交流

正文 或 背景

为什么要获取视频或者图片的解码器,以及yuv格式,因为,在以下场景中,我有一段png图片,将其解码之后,重新封装为另一种mp4视频,这里我不知道png使用的解码器是哪个,其解码出来的yuv数据又是什么格式,所以可以将解码过程中这两个数据找出来,打印出来,方便后面对mp4重新封装。

获取像素格式,也就是yuv排列格式

代码如下:

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;

AVCodecContext结构中的pix_fmt字段表示该素材的像素格式。

获取解码器id

接着上面的代码:

//打开mp4文件
	const AVCodec *codec = avcodec_find_decoder(codeCtx->codec_id);
	if (!codec)
	{
		fprintf(stderr, "Codec not found\n");
		exit(1);
	}

	std::cout << "Codec id:" << avcodec_get_name(codeCtx->codec_id) << std::endl;

AVCodecContext结构中的codec_id字段表示该素材的解码器id,通过改id可以找到解码器上下文,可以了输出名字。

获取输出文件的封装格式

封装格式,在调用代码avformat_alloc_output_context2时已经根据传入的文件名后缀解析好了,并把响应数据填充到ptOutFormatContext结构中,不需要我们显示的进行指定了。

AVFormatContext *ptOutFormatContext = NULL; //输出文件的封装格式上下文,内部包含所有的视频信息
	AVPacket tOutPacket = {0};					//存储一帧压缩编码数据给输出文件

	avformat_alloc_output_context2(&ptOutFormatContext, NULL, NULL, outFileName);
	if (!ptOutFormatContext)
	{
		printf("Could not create output context\r\n");
		ret = AVERROR_UNKNOWN;
	}
	if (avio_open(&ptOutFormatContext->pb, outFileName, AVIO_FLAG_WRITE))
	{
		return ret;
	}

	std::cout << "ptOutFormatContext ->oformat->name:" << ptOutFormatContext->oformat->name << std::endl;
	std::cout << "ptOutFormatContext ->oformat->long_name:" << ptOutFormatContext->oformat->long_name << std::endl;
	std::cout << "ptOutFormatContext ->oformat->video_codec:" << ptOutFormatContext->oformat->video_codec << std::endl;

参考:FFmpeg从入门:FFmpeg框架中的AVOutputFormat 的数据结构

在设置输出时,需要手动设置编码参数

// 2.分配内存
	AVCodecContext *codec_out_ctx = avcodec_alloc_context3(codec_out);
	if (!codec_out_ctx)
	{
		fprintf(stderr, "Could not allocate video codec context\n");
		exit(1);
	}

	// 3.设置编码参数
	/* 设置分辨率*/
	codec_out_ctx->width = 48;
	codec_out_ctx->height = 48;
	/* 设置time base */
	codec_out_ctx->time_base = (AVRational){1, 25};
	codec_out_ctx->framerate = (AVRational){25, 1};
	/* 设置I帧间隔
	 * 如果frame->pict_type设置为AV_PICTURE_TYPE_I, 则忽略gop_size的设置,一直当做I帧进行编码
	 */
	codec_out_ctx->gop_size = 25; // I帧间隔
	codec_out_ctx->max_b_frames = 2; // 如果不想包含B帧则设置为0
	codec_out_ctx->pix_fmt = AV_PIX_FMT_YUV420P;
	codec_out_ctx->codec_id = AV_CODEC_ID_H264;
	codec_out_ctx->codec_type = AVMEDIA_TYPE_VIDEO;

其中,这两行需要手动填入的,这里一定要清楚其中的关系。

codec_out_ctx->pix_fmt = AV_PIX_FMT_YUV420P;
codec_out_ctx->codec_id = AV_CODEC_ID_H264;

理解编码格式,封装格式,yuv格式的关系

  1. 编码格式:比如h264,h265,mpeg4,vp8,vp9这些是编码格式

每一种编码格式,都有对应支持的的yuv格式,不同的编码格式支持的yuv格式有交集,也有不同,可以通过如下指令进行查询:

ffmpeg -h encoder=h264

参考解决:FFmpeg报错:Specified pixel format yuvj420p is invalid or not supported(用ffmpeg程序查看编码器支持像素格式命令)

  1. 封装格式:比如mp4,mkv,avi,等
    通过获取输出文件的封装格式一节可以看到,每一种封住格式其实也会关联一种编码格式,其实一种封装格式,可以支持多种编码格式,但不是支持所有编码格式!不是支持所有编码格式!不是支持所有编码格式!重要的事情说三遍,所以封装的时候,yuv直接生成mp4,需要查看编码格式与分装个是全部支持,现如今流行的封装格式如下:

|名称 |推出机构 |流媒体 |支持的视频编码 |支持的音频编码 |目前使用领域|
|:= |=: |=: |=: |=: |=: |
|AVI |Microsoft Inc. |不支持| 几乎所有格式 |几乎所有格式 |BT下载影视|
|MP4 |MPEG |支持 |MPEG-2,MPEG-4,H.264,H.263等 |AAC,MPEG-1 layers I, II, III, AC-3| 互联网视频网站
|TS |MPEG |支持 |MPEG-1,MPEG-2,MPEG-4,H.264 |MPEG-1 Layers I, II, III, AAC |IPTV,数字电视
|FLV| Adobe Inc.| 支持 |Sorenson, VP6, H.264 |MP3, ADPCM, Linear PCM, AAC等| 互联网视频网站
|MKV| CoreCodec Inc.| 支持| 几乎所有格式| 几乎所有格式 |互联网视频网站
|RMVB| Real Networks Inc. |支持| RealVideo 8, 9, 10 |AAC, Cook Codec, RealAudio Lossless |BT下载影视

参考:FFMPEG视音频编解码学习(一)
3. yuv格式:很多,enum AVPixelFormat pix_fmt;枚举里罗列的的都是yuv的格式,通过下面的命令

ffmpeg -h encoder=h264

可以看到,某一个编码器,支持的yuv格式是有限的,不同的yuv格式需要不同的编码器,也就是编码协议来支持。

总结

所以,我想要将png图片直接封装成mp4是不可以的,需要解码,解码之后得到的是png的yuv格式数据,需要将png格式的yuv数据(带透明通道)转换成yuv420的格式数据,才能够将编码封装成的mp4正确播放,否则生成的mp4播放内容是错误的。

代码

一下代码不包含png格式的yux数据转换成yuv420的转换功能,只是一个png转mp4的流程框架。

int pngToMp4()
{
	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 = "/home/wencoo/gitcode/wen-coo-repo/study_ffmpeg/linuxPlatform/9-filterMoreChannel/filterMoreChannel/build/bg.png";
	inFile = fopen(inFileName, "rb+");
	if (!inFile)
	{
		printf("Fail to open file\n");
		return -1;
	}

	int in_width = 48;
	int in_height = 48;

	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 << "codeCtx->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);
	}

	std::cout << "codeCtx->codec_id :" << codeCtx->codec_id << std::endl;
	std::cout << "codeCtx->codec_id name:" << avcodec_get_name(codeCtx->codec_id) << std::endl;

	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;

	//==========================输出配置===============================================
	// output yuv
	FILE *outFile = NULL;
	const char *codec_name = "libx264";
	const char *outFileName = "/home/wencoo/gitcode/wen-coo-repo/study_ffmpeg/linuxPlatform/9-filterMoreChannel/filterMoreChannel/build/bg.mp4";
	outFile = fopen(outFileName, "wb");
	if (!outFile)
	{
		printf("Fail to create file for output\n");
		return -1;
	}

	AVFormatContext *ptOutFormatContext = NULL; //输出文件的封装格式上下文,内部包含所有的视频信息
	AVPacket tOutPacket = {0};					//存储一帧压缩编码数据给输出文件

	avformat_alloc_output_context2(&ptOutFormatContext, NULL, NULL, outFileName);
	if (!ptOutFormatContext)
	{
		printf("Could not create output context\r\n");
		ret = AVERROR_UNKNOWN;
	}
	if (avio_open(&ptOutFormatContext->pb, outFileName, AVIO_FLAG_WRITE))
	{
		return ret;
	}

	std::cout << "ptOutFormatContext ->oformat->name:" << ptOutFormatContext->oformat->name << std::endl;
	std::cout << "ptOutFormatContext ->oformat->long_name:" << ptOutFormatContext->oformat->long_name << std::endl;
	std::cout << "ptOutFormatContext ->oformat->video_codec:" << ptOutFormatContext->oformat->video_codec << std::endl;
	std::cout << "ptOutFormatContext ->oformat->video_codec name:" << avcodec_get_name(ptOutFormatContext->oformat->video_codec) << std::endl;
	// 1.查找编码器
	const AVCodec *codec_out = avcodec_find_encoder_by_name(codec_name);
	if (!codec_out)
	{
		fprintf(stderr, "Codec '%s' not found\n", codec_name);
		exit(1);
	}

	// 2.分配内存
	AVCodecContext *codec_out_ctx = avcodec_alloc_context3(codec_out);
	if (!codec_out_ctx)
	{
		fprintf(stderr, "Could not allocate video codec context\n");
		exit(1);
	}

	// 3.设置编码参数
	/* 设置分辨率*/
	codec_out_ctx->width = 48;
	codec_out_ctx->height = 48;
	/* 设置time base */
	codec_out_ctx->time_base = (AVRational){1, 25};
	codec_out_ctx->framerate = (AVRational){25, 1};
	/* 设置I帧间隔
	 * 如果frame->pict_type设置为AV_PICTURE_TYPE_I, 则忽略gop_size的设置,一直当做I帧进行编码
	 */
	codec_out_ctx->gop_size = 25; // I帧间隔
	codec_out_ctx->max_b_frames = 2; // 如果不想包含B帧则设置为0
	codec_out_ctx->pix_fmt = AV_PIX_FMT_YUV420P;
	codec_out_ctx->codec_id = AV_CODEC_ID_H264;
	codec_out_ctx->codec_type = AVMEDIA_TYPE_VIDEO;

	

	av_opt_set(codec_out_ctx->priv_data, "tune", "zerolatency", 0);

	if (codec_out->id == AV_CODEC_ID_H264)
	{
		// 相关的参数可以参考libx264.c的 AVOption options
		ret = av_opt_set(codec_out_ctx->priv_data, "preset", "medium", 0);
		if (ret != 0)
		{
			printf("av_opt_set preset failed\n");
		}
		ret = av_opt_set(codec_out_ctx->priv_data, "profile", "main", 0); // 默认是high
		if (ret != 0)
		{
			printf("av_opt_set profile failed\n");
		}
		ret = av_opt_set(codec_out_ctx->priv_data, "tune", "zerolatency", 0); // 直播是才使用该设置
		//        ret = av_opt_set(codec_ctx->priv_data, "tune","film",0); //  画质film
		if (ret != 0)
		{
			printf("av_opt_set tune failed\n");
		}
	}

	/* 设置bitrate */
	codec_out_ctx->bit_rate = 3000000;

	AVStream *avvideo_stream = avformat_new_stream(ptOutFormatContext, nullptr);
	avvideo_stream->codec = codec_out_ctx;
	avvideo_stream->time_base = codec_out_ctx->time_base;
	avvideo_stream->codec->codec_tag = 0;

	// 4.将codec_ctx和codec进行绑定
	ret = avcodec_open2(codec_out_ctx, codec_out, NULL);
	if (ret < 0)
	{
		//        fprintf(stderr, "Could not open codec: %s\n", av_err2str(ret));
		exit(1);
	}
	printf("thread_count: %d, thread_type:%d\n", codec_out_ctx->thread_count, codec_out_ctx->thread_type);

	// // 5.打开输入和输出文件
	// FILE *infile = fopen(in_yuv_file, "rb");
	// if (!infile)
	// {
	// 	fprintf(stderr, "Could not open %s\n", in_yuv_file);
	// 	exit(1);
	// }

	// 6.分配pkt和frame
	AVPacket *pkt_out = av_packet_alloc();
	if (!pkt_out)
	{
		fprintf(stderr, "Could not allocate video frame\n");
		exit(1);
	}
	av_init_packet(pkt_out);
	AVFrame *frame_out = av_frame_alloc();
	if (!frame_out)
	{
		fprintf(stderr, "Could not allocate video frame\n");
		exit(1);
	}

	if (avformat_write_header(ptOutFormatContext, NULL) < 0) // avformat_write_header()中最关键的地方就是调用了AVOutputFormat的write_header()
	{														 //不同的AVOutputFormat有不同的write_header()的实现方法
		printf("Error occurred when opening output file\r\n");
	}

	// 7.为frame分配buffer
	frame_out->format = codec_out_ctx->pix_fmt;
	frame_out->width = codec_out_ctx->width;
	frame_out->height = codec_out_ctx->height;
	ret = av_frame_get_buffer(frame_out, 0);
	if (ret < 0)
	{
		fprintf(stderr, "Could not allocate the video frame data\n");
		exit(1);
	}
	// 计算出每一帧的数据 像素格式 * 宽 * 高
	// 1382400
	int frame_bytes = av_image_get_buffer_size((enum AVPixelFormat)frame_out->format, frame_out->width,
											   frame_out->height, 1);

	printf("frame_bytes %d\n", frame_bytes);
	uint8_t *yuv_buf = (uint8_t *)malloc(frame_bytes);
	if (!yuv_buf)
	{
		printf("yuv_buf malloc failed\n");
		return 1;
	}
	int64_t begin_time = get_time();
	int64_t end_time = begin_time;
	int64_t all_begin_time = get_time();
	int64_t all_end_time = all_begin_time;
	int64_t pts = 0;

	//==========================编解码==================================================
	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);

					ret = av_frame_make_writable(frame_out);
					int need_size = av_image_fill_arrays(frame_out->data, frame_out->linesize, video_dst_data[0],
														 (enum AVPixelFormat)frame_out->format,
														 frame_out->width, frame_out->height, 1);
					if (need_size != frame_bytes)
					{
						printf("av_image_fill_arrays failed, need_size:%d, frame_bytes:%d\n",
							   need_size, frame_bytes);
						break;
					}
					// indexNum++;
					pts += 1;
					// 设置pts
					frame_out->pts = pts; // 使用采样率作为pts的单位,具体换算成秒 pts*1/采样率
					begin_time = get_time();

					ret = avcodec_send_frame(codec_out_ctx, frame_out);
					if (ret < 0)
					{
						std::cout << "failed avcodec_send_frame ret :" << ret << std::endl;
						ret = -1;
					}
					else
					{
						while (ret >= 0)
						{
							ret = avcodec_receive_packet(codec_out_ctx, pkt_out);
							std::cout << "1329 AVERROR(EAGAIN):" << AVERROR(EAGAIN) << " -- AVERROR_EOF:" << AVERROR_EOF << std::endl;
							if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
							{
								ret = 0;
								av_packet_unref(pkt_out);
								break;
							}
							else if (ret < 0)
							{
								ret = -1;
								av_packet_unref(pkt_out);
								break;
							}
							//                fwrite(pkt->data,1,pkt->size,outfile);

							//对264数据进行数据封装
							av_packet_rescale_ts(pkt_out, codec_out_ctx->time_base, avvideo_stream->time_base);
							pkt_out->stream_index = avvideo_stream->index;
							av_interleaved_write_frame(ptOutFormatContext, pkt_out);
						}
					}
				}
			}
		}
		av_packet_unref(pkt);
		if (ret < 0)
			break;
	}

	// 9.冲刷编码器
	ret = avcodec_send_frame(codec_out_ctx, nullptr);
	if (ret < 0)
	{
		ret = -1;
	}
	else
	{
		while (ret >= 0)
		{
			ret = avcodec_receive_packet(codec_out_ctx, pkt_out);
			std::cout << "1369 AVERROR(EAGAIN):" << AVERROR(EAGAIN) << " -- AVERROR_EOF:" << AVERROR_EOF << std::endl;
			if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
			{
				ret = 0;
				av_packet_unref(pkt_out);
				break;
			}
			else if (ret < 0)
			{
				ret = -1;
				av_packet_unref(pkt_out);
				break;
			}
			//            fwrite(pkt->data,1,pkt->size,outfile);
			av_packet_rescale_ts(pkt_out, codec_out_ctx->time_base, avvideo_stream->time_base);
			pkt_out->stream_index = avvideo_stream->index;
			av_interleaved_write_frame(ptOutFormatContext, pkt_out);
		}
	}

	// mp4封装不对,这里写文件尾会导致段错误
	av_write_trailer(ptOutFormatContext);

	fclose(inFile);
	fclose(outFile);

	av_free(avvideo_stream);
	av_frame_free(&frame_out);
	av_packet_free(&pkt_out);
	avcodec_free_context(&codec_out_ctx);

	if (ptOutFormatContext)
	{
		avio_close(ptOutFormatContext->pb);
		// avformat_free_context(ptOutFormatContext); //释放空间
	}

	return 0;
}

报错:Specified pixel format rgba is invalid or not supported

报错如下:

 Specified pixel format rgba is invalid or not supported

参考解决:FFmpeg报错:Specified pixel format yuvj420p is invalid or not supported(用ffmpeg程序查看编码器支持像素格式命令)

补充:

参考

技术交流

欢迎加微信,搜索"wencoo824",进行技术交流,备注”博客音视频技术交流“

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/568032.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

景区上线智慧客流人数采集分析系统的根本原因

智慧客流量采集系统是一种高效、智能的客流量采集解决方案&#xff0c;可以实现客流量的实时监控、数据分析和预测&#xff0c;提高服务质量、降低管理成本、提高安全性等优势。该系统适用于各种场所&#xff0c;如景区、商场、服务区、机场等。 AI客流视觉监控 一、智慧客流量…

安科瑞电力监控系统和五防系统在锡林郭勒项目的应用

摘要&#xff1a;随着电力、计算机、信息和网络等技术的不断发展&#xff0c;推动了电力监控的快速发展&#xff0c;人们对电力系统运行的安全性以及稳定性的要求越来越高。本文针对锡林郭勒供配电系统特点及供配电系统高可靠性的要求&#xff0c;提出了保护类、监测类和防误闭…

ASEMI代理长电MCR100-6可控硅的性能与应用分析

编辑-Z 本文主要介绍了新型MCR100-6晶闸管的性能与应用。首先&#xff0c;从晶闸管的基本原理和结构出发&#xff0c;分析了MCR100-6晶闸管的性能特点&#xff1b;其次&#xff0c;探讨了MCR100-6晶闸管在各种电子电路中的应用&#xff1b;最后&#xff0c;对MCR100-6晶闸管的…

档案馆建设标准条文说明

第一章 总则 第一条 本条阐明了本标准的编制目的。 中国是一个历史悠久的文明古国&#xff0c;档案事业的发展源远流长。档案是人类活动的真实记录&#xff0c;是人们认识和把握客观规律的重要依据。借助档案&#xff0c;我们能够更好地了解过去、把握现在、预见未来。档案工…

工业机器视觉缺陷检测工作小结

工业机器视觉检测工作小结 &#xff08;因为网上没有很系统的讲义和文档&#xff0c;都是零零散散的&#xff0c;因此&#xff0c;我自己尝试着总结一下、仅供参考&#xff09; 你想知道的大概率在这都可以找到、相机的了解镜头的了解光源的了解传统算法DL深度学习方法 &#…

基于微信小程序渗透-反编译小程序

文章目录 一、概述二、使用电脑版微信获取小程序源码三、使用工具解密源码四、配置nodejs环境五、使用工具解包 一、概述 微信小程序渗透时&#xff0c;因为小程序没有网页端页面&#xff0c;所以不能直接访问抓包分析&#xff0c;如果需要抓包分析&#xff0c;那么一般就是用…

Spring:用 Spring 整合 MyBatis(Spring-MyBatis)代码整理

文章目录 Spring&#xff1a;Day 05Spring - MyBatis1. 依赖&#xff1a;pom.xml2. 外部配置文件&#xff1a;db.properties3. MyBatis 核心配置文件&#xff1a;mybatis-config.xml4. 实体类5. 接口&#xff1a;xxxMapper.java6. 实现类&#xff1a;xxxMapper.xml7. Spring 通…

ATA-4014高压功率放大器驱动超声马达测试应用

ATA-4014 高压功率放大器简介 ATA-4014是一款理想的可放大交、直流信号的单通道高压功率放大器。最大输出160Vp-p&#xff08;80Vp&#xff09;电压&#xff0c;452Wp功率&#xff0c;可以驱动高压功率型负载。电压增益数控可调&#xff0c;一键保存常用设置&#xff0c;为您提…

利用 PRIMO 重构 M87 黑洞图像,普林斯顿高等研究院成功将「甜甜圈」变身「金戒指」

内容一览&#xff1a;2019 年&#xff0c;「事件视界望远镜 (Event Horizon Telescope&#xff0c;简称 EHT)」全球研究团队发布了人类历史上第一张黑洞照片&#xff0c;受限于当时的观测条件&#xff0c;这张黑洞图像只呈现出一个模糊不清的轮廓。近日&#xff0c;天体物理学期…

打家劫舍 III——力扣337

文章目录 题目描述法一&#xff1a;动态规划 题目描述 法一&#xff1a;动态规划 问题简化&#xff1a;一棵二叉树&#xff0c;树上的每个点都有对应的权值&#xff0c;每个点有两种状态&#xff08;选中和不选中&#xff09;&#xff0c;问在不能同时选中有父子关系的点的情况…

Kafka题集 - kafka术语面试题总结

文章目录 01. 什么是 Kafka&#xff1f;02. 为什么要用kafka&#xff1f;03. Kafka 消息引擎模型04. kafka 消费方式&#xff1f;05. Kafka 传输消息的编码格式&#xff1f;06. kafka 体系架构&#xff1f;07. kafka 消息和批次&#xff1f;08. kafka 主题和分区&#xff1f;09…

Weex中,关于组件的水平排列竖直排列居中对齐居左对齐居右对齐低部对齐顶部对齐布局对齐说明

容器内子组件排列方向 子组件竖直方向排列&#xff08;默认&#xff09; 子组件水平方向排列 <style> .container {flex-direction: row;direction: ltr; } </style>子组件在父组件容器中的对齐方式 我们主要使用两个属性实现子组件在父组件的对齐方式&#xff…

Qt之程序发布以及打包成exe安装包目录

Qt之程序发布以及打包成exe安装包 目录 一、简述二、设置应用程序图标三、发布程序四、打包程序 回到顶部 一、简述 Qt 项目开发完成之后&#xff0c;需要打包发布程序&#xff0c;而因为用户电脑上没有 Qt 配置环境&#xff0c;所以需要将 release 生成的 exe 文件和所依赖…

hiveSql调优

一、hiveSQL执行顺序 from … where … mapjoin … on … select&#xff08;筛选有用字段&#xff09; … group by ||… join … on … select&#xff08;筛选输出字段&#xff09; … having … distinct … order by … limit … union/union all|| 前是map阶段执行&…

五月最近一次面试,被阿里P8测开虐惨了...

都说金三银四涨薪季&#xff0c;我是着急忙慌的准备简历——5年软件测试经验&#xff0c;可独立测试大型产品项目&#xff0c;熟悉项目测试流程...薪资要求&#xff1f;5年测试经验起码能要个20K吧 我加班肝了一页半简历&#xff0c;投出去一周&#xff0c;面试电话倒是不少&a…

自动化测试框架类型,你知道几种?此处介绍5种比较常见的

每一个测试人员都应该了解每种框架的优缺点&#xff0c;以帮助你的团队更好地确定最适合的测试的框架&#xff0c;以达到事半功倍。 什么是测试自动化框架? 自动化测试框架就是用于测试自动化的框架。具体来说&#xff0c;它提供了自动化测试用例编写、自动化测试用例执行、自…

分布式ID的选择

一、分布式ID策略 1.目前数据库主键ID生成的策略整理了这么几个&#xff0c;我们分析下每个的问题 1.1 数据库自增ID分析 我们创建数据库的时候&#xff0c;指定我们的id字段是主键&#xff0c;并且是自增的 create table demo_table ( id int(10) primary key auto_increm…

【个人笔记】真寻bot部署记录+源码食用记录

安装 0. 系统配置 Centos v8.2 1. 安装 使用真寻bot https://github.com/zhenxun-org/zhenxun_bot-deploy bash <(curl -s -L https://raw.githubusercontent.com/zhenxun-org/zhenxun_bot-deploy/master/install.sh)选择1&#xff0c;安装go-cqhttp和zhenxun_bot&…

SQL Developer如何导入时间格式的字段?

SQL developer有一个非常好用的功能&#xff0c;就是导入本地的数据文件。但是导入文件时&#xff0c;如果含时间字段&#xff0c;常常无法导入成功&#xff0c;如何解决&#xff1f; 第一步&#xff1a;处理表格时间格式 选中时间列&#xff0c;右击弹出【设置单元格格式】—…

指令微调数据集整理

文章目录 开源指令数据集斯坦福数据链家数据 垂直领域数据集医疗领域的英文数据医疗领域的中文数据 COIG数据集&#xff08;可商用的中文数据集&#xff09; 开源指令数据集 斯坦福数据 斯坦福52K英文指令数据&#xff1a;https://github.com/tatsu-lab/stanford_alpaca 52K …