原文出自百度文库,但是要花费10个财富值,所以我干脆复制出来,并做简单编辑

出处:http://wenku.baidu.com/view/9ac5934be518964bcf847c2b.html?from_page=view&from_mod=download

另外,大家参考此处:http://my.oschina.net/u/555701/blog/56616

频播放过程

//2013-04-07 添加, 大概思路如下

1. 注册所有容器格式和CODEC:av_register_all()

2. 打开文件:av_open_input_file()

3. 从文件中提取流信息:av_find_stream_info()

4. 穷举所有的流,查找其中种类为CODEC_TYPE_VIDEO

5. 查找对应的解码器:avcodec_find_decoder()

6. 打开编解码器:avcodec_open()

7. 为解码帧分配内存:avcodec_alloc_frame()

8. 不停地从码流中提取出帧数据:av_read_frame()

9. 判断帧的类型,对于视频帧调用:avcodec_decode_video()

10. 解码完后,释放解码器:avcodec_close()

11. 关闭输入文件:av_close_input_file()

首先简单介绍以下视频文件的相关知识。我们平时看到的视频文件有许多格式,比如 avi, mkv, rmvb, mov, mp4等等,这些被称为容器(Container),不同的容器格式规定了其中音视频数据的组织方式(也包括其他数据,比如字幕等)。容器中一般会封装有视频和音频轨,也称为视频流(stream)和音频流,播放视频文件的第一步就是根据视频文件的格式,解析(demux)出其中封装的视频流、音频流以及字幕(如果有的话),解析的数据读到包(packet)中,每个包里保存的是视频帧(frame)或音频帧,然后分别对视频帧和音频帧调用相应的解码器(decoder)进行解码,比如使用H.264编码的视频和MP3编码的音频,会相应的调用H.264解码器和MP3解码器,解码之后得到的就是原始的图像(YUV or RGB)和声音(PCM)数据,然后根据同步好的时间将图像显示到屏幕上,将声音输出到声卡,最终就是我们看到的视频。

FFmpeg的API就是根据这个过程设计的,因此使用FFmpeg来处理视频文件的方法非常直观简单。下面就一步一步介绍从视频文件中解码出图片的过程。

声明变量

首先定义整个过程中需要使用到的变量:

int main(int argc, const char *argv[])

{

AVFormatContext *pFormatCtx = NULL;

int             i, videoStream;

AVCodecContext  *pCodecCtx;

AVCodec         *pCodec;

AVFrame         *pFrame;

AVFrame         *pFrameRGB;

AVPacket        packet;

int             frameFinished;

int             numBytes;

uint8_t         *buffer;

AVFormatContext:保存需要读入的文件的格式信息,比如流的个数以及流数据等

AVCodecCotext:保存了相应流的详细编码信息,比如视频的宽、高,编码类型等。

pCodec:真正的编解码器,其中有编解码需要调用的函数

AVFrame:用于保存数据帧的数据结构,这里的两个帧分别是保存颜色转换前后的两帧图像

AVPacket:解析文件时会将音/视频帧读入到packet中

打开文件

接下来我们打开一个视频文件。

av_register_all();

av_register_all 定义在 libavformat 里,调用它用以注册所有支持的文件格式以及编解码器,从其实现代码里可以看到它会调用 avcodec_register_all,因此之后就可以用所有ffmpeg支持的codec了。

if(avformat_open_input(&pFormatCtx, argv[1], NULL, NULL) != 0 )

return -1;

使用新的APIavformat_open_input来打开一个文件,第一个参数是一个AVFormatContext指针变量的地址,它会根据打开的文件信息填充AVFormatContext,需要注意的是,此处的pFormatContext必须为NULL或由avformat_alloc_context分配得到,这也是上一节中将其初始化为NULL的原因,否则此函数调用会出问题。第二个参数是打开的文件名,通过argv[1]指定,也就是命令行的第一个参数。后两个参数分别用于指定特定的输入格式(AVInputFormat)以及指定文件打开额外参数的AVDictionary结构,这里均留作NULL。

if(avformat_find_stream_info(pFormatCtx, NULL ) < 0 )

return -1;

av_dump_format(pFormatCtx, -1, argv[1], 0);

avformat_open_input函数只是读文件头,并不会填充流信息,因此我们需要接下来调用avformat_find_stream_info获取文件中的流信息,此函数会读取packet,并确定文件中所有的流信息,设置pFormatCtx->streams指向文件中的流,但此函数并不会改变文件指针,读取的packet会给后面的解码进行处理。

最后调用一个帮助函数av_dump_format,输出文件的信息,也就是我们在使用ffmpeg时能看到的文件详细信息。第二个参数指定输出哪条流的信息,-1表示给ffmpeg自己选择。最后一个参数用于指定dump的是不是输出文件,我们dump的是输入文件,因此一定要是0。

现在pFormatCtx->streams 中已经有所有流了,因此现在我们遍历它找到第一条视频流:

videoStream = -1;

for( i = 0; i < pFormatCtx->nb_streams; i++ )

if( pFormatCtx->streams[i]->codec->codec_type ==AVMEDIA_TYPE_VIDEO) {

videoStream = i;

break;

}

if(videoStream == -1 )

return -1;

codec_type 的宏定义已经由以前的 CODEC_TYPE_VIDEO 改为 AVMEDIA_TYPE_VIDEO 了。接下来我们通过这条 video stream 的编解码信息打开相应的解码器:

pCodecCtx = pFormatCtx->streams[videoStream]->codec;

pCodec = avcodec_find_decoder(pCodecCtx->codec_id);

if(pCodec == NULL )

return -1;

if(avcodec_open2(pCodecCtx, pCodec, NULL) < 0 )

return -1;

分配图像缓存

接下来我们准备给即将解码的图片分配内存空间。

pFrame = avcodec_alloc_frame();

if(pFrame == NULL )

return -1;

pFrameRGB = avcodec_alloc_frame();

if(pFrameRGB == NULL )

return -1;

调用avcodec_alloc_frame 分配帧,因为最后我们会将图像写成 24-bits RGB 的 PPM 文件,因此这里需要两个AVFrame,pFrame用于存储解码后的数据,pFrameRGB用于存储转换后的数据。

numBytes = avpicture_get_size(PIX_FMT_RGB24, pCodecCtx->width,

pCodecCtx->height);

这里调用 avpicture_get_size,根据 pCodecCtx 中原始图像的宽高计算 RGB24 格式的图像需要占用的空间大小,这是为了之后给 pFrameRGB 分配空间。

buffer = av_malloc(numBytes);

avpicture_fill( (AVPicture *)pFrameRGB, buffer, PIX_FMT_RGB24,

pCodecCtx->width, pCodecCtx->height);

接着上面的,首先是用av_malloc 分配上面计算大小的内存空间,然后调用 avpicture_fill 将 pFrameRGB 跟 buffer 指向的内存关联起来。

获取图像

OK,一切准备好就可以开始从文件中读取视频帧并解码得到图像了。

i =0;

while( av_read_frame(pFormatCtx, &packet) >= 0 ) {

if( packet.stream_index == videoStream ) {

avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished,&packet);

if( frameFinished ) {

structSwsContext *img_convert_ctx = NULL;

img_convert_ctx=

sws_getCachedContext(img_convert_ctx,pCodecCtx->width,

pCodecCtx->height,pCodecCtx->pix_fmt,

pCodecCtx->width,pCodecCtx->height,

PIX_FMT_RGB24, SWS_BICUBIC,

NULL, NULL, NULL);

if(!img_convert_ctx ) {

fprintf(stderr, "Cannot initialize swsconversion context\n");

exit(1);

}

sws_scale(img_convert_ctx,(const uint8_t* const*)pFrame->data,

pFrame->linesize, 0, pCodecCtx->height, pFrameRGB->data,

pFrameRGB->linesize);

if(i++ < 50 )

SaveFrame(pFrameRGB, pCodecCtx->width,pCodecCtx->height, i);

}

}

av_free_packet(&packet);

}

av_read_frame 从文件中读取一个packet,对于视频来说一个packet里面包含一帧图像数据,音频可能包含多个帧(当音频帧长度固定时),读到这一帧后,如果是视频帧,则使用 avcodec_decode_video2 对packet中的帧进行解码,有时候解码器并不能从一个packet中解码得到一帧图像数据(比如在需要其他参考帧的情况下),因此会设置 frameFinished,如果已经得到下一帧图像则设置 frameFinished 非零,否则为零。所以这里我们判断 frameFinished 是否为零来确定 pFrame 中是否已经得到解码的图像。注意在每次处理完后需要调用 av_free_packet 释放读取的packet。

解码得到图像后,很有可能不是我们想要的 RGB24 格式,因此需要使用 swscale 来做转换,调用 sws_getCachedContext 得到转换上下文,使用 sws_scale 将图形从解码后的格式转换为 RGB24,最后将前50帧写人 ppm 文件。最后释放图像以及关闭文件:

av_free(buffer);

av_free(pFrameRGB);

av_free(pFrame);

avcodec_close(pCodecCtx);

avformat_close_input(&pFormatCtx);

return 0;

}

static void SaveFrame(AVFrame *pFrame, intwidth, int height, int iFrame)

{

FILE *pFile;

char szFilename[32];

inty;

sprintf(szFilename, "frame%d.ppm", iFrame);

pFile = fopen(szFilename, "wb");

if(!pFile )

return;

fprintf(pFile, "P6\n%d %d\n255\n", width, height);

for( y = 0; y < height; y++ )

fwrite(pFrame->data[0] + y * pFrame->linesize[0], 1, width * 3,pFile);

fclose(pFile);

}

重点分析AVCodec/AVCodecContext/MsrleContext这几个数据结构,这几个数据结构定义了编解码

器的核心架构,相当于Directshow中的各种音视频解码器decoder。

typedefstructAVCodec

{

constchar*name;    // 标示Codec的名字, 比如,"msrle""truespeech" 等。

enumCodecTypetype; // 标示Codec的类型,有Video,Audio,Data等类型

enumCodecIDid;     // 标示Codec的ID,有CODEC_ID_MSRLE,CODEC_ID_TRUESPEECH等

intpriv_data_size; // 标示具体的Codec对应的Context的大小,在本例中是                          MsrleContext           // 或TSContext的大小。

int(*init)(AVCodecContext*);// 标示Codec对外提供的操作

int(*encode)(AVCodecContext*,uint8_t*buf,intbuf_size, void*data);

int(*close)(AVCodecContext*);

int(*decode)(AVCodecContext*,void*outdata,int*outdata_size,uint8_t*buf,intbuf_size);

intcapabilities;  // 标示Codec的能力,在瘦身后的ffplay中没太大作用,可忽略

structAVCodec*next;        // 用于把所有Codec串成一个链表,便于遍历

}AVCodec;

AVCodec 是类似COM接口的数据结构,表示音视频编解码器,着重于功能函数,一种媒体类型对应一个

AVCodec结构,在程序运行时有多个实例。next变量用于把所有支持的编解码器连接成链表,便于遍历查找;id

确定了唯一编解码器;priv_data_size表示具体的Codec 对应的 Context结构大小,比如MsrleContext 或

TSContext,这些具体的结够定义散落于各个.c文件中,为避免太多的ifelse类语句判断类型再计算大小,这里

就直接指明大小,因为这是一个编译时静态确定的字段,所以放在AVCodec而不是AVCodecContext中。

typedefstructAVCodecContext

{

intbit_rate;

intframe_number;

unsignedchar*extradata;//Codec的私有数据,对Audio是WAVEFORMATEX结构扩展字节。

intextradata_size;      // 对Video是BITMAPINFOHEADER后的扩展字节

intwidth,height;        // 此逻辑段仅针对视频

enumPixelFormatpix_fmt;

intsample_rate;         // 此逻辑段仅针对音频

intchannels;

intbits_per_sample;

intblock_align;

structAVCodec*codec; // 指向当前AVCodec的指针,

void*priv_data;         // 指向当前具体编解码器Codec的上下文Context。

enumCodecTypecodec_type;//seeCODEC_TYPE_xxx

enumCodecIDcodec_id;       //seeCODEC_ID_xxx

int(*get_buffer)(structAVCodecContext*c,AVFrame*pic);

void(*release_buffer)(structAVCodecContext*c,AVFrame*pic);

int(*reget_buffer)(structAVCodecContext*c,AVFrame*pic);

intinternal_buffer_count;

void*internal_buffer;

structAVPaletteControl*palctrl;

}AVCodecContext;

AVCodecContext结构表示程序运行的当前Codec使用的上下文,着重于所有Codec共有的属性(并且是在程

序运行时才能确定其值)和关联其他结构的字段。extradata和extradata_size两个字段表述了相应Codec使用的私

有数据,对Codec全局有效,通常是一些标志信息;codec字段关联相应的编解码器;priv_data字段关联各个具

体编解码器独有的属性上下文,和AVCodec结构中的priv_data_size 配对使用。

typedefstructMsrleContext

{

AVCodecContext*avctx;

AVFrameframe;

unsignedchar*buf;

intsize;

}MsrleContext;

MsrleContext结构着重于RLE行程长度压缩算法独有的属性值和关联AVCodecContext 的avctx字段。因为

RLE行程长度算法足够简单,属性值相对较少。

接着来重点分析AVInputFormat/AVFormatContext/AVIContext这几个数据结构,这几个数据结构定义了识别文件容器格式的核心架构,相当于Directshow中的各种解复用demuxer。

typedefstructAVInputFormat

{

constchar*name;

intpriv_data_size; // 标示具体的文件容器格式对应的Context的大小,在本例中是AVIContext

int(*read_probe)(AVProbeData*);

int(*read_header)(structAVFormatContext*,AVFormatParameters*ap);

int(*read_packet)(structAVFormatContext*,AVPacket*pkt);

int(*read_close)(structAVFormatContext*);

constchar*extensions;// 文件扩展名

structAVInputFormat*next;

}AVInputFormat;

AVInputFormat是类似COM接口的数据结构,表示输入文件容器格式,着重于功能函数,一种文件容器格

式对应一个AVInputFormat结构,在程序运行时有多个实例。next变量用于把所有支持的输入文件容器格式连接

成链表,便于遍历查找;priv_data_size标示具体的文件容器格式对应的Context的大小,在本例中是AVIContext,

这些具体的结够定义散落于各个.c文件中,为避免太多的ifelse 类语句判断类型再计算大小,这里就直接指明大小,因为这是一个编译时静态确定的字段,所以放在AVInputFormat而不是AVFormatContext中。

typedefstructAVFormatContext      //formatI/Ocontext

{

structAVInputFormat*iformat;

void*priv_data;               // 指向具体的文件容器格式的上下文Context,在本例中是AVIContext

ByteIOContextpb;              // 广泛意义的输入文件

intnb_streams;

AVStream*streams[MAX_STREAMS];

}AVFormatContext;

AVFormatContext结构表示程序运行的当前文件容器格式使用的上下文,着重于所有文件容器共有的属性(并且是在程序运行时才能确定其值)和关联其他结构的字段。iformat字段关联相应的文件容器格式;pb关联广义的

输入文件;streams关联音视频流;priv_data字段关联各个具体文件容器独有的属性上下文,和priv_data_size配

对使用。

typedefstructAVIContext

{

int64_triff_end;

int64_tmovi_end;

offset_tmovi_list;

intnon_interleaved;

intstream_index_2;// 为了和AVPacket中的stream_index相区别,添加后缀标记。

}AVIContext;

AVIContext定义了AVI中流的一些属性,其中stream_index_2定义了当前应该读取流的索引。

接着我们来重点分析URLProtocol/URLContext(ByteIOContext)/FILE(Socket)这几个数据结构,这几个数据结

构定义了读取文件的核心架构,相当于Directshow中的文件源filesourcefilter。

typedefstructURLProtocol

{

constchar*name;  // 便于人性化的识别理解

int(*url_open)(URLContext*h,constchar*filename,intflags);

int(*url_read)(URLContext*h,unsignedchar*buf,intsize);

int(*url_write)(URLContext*h,unsignedchar*buf,intsize);

offset_t(*url_seek)(URLContext*h,offset_tpos,intwhence);

int(*url_close)(URLContext*h);

structURLProtocol*next;

}URLProtocol;

URLProtocol是类似COM接口的数据结构,表示广义的输入文件,着重于功能函数,一种广义的输入文件

对应一个URLProtocol结构,比如file,pipe,tcp等等,但瘦身后的ffplay只支持file一种输入文件。next变量

用于把所有支持的广义的输入文件连接成链表,便于遍历查找。

typedefstructURLContext

{

structURLProtocol*prot;

intflags;

intmax_packet_size;//ifnonzero,thestreamispacketizedwiththismaxpacketsize

void*priv_data;   // 文件句柄fd,网络通信Scoket等

charfilename[1]; //specifiedfilename

}URLContext;

URLContext结构表示程序运行的当前广义输入文件使用的上下文,着重于所有广义输入文件共有的属性(并

且是在程序运行时才能确定其值)和关联其他结构的字段。prot字段关联相应的广义输入文件;priv_data字段关

联各个具体广义输入文件的句柄。

typedefstructByteIOContext

{

unsignedchar*buffer;

intbuffer_size;

unsignedchar*buf_ptr, *buf_end;

void*opaque;       // 关联URLContext

int(*read_buf)(void*opaque,uint8_t*buf,intbuf_size);

int(*write_buf)(void*opaque,uint8_t*buf,intbuf_size);

offset_t(*seek)(void*opaque,offset_toffset,intwhence);

offset_tpos;      //positioninthefileofthecurrentbuffer

intmust_flush;    //trueifthenextseekshouldflush

inteof_reached;   //trueifeofreached

intwrite_flag;     //trueifopenforwriting

intmax_packet_size;

interror;          //containstheerrorcodeor0ifnoerrorhappened

}ByteIOContext;

ByteIOContext结构扩展URLProtocol结构成内部有缓冲机制的广泛意义上的文件,改善广义输入文件的IO

性能。由其数据结构定义的字段可知,主要是缓冲区相关字段,标记字段,和一个关联字段opaque来完成广义

文件读写操作。opaque关联字段用于关联URLContext结构,间接关联并扩展URLProtocol结构。

接着我们来重点分析AVStream/AVIStream这几个数据结构,这几个数据结构定义了解析媒体流的核心属性,

主要用于读取媒体流数据,相当于Directshow中的解复用Demux内部的流解析逻辑。特别注意此结构关联

AVCodecContext 结构,并经此结构能跳转到其他结构。

typedefstructAVStream           // 解析文件容器内部使用的逻辑

{

AVCodecContext*actx;        //codeccontext,changefromAVCodecContext*codec;

void*priv_data;             //AVIStream

AVRationaltime_base;         // 由av_set_pts_info()函数初始化

AVIndexEntry*index_entries;//onlyusediftheformatdoesnotsupportseekingnatively

intnb_index_entries;

intindex_entries_allocated_size;

doubleframe_last_delay;

}AVStream;

AVStream结构表示当前媒体流的上下文,着重于所有媒体流共有的属性(并且是在程序运行时才能确定其值)

和关联其他结构的字段。actx字段关联当前音视频媒体使用的编解码器;priv_data字段关联解析各个具体媒体流

与文件容器有关的独有的属性;还有一些媒体帧索引和时钟信息。

typedefstructAVIStream

{

int64_tframe_offset;//currentframe(video)orbyte(audio)counter(usedtocomputethepts)

intremaining;

intpacket_size;

intscale;

intrate;

intsample_size;     //sizeofonesample(orpacket)(intherate/scalesense)inbytes

int64_tcum_len;    //temporarystorage(usedduringseek)

intprefix;         //normally'd'<<8+'c'or'w'<<8+'b'

intprefix_count;

}AVIStream;

AVIStream 结构定义了AVI文件中媒体流的一些属性,用于解析AVI文件。

接着我们来分析AVPacket/AVPacketList/PacketQueue这几个数据结构,这几个数据结构定义解复用demux

模块输出的音视频压缩数据流队列,相当于Directshow中Demux的OutputPin,传递数据到解码器。

typedefstructAVPacket

{

int64_tpts;//presentationtimestampintime_baseunits

int64_tdts;//decompressiontimestampintime_baseunits

int64_tpos;//bytepositioninstream,-1ifunknown

uint8_t*data;

intsize;

intstream_index;

intflags;

void(*destruct)(structAVPacket*);

}AVPacket;

AVPacket 代表音视频数据帧,固有的属性是一些标记,时钟信息,和压缩数据首地址,大小等信息。

typedefstructAVPacketList

{

AVPacketpkt;

structAVPacketList*next;

}AVPacketList;

AVPacketList 把音视频AVPacket 组成一个小链表。

typedefstructPacketQueue

{

AVPacketList*first_pkt, *last_pkt;

intsize;

intabort_request;

SDL_mutex*mutex;

SDL_cond*cond;

}PacketQueue;

PacketQueue 通过小链表AVPacketList把音视频帧AVPacket 组成一个顺序队列,是数据交换中转站,当然

同步互斥控制逻辑是必不可少的。

最后我们来重点分析VideoState这个数据结构,这个数据结构把主要的数据结构整合在一起,声明成全局变

量,起一个中转的作用,便于在各个子结构之间跳转,相当于一个大背景,大平台的作用。

typedefstructVideoState

{

SDL_Thread*parse_tid;

SDL_Thread*video_tid;

intabort_request;

AVInputFormat*iformat;

AVFormatContext*ic;  // 关联的主要数据结构是ByteIOContext 和AVStream

AVStream*audio_st;   // 关联的主要数据结构是AVCodecContext 和AVIStream

AVStream*video_st;

intaudio_stream;// 音频流索引,实际表示AVFormatContext结构中AVStream*streams[]数组中的索引

intvideo_stream;// 视频流索引,实际表示AVFormatContext结构中AVStream*streams[]数组中的索引

PacketQueueaudioq; // 音频数据包队列,注意一包音频数据可能包含几个音频帧

PacketQueuevideoq; // 视频数据包队列,注意瘦身后的ffplay一包视频数据是完整的一帧

VideoPicturepictq[VIDEO_PICTURE_QUEUE_SIZE];// 输出视频队列,瘦身后的ffplay只有一项

doubleframe_last_delay;

uint8_taudio_buf[(AVCODEC_MAX_AUDIO_FRAME_SIZE*3)/2];// 输出的音频缓存

unsignedintaudio_buf_size;

intaudio_buf_index;

AVPacketaudio_pkt;  // 音频包属性,只一个指针指向原始音频包数据,非直接包含音频数据包数据

uint8_t*audio_pkt_data;

intaudio_pkt_size;

SDL_mutex*video_decoder_mutex;// 视频线程同步互斥变量

SDL_mutex*audio_decoder_mutex;// 音频线程同步互斥变量

charfilename[240]; // 媒体文件名

}VideoState;

音视频数据流简单流程,由ByteIOContext(URLContext/URLProtocol )表示的广义输入文件,在

AVStream(AVIStreamt)提供的特定文件容器流信息的指引下,用AVInputFormat(AVFormatContext/AVInputFormat

)接口的read_packet()函数读取完整的一帧数据,分别放到音频或视频PacketQueue(AVPacketList/AVPacket)队列

中,这部分功能由decode_thread线程完成。对于视频数据,video_thread线程不停的从视频PacketQueue队列中

取出视频帧,调用AVCodec(AVCodecContext/MsrleContext)接口的decode()函数解码视频帧,在适当延时后做颜

色空间转化并调用 SDL 库显示出来。对于音频数据,SDL播放库播放完缓冲区的 PCM 数据后,调用

sdl_audio_callback()函数解码音频数据,并把解码后的PCM数据填充到SDL音频缓存播放。当下次播放完后,

再调用sdl_audio_callback()函数解码填充,如此循环不已。

ffmpeg视频播放过程相关推荐

  1. 【Android FFMPEG 开发】FFMPEG 视频播放进度控制 ( 显示播放进度 | 拖动进度条播放 )

    文章目录 I . FFMPEG 播放进度控制 II . FFMPEG 播放视频 ( 效果展示 ) III . FFMPEG 获取视频时长 IV . FFMPEG 视频播放进度获取 V . FFMPEG ...

  2. 视频教程-FFmpeg视频播放器开发-C/C++

    FFmpeg视频播放器开发 精通Android应用.音视频开发及JNI,熟悉FFmpeg,主导过多个电商.直播.音视频执法记录仪项目的开发,为企业开发过多款成功的产品.有完整的4G执法记录仪解决方案. ...

  3. Qt FFmpeg视频播放器开发(八):播放器UI改造、高仿QQ影音

      最近把播放器项目进行了更新,决定参照QQ影音的界面进行实现,我现在的实现如下:   下图是真实的QQ影音   相比QQ影音界面,我的实现有一定的差距,主要是控件的配色,以及中间那个动态图,由于没有 ...

  4. Android FFmpeg视频播放器三 音频封装格式解码播放

    Android FFmpeg视频播放器一解封装 Android Android FFmpeg视频播放器二 视频封装格式解码播放 视频解封装之后就会得到音频流和视频流,解封状得到的数据是AVPackag ...

  5. Jquery解决视频播放过程中定时弹出确认窗口

    Jquery解决视频播放过程中定时弹出确认窗口 前言 一.目标 二.实现目标 1.通过video标签,播放视频 2.编写播放.暂停等函数 3.获得当前时间和总时长 4.添加弹窗事件 5.完整代码 总结 ...

  6. 【FFmpeg视频播放器开发】解封装解码流程、常用API和结构体简介(一)

    一.前言 在正式编写 FFmpeg 播放器前,我们需要先简单了解下所要用到的 FFmpeg 库.播放与解码流程.函数和相关结构体. 二.FFmpeg 库简介 库 介绍 avcodec 音视频编解码核心 ...

  7. 一文读懂 Android FFmpeg 视频解码过程与实战分析

    概述 本文首先以 FFmpeg 视频解码为主题,主要介绍了 FFmpeg 进行解码视频时的主要流程.基本原理:其次,文章还讲述了与 FFmpeg 视频解码有关的简单应用,包括如何在原有的 FFmpeg ...

  8. Qt + FFmpeg 视频播放器

    一. 环境搭建 1. 下载 QT:window 5.7.0版本 FFmpeg: ffmpeg-20200522-38490cb-win32-dev 注意:这里下载 32位dev版本,要和编译器对应(我 ...

  9. 基于最简单的FFmpeg包封过程:视频和音频分配器启动(demuxer-simple)

    ===================================================== 基于最简单的FFmpeg封装工艺的系列文章上市: 最简单的基于FFmpeg的封装格式处理:视 ...

最新文章

  1. 阿里巴巴笔试题-马尔科夫(HMM)的特征
  2. Web系统中Mic设备的应用实例
  3. 7999元大疆最新无人机,支持第一人称视角极速拍摄,网友:不是航拍,是直接起飞...
  4. PyTorch中如何使用tensorboard可视化
  5. 精简版开发工具使用手记2(图解)
  6. linux find 文件夹下查找字符串
  7. spark mapreduce术语梳理
  8. Windows 7 资源管理器搜索Channel 9 视频
  9. 00、Python源码编译
  10. python进行列联表卡方检验
  11. 自考汉语言文学本科要考几门?专业有哪些课程?
  12. 利用 Python 读写文本内容
  13. SQL 编写能力提升-01 基础强化(Mysql)
  14. 嵌入式软件开发需要学习的知识点
  15. WinMerge 过滤器的使用方法
  16. 学习Python会用到的8个软件,你用的哪些
  17. 一些有趣的软件分享,给生活带来一点乐趣
  18. excel单元格内容拆分_Excel中把一个单元格内容拆分到多个单元格内的两种方法...
  19. Linux文本处理三剑客(awk、grep、sed)
  20. asr语音识别入门材料

热门文章

  1. 申报高新技术企业认定前需要做哪些准备工作?
  2. 配流02—DIAL算法(改进)
  3. Perl常用模块使用例子
  4. 2006年上市公司A股市值百强榜单
  5. 2的0次方为什么等于1?
  6. win10系统dns错误如何解决【系统天地】
  7. 太极拳“引进落空”的学理研究
  8. Kubernetes VPA配置
  9. CF407B 「Long Path」
  10. HTML+CSS+JavaScript实现的动态爱心,超简单直接用!