(二) FFmpeg解码视频学习

FFmpeg第三话:FFmpeg 视频解码详解 在多媒体技术蓬勃发展的当下,视频处理已然成为众多领域不可或缺的关键环节。而 FFmpeg,这款开源、跨平台且功能强大到近乎“神器”级别的音视频处理库,始终站在行业的前沿,为视频解码、编码、转码、滤镜处理等一系列复杂操作提供坚实的技术支撑。今天,就让我们一同深入探寻 FFmpeg 视频解码的核心世界,从基础概念到实际代码,彻底揭开它神秘的面纱。视频解码基础概念:介绍视频存储与传输时会压缩,解码则是逆向还原为原始视频帧序列的过程,以常见编码标准举例说明了编码和解码的关键技术要点。 阅读详情

目录

前言

概述

编码(encode):通过特定的压缩技术,将某个视频的视频流格式转换成另一种视频格式的视频流方式。比如视频:YUV420/422->h264;音频:PCM(原始)->AAC
解码(decode):通过特定的解压缩技术,将某个视频格式的视频流转换成另一种视频格式的视频流方式。
转码(transcode):视频转码技术将视频信号从一种格式转换成另一种格式。比如:视频包括改变分辨率;改变帧率;改变比特率(bir rate)等编码参数;音频包括改变采样率;改变通道数(双通道,单通道);改变位宽(sample format)。
封装(mux):复用,按一定格式组织原始音视频流。
解封装(demux):解复用,按一定格式解析出原始音视频流。
封装可以看做是对原始数据的一些解释,就如同bmp图像数据有文件头一样。
ES流:原始流,直接从编码器出来的数据流。
rtsp流:RTSP(Real Time Streaming Protocol) RFC2326s,实时流传输协议,是TCP/IP协议系中的一个应用层协议。
rtmp流:Real Time Messaging Protocol(实时消息传输协议),是adobe公司的协议
服务端:服务端是为客户端服务的,向客户端提供资源,保存客户端数据。
客户端:也可以称用户端,与服务端相对应,为客户提供本地服务的程序。
流媒体:采用流式传输方式在Internet播放的媒体格式。
推模式:当通知消息来之时,把所有相关信息都通过参数的形式”推给”观察者。就比如微信公众号的推送通知。
拉模式:当通知消息来之时,通知的函数不带任何相关的信息,而是要观察者主动去”拉”信息。就比如我们刷微博。
实时流:Real Time stream 实时传输的音视频流。比如直播。

FFmpeg结构体和函数

FFmpeg的关键结构体

FFmpeg关键结构体概述

  • 解协议(http,rtsp,rtmp,mms)
    AVIOContext,URLContext,URLContext主要存储视音频使用的协议类型以及状态。URLProtocol存储输入视音频使用的封装格式。每种协议都对应URLProtocol结构。(注意:FFmpeg中文件也被当作一种协议)
  • 解封装(flv,avi,rmvb,mp4)
    AVFormatContext主要存储视音频封装格式中包含的信息;AVInputFormat存储输入视音频使用的封装格式。每种视音频的封装格式都对应一个AVInputFormat。
  • 解码(h264,mpeg2,aac, mp3)
    每个AVStream存储一个视频/音频流的相关数据;每个AVStream对应于AVCodecContext,存储该视频/音频流使用解码方式的相关数据;每个AVCodecContext中对应一个AVCodec,包含该视频/音频对应的解码器。每种解码器都对应一个AVCodec结构。
  • 存数据
    视频的话,每个结构一般是存一帧;音频可能是好几帧。
    解码前数据:AVPacket
    解码后数据:AVFrame
    0
    从图中可以看出AVFormat Context这个结构体包含协议层结构体,封装层结构体,编码层结构体等。总之,这个结构体中贯穿编解码过程。

FFmpeg结构体详解

  • AVFormatContext
    AVFormatContext是FFmpeg解封装(flv,mp4,rmvb,avi)功能的结构体。
struct AVInputFormat *iformat:输入数据的封装格式
AVIOContext* pb:输入数据缓存
unsigned int nb_streams:视音频流的个数
AVStream **streams:视音频流
char filename[1024]:文件名

FFMPEG结构体分析:AVFormatContext

  • AVIOContext
    AVIOContext是FFmpeg管理输入输出数据的结构体。
unsigned char *buffer:缓存开始位置
int buffer_size:缓存大小
unsigned char* buf_ptr:当前指针读取到的位置
unsigned char* buf_end:缓存结束的位置
void *opaque:URLContext结构体,URLContext结构体中有一个结构体URLProtocol.注:每种协议(rtp,rtmp,file等)对应一个URLProtocol.

在解码的情况下,buffer用于存储ffmpeg读入的数据。例如:打开一个视频文件的时候,先把数据从硬盘读入buffer,然后送给解码器用于解码。
FFMPEG结构体分析:AVIOContext

  • AVStream
    AVStream是存储每一个视频/音频流信息的结构体。
int index:标识该视频/音频
AVCodecContex *codec:指向该视频/音频流的AVCodecContext
int64_t duration:该视频/音频流长度

FFMPEG结构体分析:AVStream

  • AVCodecContext
enum AVMeiaType codec_type:编解码器类型(视频、音频)
enum AVMediaType {
    AVMEDIA_TYPE_UNKNOWN = -1,  ///< Usually treated as AVMEDIA_TYPE_DATA
    AVMEDIA_TYPE_VIDEO,
    AVMEDIA_TYPE_AUDIO,
    AVMEDIA_TYPE_DATA,          ///< Opaque data information usually continuous
    AVMEDIA_TYPE_SUBTITLE,
    AVMEDIA_TYPE_ATTACHMENT,    ///< Opaque data information usually sparse
    AVMEDIA_TYPE_NB
};
enum AVMediaType codec_type; // 编码器类型
enum AVSampleFormat sample_fmt; // 采样格式

每个AVStream存储一个视频/音频流的相关数据;每一个AVStream对应一个AVCodecContext,存储该视频/音频流使用解码方式的相关数据;每个AVCodecContext中对应一个AVCodec,包含该视频/音频对应的解码器。每种解码器都对应一个AVCodec结构。
FFMPEG结构体分析:AVCodecContext

  • AVCodec
    AVCodec是视频/音频对应的解码器。
const char* name:编解码器的名字
const char* long_name:编解码其的名字,全称
enum AVMediaType type: 指明类型,视频,音频,字母
enum AVCodecID id:ID
const AVRational *supported_framerates:支持的帧率(仅视频)
const enum AVPixelFormat *pix_fmts:支持的像素格式(仅视频)
const int *supported_samplerates:支持的采样率(仅音频)
const enum AVSampleFormat *sample_fmts:支持的采样格式(仅音频)
const uint64_t *channel_layouts:支持的声道数(仅音频)
int priv_data_size:私有数据的大小

每一个编解码器对应一个该结构体:H.264解码器

AVCodec ff_h264_decoder = {  
    .name           = "h264",  
    .type           = AVMEDIA_TYPE_VIDEO,  
    .id             = CODEC_ID_H264,  
    .priv_data_size = sizeof(H264Context),  
    .init           = ff_h264_decode_init,  
    .close          = ff_h264_decode_end,  
    .decode         = decode_frame,  
    .capabilities   = /*CODEC_CAP_DRAW_HORIZ_BAND |*/ CODEC_CAP_DR1 | CODEC_CAP_DELAY | CODEC_CAP_SLICE_THREADS | CODEC_CAP_FRAME_THREADS,  
    .flush= flush_dpb,  
    .long_name = NULL_IF_CONFIG_SMALL("H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10"),  
    .init_thread_copy      = ONLY_IF_THREADS_ENABLED(decode_init_thread_copy),  
    .update_thread_context = ONLY_IF_THREADS_ENABLED(decode_update_thread_context),  
    .profiles = NULL_IF_CONFIG_SMALL(profiles),  
    .priv_class     = &h264_class,  
};  

遍历ffmpeg中的解码器信息的方法:
1. 注册所有的编解码器:av_register_all();
2. 声明一个AVCodec类型的指针,比如:AVCodec* first_c;
3. 调用av_codec_next()函数,即可获得指向链表下一个解码器的指针,循环往复可以获得所有解码器的信息。注意,如果想要获得指向第一个解码器的指针,则需要将该函数的参数设置为NULL.
FFMPEG结构体分析:AVCodec
- AVPacket
AVPacket是存储压缩编码数据相关信息的结构体。

uint8_t *data:压缩编码的数据
int size:data的大小
int64_t pts:显示时间戳
int64_t dts:解码时间戳
int stream_index:标识该AVPacket所属的视频/音频流

FFMPEG结构体分析:AVPacket

  • AVFrame
    AVFrame结构体一般用于存储原始数据(即非压缩数据,例如对视频来说是YUV/RGB,对音频来说是PCM),此外还包含一些相关信息。比如:解码时存储宏块类型表,QP表,运动矢量表等数据。编码时也存储了相关数据。比如:
typedef struct AVFrame  
{  
#define AV_NUM_DATA_POINTERS 8  
    uint8_t* data [AV_NUM_DATA_POINTERS]; // 指向图像数据   
    int linesize [AV_NUM_DATA_POINTERS];   // 行的长度
    int width; //图像的宽  
    int height; //图像的高  
    int format;  //图像格式  
     ……  
}AVFrame;  
AVFrame* frame = av_frame_alloc();  // 只是分配AVFrame结构体 data指向的内存并没有分配
int bytes_num = avpicture_get_size(AV_PIX_FMT_YUV420P, width, height); // AV_PIX_FMT_YUV420P是FFmpeg定义的标明YUV420P图像格式的宏定义
// 这个函数中会帮我们计算这个格式的图片大小

// 申请空间来存放图片数据。包含源数据和目标数据  
uint8_t* buff = (uint8_t*)av_malloc(bytes_num); 

// 把AVFrame结构体指针的图像数据指针赋值,也就是给图像数据指针和指向的内存之间做关联
avpicture_fill((AVPicture*)frame, buff, AV_PIX_FMT_ YUV420P,width, height); 

uint8_t* data [AV_NUM_DATA_POINTERS];指向图像数据,图像有存储方式有planar和packed两种模式。对于planar模式的YUV,data[0]指向Y分量的开始位置、data[1]指向U分量的开始位置、data[2]指向V分量的开始位置。对于packed模式YUV,data[0]指向数据的开始位置,而data[1]和data[2]都为NULL。

FFMPEG结构体分析:AVFrame
图像视频编码和FFmpeg(3)—–用FFmpeg进行图像格式转换和AVFrame简介

  • SwsContext
    记录进行图像格式转换时,源图像和目标图像的格式、大小分别是什么。

FFmpeg的函数

  • av_register_all()
    av_register_all()用于注册复用器,该函数在所有基于ffmpeg的应用程序中几乎都是第一个被调用的。只有调用了该函数,才能使用复用器,编码器等。
  • avformat_open_input()
    avformat_open_input用于打开多媒体数据并且获得一些相关的信息。
int avformat_open_input(AVFormatContext **ps, const char *filename, AVInputFormat *fmt, AVDictionary **options); 
ps: 函数调用之后处理过的`AVFormatContext`结构体
file: 打开的视音频流的URL
fmt:强制指定AVFormatContext中AVInputFormat。这个参数一般情况下可以设置为NULL
dictionary:附加的一些选项,一般情况下可以设置为NULL.

在这个函数中,FFmpeg完成了:
1. 输入输出结构体AVIOContext的初始化
2. 输入数据的协议的识别(例如:RTMP, 或者file)的识别:判断文件名后缀;读取文件头的数据进行比对。
3. 使用获得最高分的文件协议对应的URLProtocol,通过函数指针的方式,与FFmpeg连接。
4. 调用该URLProtocol的函数进行open, read等操作。
- avformat_find_stream_info()
avformat_find_stream_info()可以读取一部分视音频数据并且获得一些相关信息。这个函数主要用于给每个媒体流(音频/视频)的AVStream结构体赋值。据雷神说这个函数已经实现了解码器的查找,解码器的打开,视音频帧的读取,视音频帧的解码等工作。换句话说,该函数实际上已经”走通”了解码的整个流程。

  • avcodec_open2()
    1) 为各种结构体分配内存
    2) 将输入的AVDictionary形式的选项设置为AVCodecContext
    3) 一些其他检查,比如检测编解码其是否处于”实验”阶段
    4) 如果是编码器,检测输入参数是否符合编码器的要求
    5) 调用AVCodec的init()初始化具体的解码器

  • sws_getContext()
    libswscale主要用于处理图片像素数据的类库,可以完成图片像素格式的转换,图片的拉伸等工作。sws_getContext()用于初始化一个SwsContext:

struct SwsContext *sws_getContext(int srcW, int srcH, enum AVPixelFormat srcFormat, int dstW, int dstH, enum AVPixelFormat dstFormat, int flags, SwsFilter *srcFilter, SwsFilter *dstFilter, const double *param);  
srcW:源图像的宽
srcH:源图像的高
srcFormat:源图像的像素格式
dstW:目标图像的宽
dstH:目标图像的高
dstFormat:目标图像的像素格式
flags:设定图像拉伸使用的算法
  • avcodec_decode_video2()
    avcodec_decode_video2()的作用是实现压缩视频的解码,解码一帧视频数据。输入一个压缩编码的结构体AVPacket,输出一个解码后的结构体AVFrame。
int avcodec_decode_video2(AVCodecContext *avctx, AVFrame *picture, int *got_picture_ptr, const AVPacket *avpkt);  

AVCodecContext* avctx:编解码上下文环境,定义了编解码操作的一些细节;
AVFrame* picture:输出参数,传递到该方法的对象本身必须在外部有av_frame_alloc()分配空间。
got_picture_ptr:该值为0表示没有图像可以解码,否则表明有图像可以解码。
avpkt:输入参数,包含待解码数据

FFmpeg源代码简单分析:libswscale的sws_getContext()

解码视频代码

参考这篇从零开始学习音视频编程技术(五) 使用FFMPEG解码视频之保存成图片博文。我直接在Ubuntu下成功运行了这篇博文中运行的代码,但是ppm格式不好打开,正好之前有写过保存成bmp图片的文件,但是写得不是很好,顺便把这一部分整理一下!顺便测试一下解码视频是否成功!附上修改的保存bmp的函数!bmp格式参考 linux下位图结构解析(二)

bool saveAsBitMap(AVFrame* pFrameRGB, int width, int height, int iFrame)
{
    FILE *pFile = NULL;
    BITMAPFILEHEADER_t bmpHeader;
    BITMAPINFOHEADER_t bmpInfoHeader;

    char fileName[32];
    int bpp = 24;

    // open file
    sprintf(fileName, "frame%d.bmp", iFrame);
    pFile = fopen(fileName, "wb");
    if(!pFile)
    {
        return false;
    }

    bmpHeader.bfType = ('M'<<8)|'B';    // 0x4D42
    bmpHeader.bfReserved = 0;
    bmpHeader.bfOffBits = sizeof(BITMAPFILEHEADER_t)+sizeof(BITMAPINFOHEADER_t);
    bmpHeader.bfSize = bmpHeader.bfOffBits + width*height*bpp/8;

    bmpInfoHeader.biSize =  sizeof(BITMAPINFOHEADER_t);
    bmpInfoHeader.biWidth = width;
    bmpInfoHeader.biHeight = -height;
    bmpInfoHeader.biPlanes = 1;
    bmpInfoHeader.biBitCount = bpp;
    bmpInfoHeader.biCompression = 0;
    bmpInfoHeader.biSizeImage = 0;
    bmpInfoHeader.biXPelsPerMeter = 0;
    bmpInfoHeader.biYPelsPerMeter = 0;
    bmpInfoHeader.biClrUsed = 0;
    bmpInfoHeader.biClrImportant = 0;

    fwrite(&bmpHeader, sizeof(BITMAPFILEHEADER_t), 1, pFile);
    fwrite(&bmpInfoHeader, sizeof(BITMAPINFOHEADER_t), 1, pFile);

    uint8_t *buffer = pFrameRGB->data[0];
    for(int h=0; h<height; h++)
    {
        for(int w=0; w<width; w++)
        {
            fwrite(buffer+2, 1, 1, pFile);
            fwrite(buffer+1, 1, 1, pFile);
            fwrite(buffer,   1, 1, pFile);
            buffer += 3;
        }
    }
    fclose(pFile);

    return true;

}

总结

网上各种查资料,就着前辈们的代码,完成了FFmpeg解码视频的学习。虽然只是刚刚跑通了一个小例子。但是也算是个小入门了!在这个时代,资源比以前多很多,感谢大神们的无私奉献!同时也要明白资源好找,别人可以很快达到这个水平,要更加努力才行呢!

链接地址

从零开始学习音视频编程技术(五) 使用FFMPEG解码视频之保存成图片

使用FFmpeg做视频解码 音频的压缩编码标准包含AAC,MP3,AC-3等等,视频的压缩编码标准则包含H.264,MPEG2,VC-1等等。封装格式种类很多,例如MP4,MKV,RMVB,TS,FLV,AVI等等,它的作用就是将已经压缩编码的视频数据和音频数据按照一定的格式放到一起。例如,FLV格式的数据,经过解封装操作后,输出H.264编码的视频码流和AAC编码的音频码流。视音频同步的作用,就是根据解封装模块处理过程中获取到的参数信息,同步解码出来的视频和音频数据,并将视频音频数据送至系统的显卡和声卡播放出来。 阅读详情

相关推荐

音视频学习二: android平台下ffmpeg编解码简记-编解码

               编解码 1.主要函数 avcodec_register_all(); 注册所有解码器 AVCodec *avcodec_find_decoder(enum AVCodecID id); 软件码:根据解码器id找到解码器 AVCodec *avcodec_find_decoder_by_name(const char *name); 硬解码:根据解码器名称找到解...

qq_33635618的博客 955

FFmpeg音视频开发知识点(一)

最近在做音视频编解码实时流项目【h323+ffmpeg+rtp】,特意记录一下开发中遇到的部分问题,以及现学现用的部分知识点,前期急急忙忙没认真看,直接拿过来用,用的不对,各种问题,真的一言难尽,最终还是要静下心来认真研究才行;温馨提示:我使用的ffmpeg版本是4.4,不同版本可能有所差异。

流云落尘 3875

FFmpeg视频解码流程详解及demo

本文主要讲解FFmpeg的视频解码具体流程,API使用,以及相关结构体介绍。最后再以一个非常简单的demo演示将一个mp4格式的视频文件解码为原始数据yuv文件。

分享音视频技术 9640

FFmpeg 视频解码(秒懂)

解码如下图所示,将H.264数据解码为YUV。

希望能帮助大家,希望大家多多支持,你们的支持是我前进的动力。 8112

ffmpeg解码H.264视频数据,MFC播放视频

ffmpeg库 在vs2012中的调用, 用ffmpeg实现H.264视频数据的解码,在MFC中实现视频的播放显示

cc_fys的博客 4439

在Qml中显示FFmpeg解码视频

本文主要讲述ffmpeg解码的视频如何现实到qml窗口上的过程,文末有代码地址。文章开始处先贴一张效果图 1、绘制类通过继承QQuickPaintedItem可以使用QPainter接口将一帧解码QImage绘制到Qml上面。(XVideo是QQuickPaintedItem的子类)当接收到一帧(QImage)的时候直接调用update()更新。 void XVideo::paint(QPaint...

cxc233的博客 5307

【Qt+FFmpeg】 - FFmpeg解码详细流程

FFmpeg解码详细流程

m0_60259116的博客 3867

ffmpeg库视频硬解码使用流程

FFmpeg 的硬解码(Hardware Decoding)通过调用 GPU 或专用硬件的编解码能力实现,能显著降低 CPU 占用率。

深之JohnChen的专栏 3144

ffmpeg视频解码

和,以下代码以mjpeg为例。

qq_51699436的博客 1459

CUDA和FFMPEG硬件解码视频流

其他博客给出的教程要么只是给出了伪代码,非常的模糊,要么是基于D3D进行显示,使得给出的源码非常复杂,而无法看出CUDA解码的核心框架,而本文将其他非核心部分剥离出去,视频播放部分通过opencv调用cv::mat显示。示例中NvDecodeD3D9.cpp实现了D3D环境的创建,CUDA模块的初始化,其中取视频帧图像显示的函数如下,该函数实现了从解码图像队列取出图像(实际上是显存指针),完成格式转换(NV12到ARGB),最后映射到D3D的Texture进行显示等功能,代码中我给出了关键部位的解释。

yinshipin007的博客 2165

FFmpeg-之音视频解码与音视频同步(二)

/YUV格式的数据转换成RGBA 8888格式的数据, FFmpeg 也可以转换,但是存在问题,使用libyuv这个库实现。LOGI(“视频时长:%lld”, (pFormatCtx->duration) / (1000 * 1000));//rgb_frame的缓冲区就是Window的缓冲区,同一个,解锁的时候就会进行绘制。//封装格式上下文,统领全局的结构体,保存了视频文件封装格式的相关信息。//封装格式上下文,统领全局的结构体,保存了视频文件封装格式的相关信息。

2401_85121663的博客 1324

[笔记]音视频学习之ffmpeg实践《二》ffmpeg解码

FFmpeg学习教程 视音频数据处理入门:H.264视频码流解析 FFmpeg 4.0.2 + SDL2-2.0.8 实现H264解码后播放 文章目录准备总结 准备 ffmpeg库 SDL2库 cmake构建 h264文件 总结

二次元怪兽的博客 439

FFmpeg 6.0实现视频硬解码

以上就是利用FFmpeg 6.0实现视频硬解码输出到Surface设备的详细步骤。通过以上的介绍,我们可以看到,虽然这个过程涉及到多个复杂的技术概念,但是只要我们按照步骤进行操作,并仔细阅读每个步骤,就可以顺利完成视频的硬解码和输出。希望这篇文章能够帮助大家更好地理解FFmpeg和Surface设备的相关技术,并在实际的项目中进行应用和实践。

程序猿老樊的博客 1495

【FFmpeg】 音视频解码详细流程

【FFmpeg】 音视频解码详细流程

m0_56051805的博客 5401

FFMpeg 实现视频编码、解码

FFMpeg 作为音视频领域的开源工具,它几乎可以实现所有针对音视频的处理,本文主要利用 FFMpeg 官方提供的 SDK 实现音视频最简单的几个实例:编码、解码、封装、解封装、转码、缩放以及添加水印。 接下来会由发现问题->分析问题->解决问题->实现方案,循序渐进的完成。 FFMpeg 编码实现 本例子实现的是将视频域 YUV 数据编码为压缩域的帧数据,编码格式包含了 H.264/H.265/MPEG1/MPEG2 四种 CODEC 类型。 实现的过程,可以大致用如下图表示: 从图中可以大

m0_68918744的博客 5403

【ffmpeg】视频解码器

本文主要阐述了使用ffmpeg解码的相关内容: 1.解码理论 2.ffmpeg代码配置验证 3.ffmpeg解码的流程 4.ffmpeg解码过程中API解析 5.ffmpeg解码过程中数据结构解析

MichaelKongChina的博客 2196

利用ffmpeg和opencv进行视频的解码播放

OpenCV中有自己的用于处理图片和视频的类,可以很方便的读入文件和显示。 现在视频数据流是ffmpeg解码h264文件得到的,由于要依赖该数据源进行相应的后续处理,所以需要将ffmpeg中得到的数据缓存转换成可以被OpenCV处理的Mat类对象。

Jason Ding的专栏 1万+

Rasa Core开发指南

文章目录1. Rasa Core简介1.1 Rasa Core消息处理流程1.2 安装Rasa Core2. Dialogue模型训练2.1 Story样本数据2.2 Domain2.2.0 intents2.2.1 actions2.2.2 templates2.2.3 entities2.2.4 slots3 .训练和使用对话模型3.1 训练对话模型3.2 使用对话模型4. 搭建CustomA...

老蒋也疯狂 1万+

Android FFmpeg开发(二),实现视频解码和渲染

上一篇文章我们对FFmpeg进行交叉编译,得到了编译产物:libffmpeg.so,然后创建了一个Android项目,对libffmpeg.so库实现了集成,还没阅读上一篇文章建议先阅读:Android FFmpeg开发(一),FFmpeg编译与集成 本文将利用FFmpeg对本地MP4视频文件进行视频流解码,然后使用FFmpeg中的libswscale模块将原始视频YUV帧转成RGB帧,最后将RGB帧数据刷到SurfaceView的surface中实现视频画面的渲染。 接下来,介绍下利用FFmpeg完成

Lorien Zhang的博客 6843

Python实战:用MNE-Python从脑电数据中提取P300成分(附完整代码)

本文提供了一份使用MNE-Python从脑电数据中提取P300成分的完整实战指南。通过详细的代码示例,系统讲解了从环境搭建、数据加载、预处理(滤波、分段、伪迹剔除)到P300波形提取、可视化与参数量化的全流程。重点介绍了如何利用零相位滤波和叠加平均技术,从EEG信号中精准分离出反映认知加工的P300事件相关电位,适用于脑机接口与认知神经科学研究。

weixin_29240343的博客 338

【系统架构设计师】论文:论虚拟现实技术的应用与发展

虚拟现实技术是当前科学研究的热点,同时也是国家大力支持发展的核心技术之一。所谓虚拟现实,就是通过计算机等虚拟手段来构造一个非常接近真实世界的虚拟环境,它主要体现在视觉、触觉、嗅觉等方面的逼真模拟来达到高度的沉浸性,也就是如我们通常所说的“身临其境”。

数据知道的博客 1万+
上一篇: linux下位图结构解析(二)
下一篇: Linux网络编程学习——TCP/IP基础(一)
simonXi-tech
博客等级 码龄10年 398粉丝 52原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值