ffmpeg+D3D实现的MFC音视频播放器,支持录像、截图、音视频播放、码流信息显示等功能
一、简介
本播放器是在vs2019下开发,通过ffmpeg实现拉流解码功能,通过D3D实现视频的渲染功能。截图功能采用libjpeg实现,可以截取jpg图片,图片的默认保存路径是在C:\MYRecPath中。录像功能采用封装好的类Mp4Record实现,在Mp4Record类中主要还是采用ffmpeg的相关函数方法进行mp4视频的录制。音频的播放采用DirectSound实现,将ffmpeg解码后的音频数据存储到DirectSound的buffer中,再调用DirectSound的play实现对音频的播放功能。码流信息的显示,通过D3D的文本绘制实现。本播放器提供源码下载,直接下载请点击最后的下载链接。
二、界面展示

三、相关代码
开始播放
int CVideoPlayer::StartPlay(const char* sUrl)
{m_bStop = false;m_nVideoIndex = -1;m_nAudioIndex = -1;int i = 0, res = 0, nValue = 0;char buf[64] = { 0 };m_bPlaying = false;AVStream* in_stream;_snprintf_s(m_sConnectUrl, sizeof(m_sConnectUrl), sizeof(m_sConnectUrl) - 1, "%s", sUrl);//av_register_all();avformat_network_init();AVDictionary* optionsDict = nullptr;av_dict_set(&optionsDict, "rtsp_transport", "tcp", 0);av_dict_set(&optionsDict, "stimeout", "5000000", 0);av_dict_set(&optionsDict, "buffer_size", "8192000", 0);av_dict_set(&optionsDict, "recv_buffer_size", "8192000", 0);m_lastReadPacktTime = av_gettime();m_pAVFmtCxt = avformat_alloc_context();m_pAVFmtCxt->interrupt_callback.opaque = this;m_pAVFmtCxt->interrupt_callback.callback = decodeInterruptCb;res = avformat_open_input(&m_pAVFmtCxt, m_sConnectUrl, NULL, &optionsDict);if (res < 0){myprint("avformat_open_input fail: %d", res);return -1;}if (!m_pAVFmtCxt){return -1;}m_pAVFmtCxt->probesize = 100 * 1024; m_pAVFmtCxt->max_analyze_duration = 1 * AV_TIME_BASE; res = avformat_find_stream_info(m_pAVFmtCxt, NULL);if (res < 0){myprint("error %x in avformat_find_stream_info\n", res);return -1;}av_dump_format(m_pAVFmtCxt, 0, m_sConnectUrl, 0);for (i = 0; i < m_pAVFmtCxt->nb_streams; i++){if (m_pAVFmtCxt->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO){m_nVideoIndex = i;}else if (m_pAVFmtCxt->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {m_nAudioIndex = i;}myprint("m_pAVFmtCxt->streams[i]->codec->codec_type:%d", m_pAVFmtCxt->streams[i]->codecpar->codec_type);}//videoindex not findif (m_nVideoIndex == -1){myprint("can't find video stream.");return -1;}m_pCodec = avcodec_find_decoder(m_pAVFmtCxt->streams[m_nVideoIndex]->codecpar->codec_id);if (!m_pCodec){myprint("video decoder not found\n");return -1;}if (m_bSupportAudio && m_nAudioIndex != -1){myprint("start audio decoder \n");if (!m_pAudioCodecCxt)m_pAudioCodecCxt = avcodec_alloc_context3(NULL);auto pAudioCodecpar = m_pAVFmtCxt->streams[m_nAudioIndex]->codecpar;avcodec_parameters_to_context(m_pAudioCodecCxt, pAudioCodecpar);m_pAudioCodec = avcodec_find_decoder(pAudioCodecpar->codec_id);if (nullptr == m_pAudioCodec || nullptr == m_pAudioCodecCxt){myprint("audio decoder not found\n");return -1;}m_pSwrContext = swr_alloc_set_opts(0, av_get_default_channel_layout(m_channels_play),AV_SAMPLE_FMT_S16, m_nSampleRate, av_get_default_channel_layout(m_pAudioCodecCxt->channels),m_pAudioCodecCxt->sample_fmt, m_pAudioCodecCxt->sample_rate, 0,0);auto ret = swr_init(m_pSwrContext);if (ret < 0){myprint("Failed to swr_init(pSwrContext);");return -1;}if (InitDirectSound() == FALSE)m_bSupportAudio = false;}m_CodecId = m_pCodec->id;if(!m_pCodecCxt)m_pCodecCxt = avcodec_alloc_context3(NULL);avcodec_parameters_to_context(m_pCodecCxt, m_pAVFmtCxt->streams[m_nVideoIndex]->codecpar);if (m_pCodecCxt){if (m_pCodecCxt->width == 0 || m_pCodecCxt->height == 0){myprint("m_pCodecCxt->width:%d, m_pCodecCxt->height:%d", m_pCodecCxt->width, m_pCodecCxt->height);return -1;}}elsereturn -1;AVCodecContext* temp_codecctx = m_pCodecCxt;memcpy(temp_codecctx, m_pCodecCxt, sizeof(m_pCodecCxt));if (m_pCodecCxt->codec_type == AVMEDIA_TYPE_VIDEO){myprint("Soft Solution");avcodec_close(m_pCodecCxt);m_pCodecCxt = temp_codecctx;m_pCodecCxt->thread_count = 4;if (m_Dxva2D3DRender.InitD3DRender(m_showWnd, m_pCodecCxt->width, m_pCodecCxt->height) == false){myprint("InitD3DRender fail");}m_pOutBuffer = (uint8_t*)av_malloc(av_image_get_buffer_size(AV_PIX_FMT_YUV420P, m_pCodecCxt->width, m_pCodecCxt->height, 1));if (nullptr == m_pOutBuffer)return -1;av_image_fill_arrays(m_pFrameBGR->data, m_pFrameBGR->linesize, m_pOutBuffer, AV_PIX_FMT_YUV420P, m_pCodecCxt->width, m_pCodecCxt->height, 1); //填充AVFrame数据缓冲m_pImgConvertCtx = sws_getContext(m_pCodecCxt->width, m_pCodecCxt->height, m_pCodecCxt->pix_fmt, m_pCodecCxt->width, m_pCodecCxt->height, AV_PIX_FMT_YUV420P, SWS_FAST_BILINEAR, NULL, NULL, NULL);if (nullptr == m_pImgConvertCtx)return -1;m_nActualWidth = m_pCodecCxt->width;m_nActualHeight = m_pCodecCxt->height;res = avcodec_open2(m_pCodecCxt, m_pCodec, NULL);if (res < 0){myprint("avcodec_open2 video fail error:%x", res);return -1;}}if (m_bSupportAudio && m_pAudioCodecCxt){if (m_pAudioCodecCxt->codec_type == AVMEDIA_TYPE_AUDIO){res = avcodec_open2(m_pAudioCodecCxt, m_pAudioCodec, NULL);if (res < 0){myprint("avcodec_open2 audio fail error:%x", res);avcodec_close(m_pAudioCodecCxt);return -1;}myprint("===Audio Message===");myprint(" bit_rate = %d ", m_pAudioCodecCxt->bit_rate);myprint(" sample_rate = %d ", m_pAudioCodecCxt->sample_rate);myprint(" channels = %d ", m_pAudioCodecCxt->channels);myprint(" code_name = %s ", m_pAudioCodecCxt->codec->name);myprint(" block_align = %d ", m_pAudioCodecCxt->block_align);}}m_pDecodeThread = (my_thread_t*)my_malloc(sizeof(my_thread_t));if (nullptr != m_pDecodeThread){m_bDecodeThreadRun = true;res = my_thread_create(m_pDecodeThread, ThreadDecode, this);if (res == -1){myprint("my_thread_create ThreadDecode failed res:%x", res);return -1;}}return 0;
}
停止播放
void CVideoPlayer::StopPlay()
{m_bPlaying = false;m_CaptureAudio.SetGrabAudioFrames(FALSE, NULL);m_CaptureAudio.Close();m_bStopAudio = true;while (!m_AudioPlayQue.empty()){m_AudioPlayQue.pop();}while (!m_AudioTalkQue.empty()){EnterCriticalSection(&m_talklock);m_AudioTalkQue.pop();LeaveCriticalSection(&m_talklock);}m_bDecodeThreadRun = false;if (m_pDecodeThread){my_thread_join(m_pDecodeThread);my_free(m_pDecodeThread);m_pDecodeThread = nullptr;}if (m_pAudioPlayThread) {SetEvent(m_event);if (m_pAudioPlayThread->handle) {my_thread_join(m_pAudioPlayThread);m_pAudioPlayThread->handle = nullptr;}}if (m_pDSBuffer8){m_pDSBuffer8->Stop();m_pDSBuffer8->Restore();}m_Dxva2D3DRender.UnitD3DRender();if (m_pCodecCxt){avcodec_close(m_pCodecCxt);}if (m_pAudioCodecCxt){avcodec_close(m_pAudioCodecCxt);}if (m_pSwrContext){swr_free(&m_pSwrContext);m_pSwrContext = nullptr;}if (m_pAVFmtCxt) {avformat_close_input(&m_pAVFmtCxt);avformat_free_context(m_pAVFmtCxt);m_pAVFmtCxt = nullptr;}}
解码线程
void CVideoPlayer::DecodeAndShow()
{if (m_pAVFmtCxt == nullptr || m_pCodecCxt == nullptr)return;AVPacket pkt = { 0 };m_bPlaying = true;uint8_t* pBuffer;bool bEnoughSpace = true;int nTimeCnt = 0;int res = 0;struct SwsContext* img_convert_ctx = nullptr;int nRectDrawWait = 0;bool bRecordLastIFrame = false;int num_av_read_frame_err = 0;int num_stream_index_err = 0;uint8_t * outData[2] = {0};outData[0] = (uint8_t*)av_malloc(1152 * 8);outData[1] = (uint8_t*)av_malloc(1152 * 8);uint8_t* pktdata;int pktsize;int len = 0;bool bPushAudioToQueue = false;m_bStopAudio = false;CRect ShowRect;AVFrame* pAvFrame = av_frame_alloc();if (nullptr == pAvFrame)return;AVFrame* pFrameRGB = av_frame_alloc();if (nullptr == pFrameRGB)return;int numBytes = av_image_get_buffer_size(AV_PIX_FMT_RGB24, m_pCodecCxt->width, m_pCodecCxt->height, 1);pBuffer = (uint8_t*)av_malloc(numBytes);if (nullptr == pBuffer)return;av_image_fill_arrays(pFrameRGB->data,pFrameRGB->linesize, pBuffer, AV_PIX_FMT_RGB24, m_pCodecCxt->width, m_pCodecCxt->height, 1);img_convert_ctx = sws_getCachedContext(img_convert_ctx, m_pCodecCxt->width, m_pCodecCxt->height,m_pCodecCxt->pix_fmt, m_pCodecCxt->width, m_pCodecCxt->height, AV_PIX_FMT_RGB24, SWS_FAST_BILINEAR/*SWS_BICUBIC*/, NULL, NULL, NULL);//Audioif (m_bSupportAudio && m_pAudioPlayThread){res = my_thread_create(m_pAudioPlayThread, ThreadAudioPlay, this);if (res < 0)myprint("my_thread_create ThreadAudioPlay fail");}while (m_bDecodeThreadRun && !m_bQuit){if (m_bPause){Sleep(100);continue;}{if (m_bReconnect){myprint("bReConnect = true, break");break;}}m_lastReadPacktTime = av_gettime();if (av_read_frame(m_pAVFmtCxt, &pkt) >= 0){num_av_read_frame_err = 0;if (pkt.stream_index == m_nVideoIndex || pkt.stream_index == m_nAudioIndex){if (m_bRecord)//Record{if (nTimeCnt != 0 || (!bRecordLastIFrame && pkt.flags == AV_PKT_FLAG_KEY)) {if (m_sRecPath[0] != '\0' && nTimeCnt++ % 200 == 0){bEnoughSpace = CheckRemainSpace(m_sRecPath);if (bEnoughSpace == true){myprint("bEnoughSpace = true");}elsemyprint("bEnoughSpace = false");}m_nRecordCurrentTime = time(NULL);if ((m_nRecordCurrentTime - m_nRecordStartTime) >= (m_nRecordTime * 60)){myprint("Record Finsh!");stopRecord();}else if (bEnoughSpace == false){myprint("bEnoughSpace == false");stopRecord();}else{AVPacket* pPkt = av_packet_clone(&pkt);m_mp4Recorder.saveOneFrame(*pPkt, m_CodecId);av_packet_free(&pPkt);}}bRecordLastIFrame = pkt.flags == AV_PKT_FLAG_KEY;}elsenTimeCnt = 0;}if (pkt.stream_index == m_nVideoIndex){num_stream_index_err = 0;nTimeCnt = 0;if (pkt.flags == 1)bPushAudioToQueue = true;if (nullptr == m_pCodecCxt || nullptr == pAvFrame) {myprint("m_pCodecCxt == NULL || pAvFrame == NULL");break;}int gotvframe = 0;auto sd_ret = avcodec_send_packet(m_pCodecCxt, &pkt);if (sd_ret != 0 && sd_ret != AVERROR(EAGAIN)) {myprint("avcodec_send_packet err, rt=%d", sd_ret);enableReConnect();}else {while (gotvframe == 0 && !m_bQuit) {gotvframe = avcodec_receive_frame(m_pCodecCxt, pAvFrame);if (gotvframe == 0){try{GetShowRectSize(&ShowRect);}catch (const std::exception&){myprint("GetClientRect throw, error");break;}m_nCurPKSize = pkt.size; SetStreamInfoToD3d();if (pAvFrame->width != m_nActualWidth || pAvFrame->height != m_nActualHeight){myprint("video size change reconnect...");enableReConnect();m_nActualWidth = pAvFrame->width;m_nActualHeight = pAvFrame->height;av_packet_unref(&pkt);continue;}if (m_pImgConvertCtx && m_pFrameBGR && m_pOutBuffer && pAvFrame){sws_scale(m_pImgConvertCtx, (const uint8_t* const*)pAvFrame->data, pAvFrame->linesize, 0,m_pCodecCxt->height, m_pFrameBGR->data, m_pFrameBGR->linesize);{ try{int re = 5;for (int i = 0; m_bPlaying && re == 5 && i < 10; ++i) { // LockRect失败时重复尝试,最多10次re = m_Dxva2D3DRender.D3DSoftDisplayFrame(m_pOutBuffer, pAvFrame->width, pAvFrame->height, ShowRect);Sleep(1);}}catch (int re){myprint("m_Dxva2D3DRender.InitD3DRender again");if (m_Dxva2D3DRender.InitD3DRender(m_showWnd, m_pCodecCxt->width, m_pCodecCxt->height) == false){myprint("m_Dxva2D3DRender.InitD3DRender again fail");av_packet_unref(&pkt);continue;}}} }if (m_bCapture /*&& pkt.flags == 1*/ && img_convert_ctx){sws_scale(img_convert_ctx, (const uint8_t* const*)pAvFrame->data, pAvFrame->linesize, 0, m_pCodecCxt->height,pFrameRGB->data, pFrameRGB->linesize);SaveIFrameImage(pFrameRGB->data[0], m_pCodecCxt->width, m_pCodecCxt->height);m_bCapture = false;}}}}}else if (pkt.stream_index == m_nAudioIndex){num_stream_index_err = 0;if (m_bSupportAudio) {pktdata = pkt.data;pktsize = pkt.size;if (pktsize > 0){int gotframe = 0;if (nullptr == m_pAudioCodecCxt || nullptr == pAvFrame) {myprint("m_pAudioCodecCxt == NULL || pAvFrame == NULL");break;}len = avcodec_send_packet(m_pAudioCodecCxt, &pkt);if (len != 0 && len != AVERROR(EAGAIN)){pktsize = 0;myprint("avcodec_send_packet len < 0");break;}auto data_size = av_get_bytes_per_sample(m_pAudioCodecCxt->sample_fmt); if (data_size < 0) {myprint("Failed to calculate data size\n");break;}while (gotframe == 0 && !m_bQuit) {gotframe = avcodec_receive_frame(m_pAudioCodecCxt, pAvFrame);if (!gotframe){if (bPushAudioToQueue == true && m_bEnableAudio && !m_bStopAudio){audio_frame_t audioFrame;numBytes = av_get_bytes_per_sample(AV_SAMPLE_FMT_S16);auto dstNbSamples = av_rescale_rnd(pAvFrame->nb_samples,m_src_sample_rate,pAvFrame->sample_rate,AV_ROUND_ZERO);int data_size = 0;try{auto nb = swr_convert(m_pSwrContext,(uint8_t**)outData,dstNbSamples,(const uint8_t**)pAvFrame->data,pAvFrame->nb_samples);data_size = av_samples_get_buffer_size(nullptr, m_channels_play, nb, AV_SAMPLE_FMT_S16, 1);}catch (const std::exception&){m_bSupportAudio = false;myprint("swr_convert throw err, set m_bSupportAudio false");continue;}int copy_size = 0; int copy_ptr = 0; for (int isub = data_size; isub > 0; isub -= copy_size) {if (isub > m_audio_buffer_notify_size) {copy_size = m_audio_buffer_notify_size;copy_ptr = data_size - isub;}elsecopy_size = isub;audioFrame.data_size = copy_size;memcpy(audioFrame.data, outData[0] + copy_ptr, copy_size);EnterCriticalSection(&m_lock);m_AudioPlayQue.push(audioFrame);LeaveCriticalSection(&m_lock);}}}}}}}else if (++num_stream_index_err > 20) {myprint("pkt.stream_index unfind, %d",pkt.stream_index);enableReConnect();}av_packet_unref(&pkt);}else {if (++num_av_read_frame_err > 10) {myprint("num_av_read_frame_err is more than 10");enableReConnect();}}}if (m_bDecodeThreadRun) {myprint("m_bDecodeThreadRun is true");enableReConnect();}if (pAvFrame)av_free(pAvFrame);if (pFrameRGB)av_free(pFrameRGB);if (pBuffer)av_free(pBuffer);if (img_convert_ctx)sws_freeContext(img_convert_ctx);if (outData[0] && outData[1]){av_free(outData[0]);av_free(outData[1]);outData[0] = 0;outData[1] = 0;}
}
四、相关下载
链接: 可执行程序下载
链接: 源码下载
相关文章:
ffmpeg+D3D实现的MFC音视频播放器,支持录像、截图、音视频播放、码流信息显示等功能
一、简介 本播放器是在vs2019下开发,通过ffmpeg实现拉流解码功能,通过D3D实现视频的渲染功能。截图功能采用libjpeg实现,可以截取jpg图片,图片的默认保存路径是在C:\MYRecPath中。录像功能采用封装好的类Mp4Record实现,…...
【Flink】-- flink新版本发布:v2.0-preview1
目录 1、简介 2、非兼容变更 2.1、API 2.2、连接器适配计划 2.3、配置 2.4、其它 3、重要新特性 3.1、存算分离状态管理 3.2、物化表 3.3、批作业的自适应执行 3.4、流式湖仓 4、附加 4.1、非兼容性的 api 程序变更 4.1.2、Removed Classes # 4.1.3、Modified Cl…...
Node.js 版本管理的最终答案 Volta
文章目录 特点安装Unix系统安装Windows系统安装 常用命令volta fetchvolta installvolta uninstallvolta pinvolta listvolta completionsvolta whichvolta setupvolta runvolta help 建议 目前对于前端项目的node 版本,我们一般会在项目 package.json 的 engines 字…...
蓝桥杯每日真题 - 第11天
题目:(合并数列) 题目描述(14届 C&C B组D题) 解题思路: 题意理解:给定两个数组,目标是通过若干次合并操作使两个数组相同。每次合并操作可以将数组中相邻的两个数相加ÿ…...
Vue vs React:两大前端框架的区别解析
在现代前端开发中,Vue.js 和 React.js 是两个最受欢迎的框架和库。我们常常面临选择它们的困惑。虽然这两者在本质上都是为了构建用户界面而设计的,但它们在设计理念、使用方式和生态系统等方面有着显著的区别。今天,我们将通过深入分析这两个…...
【树莓派raspberrypi烧录Ubuntu远程桌面登入树莓派】
提示:本文利用的是Ubuntu主机和树莓派4B开发板,示例仅供参考 文章目录 一、树莓派系统安装下载前准备工作下载安装树莓派的官方烧录软件imagerimager的使用方法 二、主机与树莓SSH连接查看数梅派IP地址建立ssh连接更新树莓派源地址 三、主机端远程桌面配…...
c# 调用c++ 的dll 出现找不到函数入口点
今天在调用一个设备的dll文件时遇到了一点波折,因为多c 不熟悉,调用过程张出现了找不到函数入口点,一般我们使用c# 调用c 文件,还是比较简单。 [DllImport("AtnDll2.dll",CharSet CharSet.Ansi)]public static extern …...
LInux——环境基础开发工具使用(正在更新中...)
1.软件包管理器 Linux下安装软件的方案: 1. 源代码安装 2. rpm包安装 3. 包管理器安装 --- yum/ apt (此图片来自于比特就业课课件) 1.1 操作生态系统 好的操作系统定义: 生态环境好 不同的操作系统根本是生态不同(…...
linux 内核asmlinkage关键字总结
1,看一下asmlinkage的定义 CPP_ASMLINKAGE __attribute__((regparm(0))) GCC中使用__attribute__((regparm(n)))指定最多可以使用n个寄存器(eax, edx, ecx)传递参数,n的范围是0~3,超过n时则将参数压入栈中(…...
⚡️如何在 React 和 Next.js 项目里优雅的使用 Zustand
前言 你是否曾感觉在 React 中管理状态简直是一场噩梦?如果你已经厌倦了不停地处理 props、context 和 hooks,那么现在是时候认识 Zustand 了。Zustand 是一个轻量级的状态管理库,它简化了你处理应用状态的方式。在这篇文章中,我…...
Pinpoint(APM)进阶--Pinot指标采集(System Metric/Inspector)
接上文 Pinpoint使用Pinot进行指标数据存储,Pinot流摄入需要Kafka 本文详解Kafka和Pinot的安装部署,以及Pinpoint的指标采集 Pinot 简介 Apache Pinot是一个实时分布式OLAP数据存储,专为低延迟、高吞吐量分析而构建,非常适合面…...
Mysql:使用binlog的一些常用技巧
1、如何查看binlog的存放路径 show variables like log% 执行结果: 2、如何清除binlog (1)按时间清除 purge binary logs before ‘2023-06-5 10:12:00’ (2)按文件文件名清除 purge binary logs to ‘mybinlog.0000…...
Electron 项目启动外部可执行文件的几种方式
Electron 项目启动外部可执行文件的几种方式 序言 在开发 Electron 应用程序时,有时需要启动外部的可执行文件(如 .exe 文件)。这可能是为了调用系统工具、运行第三方软件或者集成现有的应用程序。 Electron 提供了多种方式来启动外部可执行…...
前端开发中常用的包管理器(npm、yarn、pnpm、bower、parcel)
文章目录 1. npm (Node Package Manager)2. Yarn (Yarn Package Manager)3. pnpm4. Bower5. Parcel总结 前端开发中常用的包管理器主要有以下几个: 1. npm (Node Package Manager) 简介: npm 是 Node.js 的默认包管理器,也是最广泛使用的包…...
Linux入门:环境变量与进程地址空间
一. 环境变量 1. 概念 1️⃣基本概念: 环境变量(environment variables)一般是指在操作系统中用来指定操作系统运行环境的一些参数 如:我们在编写C/C代码的时候,在链接的时候,从来不知道我们的所链接的动态静态库在哪里&#x…...
【Jenkins实战】Windows安装服务启动失败
写此篇短文,望告诫后人。 如果你之前装过Jenkins,出于换域账号/本地帐号的原因想重新安装,你大概率会遇上一次Jenkins服务启动失败提示: Jenkins failed to start - Verify that you have sufficient privileges to start system…...
web实操5——http数据详解,request对象功能
http请求数据 现在我们浏览器f12的那些是浏览器给http格式数据整理之后便于我们阅读的。 原始的http格式信息: 就是按照一定格式和符号的字符串: 请求行:格式如下图 请求头:一个个key,value数据,用,分割…...
C# 如何动态加载程序集
程序集的加载,默认是从当前目录下查找,如果当前目录查找不到,然后再去系统目录中查找,依然查找不到就会从环境变量中查找,如果依然找不到,则会抛出一个异常 FileNotFoundException。 托管代码中࿰…...
前端基础的讲解-JS(10)
作用域链 通过上节作用域我们知道,当我们声明一个函数时,程序会生成一个独立的作用域,如果函数中还有函数,那么在这个作用域中就又可以诞生一个作用域;根据 内部函数可以访问外部函数变量 的这种机制,用链…...
JNI整理总结
JNI JNI基础 JNI基础 JNI,java native interface,即java本地接口,是java调用本地化方法的接口,是为java编写本地方法,为jvm嵌入本地应用程序的标准化接口。首要目标是在给定的平台上采用java通过JNI调用本地化方法&am…...
Python|GIF 解析与构建(5):手搓截屏和帧率控制
目录 Python|GIF 解析与构建(5):手搓截屏和帧率控制 一、引言 二、技术实现:手搓截屏模块 2.1 核心原理 2.2 代码解析:ScreenshotData类 2.2.1 截图函数:capture_screen 三、技术实现&…...
【Python】 -- 趣味代码 - 小恐龙游戏
文章目录 文章目录 00 小恐龙游戏程序设计框架代码结构和功能游戏流程总结01 小恐龙游戏程序设计02 百度网盘地址00 小恐龙游戏程序设计框架 这段代码是一个基于 Pygame 的简易跑酷游戏的完整实现,玩家控制一个角色(龙)躲避障碍物(仙人掌和乌鸦)。以下是代码的详细介绍:…...
【WiFi帧结构】
文章目录 帧结构MAC头部管理帧 帧结构 Wi-Fi的帧分为三部分组成:MAC头部frame bodyFCS,其中MAC是固定格式的,frame body是可变长度。 MAC头部有frame control,duration,address1,address2,addre…...
【入坑系列】TiDB 强制索引在不同库下不生效问题
文章目录 背景SQL 优化情况线上SQL运行情况分析怀疑1:执行计划绑定问题?尝试:SHOW WARNINGS 查看警告探索 TiDB 的 USE_INDEX 写法Hint 不生效问题排查解决参考背景 项目中使用 TiDB 数据库,并对 SQL 进行优化了,添加了强制索引。 UAT 环境已经生效,但 PROD 环境强制索…...
LeetCode - 394. 字符串解码
题目 394. 字符串解码 - 力扣(LeetCode) 思路 使用两个栈:一个存储重复次数,一个存储字符串 遍历输入字符串: 数字处理:遇到数字时,累积计算重复次数左括号处理:保存当前状态&a…...
macOS多出来了:Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用
文章目录 问题现象问题原因解决办法 问题现象 macOS启动台(Launchpad)多出来了:Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用。 问题原因 很明显,都是Google家的办公全家桶。这些应用并不是通过独立安装的…...
剑指offer20_链表中环的入口节点
链表中环的入口节点 给定一个链表,若其中包含环,则输出环的入口节点。 若其中不包含环,则输出null。 数据范围 节点 val 值取值范围 [ 1 , 1000 ] [1,1000] [1,1000]。 节点 val 值各不相同。 链表长度 [ 0 , 500 ] [0,500] [0,500]。 …...
Hive 存储格式深度解析:从 TextFile 到 ORC,如何选对数据存储方案?
在大数据处理领域,Hive 作为 Hadoop 生态中重要的数据仓库工具,其存储格式的选择直接影响数据存储成本、查询效率和计算资源消耗。面对 TextFile、SequenceFile、Parquet、RCFile、ORC 等多种存储格式,很多开发者常常陷入选择困境。本文将从底…...
sipsak:SIP瑞士军刀!全参数详细教程!Kali Linux教程!
简介 sipsak 是一个面向会话初始协议 (SIP) 应用程序开发人员和管理员的小型命令行工具。它可以用于对 SIP 应用程序和设备进行一些简单的测试。 sipsak 是一款 SIP 压力和诊断实用程序。它通过 sip-uri 向服务器发送 SIP 请求,并检查收到的响应。它以以下模式之一…...
Python基于历史模拟方法实现投资组合风险管理的VaR与ES模型项目实战
说明:这是一个机器学习实战项目(附带数据代码文档),如需数据代码文档可以直接到文章最后关注获取。 1.项目背景 在金融市场日益复杂和波动加剧的背景下,风险管理成为金融机构和个人投资者关注的核心议题之一。VaR&…...
