首页 > 其他分享 >记录 FFmpeg开发常用功能封装

记录 FFmpeg开发常用功能封装

时间:2023-08-15 14:47:43浏览次数:48  
标签:封装 FFmpeg 记录 int frame ret int64 videoEnCodecCtx include

说明

记录下个人在开发中使用到的FFmpeg常用功能,避免相同功能代码的重复编写,使用时直接复制提升效率。由于音视频处理的场景众多,无法编写完全通用的方法接口,可能需根据实际场景进行一定的修改,本文章中的代码也将持续更新优化

代码

这里提供ffmpegheader.h,ffmpegheader.cpp。配置好基本的FFmpeg库环境后,直接导入上述两个文件,即可直接使用对应功能。

更新记录

2023.05.29  优化编码时间戳为 固定累加+实时矫正

2023.06.13  优化编码类;新增时间戳处理类

1、头文件

 
  #ifndef FFMPEGHEADER_H   #define FFMPEGHEADER_H       /**   * 封装常用的ffmpeg方法以及类 只需要引入文件即可直接使用 避免重复轮子   * By ZXT   */       extern "C"   {   #include "./libavcodec/avcodec.h"   #include "./libavformat/avformat.h"   #include "./libavformat/avio.h"   #include "./libavutil/opt.h"   #include "./libavutil/time.h"   #include "./libavutil/imgutils.h"   #include "./libswscale/swscale.h"   #include "./libswresample/swresample.h"   #include "./libavutil/avutil.h"   #include "./libavutil/ffversion.h"   #include "./libavutil/frame.h"   #include "./libavutil/pixdesc.h"   #include "./libavutil/imgutils.h"   #include "./libavfilter/avfilter.h"   #include "./libavfilter/buffersink.h"   #include "./libavfilter/buffersrc.h"   #include "./libavdevice/avdevice.h"   }       #include <QDebug>       /************************************* 常用函数封装 ************************************/   //获取ffmpeg报错信息   char *getAVError(int errNum);       //根据pts计算实际时间us   int64_t getRealTimeByPTS(int64_t pts, AVRational timebase);   //pts转换为us差时进行延时   void calcAndDelay(int64_t startTime, int64_t pts, AVRational timebase);       //十六进制字节数组转十进制   int32_t hexArrayToDec(char *array, int len);           /************************************* 常用类封装 *************************************/   //视频图像转换类   class VideoSwser   {   public:   VideoSwser();   ~VideoSwser();       //初始化转换器   bool initSwsCtx(int srcWidth, int srcHeight, AVPixelFormat srcFmt, int dstWidth, int dstHeight, AVPixelFormat dstFmt);   void release();       //返回转换格式后的AVFrame   AVFrame *getSwsFrame(AVFrame *srcFrame);       private:   bool hasInit;   bool needSws;       int dstWidth;   int dstHeight;   AVPixelFormat dstFmt;       //格式转换   SwsContext *videoSwsCtx;   };       //视频编码器类   class VideoEncoder   {   public:   VideoEncoder();   ~VideoEncoder();       //初始化编码器   bool initEncoder(int width, int height, AVPixelFormat fmt, int fps);   void release();       //返回编码后AVpacket   AVPacket *getEncodePacket(AVFrame *srcFrame);   AVPacket *flushEncoder();       //返回编码器上下文   AVCodecContext *getCodecContent();       private:   bool hasInit;       //编码器   AVCodecContext *videoEnCodecCtx;   };           //音频重采样类   class AudioSwrer   {   public:   AudioSwrer();   ~AudioSwrer();       //初始化转换器   bool initSwrCtx(int inChannels, int inSampleRate, AVSampleFormat inFmt, int outChannels, int outSampleRate, AVSampleFormat outFmt);   void release();       //返回转换格式后的AVFrame   AVFrame *getSwrFrame(AVFrame *srcFrame);   //返回转换格式后的AVFrame srcdata为一帧源格式的数据   AVFrame *getSwrFrame(uint8_t *srcData);       private:   bool hasInit;   bool needSwr;       int outChannels;   int outSampleRate;   AVSampleFormat outFmt;       //格式转换   SwrContext *audioSwrCtx;   };       //音频编码器类   class AudioEncoder   {   public:   AudioEncoder();   ~AudioEncoder();       //初始化编码器   bool initEncoder(int channels, int sampleRate, AVSampleFormat sampleFmt);   void release();       //返回编码后AVpacket   AVPacket *getEncodePacket(AVFrame *srcFrame);   AVPacket *flushEncoder();       //返回编码器上下文   AVCodecContext *getCodecContent();       private:   bool hasInit;       //编码器   AVCodecContext *audioEnCodecCtx;   };       //实时采集场景时间戳处理类   class AVTimeStamp   {   public:   //累加帧间隔 优点:时间戳稳定均匀 缺点:实际采集帧率可能不稳定,固定累加或忽略小数会累加误差造成不同步   //实时时间戳 优点:时间戳保持实时及正确 缺点:存在帧间隔不均匀,极端情况不能正常播放   //累加+实时矫正 优点:时间戳实时且较为均匀 缺点:纠正时间戳的某一时刻可能画面或声音卡顿   enum PTSMode   {   PTS_RECTIFY = 0, //默认矫正类型 保持帧间隔尽量均匀   PTS_REALTIME //实时pts   };       public:   AVTimeStamp();   ~AVTimeStamp();       //初始化时间戳参数   void initAudioTimeStampParm(int sampleRate, PTSMode mode = PTS_RECTIFY);   void initVideoTimeStampParm(int fps, PTSMode mode = PTS_RECTIFY);       //开始时间戳记录   void startTimeStamp();       //返回pts   int64_t getAudioPts();   int64_t getVideoPts();       private:   //当前模式   PTSMode aMode;   PTSMode vMode;       //时间戳相关记录 均us单位   int64_t startTime;   int64_t audioTimeStamp;   int64_t videoTimeStamp;   double audioDuration;   double videoDuration;   };       #endif // FFMPEGHEADER_H    
 
 

2、实现文件

 
  #include "ffmpegheader.h"       char *getAVError(int errNum)   {   static char msg[32] = {0};   av_strerror(errNum, msg, 32);   return msg;   }       int64_t getRealTimeByPTS(int64_t pts, AVRational timebase)   {   //pts转换为对应us值   AVRational timebase_q = {1, AV_TIME_BASE};   int64_t ptsTime = av_rescale_q(pts, timebase, timebase_q);   return ptsTime;   }       void calcAndDelay(int64_t startTime, int64_t pts, AVRational timebase)   {   int64_t ptsTime = getRealTimeByPTS(pts, timebase);       //计算startTime到此刻的时间差值   int64_t nowTime = av_gettime() - startTime;   int64_t offset = ptsTime - nowTime;       //大于2秒一般时间戳存在问题 延时无法挽救   if(offset > 1000 && offset < 2*1000*1000)   av_usleep(offset);   }       int32_t hexArrayToDec(char *array, int len)   {   //目前限制四字节长度 超过则注意返回类型 防止溢出   if(array == nullptr || len > 4)   return -1;       int32_t result = 0;   for(int i=0; i<len; i++)   result = result * 256 + (unsigned char)array[i];       return result;   }           VideoSwser::VideoSwser()   {   videoSwsCtx = nullptr;   hasInit = false;   needSws = false;   }       VideoSwser::~VideoSwser()   {   release();   }       bool VideoSwser::initSwsCtx(int srcWidth, int srcHeight, AVPixelFormat srcFmt, int dstWidth, int dstHeight, AVPixelFormat dstFmt)   {   release();       if(srcWidth == dstWidth && srcHeight == dstHeight && srcFmt == dstFmt)   {   needSws = false;   }   else   {   //设置转换上下文 srcFmt 到 dstFmt(一般为AV_PIX_FMT_YUV420P)的转换   videoSwsCtx = sws_getContext(srcWidth, srcHeight, srcFmt, dstWidth, dstHeight, dstFmt, SWS_BILINEAR, NULL, NULL, NULL);   if (videoSwsCtx == NULL)   {   qDebug() << "sws_getContext error";   return false;   }       this->dstFmt = dstFmt;   this->dstWidth = dstWidth;   this->dstHeight = dstHeight;       needSws = true;   }       hasInit = true;   return true;   }       void VideoSwser::release()   {   if(videoSwsCtx)   {   sws_freeContext(videoSwsCtx);   videoSwsCtx = nullptr;   }       hasInit = false;   needSws = false;   }       AVFrame *VideoSwser::getSwsFrame(AVFrame *srcFrame)   {   if(!hasInit)   {   qDebug() << "Swser未初始化";   return nullptr;   }       if(!srcFrame)   return nullptr;       if(!needSws)   return srcFrame;       AVFrame *frame = av_frame_alloc();   frame->format = dstFmt;   frame->width = dstWidth;   frame->height = dstHeight;       int ret = av_frame_get_buffer(frame, 0);   if (ret != 0)   {   qDebug() << "av_frame_get_buffer swsFrame error";   return nullptr;   }       ret = av_frame_make_writable(frame);   if (ret != 0)   {   qDebug() << "av_frame_make_writable swsFrame error";   return nullptr;   }       sws_scale(videoSwsCtx, (const uint8_t *const *)srcFrame->data, srcFrame->linesize, 0, dstHeight, frame->data, frame->linesize);   return frame;   }           VideoEncoder::VideoEncoder()   {   videoEnCodecCtx = nullptr;   hasInit = false;   }       VideoEncoder::~VideoEncoder()   {   release();   }       bool VideoEncoder::initEncoder(int width, int height, AVPixelFormat fmt, int fps)   {   //重置编码信息   release();       //设置编码器参数 默认AV_CODEC_ID_H264   AVCodec *videoEnCoder = avcodec_find_encoder(AV_CODEC_ID_H264);   if(!videoEnCoder)   {   qDebug() << "avcodec_find_encoder AV_CODEC_ID_H264 error";   return false;   }       videoEnCodecCtx = avcodec_alloc_context3(videoEnCoder);   if(!videoEnCodecCtx)   {   qDebug() << "avcodec_alloc_context3 AV_CODEC_ID_H264 error";   return false;   }       //重要!编码参数设置 应根据实际场景修改以下参数   videoEnCodecCtx->bit_rate = 2*1024*1024; //1080P:4Mbps 720P:2Mbps 480P:1Mbps 默认中等码率可适当增大   videoEnCodecCtx->width = width;   videoEnCodecCtx->height = height;   videoEnCodecCtx->framerate = {fps, 1};   videoEnCodecCtx->time_base = {1, AV_TIME_BASE};   videoEnCodecCtx->gop_size = fps;   videoEnCodecCtx->max_b_frames = 0;   videoEnCodecCtx->pix_fmt = fmt;   videoEnCodecCtx->thread_count = 2;   videoEnCodecCtx->thread_type = FF_THREAD_FRAME;       //设置QP最大和最小量化系数,取值范围为0~51 越大编码质量越差   videoEnCodecCtx->qmin = 10;   videoEnCodecCtx->qmax = 30;       //若设置此项 则sps、pps将保存在extradata;否则放置于每个I帧前   videoEnCodecCtx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;       //预设参数 编码速度与压缩率的平衡 如编码快选择的算法就偏简单 压缩率低   //由慢到快veryslow slower slow medium fast faster veryfast superfast ultrafast 默认medium   int ret = av_opt_set(videoEnCodecCtx->priv_data, "preset", "ultrafast", 0);   if(ret != 0)   qDebug() << "av_opt_set preset error";       //偏好设置 进行视觉优化   //film电影 animation动画片 grain颗粒物 stillimage静止图片 psnr ssim图像评价指标 fastdecode快速解码 zerolatency零延迟   ret = av_opt_set(videoEnCodecCtx->priv_data, "tune", "zerolatency", 0);   if(ret != 0)   qDebug() << "av_opt_set preset error";       //画质设置 可能自动改变 如编码很快很难保证高画质会自动降级   //baseline实时通信 extended使用较少 main流媒体 high广电、存储   ret = av_opt_set(videoEnCodecCtx->priv_data, "profile", "main", 0);   if(ret != 0)   qDebug() << "av_opt_set preset error";       ret = avcodec_open2(videoEnCodecCtx, videoEnCoder, NULL);   if(ret != 0)   {   qDebug() << "avcodec_open2 video error";   return false;   }       hasInit = true;   return true;   }       void VideoEncoder::release()   {   if(videoEnCodecCtx)   {   avcodec_free_context(&videoEnCodecCtx);   videoEnCodecCtx = nullptr;   }       hasInit = false;   }       AVPacket *VideoEncoder::getEncodePacket(AVFrame *srcFrame)   {   if(!hasInit)   {   qDebug() << "VideoEncoder no init";   return nullptr;   }       if(!srcFrame)   return nullptr;       if(srcFrame->width != videoEnCodecCtx->width   || srcFrame->height != videoEnCodecCtx->height   || srcFrame->format != videoEnCodecCtx->pix_fmt)   {   qDebug() << "srcFrame不符合视频编码器设置格式";   return nullptr;   }       //应保证srcFrame pts为us单位   srcFrame->pts = av_rescale_q(srcFrame->pts, AVRational{1, AV_TIME_BASE}, videoEnCodecCtx->time_base);   int ret = avcodec_send_frame(videoEnCodecCtx, srcFrame);   if (ret != 0)   return nullptr;       //接收者负责释放packet   AVPacket *packet = av_packet_alloc();   ret = avcodec_receive_packet(videoEnCodecCtx, packet);   if (ret != 0)   {   av_packet_free(&packet);   return nullptr;   }       return packet;   }       AVPacket *VideoEncoder::flushEncoder()   {   if(!hasInit)   {   qDebug() << "VideoEncoder no init";   return nullptr;   }       int ret = avcodec_send_frame(videoEnCodecCtx, NULL);   if (ret != 0)   return nullptr;       //接收者负责释放packet   AVPacket *packet = av_packet_alloc();   ret = avcodec_receive_packet(videoEnCodecCtx, packet);   if (ret != 0)   {   av_packet_free(&packet);   return nullptr;   }       return packet;   }       AVCodecContext *VideoEncoder::getCodecContent()   {   return videoEnCodecCtx;   }           AudioSwrer::AudioSwrer()   {   audioSwrCtx = nullptr;   hasInit = false;   needSwr = false;   }       AudioSwrer::~AudioSwrer()   {   release();   }       bool AudioSwrer::initSwrCtx(int inChannels, int inSampleRate, AVSampleFormat inFmt, int outChannels, int outSampleRate, AVSampleFormat outFmt)   {   release();       if(inChannels == outChannels && inSampleRate == outSampleRate && inFmt == outFmt)   {   needSwr = false;   }   else   {   audioSwrCtx = swr_alloc_set_opts(NULL, av_get_default_channel_layout(outChannels), outFmt, outSampleRate,   av_get_default_channel_layout(inChannels), inFmt, inSampleRate, 0, NULL);   if (!audioSwrCtx)   {   qDebug() << "swr_alloc_set_opts failed!";   return false;   }       int ret = swr_init(audioSwrCtx);   if (ret != 0)   {   qDebug() << "swr_init error";   swr_free(&audioSwrCtx);   return false;   }       this->outFmt = outFmt;   this->outChannels = outChannels;   this->outSampleRate = outSampleRate;       needSwr = true;   }       hasInit = true;   return true;   }       void AudioSwrer::release()   {   if(audioSwrCtx)   {   swr_free(&audioSwrCtx);   audioSwrCtx = nullptr;   }       hasInit = false;   needSwr = false;   }       AVFrame *AudioSwrer::getSwrFrame(AVFrame *srcFrame)   {   if(!hasInit)   {   qDebug() << "Swrer未初始化";   return nullptr;   }       if(!srcFrame)   return nullptr;       if(!needSwr)   return srcFrame;       AVFrame *frame = av_frame_alloc();   frame->format = outFmt;   frame->channels = outChannels;   frame->channel_layout = av_get_default_channel_layout(outChannels);   frame->nb_samples = 1024; //默认aac       int ret = av_frame_get_buffer(frame, 0);   if (ret != 0)   {   qDebug() << "av_frame_get_buffer audio error";   return nullptr;   }       ret = av_frame_make_writable(frame);   if (ret != 0)   {   qDebug() << "av_frame_make_writable swrFrame error";   return nullptr;   }       const uint8_t **inData = (const uint8_t **)srcFrame->data;   swr_convert(audioSwrCtx, frame->data, frame->nb_samples, inData, frame->nb_samples);   return frame;   }       AVFrame *AudioSwrer::getSwrFrame(uint8_t *srcData)   {   if(!hasInit)   {   qDebug() << "Swrer未初始化";   return nullptr;   }       if(!srcData)   return nullptr;       if(!needSwr)   return nullptr;       AVFrame *frame = av_frame_alloc();   frame->format = outFmt;   frame->channels = outChannels;   frame->sample_rate = outSampleRate;   frame->channel_layout = av_get_default_channel_layout(outChannels);   frame->nb_samples = 1024; //默认aac       int ret = av_frame_get_buffer(frame, 0);   if (ret != 0)   {   qDebug() << "av_frame_get_buffer audio error";   return nullptr;   }       ret = av_frame_make_writable(frame);   if (ret != 0)   {   qDebug() << "av_frame_make_writable swrFrame error";   return nullptr;   }       const uint8_t *indata[AV_NUM_DATA_POINTERS] = {0};   indata[0] = srcData;   swr_convert(audioSwrCtx, frame->data, frame->nb_samples, indata, frame->nb_samples);   return frame;   }       AudioEncoder::AudioEncoder()   {   audioEnCodecCtx = nullptr;   hasInit = false;   }       AudioEncoder::~AudioEncoder()   {   release();   }       bool AudioEncoder::initEncoder(int channels, int sampleRate, AVSampleFormat sampleFmt)   {   release();       //初始化音频编码器相关 默认AAC   AVCodec *audioEnCoder = avcodec_find_encoder(AV_CODEC_ID_AAC);   if (!audioEnCoder)   {   qDebug() << "avcodec_find_encoder AV_CODEC_ID_AAC failed!";   return false;   }       audioEnCodecCtx = avcodec_alloc_context3(audioEnCoder);   if (!audioEnCodecCtx)   {   qDebug() << "avcodec_alloc_context3 AV_CODEC_ID_AAC failed!";   return false;   }       //ffmpeg -h encoder=aac 自带编码器仅支持AV_SAMPLE_FMT_FLTP 大多数AAC编码器都采用平面布局格式 提高数据访问效率和缓存命中率 加快编码效率   //音频数据量偏小 设置较为简单   audioEnCodecCtx->bit_rate = 64*1024;   audioEnCodecCtx->time_base = AVRational{1, sampleRate};   audioEnCodecCtx->sample_rate = sampleRate;   audioEnCodecCtx->sample_fmt = sampleFmt;   audioEnCodecCtx->channels = channels;   audioEnCodecCtx->channel_layout = av_get_default_channel_layout(channels);   audioEnCodecCtx->frame_size = 1024;       //打开音频编码器   int ret = avcodec_open2(audioEnCodecCtx, audioEnCoder, NULL);   if (ret != 0)   {   qDebug() << "avcodec_open2 audio error" << getAVError(ret);   return false;   }       hasInit = true;   return true;   }       void AudioEncoder::release()   {   if(audioEnCodecCtx)   {   avcodec_free_context(&audioEnCodecCtx);   audioEnCodecCtx = nullptr;   }       hasInit = false;   }       AVPacket *AudioEncoder::getEncodePacket(AVFrame *srcFrame)   {   if(!hasInit)   {   qDebug() << "AudioEncoder no init";   return nullptr;   }       if(!srcFrame)   return nullptr;       if(srcFrame->channels != audioEnCodecCtx->channels   || srcFrame->sample_rate != audioEnCodecCtx->sample_rate   || srcFrame->format != audioEnCodecCtx->sample_fmt)   {   qDebug() << "srcFrame不符合音频编码器设置格式";   return nullptr;   }       //应保证srcFrame pts为us单位   srcFrame->pts = av_rescale_q(srcFrame->pts, AVRational{1, AV_TIME_BASE}, audioEnCodecCtx->time_base);       //进行音频编码得到编码数据AVPacket   int ret = avcodec_send_frame(audioEnCodecCtx, srcFrame);   if (ret != 0)   return nullptr;       //接收者负责释放packet   AVPacket *packet = av_packet_alloc();   ret = avcodec_receive_packet(audioEnCodecCtx, packet);   if (ret != 0)   {   av_packet_free(&packet);   return nullptr;   }       return packet;   }       AVPacket *AudioEncoder::flushEncoder()   {   if(!hasInit)   {   qDebug() << "AudioEncoder no init";   return nullptr;   }       int ret = avcodec_send_frame(audioEnCodecCtx, NULL);   if (ret != 0)   return nullptr;       //接收者负责释放packet   AVPacket *packet = av_packet_alloc();   ret = avcodec_receive_packet(audioEnCodecCtx, packet);   if (ret != 0)   {   av_packet_free(&packet);   return nullptr;   }       return packet;   }       AVCodecContext *AudioEncoder::getCodecContent()   {   return audioEnCodecCtx;   }       AVTimeStamp::AVTimeStamp()   {   aMode = PTS_RECTIFY;   vMode = PTS_RECTIFY;   startTime = 0;   audioTimeStamp = 0;   videoTimeStamp = 0;       //默认视频264编码 25帧   videoDuration = 1000000 / 25;   //默认音频aac编码 44100采样率   audioDuration = 1000000 / (44100 / 1024);   }       AVTimeStamp::~AVTimeStamp()   {       }       void AVTimeStamp::initAudioTimeStampParm(int sampleRate, AVTimeStamp::PTSMode mode)   {   aMode = mode;   audioDuration = 1000000 / (sampleRate / 1024);   }       void AVTimeStamp::initVideoTimeStampParm(int fps, AVTimeStamp::PTSMode mode)   {   vMode = mode;   videoDuration = 1000000 / fps;   }       void AVTimeStamp::startTimeStamp()   {   audioTimeStamp = 0;   videoTimeStamp = 0;   startTime = av_gettime();   }       int64_t AVTimeStamp::getAudioPts()   {   if(aMode == PTS_RECTIFY)   {   int64_t elapsed = av_gettime() - startTime;   uint32_t offset = qAbs(elapsed - (audioTimeStamp + audioDuration));   if(offset < (audioDuration * 0.5))   audioTimeStamp += audioDuration;   else   audioTimeStamp = elapsed;   }   else   {   audioTimeStamp = av_gettime() - startTime;   }       return audioTimeStamp;   }       int64_t AVTimeStamp::getVideoPts()   {   if(vMode == PTS_RECTIFY)   {   int64_t elapsed = av_gettime() - startTime;   uint32_t offset = qAbs(elapsed - (videoTimeStamp + videoDuration));   if(offset < (videoDuration * 0.5))   videoTimeStamp += videoDuration;   else   videoTimeStamp = elapsed;   }   else   {   videoTimeStamp = av_gettime() - startTime;   }       return videoTimeStamp;   }
 
 

 

 

标签:封装,FFmpeg,记录,int,frame,ret,int64,videoEnCodecCtx,include
From: https://www.cnblogs.com/lidabo/p/17631228.html

相关文章

  • Git使用问题记录
    问题一fatal:unabletoaccess‘https://…git/’:SSLcertificateproblem:selfsignedcertificateincertificatechain打开GitBash运行如下命令exportGIT_SSL_NO_VERIFY=truegitconfig--globalhttp.sslVerify"false"或者在windows的命令行中,进入到git命令所......
  • 使用FFmpeg进行yuv420转rgba
    讲解一下将获取到视频数据,进行rgb转码,并且进行相应的缩放操作//存放解码过后的数据unsignedchar*decode_data;intdecode_size=0;/***解码AVFrame中的yuv420数据并且转换为rgba数据**@paramframe需要解码的帧结构*@paramsrc_width需要转换的帧宽度*......
  • 记录一次错误(打印一个菱形)
    记录一次错误(打印一个菱形)正确代码publicclassExercise{ publicstaticvoidmain(String[]args){ /*输出一个菱形*/ /* *12 ** 31 ** 50 ** 3 * 1 */ //代表层数 for(inti=1;i<=3;i++){......
  • SOIC封装的两种形式
    SOIC封装,实际上分两种,一个是比较宽一点的,一个是比较窄一点的。 下面是AT24C02手册中的, SOIC-8封装, E1 =3.81mm=150mil另外GD25q16C芯片,有两种封装如下图摘自于芯片手册,可以知道SOP8封装,有体宽是150mil的,还有一种体宽是208mil的。注意这里的体宽是指芯片的宽度(不......
  • MySQL 使用表的自联结,lag,lead得到该行记录所在连续段长度
    目录题目地址代码题目地址https://leetcode.cn/problems/human-traffic-of-stadium/description/代码##WriteyourMySQLquerystatementbelow##本质上就是连续签到问题呗#SELECTVersion()#8.0.33,用户变量编程用不了witht1as(SELECT*fromstadium......
  • FFmpeg3.2 msvc+msys 源码编译
    材料FFmpeg3.2源码x264x265fdk-aac注意:由于FFmpeg源码的版本太久,采用的第三方库是最新的,因此需要做调整基本操作编译64位FFmpeg程序Windows开始菜单->VisualStudio2022->x64NativeToolsCommandPromptforVS2019编译32位FFmpeg程序Windows开始菜单->VisualStudio2......
  • 关于Python的学习记录(二十二_读写 CSV 文件)
    CSV文件介绍CSV(CommaSeparatedValues)全称逗号分隔值文件是一种简单、通用的文件格式,被广泛的应用于应用程序(数据库、电子表格等)数据的导入和导出以及异构系统之间的数据交换。因为CSV是纯文本文件,不管是什么操作系统和编程语言都是可以处理纯文本的,而且很多编程语言中都提供了......
  • 记录--form 表单恢复初始数据
    这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助form表单恢复初始数据在现代的Web开发中,表单是不可或缺的组件之一。用户可以通过表单输入和提交数据,而开发者则需要对这些数据进行处理和存储。然而,在某些情况下,我们可能需要重置表单并恢复到最初的状态。本......
  • pte 记录 daily
         20230814   1RAreading阅读speaking口语在app上练习RA:流利度75分以上,发音70分以上(要稳定)全部机经刷2遍5-10    2RSlistening听力speaking口语 短句全复述,长句至少能流利复述前半句或后半句,内容输出50%以上机经过完2遍......
  • uni-app中html5+开发记录
    代码示例:1、创建dom并绑定click事件 btnBack=newplus.nativeObj.View('btnBack',{top:systemInfo.statusBarHeight+'px',//此处top和left是相对于手机屏幕左上角为基准,不支持rightleft:'10px',height:&......