Linux系统USB摄像头测试程序(三)_视频预览

这是在linux上usb摄像头视频预览程序,此程序用到了ffmpeg、sdl2、gtk3组件,程序编译之前应先安装他们。

#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <zconf.h>
#include <linux/videodev2.h>
#include <sys/mman.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <gtk-3.0/gtk/gtk.h>


#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
#include "libswscale/swscale.h"
#include "libavdevice/avdevice.h"
#include "libavutil/imgutils.h"
#include <libavfilter/avfilter.h>
#include <libavfilter/buffersrc.h>
#include <libavfilter/buffersink.h>

#include <SDL2/SDL.h>


//dhl:gtk窗口组件
GtkWidget *window;
GtkWidget *fixed;
GtkWidget *button1,*button2,*button3;
GtkWidget *text,*text1,*text2,*text3;
GtkTextBuffer *buffer,*buffer1,*buffer2,*buffer3;
GtkWidget *label1,*label2,*label3,*label_line;

//dhl:sdl窗口组件
SDL_Window *sdl_window; 
SDL_Renderer *sdl_renderer;
SDL_Texture *sdl_texture;


//dhl:消息缓存
char disp[2048]={0};
char temp[128]={0};

int getWHR(char *device_name,char *win_size,int *win_width,int *win_height, char *frame_rate_t)
{
	GtkTextIter start,end;
	gtk_text_buffer_get_bounds(GTK_TEXT_BUFFER(buffer1),&start,&end);
	GtkTextIter s=start,e=end;
	sprintf(device_name,"%s",gtk_text_buffer_get_text(GTK_TEXT_BUFFER(buffer1),&s,&e,FALSE));
	
	gtk_text_buffer_get_bounds(GTK_TEXT_BUFFER(buffer2),&start,&end);
	s=start,e=end;
	gchar *win_size1 = gtk_text_buffer_get_text(GTK_TEXT_BUFFER(buffer2),&s,&e,FALSE);
	sprintf(win_size,"%s",gtk_text_buffer_get_text(GTK_TEXT_BUFFER(buffer2),&s,&e,FALSE));
    
	gtk_text_buffer_get_bounds(GTK_TEXT_BUFFER(buffer3),&start,&end);
	s=start,e=end;
    sprintf(frame_rate_t,"%s",gtk_text_buffer_get_text(GTK_TEXT_BUFFER(buffer3),&s,&e,FALSE));
    
    
    if (!strcmp(device_name,"")|| !strcmp(win_size,"")||!strcmp(frame_rate_t,"")) {
		GtkWidget * dialog= dialog = gtk_message_dialog_new (NULL,
                                 GTK_DIALOG_DESTROY_WITH_PARENT,
                                 GTK_MESSAGE_INFO,
                                 GTK_BUTTONS_CLOSE,
                                 "请输入摄像头设备名称、窗口尺寸、帧速率");
		gtk_dialog_run (GTK_DIALOG (dialog));
		gtk_widget_destroy (dialog);
		return -1;
		
	}
    
    sscanf(win_size1, "%dx%d", win_width, win_height);
	return 0;
}




//dhl:发现摄像头
void button1_clicked(GtkWidget *widget, gpointer data)
{
	char camera_devices_name[128]={0};
	for (int loop=0;loop<10;loop++) {
		sprintf(camera_devices_name,"/dev/video%d",loop);
		int fd = open(camera_devices_name, O_RDWR);
		if(fd < 0)
		{
			printf("打开设备失败(%s)\n",camera_devices_name);
			close(fd);
			continue;
		}
	    close(fd);
		sprintf(temp,"发现摄像头:%s\n",camera_devices_name);
		strcat(disp,temp);
		gtk_text_buffer_set_text(buffer,disp,-1);
	}
	sprintf(disp,"%s","");
}

//dhl:查询配置信息
void button2_clicked(GtkWidget *widget, gpointer data)
{
	int line_num=0;
	gchar *device_name;
	GtkTextIter start,end;
	gtk_text_buffer_get_bounds(GTK_TEXT_BUFFER(buffer1),&start,&end);
	const GtkTextIter s=start,e=end;
	device_name=gtk_text_buffer_get_text(GTK_TEXT_BUFFER(buffer1),&s,&e,FALSE);
	if (!strcmp(device_name,""))
	{
		sprintf(temp,"请输入摄像头设备文件名\n");
		strcat(disp,temp);
		gtk_text_buffer_set_text(buffer,disp,-1);
		sprintf(disp,"%s","");
		return;
	}
		
		
	//dhl:查询摄像头支持的视频格式
	int fd = open(device_name, O_RDWR);
	if(fd < 0)
	{
		printf("打开设备失败\n");
		return;
	}

	struct v4l2_fmtdesc v4fmt;
	v4fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; //视频捕获设备
	int i=0;

	while(1)
	{
		v4fmt.index = i++;
		int ret = ioctl(fd, VIDIOC_ENUM_FMT, &v4fmt);
		if(ret < 0)
		{
			printf("获取摄像头格式失败");
			break;
		}
		printf("index=%d\n", v4fmt.index);
		printf("flags=%d\n", v4fmt.flags);
		printf("description=%s\n", v4fmt.description);
		unsigned char *p = (unsigned char *)&v4fmt.pixelformat;
		printf("pixelformat=%c%c%c%c\n", p[0],p[1],p[2],p[3]);
		printf("reserved=%d\n", v4fmt.reserved[0]);
		
		sprintf(temp,"摄像头支持的视频格式(%d)\n",i);
		strcat(disp,temp);
		
		sprintf(temp,"index=%d,", v4fmt.index);
		strcat(disp,temp);
		
		sprintf(temp,"flags=%d,", v4fmt.flags);
		strcat(disp,temp);
		
		sprintf(temp,"description=%s,", v4fmt.description);
		strcat(disp,temp);
		
		sprintf(temp,"pixelformat=%c%c%c%c,", p[0],p[1],p[2],p[3]);
		strcat(disp,temp);
		
		sprintf(temp,"reserved=%d\n", v4fmt.reserved[0]);
		strcat(disp,temp);
		
	}
	
	close(fd);
	
	//dhl:MJPG支持的所有分辨率如下
	fd = open(device_name, O_RDWR);
	if(fd < 0)
	{
		perror("打开设备失败");
		return;
	}
	struct v4l2_frmsizeenum frmsize;
	frmsize.index = 0;
	frmsize.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
	printf("MJPEG格式支持所有分辨率如下:\n");
	//frmsize.pixel_format = V4L2_PIX_FMT_YUYV;
	frmsize.pixel_format = V4L2_PIX_FMT_MJPEG;
	sprintf(temp,"MJPG支持的分辨率:\n");
	strcat(disp,temp);
	line_num=1;
	while(ioctl(fd,VIDIOC_ENUM_FRAMESIZES,&frmsize) == 0){
		printf("frame_size<%d*%d>\n",frmsize.discrete.width,frmsize.discrete.height);
		frmsize.index++;
		if ((line_num % 5) != 0) { 
			sprintf(temp,"MJPEG frame_size<%d*%d>, ",frmsize.discrete.width,frmsize.discrete.height);
		}else {
			sprintf(temp,"MJPEG frame_size<%d*%d>\n",frmsize.discrete.width,frmsize.discrete.height);
		}
		strcat(disp,temp);
		line_num++;
		if (line_num == 6) {
			line_num = 1;
		}
	}
	close(fd);
	sprintf(temp,"%s","\n");
	strcat(disp,temp);
	
	
	//dhl:YUV支持所有分辨率如下
	fd = open(device_name, O_RDWR);
	if(fd < 0)
	{
		perror("打开设备失败");
		return;
	}
	//struct v4l2_frmsizeenum frmsize;
	frmsize.index = 0;
	frmsize.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
	printf("MJPEG格式支持所有分辨率如下:\n");
	frmsize.pixel_format = V4L2_PIX_FMT_YUYV;
	//frmsize.pixel_format = V4L2_PIX_FMT_MJPEG;
	sprintf(temp,"YUV支持的分辨率:\n");
	strcat(disp,temp);
	line_num = 1;
	while(ioctl(fd,VIDIOC_ENUM_FRAMESIZES,&frmsize) == 0){
		printf("frame_size<%d*%d>\n",frmsize.discrete.width,frmsize.discrete.height);
		frmsize.index++;
		if ((line_num % 5) != 0) { 
			sprintf(temp,"YUYV frame_size<%d*%d>, ",frmsize.discrete.width,frmsize.discrete.height);
		}else {
			sprintf(temp,"YUYV frame_size<%d*%d>\n",frmsize.discrete.width,frmsize.discrete.height);
			
		}
		strcat(disp,temp);
		line_num++;
		if (line_num == 6) {
			line_num = 1;
		}
	}
	
	close(fd);
	
	
	gtk_text_buffer_set_text(buffer,disp,-1);
	sprintf(disp,"%s","");
	
}



//dhl:视频预览
void button3_clicked(GtkWidget *widget, gpointer data)
{

	AVFormatContext *pFormatCtx;
    int             i, videoindex;
    AVCodecContext  *pCodecCtx;
    AVCodec         *pCodec;
    int ret = -1;

    int win_width=0, win_height=0;
    gchar device_name[128];
    gchar win_size[128];
    gchar frame_rate_t[128];
    
    
    int iRet=getWHR(device_name,win_size,&win_width,&win_height, frame_rate_t);
    if (iRet!=0) {
		return;
	}
  
 
    
    const char * out_path = "out_yuyv422.yuv";
    FILE* outFile = fopen(out_path, "wb");
    if (!outFile) {
        printf("Could not open %s\n", out_path);
        return;
    }
    
    if (SDL_Init(SDL_INIT_VIDEO)) {
        printf("Could not initialize SDL - %s\n", SDL_GetError());
        return;
    }else{
		
		printf("initialize SDL ok\n");
	}
    
    sdl_window = SDL_CreateWindow("视频预览"
			,SDL_WINDOWPOS_CENTERED
			,SDL_WINDOWPOS_CENTERED
			,win_width
			,win_height
			,SDL_WINDOW_OPENGL|SDL_WINDOW_RESIZABLE);
    if(sdl_window == NULL){
        printf("SDL_window创建失败\n");
        return;
    }



	sdl_renderer = SDL_CreateRenderer(sdl_window
            ,-1
            ,SDL_RENDERER_ACCELERATED);
 
	sdl_texture = SDL_CreateTexture(sdl_renderer
			//,SDL_PIXELFORMAT_IYUV
			,SDL_PIXELFORMAT_YUY2
            ,SDL_TEXTUREACCESS_TARGET
            ,win_width
            ,win_height);
    
	SDL_Rect sdl_rect;
   
   
    char *buffer_pixels = malloc(win_width*win_height*4);

    pFormatCtx = avformat_alloc_context();
    const AVInputFormat *ifmt = av_find_input_format("v4l2");
    
    AVDictionary *option =NULL;
    av_dict_set(&option,"video_size",win_size,0);
    av_dict_set(&option,"framerate",frame_rate_t,0);
    //av_dict_set(&option,"pixel_format","yuv420p12be",0); //指定格式
   
    avformat_open_input(&pFormatCtx, device_name, ifmt,&option);
    
    
    if(avformat_find_stream_info(pFormatCtx, NULL) < 0)
    {
        printf("Couldn't find stream information.\n");
        return;
    }
    
    videoindex = -1;
    for(i = 0; i < pFormatCtx->nb_streams; i++){
        if(pFormatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
        {
            videoindex = i;
            break;
        }
    }
    if(videoindex == -1)
    {
        printf("Didn't find a video stream.\n");
        return;
    }
    else{
        printf("Find a video stream:%d.\n", videoindex);
    }
    
    pCodec = (AVCodec*)avcodec_find_decoder(pFormatCtx->streams[videoindex]->codecpar->codec_id);
    if(pCodec == NULL)
    {
        printf("Codec not found.\n");
        return;
    }
    
    pCodecCtx = avcodec_alloc_context3(pCodec);
    avcodec_parameters_to_context(pCodecCtx, pFormatCtx->streams[videoindex]->codecpar);
    printf("VideoStream:Frame.Width=%d,Height=%d\n",
           pCodecCtx->width, pCodecCtx->height);

    if(avcodec_open2(pCodecCtx, pCodec, NULL) < 0)
    {
        printf("Could not open codec.\n");
        return;
    }
    
    AVPacket *pkt = av_packet_alloc();
    if(!pkt){
        printf("av_packet_alloc错误\n");
        return;
    }

    AVFrame *frame_yuyv422 = av_frame_alloc();
    if(!frame_yuyv422){
        printf("av_frame_alloc错误\n");
        return;
    }


	int frame_count = 0;//记录获取的帧数
    SDL_Event event;
    
    while (av_read_frame(pFormatCtx, pkt) >= 0 ) {
		 if(pkt->stream_index == videoindex){
            //dhl:发送给解码器
            if(avcodec_send_packet(pCodecCtx,pkt) != 0){
                printf("avcodec_send_packet error ...\n");
                break;
            }
            
     
            //dhl:从解码器中得到摄像头的原始视频帧
            int loop=0;
            while(avcodec_receive_frame(pCodecCtx,frame_yuyv422) == 0){
				frame_count++;
				for(int i = 0;i < frame_yuyv422->height;i++){
					
                    memcpy(buffer_pixels+i * frame_yuyv422->linesize[0],frame_yuyv422->data[0] + i * frame_yuyv422->linesize[0],frame_yuyv422->linesize[0]);
				}
				
				SDL_UpdateTexture(sdl_texture,NULL,buffer_pixels,win_width*2);
				
				//dhl:将纹理数据拷贝给渲染器
				sdl_rect.x = 0;
				sdl_rect.y = 0;
				sdl_rect.w = win_width;
				sdl_rect.h = win_height;
				
				
				//dhl:先清空帧画面,再重新绘制
				SDL_RenderClear(sdl_renderer);
				SDL_RenderCopy(sdl_renderer,sdl_texture,NULL,&sdl_rect);
				//dhl:显示帧画面
				SDL_RenderPresent(sdl_renderer);
				//dhl:延时渲染
				//SDL_Delay(frame_rate);//延时
				
			}
		}
		av_packet_unref(pkt);
		for (int ll=0;ll<10;ll++) {
			SDL_PollEvent(&event);
				
		}	
		if (event.type == SDL_QUIT) {
			 break;
		}
	}
    
    fclose(outFile);
    
    sprintf(disp,"预览总帧数:%d",frame_count);
	gtk_text_buffer_set_text(buffer,disp,-1);
	sprintf(disp,"%s","");
    
    av_free(frame_yuyv422);
    av_packet_free(&pkt);
    avformat_close_input(&pFormatCtx);
    free(buffer_pixels);
    
    SDL_DestroyTexture(sdl_texture);
    SDL_DestroyRenderer(sdl_renderer);
	SDL_DestroyWindow(sdl_window );		
	SDL_Quit();
	
	return;
	
}





int main(int argc,char *argv[])
{
	gtk_init(&argc,&argv);
	avdevice_register_all();
    
    window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
    gtk_window_set_title(GTK_WINDOW(window),"USB摄像头测试程序(v1.0.20230728)");
    //gtk_window_set_resizable(GTK_WINDOW(window),FALSE);
    gtk_window_set_default_size(GTK_WINDOW(window),1280,800);
    gtk_window_set_position(GTK_WINDOW(window),GTK_WIN_POS_CENTER);
	
    fixed = gtk_fixed_new();
    gtk_container_add(GTK_CONTAINER(window),fixed);
    
    text = gtk_text_view_new();
    buffer=gtk_text_view_get_buffer(GTK_TEXT_VIEW(text));
    gtk_text_buffer_set_text(buffer,"",-1);
    gtk_fixed_put(GTK_FIXED(fixed),text,20,480);
    gtk_widget_set_size_request(text,1240,300);
    
    button1 = gtk_button_new_with_label("查询摄像头");
    gtk_fixed_put(GTK_FIXED(fixed),button1,320,14);
    gtk_widget_set_size_request(button1,100,20);
    
    label1 = gtk_label_new("摄像头:");
    gtk_fixed_put(GTK_FIXED(fixed),label1,440,14);
    gtk_widget_set_size_request(label1,50,30);
    
    text1 = gtk_text_view_new();
    buffer1=gtk_text_view_get_buffer(GTK_TEXT_VIEW(text1));
    gtk_text_buffer_set_text(buffer1,"",-1);
    gtk_fixed_put(GTK_FIXED(fixed),text1,500,16);
    gtk_widget_set_size_request(text1,100,28);
    sprintf(disp,"/dev/video0");
	gtk_text_buffer_set_text(buffer1,disp,-1);
    
    button2 = gtk_button_new_with_label("查询配置");
    gtk_fixed_put(GTK_FIXED(fixed),button2,610,14);
    gtk_widget_set_size_request(button2,80,35);
    
    
    label2 = gtk_label_new("分辨率:");
    gtk_fixed_put(GTK_FIXED(fixed),label2,740,18);
    gtk_widget_set_size_request(label2,50,30);
    text2 = gtk_text_view_new();
    buffer2=gtk_text_view_get_buffer(GTK_TEXT_VIEW(text2));
    gtk_text_buffer_set_text(buffer2,"",-1);
    gtk_fixed_put(GTK_FIXED(fixed),text2,800,16);
    gtk_widget_set_size_request(text2,100,28);
    sprintf(disp,"640x480");
	gtk_text_buffer_set_text(buffer2,disp,-1);
    
    
    label3 = gtk_label_new("帧率:");
    gtk_fixed_put(GTK_FIXED(fixed),label3,930,18);
    gtk_widget_set_size_request(label3,50,30);
    text3 = gtk_text_view_new();
    buffer3=gtk_text_view_get_buffer(GTK_TEXT_VIEW(text3));
    gtk_text_buffer_set_text(buffer3,"",-1);
    gtk_fixed_put(GTK_FIXED(fixed),text3,980,16);
    gtk_widget_set_size_request(text3,100,28);
    sprintf(disp,"30");
	gtk_text_buffer_set_text(buffer3,disp,-1);
	
	
	label_line = gtk_label_new("______________________________________________________________________________________________________________________________");
    gtk_fixed_put(GTK_FIXED(fixed),label_line,320,45);
    gtk_widget_set_size_request(label_line,800,3);
    
    
	GtkWidget *labelChild;
	PangoFontDescription *font;
	int fontSize = 10;
	font = pango_font_description_from_string("Sans");				//"Sans"字体名
	pango_font_description_set_size(font, fontSize * PANGO_SCALE);	//设置字体大小
	labelChild = gtk_bin_get_child(GTK_WIDGET(button1));			//取出GtkButton里的label
	gtk_widget_modify_font(GTK_WIDGET(labelChild), font);			//设置label的字体, 这样这个GtkButton上面显示的字体就变了
	
	labelChild = gtk_bin_get_child(GTK_WIDGET(button2));			
	gtk_widget_modify_font(GTK_WIDGET(labelChild), font);			


    button3 = gtk_button_new_with_label("视频预览");
    gtk_fixed_put(GTK_FIXED(fixed),button3,320,80);
    gtk_widget_set_size_request(button3,80,20);
    
    
    g_signal_connect_swapped(G_OBJECT(window),"destroy",G_CALLBACK(gtk_main_quit),NULL);
    
    g_signal_connect_swapped(G_OBJECT(window),"destroy",G_CALLBACK(gtk_main_quit),NULL);
    g_signal_connect(G_OBJECT(button1), "clicked", G_CALLBACK(button1_clicked),NULL);
    g_signal_connect(G_OBJECT(button2), "clicked", G_CALLBACK(button2_clicked),NULL);
    g_signal_connect(G_OBJECT(button3), "clicked", G_CALLBACK(button3_clicked),NULL);	
    
    gtk_widget_show_all(window);
    gtk_main();

    return 0;
}

编译命令:gcc preview_camera.c  -o camera_preview `pkg-config --cflags --libs  libavdevice libavfilter libavformat  libavcodec libavutil libpostproc  libswresample  libswscale` `pkg-config --cflags --libs sdl2` `pkg-config --cflags --libs gtk+-3.0`  -w

运行截图:

 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

C++基础Ⅰ编译、链接

目录儿 1 C是如何工作的1.1 预处理语句1.2 include1.3 main()1.4 编译单独编译项目编译 1.5 链接 2 定义和调用函数3 编译器如何工作3.1 编译3.1.1 引入头文件系统头文件自定义头文件 3.1.2 自定义类型3.1.3 条件判断拓展: 汇编 3.2 链接3.2.1 起始函数3.2.2 被调用的函数 3.3 …

ChatGPT帮助提升工作效率和质量:完成时间下降40%,质量评分上升 18%

自ChatGPT去年11月发布以来&#xff0c;人们就开始使用它来协助工作&#xff0c;热心的用户利用它帮助撰写各种内容&#xff0c;从宣传材料到沟通话术再到调研报告。 两名MIT经济学研究生近日在《科学》杂志上发表的一项新研究表明&#xff0c;ChatGPT可能有助于减少员工之…

数字图像处理—— Lab、YCbCr、HSV、RGB之间互转

Lab “Lab” 图像格式通常指的是 CIELAB 色彩空间&#xff0c;也称为 Lab 色彩空间。它是一种用于描述人类视觉感知的颜色的设备无关色彩空间&#xff0c;与常见的 RGB 和 CMYK 色彩空间不同。CIELAB 由国际照明委员会&#xff08;CIE&#xff09;于1976年定义&#xff0c;用于…

【SQL应知应会】索引(三)• MySQL版:聚簇索引与非聚簇索引;查看索引与删除索引;索引方法

欢迎来到爱书不爱输的程序猿的博客, 本博客致力于知识分享&#xff0c;与更多的人进行学习交流 本文收录于SQL应知应会专栏,本专栏主要用于记录对于数据库的一些学习&#xff0c;有基础也有进阶&#xff0c;有MySQL也有Oracle 索引 • MySQL版 前言一、索引1.简介2.索引类型之逻…

【Java 高阶】一文精通 Spring MVC - 基础概念(一)

&#x1f449;博主介绍&#xff1a; 博主从事应用安全和大数据领域&#xff0c;有8年研发经验&#xff0c;5年面试官经验&#xff0c;Java技术专家&#xff0c;WEB架构师&#xff0c;阿里云专家博主&#xff0c;华为云云享专家&#xff0c;51CTO 专家博主 ⛪️ 个人社区&#x…

Centos 解决 XXX不在 sudoers 文件中。此事将被报告。的错误

本来想使用 sudo 拷贝一个文件&#xff0c;结果出现上面的问题&#xff01; 下面是解决方法&#xff1a; 首先登录root&#xff0c;然后执行下面的命令 vim /etc/sudoers 将你需要添加的用户带红色框线的地方&#xff0c;模仿root写一遍&#xff0c;然后保存&#xff01; …

每天一道leetcode:1306. 跳跃游戏 III(图论中等广度优先遍历)

今日份题目&#xff1a; 这里有一个非负整数数组 arr&#xff0c;你最开始位于该数组的起始下标 start 处。当你位于下标 i 处时&#xff0c;你可以跳到 i arr[i] 或者 i - arr[i]。 请你判断自己是否能够跳到对应元素值为 0 的 **任一** 下标处。 注意&#xff0c;不管是什…

Kafka单节点部署

&#x1f388; 作者&#xff1a;互联网-小啊宇 &#x1f388; 简介&#xff1a; CSDN 运维领域创作者、阿里云专家博主。目前从事 Kubernetes运维相关工作&#xff0c;擅长Linux系统运维、开源监控软件维护、Kubernetes容器技术、CI/CD持续集成、自动化运维、开源软件部署维护…

【数据结构练习】链表面试题锦集一

目录 前言&#xff1a; 1. 删除链表中所有值为key的节点 方法一&#xff1a;正常删除&#xff0c;头结点另外讨论 方法二:虚拟头结点法 方法三&#xff1a;递归 2.反转链表 方法一&#xff1a;双指针迭代 方法二&#xff1a;递归法解析&#xff1a; 3.链表的中间结点 方法…

Android开发基础知识总结(三)简单控件(上)

一.文本显示 考虑到结构样式相分离的思想&#xff0c;我们往往在XML中设置文本 <TextViewandroid:layout_width"342dp"android:layout_height"70dp"android:text"房价计算器"android:layout_gravity"center"android:textColor"…

科研论文配图绘制指南——基于Python—第二章1.matplotlib

目录 第二章2.0 安装所需的环境2.1 Matplotlib2.1.1 图形元素2.1.2 图层顺序2.1.5 子图绘制2.1.7 结果保存 第二章 2.0 安装所需的环境 attrs23.1.0 certifi2023.7.22 click8.1.6 click-plugins1.1.1 cligj0.7.2 colorama0.4.6 cycler0.11.0 Fiona1.9.4.post1 geopandas0.13.…

AMBA总线协议(6)——AHB(四):传输细节

一、前言 在之前的文章中&#xff0c;我们已经讲述了AHB传输中的两种情况&#xff0c;基本传输和猝发传输。我们进行一个简单的回顾&#xff0c;首先&#xff0c;开始一次传输之前主机需要向仲裁器申请获得总线的使用权限&#xff0c;然后主机给出地址和控制信号&#xff0c;根…

使用Java开发Jmeter自定义取样器(Sampler)插件

文章目录 1、Jmeter自定义取样器扩展类2、SpringBoot服务器端http测试例子3、自定义取样器实现3.1、默认界面的AbstractJavaSamplerClient扩展实现3.2、自定义界面的AbstractSamplerGui扩展实现 3、自定义取样器运行效果3.1、AbstractJavaSamplerClient运行效果3.2、AbstractSa…

2023-08-21 Unity Shader 开发入门1 —— 渲染管线

文章目录 一、概述二、应用阶段三、几何阶段四、光栅化阶段 一、概述 ​ Unity 中的渲染管线和图形学中的渲染管线基本上指的是相同的概念&#xff0c;但是具体实现和细节方面可能存在一些差异。 ​ Unity 的渲染管线建立在图形学的基础上&#xff0c;但具有自己的实现和拓展。…

如何在服务器上用kaggle下载数据集

S1 服务器上安装kaggle cli工具 pip install --user kaggleS2 服务器上创建kaggle目录 mkdir ~/.kaggleS3 进入kaggle账户创建token 生成token 点击右上角头像&#xff0c;选择setting 点击create new token 进入你的浏览器下载页&#xff0c;可以看到有了一个kaggle.jso…

数据结构-----树的易错点

1.树的度和m叉树 •度为m的树&#xff08;度表示该结点有多少个孩子&#xff08;分支&#xff09;&#xff09; 任意结点的度<m(最多m个孩子) 至少又一个结点度m(有m个孩子) 一定是非空树&#xff0c;至少有m1个结点 •m叉树 任意结点的度<m(最多有m个孩子) 允许所…

计算机竞赛 python的搜索引擎系统设计与实现

0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; python的搜索引擎系统设计与实现 &#x1f947;学长这里给一个题目综合评分(每项满分5分) 难度系数&#xff1a;3分工作量&#xff1a;5分创新点&#xff1a;3分 该项目较为新颖&#xff…

根据源码,模拟实现 RabbitMQ - 虚拟主机 + Consume设计 (7)

目录 一、虚拟主机 Consume设计 1.1、承接问题 1.2、具体实现 1.2.1、消费者订阅消息实现思路 1.2.2、消费者描述自己执行任务方式实现思路 1.2.3、消息推送给消费者实现思路 1.2.4、消息确认 一、虚拟主机 Consume设计 1.1、承接问题 前面已经实现了虚拟主机大部分功…

软考高级系统架构设计师(二)计算机操作系统

【原文链接】软考高级系统架构设计师&#xff08;二&#xff09;计算机操作系统 2.1 进程管理 2.1.1 操作系统的三个重要作用 管理计算机中运行的程序和分配各种软硬件资源为用户提供友善的人机界面为应用程序的开发和运行提供一个高效的平台 2.1.2 操作系统的四个特征 并…

Linux入门

一、安装相关软件 1.下载vmware (很容易下载,搜一下官网 ) 在cmd敲入 ncpa.cpl &#xff0c;查看是否有vmware 2.下载centos 下面是镜像源网站&#xff0c;当然你可以选择其他的镜像源&#xff0c;像清华镜像源和阿里镜像源。 Index of /centos/7.9.2009/isos/x86_64/ | …
最新文章