FFmpeg-基础组件-AVFrame

本章主要介绍FFmpeg基础组件AVFrame.

文章目录

    • 1.结构体成员
    • 2.成员函数
    • AVFrame Host内存的获取 av_frame_get_buffer
    • AVFrame device内存获取av_hwframe_get_buffer()

1.结构体成员

我们把所有的代码先粘贴上来,在后边一个一个解释。


typedef struct AVFrame {
#define AV_NUM_DATA_POINTERS 8/*** pointer to the picture/channel planes.* This might be different from the first allocated byte. For video,* it could even point to the end of the image data.** All pointers in data and extended_data must point into one of the* AVBufferRef in buf or extended_buf.** Some decoders access areas outside 0,0 - width,height, please* see avcodec_align_dimensions2(). Some filters and swscale can read* up to 16 bytes beyond the planes, if these filters are to be used,* then 16 extra bytes must be allocated.** NOTE: Pointers not needed by the format MUST be set to NULL.** @attention In case of video, the data[] pointers can point to the* end of image data in order to reverse line order, when used in* combination with negative values in the linesize[] array.*/uint8_t *data[AV_NUM_DATA_POINTERS];/*** For video, a positive or negative value, which is typically indicating* the size in bytes of each picture line, but it can also be:* - the negative byte size of lines for vertical flipping*   (with data[n] pointing to the end of the data* - a positive or negative multiple of the byte size as for accessing*   even and odd fields of a frame (possibly flipped)** For audio, only linesize[0] may be set. For planar audio, each channel* plane must be the same size.** For video the linesizes should be multiples of the CPUs alignment* preference, this is 16 or 32 for modern desktop CPUs.* Some code requires such alignment other code can be slower without* correct alignment, for yet other it makes no difference.** @note The linesize may be larger than the size of usable data -- there* may be extra padding present for performance reasons.** @attention In case of video, line size values can be negative to achieve* a vertically inverted iteration over image lines.*/int linesize[AV_NUM_DATA_POINTERS];/*** pointers to the data planes/channels.** For video, this should simply point to data[].** For planar audio, each channel has a separate data pointer, and* linesize[0] contains the size of each channel buffer.* For packed audio, there is just one data pointer, and linesize[0]* contains the total size of the buffer for all channels.** Note: Both data and extended_data should always be set in a valid frame,* but for planar audio with more channels that can fit in data,* extended_data must be used in order to access all channels.*/uint8_t **extended_data;/*** @name Video dimensions* Video frames only. The coded dimensions (in pixels) of the video frame,* i.e. the size of the rectangle that contains some well-defined values.** @note The part of the frame intended for display/presentation is further* restricted by the @ref cropping "Cropping rectangle".* @{*/int width, height;/*** @}*//*** number of audio samples (per channel) described by this frame*/int nb_samples;/*** format of the frame, -1 if unknown or unset* Values correspond to enum AVPixelFormat for video frames,* enum AVSampleFormat for audio)*/int format;/*** 1 -> keyframe, 0-> not*/int key_frame;/*** Picture type of the frame.*/enum AVPictureType pict_type;/*** Sample aspect ratio for the video frame, 0/1 if unknown/unspecified.*/AVRational sample_aspect_ratio;/*** Presentation timestamp in time_base units (time when frame should be shown to user).*/int64_t pts;/*** DTS copied from the AVPacket that triggered returning this frame. (if frame threading isn't used)* This is also the Presentation time of this AVFrame calculated from* only AVPacket.dts values without pts values.*/int64_t pkt_dts;/*** Time base for the timestamps in this frame.* In the future, this field may be set on frames output by decoders or* filters, but its value will be by default ignored on input to encoders* or filters.*/AVRational time_base;/*** picture number in bitstream order*/int coded_picture_number;/*** picture number in display order*/int display_picture_number;/*** quality (between 1 (good) and FF_LAMBDA_MAX (bad))*/int quality;/*** for some private data of the user*/void *opaque;/*** When decoding, this signals how much the picture must be delayed.* extra_delay = repeat_pict / (2*fps)*/int repeat_pict;/*** The content of the picture is interlaced.*/int interlaced_frame;/*** If the content is interlaced, is top field displayed first.*/int top_field_first;/*** Tell user application that palette has changed from previous frame.*/int palette_has_changed;/*** reordered opaque 64 bits (generally an integer or a double precision float* PTS but can be anything).* The user sets AVCodecContext.reordered_opaque to represent the input at* that time,* the decoder reorders values as needed and sets AVFrame.reordered_opaque* to exactly one of the values provided by the user through AVCodecContext.reordered_opaque*/int64_t reordered_opaque;/*** Sample rate of the audio data.*/int sample_rate;/*** Channel layout of the audio data.*/uint64_t channel_layout;/*** AVBuffer references backing the data for this frame. All the pointers in* data and extended_data must point inside one of the buffers in buf or* extended_buf. This array must be filled contiguously -- if buf[i] is* non-NULL then buf[j] must also be non-NULL for all j < i.** There may be at most one AVBuffer per data plane, so for video this array* always contains all the references. For planar audio with more than* AV_NUM_DATA_POINTERS channels, there may be more buffers than can fit in* this array. Then the extra AVBufferRef pointers are stored in the* extended_buf array.*/AVBufferRef *buf[AV_NUM_DATA_POINTERS];/*** For planar audio which requires more than AV_NUM_DATA_POINTERS* AVBufferRef pointers, this array will hold all the references which* cannot fit into AVFrame.buf.** Note that this is different from AVFrame.extended_data, which always* contains all the pointers. This array only contains the extra pointers,* which cannot fit into AVFrame.buf.** This array is always allocated using av_malloc() by whoever constructs* the frame. It is freed in av_frame_unref().*/AVBufferRef **extended_buf;/*** Number of elements in extended_buf.*/int        nb_extended_buf;AVFrameSideData **side_data;int            nb_side_data;/*** @defgroup lavu_frame_flags AV_FRAME_FLAGS* @ingroup lavu_frame* Flags describing additional frame properties.** @{*//*** The frame data may be corrupted, e.g. due to decoding errors.*/
#define AV_FRAME_FLAG_CORRUPT       (1 << 0)
/*** A flag to mark the frames which need to be decoded, but shouldn't be output.*/
#define AV_FRAME_FLAG_DISCARD   (1 << 2)
/*** @}*//*** Frame flags, a combination of @ref lavu_frame_flags*/int flags;/*** MPEG vs JPEG YUV range.* - encoding: Set by user* - decoding: Set by libavcodec*/enum AVColorRange color_range;enum AVColorPrimaries color_primaries;enum AVColorTransferCharacteristic color_trc;/*** YUV colorspace type.* - encoding: Set by user* - decoding: Set by libavcodec*/enum AVColorSpace colorspace;enum AVChromaLocation chroma_location;/*** frame timestamp estimated using various heuristics, in stream time base* - encoding: unused* - decoding: set by libavcodec, read by user.*/int64_t best_effort_timestamp;/*** reordered pos from the last AVPacket that has been input into the decoder* - encoding: unused* - decoding: Read by user.*/int64_t pkt_pos;/*** duration of the corresponding packet, expressed in* AVStream->time_base units, 0 if unknown.* - encoding: unused* - decoding: Read by user.*/int64_t pkt_duration;/*** metadata.* - encoding: Set by user.* - decoding: Set by libavcodec.*/AVDictionary *metadata;/*** decode error flags of the frame, set to a combination of* FF_DECODE_ERROR_xxx flags if the decoder produced a frame, but there* were errors during the decoding.* - encoding: unused* - decoding: set by libavcodec, read by user.*/int decode_error_flags;
#define FF_DECODE_ERROR_INVALID_BITSTREAM   1
#define FF_DECODE_ERROR_MISSING_REFERENCE   2
#define FF_DECODE_ERROR_CONCEALMENT_ACTIVE  4
#define FF_DECODE_ERROR_DECODE_SLICES       8/*** number of audio channels, only used for audio.* - encoding: unused* - decoding: Read by user.*/int channels;/*** size of the corresponding packet containing the compressed* frame.* It is set to a negative value if unknown.* - encoding: unused* - decoding: set by libavcodec, read by user.*/int pkt_size;/*** For hwaccel-format frames, this should be a reference to the* AVHWFramesContext describing the frame.*/AVBufferRef *hw_frames_ctx;/*** AVBufferRef for free use by the API user. FFmpeg will never check the* contents of the buffer ref. FFmpeg calls av_buffer_unref() on it when* the frame is unreferenced. av_frame_copy_props() calls create a new* reference with av_buffer_ref() for the target frame's opaque_ref field.** This is unrelated to the opaque field, although it serves a similar* purpose.*/AVBufferRef *opaque_ref;/*** @anchor cropping* @name Cropping* Video frames only. The number of pixels to discard from the the* top/bottom/left/right border of the frame to obtain the sub-rectangle of* the frame intended for presentation.* @{*/size_t crop_top;size_t crop_bottom;size_t crop_left;size_t crop_right;/*** @}*//*** AVBufferRef for internal use by a single libav* library.* Must not be used to transfer data between libraries.* Has to be NULL when ownership of the frame leaves the respective library.** Code outside the FFmpeg libs should never check or change the contents of the buffer ref.** FFmpeg calls av_buffer_unref() on it when the frame is unreferenced.* av_frame_copy_props() calls create a new reference with av_buffer_ref()* for the target frame's private_ref field.*/AVBufferRef *private_ref;
} AVFrame;

AVFrame中核心成员,我们常用的就是下面几个

typedef struct AVFrame {
...uint8_t *data[AV_NUM_DATA_POINTERS]int linesize[AV_NUM_DATA_POINTERS];uint8_t **extended_data;uint8_t **extended_data;int width, height;int format;int key_frame;int64_t pts;int64_t pkt_dts;AVRational time_base;AVBufferRef *buf[AV_NUM_DATA_POINTERS];
...
}

这个结构体主要保存解码后的YUV数据,特别注意的是AVBufferRef *buf[AV_NUM_DATA_POINTERS];这个成员,因为它用来进行分配内存的释放。
其实在很多地方用到了AVBufferRef ,原理就是其中内部使用了一个引用,当引用为1的时候,就把内部指向的memory释放掉。

/*** A reference counted buffer type. It is opaque and is meant to be used through* references (AVBufferRef).*/
typedef struct AVBuffer AVBuffer;/*** A reference to a data buffer.** The size of this struct is not a part of the public ABI and it is not meant* to be allocated directly.*/
typedef struct AVBufferRef {AVBuffer *buffer;/*** The data buffer. It is considered writable if and only if* this is the only reference to the buffer, in which case* av_buffer_is_writable() returns 1.*/uint8_t *data;/*** Size of data in bytes.*/size_t   size;
} AVBufferRef;

其中data就是yuv数据,size就是数据大小,我们看到里面的AVBuffer ,其详细结构如下,其中refcount就是引用数量,free就是释放函数

struct AVBuffer {uint8_t *data; /**< data described by this buffer */size_t size; /**< size of data in bytes *//***  number of existing AVBufferRef instances referring to this buffer*/atomic_uint refcount;/*** a callback for freeing the data*/void (*free)(void *opaque, uint8_t *data);/*** an opaque pointer, to be used by the freeing callback*/void *opaque;/*** A combination of AV_BUFFER_FLAG_**/int flags;/*** A combination of BUFFER_FLAG_**/int flags_internal;
};

关于这一块智能引用,其提供了一些函数族

/*** Allocate an AVBuffer of the given size using av_malloc().** @return an AVBufferRef of given size or NULL when out of memory*/
AVBufferRef *av_buffer_alloc(size_t size);/*** Same as av_buffer_alloc(), except the returned buffer will be initialized* to zero.*/
AVBufferRef *av_buffer_allocz(size_t size);
/*** Create an AVBuffer from an existing array.** If this function is successful, data is owned by the AVBuffer. The caller may* only access data through the returned AVBufferRef and references derived from* it.* If this function fails, data is left untouched.* @param data   data array* @param size   size of data in bytes* @param free   a callback for freeing this buffer's data* @param opaque parameter to be got for processing or passed to free* @param flags  a combination of AV_BUFFER_FLAG_*** @return an AVBufferRef referring to data on success, NULL on failure.*/
AVBufferRef *av_buffer_create(uint8_t *data, size_t size,void (*free)(void *opaque, uint8_t *data),void *opaque, int flags);
/*** Default free callback, which calls av_free() on the buffer data.* This function is meant to be passed to av_buffer_create(), not called* directly.*/
void av_buffer_default_free(void *opaque, uint8_t *data);
/*** Create a new reference to an AVBuffer.** @return a new AVBufferRef referring to the same AVBuffer as buf or NULL on* failure.*/
AVBufferRef *av_buffer_ref(const AVBufferRef *buf);/*** Free a given reference and automatically free the buffer if there are no more* references to it.** @param buf the reference to be freed. The pointer is set to NULL on return.*/
void av_buffer_unref(AVBufferRef **buf);/*** @return 1 if the caller may write to the data referred to by buf (which is* true if and only if buf is the only reference to the underlying AVBuffer).* Return 0 otherwise.* A positive answer is valid until av_buffer_ref() is called on buf.*/
int av_buffer_is_writable(const AVBufferRef *buf);/*** @return the opaque parameter set by av_buffer_create.*/
void *av_buffer_get_opaque(const AVBufferRef *buf);int av_buffer_get_ref_count(const AVBufferRef *buf);

这些函数族用户是用不到的,一般在ffmpeg内部模块中使用到。比如AVFrame函数族中。

其余根据字面意思很好理解。其中linesize表示每个plane的步长。
比如YUV420的数,其数据长度大小为:

  if (frame->pixel_format == TOPSCODEC_PIX_FMT_I420 ||frame->pixel_format == TOPSCODEC_PIX_FMT_NV12 ||frame->pixel_format == TOPSCODEC_PIX_FMT_NV21 ||frame->pixel_format == TOPSCODEC_PIX_FMT_P010 ||frame->pixel_format == TOPSCODEC_PIX_FMT_P010LE) {int Y = frame->linesize[0] * frame->height;int U = frame->linesize[1] * ((frame->height + 1) / 2);int V = frame->linesize[2] * ((frame->height + 1) / 2);}

也就是说yuv数据的宽度是多大。
其实这个并不用手工来计算,ffmpeg框架提供了专用的函数来处理:

int av_image_fill_plane_sizes(size_t sizes[4], enum AVPixelFormat pix_fmt,int height, const ptrdiff_t linesizes[4])

这个函数用来计算每个plane的长度是多少,通过传入参数我们很容易看到height.原理和我们上面一样。

下面这个函数比较特殊,可以计算linesizes,也就是每个通道的stride.

int av_image_fill_linesizes(int linesizes[4], enum AVPixelFormat pix_fmt, int width)

这个函数专门通过width和pix_fmt来计算linesizes[4],这样就不用我们通过手动来去计算了。

还有另外一个函数用来计算每个planes数据长度

该类函数族ffmpeg提供了很多,具体在imgutils.h中

/*** Compute the size of an image line with format pix_fmt and width* width for the plane plane.** @return the computed size in bytes*/
int av_image_get_linesize(enum AVPixelFormat pix_fmt, int width, int plane);
/*** Fill plane linesizes for an image with pixel format pix_fmt and* width width.** @param linesizes array to be filled with the linesize for each plane* @return >= 0 in case of success, a negative error code otherwise*/
int av_image_fill_linesizes(int linesizes[4], enum AVPixelFormat pix_fmt, int width);
/*** Fill plane sizes for an image with pixel format pix_fmt and height height.** @param size the array to be filled with the size of each image plane* @param linesizes the array containing the linesize for each*        plane, should be filled by av_image_fill_linesizes()* @return >= 0 in case of success, a negative error code otherwise** @note The linesize parameters have the type ptrdiff_t here, while they are*       int for av_image_fill_linesizes().*/
int av_image_fill_plane_sizes(size_t size[4], enum AVPixelFormat pix_fmt,int height, const ptrdiff_t linesizes[4]);
/*** Fill plane data pointers for an image with pixel format pix_fmt and* height height.** @param data pointers array to be filled with the pointer for each image plane* @param ptr the pointer to a buffer which will contain the image* @param linesizes the array containing the linesize for each* plane, should be filled by av_image_fill_linesizes()* @return the size in bytes required for the image buffer, a negative* error code in case of failure*/
int av_image_fill_pointers(uint8_t *data[4], enum AVPixelFormat pix_fmt, int height,uint8_t *ptr, const int linesizes[4]);
/*** Allocate an image with size w and h and pixel format pix_fmt, and* fill pointers and linesizes accordingly.* The allocated image buffer has to be freed by using* av_freep(&pointers[0]).** @param align the value to use for buffer size alignment* @return the size in bytes required for the image buffer, a negative* error code in case of failure*/
int av_image_alloc(uint8_t *pointers[4], int linesizes[4],int w, int h, enum AVPixelFormat pix_fmt, int align);
/*** Copy image plane from src to dst.* That is, copy "height" number of lines of "bytewidth" bytes each.* The first byte of each successive line is separated by *_linesize* bytes.** bytewidth must be contained by both absolute values of dst_linesize* and src_linesize, otherwise the function behavior is undefined.** @param dst_linesize linesize for the image plane in dst* @param src_linesize linesize for the image plane in src*/
void av_image_copy_plane(uint8_t       *dst, int dst_linesize,const uint8_t *src, int src_linesize,int bytewidth, int height);
/*** Copy image in src_data to dst_data.** @param dst_linesizes linesizes for the image in dst_data* @param src_linesizes linesizes for the image in src_data*/
void av_image_copy(uint8_t *dst_data[4], int dst_linesizes[4],const uint8_t *src_data[4], const int src_linesizes[4],enum AVPixelFormat pix_fmt, int width, int height);
/*** Setup the data pointers and linesizes based on the specified image* parameters and the provided array.** The fields of the given image are filled in by using the src* address which points to the image data buffer. Depending on the* specified pixel format, one or multiple image data pointers and* line sizes will be set.  If a planar format is specified, several* pointers will be set pointing to the different picture planes and* the line sizes of the different planes will be stored in the* lines_sizes array. Call with src == NULL to get the required* size for the src buffer.** To allocate the buffer and fill in the dst_data and dst_linesize in* one call, use av_image_alloc().** @param dst_data      data pointers to be filled in* @param dst_linesize  linesizes for the image in dst_data to be filled in* @param src           buffer which will contain or contains the actual image data, can be NULL* @param pix_fmt       the pixel format of the image* @param width         the width of the image in pixels* @param height        the height of the image in pixels* @param align         the value used in src for linesize alignment* @return the size in bytes required for src, a negative error code* in case of failure*/
int av_image_fill_arrays(uint8_t *dst_data[4], int dst_linesize[4],const uint8_t *src,enum AVPixelFormat pix_fmt, int width, int height, int align);
/*** Return the size in bytes of the amount of data required to store an* image with the given parameters.** @param pix_fmt  the pixel format of the image* @param width    the width of the image in pixels* @param height   the height of the image in pixels* @param align    the assumed linesize alignment* @return the buffer size in bytes, a negative error code in case of failure*/
int av_image_get_buffer_size(enum AVPixelFormat pix_fmt, int width, int height, int align);
/*** Copy image data from an image into a buffer.** av_image_get_buffer_size() can be used to compute the required size* for the buffer to fill.** @param dst           a buffer into which picture data will be copied* @param dst_size      the size in bytes of dst* @param src_data      pointers containing the source image data* @param src_linesize  linesizes for the image in src_data* @param pix_fmt       the pixel format of the source image* @param width         the width of the source image in pixels* @param height        the height of the source image in pixels* @param align         the assumed linesize alignment for dst* @return the number of bytes written to dst, or a negative value* (error code) on error*/
int av_image_copy_to_buffer(uint8_t *dst, int dst_size,const uint8_t * const src_data[4], const int src_linesize[4],enum AVPixelFormat pix_fmt, int width, int height, int align);
/*** Check if the given dimension of an image is valid, meaning that all* bytes of the image can be addressed with a signed int.** @param w the width of the picture* @param h the height of the picture* @param log_offset the offset to sum to the log level for logging with log_ctx* @param log_ctx the parent logging context, it may be NULL* @return >= 0 if valid, a negative error code otherwise*/
int av_image_check_size(unsigned int w, unsigned int h, int log_offset, void *log_ctx);
/*** Check if the given dimension of an image is valid, meaning that all* bytes of a plane of an image with the specified pix_fmt can be addressed* with a signed int.** @param w the width of the picture* @param h the height of the picture* @param max_pixels the maximum number of pixels the user wants to accept* @param pix_fmt the pixel format, can be AV_PIX_FMT_NONE if unknown.* @param log_offset the offset to sum to the log level for logging with log_ctx* @param log_ctx the parent logging context, it may be NULL* @return >= 0 if valid, a negative error code otherwise*/
int av_image_check_size2(unsigned int w, unsigned int h, int64_t max_pixels, enum AVPixelFormat pix_fmt, int log_offset, void *log_ctx);

2.成员函数

const char *av_get_colorspace_name(enum AVColorSpace val);
AVFrame *av_frame_alloc(void);
void av_frame_free(AVFrame **frame);
int av_frame_ref(AVFrame *dst, const AVFrame *src);
AVFrame *av_frame_clone(const AVFrame *src);
void av_frame_move_ref(AVFrame *dst, AVFrame *src);
int av_frame_get_buffer(AVFrame *frame, int align);
int av_frame_is_writable(AVFrame *frame);
int av_frame_make_writable(AVFrame *frame);
int av_frame_copy(AVFrame *dst, const AVFrame *src);
int av_frame_copy_props(AVFrame *dst, const AVFrame *src);
AVFrameSideData *av_frame_new_side_data(AVFrame *frame,enum AVFrameSideDataType type,size_t size);
AVFrameSideData *av_frame_new_side_data_from_buf(AVFrame *frame,enum AVFrameSideDataType type,AVBufferRef *buf);
void av_frame_remove_side_data(AVFrame *frame, enum AVFrameSideDataType type);
const char *av_frame_side_data_name(enum AVFrameSideDataType type);

上面函数核心就是操作AVFrame。

AVFrame Host内存的获取 av_frame_get_buffer

ffmpeg提供了一个比较特殊的接口

/*** Allocate new buffer(s) for audio or video data.** The following fields must be set on frame before calling this function:* - format (pixel format for video, sample format for audio)* - width and height for video* - nb_samples and channel_layout for audio** This function will fill AVFrame.data and AVFrame.buf arrays and, if* necessary, allocate and fill AVFrame.extended_data and AVFrame.extended_buf.* For planar formats, one buffer will be allocated for each plane.** @warning: if frame already has been allocated, calling this function will*           leak memory. In addition, undefined behavior can occur in certain*           cases.** @param frame frame in which to store the new buffers.* @param align Required buffer size alignment. If equal to 0, alignment will be*              chosen automatically for the current CPU. It is highly*              recommended to pass 0 here unless you know what you are doing.** @return 0 on success, a negative AVERROR on error.*/
int av_frame_get_buffer(AVFrame *frame, int align)

这个函数是用来从ffmpeg内存池中为frame中获取buf,从上面的注释可以看到,如果想要获取buf,必须要设置

 /** The following fields must be set on frame before calling this function:* - format (pixel format for video, sample format for audio)* - width and height for video* - nb_samples and channel_layout for audio* /

查看详细的函数代码:

int av_frame_get_buffer(AVFrame *frame, int align)
{if (frame->format < 0)return AVERROR(EINVAL);if (frame->width > 0 && frame->height > 0)return get_video_buffer(frame, align);else if (frame->nb_samples > 0 && (frame->channel_layout || frame->channels > 0))return get_audio_buffer(frame, align);return AVERROR(EINVAL);
}

详细的调用流程如下:
在这里插入图片描述

AVFrame device内存获取av_hwframe_get_buffer()

既然有host的内存获取,那么就有device内存的获取

/*** Allocate a new frame attached to the given AVHWFramesContext.** @param hwframe_ctx a reference to an AVHWFramesContext* @param frame an empty (freshly allocated or unreffed) frame to be filled with*              newly allocated buffers.* @param flags currently unused, should be set to zero* @return 0 on success, a negative AVERROR code on failure*/
int av_hwframe_get_buffer(AVBufferRef *hwframe_ctx, AVFrame *frame, int flags);

其调用流程如下,注意分支代码,这里是继承了父类后,通过mmap去map到父类的内存上去。
在这里插入图片描述

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

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

相关文章

[MySQL]SQL优化之sql语句优化

&#x1f308;键盘敲烂&#xff0c;年薪30万&#x1f308; 目录 一、索引优化 回顾&#xff1a; &#x1f4d5;索引分类&#xff1a; &#x1f4d5;索引失效&#xff1a; &#x1f4d5;设计原则&#xff1a; &#x1f4d5;SQL性能分析 二、SQL优化 语句优化 &#x1f4d…

越南语翻译,人工翻译哪个值得信赖?

近年来&#xff0c;随着中越两国的交流日益频繁&#xff0c;为了促进双方的交流与理解&#xff0c;市场上对越南语翻译的需求也日益增加。那么&#xff0c;如何做好越南语翻译&#xff0c;人工翻译哪家公司值得信赖呢&#xff1f; 据了解&#xff0c;中文翻译越南语是一项颇具挑…

科技与艺术相结合,虚拟人裸眼3D动画亮相城市商圈

随着元宇宙概念的火爆&#xff0c;虚拟制作技术的快速发展&#xff0c;虚拟人可以将虚拟世界与现实世界相结合&#xff0c;为用户带来沉浸式体验。如虚拟人壬子希以裸眼3D动画的形式亮相城市商圈&#xff0c;助力文旅以科技与艺术相结合的形式&#xff0c;展现城市文化与科技成…

【数据结构(九)】顺序存储二叉树(2)

文章目录 1. 相关概念2. 顺序存储二叉树的遍历 1. 相关概念 从数据存储来看&#xff0c;数组存储方式和树的存储方式可以相互转换&#xff0c;即数组可以转换成树&#xff0c;树也可以转换成数组&#xff0c;看右面的示意图。 转换原则:     1.上图的二叉树的结点&#xff…

每日一练【长度最小的子数组】

一、题目描述 给定一个含有 n 个正整数的数组和一个正整数 target 。 找出该数组中满足其总和大于等于 target 的长度最小的 连续子数组 [numsl, numsl1, ..., numsr-1, numsr] &#xff0c;并返回其长度。如果不存在符合条件的子数组&#xff0c;返回 0 。 二、题目解析 经…

DeepDrive双转子径向磁通电机

DeepDrive公司开发的是一种高效、高性能、低成本的双转子径向磁通电机系统&#xff08;含控制器&#xff09;。该系统具有较高的成本效益和资源效率&#xff0c;并拥有更高的能效&#xff0c;能显著提升电动车续航能力&#xff0c;同时亦能有效控制生产成本&#xff0c;减少自然…

3_流量预测综述阅读_Cellular traffic prediction with machine learning: A survey

为了方便学习英语书写&#xff0c;总结的一些话用英语书写 ♥目录♥ 0、文献来源and摘要1、introduction2、prediction problems and datasets2.1 prediction problems2.2 dataset&#xff08;1&#xff09;Telecom Italia 意大利电信 2015&#xff08;2&#xff09;City Cell…

AI写文案工具大全介绍,免费的AI写文案工具

随着人工智能技术的不断发展&#xff0c;AI写文案成为一个备受关注的话题。本文将专注于AI写文案工具&#xff0c;深入探讨各类好用的AI写文案软件。 AI写文案工具介绍&#xff1a; OpenAIs GPT系列&#xff1a; GPT-3是由OpenAI开发的语言模型&#xff0c;能够生成高质量的文…

uniapp点击按钮,防止按钮多次点击多次触发事件【防抖操作】

图片、 一、在根目录下新建common文件并创建common.js文件&#xff0c;输入下面代码 // 防止处理多次点击function noMultipleClicks(methods, info) {// methods是需要点击后需要执行的函数&#xff0c; info是点击需要传的参数let that this;if (that.noClick) {// 第一次点…

C语言leetcode集训二:字符串(1):字符串遍历

今天集训的内容是字符串中的字符串遍历题&#xff0c;仍然是简单题&#xff0c;但也可以掌握一些字符串所必要的知识&#xff0c;加深对字符串的理解&#xff0c;关于字符数组和字符串&#xff0c;字符串的输入输出在这就不再做过多赘述&#xff0c;关于字符串的问题&#xff0…

串口通信(1)-硬件知识

本文讲解串口通信的硬件知识。让读者快速了解硬件知识&#xff0c;为下一步编写代码做基础。 目录 一、概述 二、串口通信分类 2.1信息的传送方向进行分类 2.2同步通信和异步通信 三、串口协议 3.1 RS232 3.1.1 电气特性 3.1.2 连接器的机械特性 3.1.3 连接类型 3.1…

【SpringBoot】入门精简

目录 一、初识 SpringBoot 1.1 介绍 1.2 项目创建 1.3 目录结构 1.4 修改配置 二、SpringBoot 集成 2.1 集成 Mybatis框架 2.2 集成 Pagehepler分页插件 2.3 集成 Druid数据库连接池 2.4 集成 Log日志管理 一、初识 SpringBoot 1.1 介绍 Spring Boot是一个用于简化Sp…

猎豹浏览器如何设置ip使用?socks5在网络安全中有什么优势?

猎豹浏览器如何设置ip使用&#xff1f;socks在网络安全中有什么优势&#xff1f; 一、猎豹浏览器如何设置ip使用&#xff1f; 在使用猎豹浏览器时&#xff0c;可以通过以下步骤来设置IP使用&#xff1a; 1. 打开猎豹浏览器&#xff0c;点击右上角的“菜单”按钮&#xff0c;在…

有趣的数学 数学建模入门三 数学建模入门示例两例 利用微积分求解

一、入门示例1 1、问题描述 某宾馆有150间客房&#xff0c;经过一段时间的经营&#xff0c;该宾馆经理得到一些数据&#xff1a;如果每间客房定价为200元&#xff0c;入住率为55&#xff05;&#xff1b;定价为180元&#xff0c;入住率为65&#xff05;&#xff1b;定价为160元…

圆通单号查询,圆通速递物流查询,用表格导出单号的详细物流信息

批量查询圆通速递单号的物流信息&#xff0c;以表格的形式导出单号的详细物流信息。 所需工具&#xff1a; 一个【快递批量查询高手】软件 圆通速递单号若干 操作步骤&#xff1a; 步骤1&#xff1a;运行【快递批量查询高手】软件&#xff0c;并登录 步骤2&#xff1a;点击主…

解决canvas清晰度问题devicePixelRatio

视频教程 解决canvas清晰度的问题【渡一教育】_哔哩哔哩_bilibili 检测网页本身是否缩放 ,即缩放倍率 window.devicePixelRatio 为了获得清晰图像,需要遵循以下公式 原始尺寸样式尺寸*缩放倍率 在项目中,canvas里的原始尺寸一般与css中的样式尺寸一样,所以在写js代码时,涉…

数据库 02-03补充 聚合函数--一般聚合分组和having

聚合函数&#xff1a; 01.一般的聚合函数&#xff1a; 举个例子&#xff1a; 一般聚合函数是用于单个元祖&#xff0c;就是返回一个数值。 02.分组聚合&#xff1a;可以返回多个元祖 举个例子&#xff1a; 分组的注意&#xff1a; 主要的是根据分组的话&#xff0c;一个…

盲盒小程序搭建:年入百W的“盲盒经济”

盲盒作为一种新的商业模式&#xff0c;正引领着新的消费热潮。尤其是在当下年轻人群体中&#xff0c;盲盒的影响力非常大。 盲盒作为一种新的消费方式&#xff0c;因其具备的不确定性、未知性、惊喜性&#xff0c;刺激着消费者的购买欲。在现在的商城中&#xff0c;盲盒的身影…

AutoAnimate动画库,仅需一行代码

插件官网,支持react,vue AutoAnimate - Add motion to your apps with a single line of code 自动加动画原理 AutoAnimate 加动画的原理也很简单&#xff0c;监听绑定的 DOM 节点里 DOM 结构变化&#xff0c;自动添加对应的过渡动画&#xff1a; 增加子节点 > 渐入动画…

Redis(三):常见数据类型:List、Set、Zset

List 列表 列表类型是用来存储多个有序的字符串&#xff0c; 如图&#xff1a; a、b、c、d、e 五个元素从左到右组成 了⼀个有序的列表&#xff0c;列表中的每个字符串称为元素&#xff08;element&#xff09;&#xff0c;⼀个列表最多可以存储个元素。在 Redis 中&#xff…