FFmpeg 入门[四] 解码函数及数据结构总结
1、大体流程
- (1)打开视频文件
- (2)获取视频流
- (3)得到流的编码器
- (4)获取该编码器的具体信息
- (5)根据(3)(4)查找编解码器
- (6)打开编码器
- (7)初始化SDL显示图像需要的环境
- (8)读取数据帧
- (9)解码数据帧
- (10)将解码得到的数据帧用SDL显示出来
2、解码函数分析
(1)av_register_all() 注册库
(2)avformat_open_input(&pFormatCtx, filepath, NULL, NULL)
作用:打开视频文件,把流信息填充到pFormatCtx指向的AVFormatContext结构体中。
参数意义:
- pFormatCtx是AVFormatContext结构体的指针
- filepath 就是要播放视频的地址啦
- 后面两个参数用来指定特殊的文件格式,缓冲大小和格式参数,但如果把它们设置为空 NULL 或 0, 将自动检测这些参数。
(3)avformat_find_stream_info(pFormatCtx, NULL)
作用:如果上面打开视频文件的函数获取到的流信息不完整,就要用这个函数获取完整的流信息,继续放到 AVFormatContext结构体中。事实上,上面的函数只打开了文件的头部,这个函数才是检查文件的流信息
参数意义:
- pFormatCtx是AVFormatContext结构体的指针
- 第二个参数,我也不知道是什么
(4)pCodecCtx = pFormatCtx->streams[videoindex]->codec;
pCodec = avcodec_find_decoder(pCodecCtx->codec_id)
作用:查找解码器,根据流的编解码器的id来获取该编解码器的具体信息,放到AVCodec结构体里
参数意义:
- pCodecCtx 是指向AVCodecContext结构体的指针,AVCodecContext结构体里面放了该流的编解码器
- codec_id 就是结构体里的一个属性啦
返回值:是一个结构体指针,指向AVCodec结构体
(5)avcodec_open2(pCodecCtx, pCodec, NULL)
作用:打开解码器
参数意义:
(6) av_frame_alloc()
作用:为指向AVFrame结构体的指针进行初始化,此时并不分配内部缓存,只是初始化以下?
(7)av_malloc()和 av_image_fill_arrays()
作用:两个函数分别的作用不知道,连起来用实现的功能就是实际的分配了内存,并用一个无符号字符型的指针指向了这块内存
- pCodecCtx是指向AVCodecContext结构体的指针
- pCodec是指向AVCodec结构体的指针
- 第三个参数不知道什么意思
unsigned char *out_buffer;
out_buffer = (unsigned char *)av_malloc(av_image_get_buffer_size(AV_PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height, 1));
av_image_fill_arrays(pFrameYUV->data, pFrameYUV->linesize, out_buffer,
AV_PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height, 1);
(8)img_convert_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt,
pCodecCtx->width, pCodecCtx->height, AV_PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL);
返回值:img_convert_ctx是指向SwsContext结构体的指针
作用:初始化,输入输出图像的宽、高、颜色空间
参数意义:https://blog.csdn.net/qingkongyeyue/article/details/53141356里面有
(9)av_read_frame(pFormatCtx, packet)
作用:从流中读取数据帧放到 AVPacket结构体,此时还没有解码
参数意义:
- pFormatCtx是指向AVFormatContext结构体的指针,里面已经放了流的信息
- packet是指向AVPacket结构体的指针,在这之前进行了内存分配 packet = (AVPacket *)av_malloc(sizeof(AVPacket))
(10)ret = avcodec_decode_video2(pCodecCtx, pFrame, &got_picture, packet);
返回值:ret是整型数据,返回值小于0说明解码错误
作用:这个函数就是真正用来解码的,他从AVPacket结构体中获取数据并解码放到AVFrame结构体中
参数意义:
- pCodecCtx指向AVCodecContext结构体的指针,AVCodecContext结构体里面放了该流的编解码器
- pFrame是指向AVFrame结构体的指针,已经进行了初始化,但是没有分别实际内存
- &got_picture 是一个整型数据的地址,这个函数会把把解码后的某一种数据放到这个里面,应该是一个指向某种信息的指针。到底哪种信息我还不知道。
- packet指向AVPacket结构体的指针,AVPacket结构体中放了没有解码的数据帧信息
(11) sws_scale(img_convert_ctx, (const unsigned char* const*)pFrame->data, pFrame->linesize, 0, pCodecCtx->height,
pFrameYUV->data, pFrameYUV->linesize);
作用:做转换
参数意义:看这里
(12)最后就是一些释放空间的函数
- sws_freeContext(img_convert_ctx)
- av_free_packet(packet);
- SDL_Quit()
- av_frame_free(&pFrameYUV);
- av_frame_free(&pFrame);
- avcodec_close(pCodecCtx);
- avformat_close_input(&pFormatCtx);
总结:其实以上分析,基本就给出了整个过程的数据结构,也就是用哪个函数获取数据存到结构体,再用哪个函数获取哪个结构体里的数据存到另一个结构体里面。
对于SwsContext,以及对它进行操作的两个函数,貌似是进行一些转换的,具体看这里
3、数据结构图,我的字只有我能看懂系列
4、SDL流程
- 初始化SDL显示图像需要的环境
- 将解码得到的图像帧用SDL显示出来
5、又一张我的字只有我能看懂系列
6、SDL的函数分析
(1)SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER))
作用:初始化SDL
参数意义:暂时不知道
(2)
screen = SDL_CreateWindow("Simplest ffmpeg player's Window",
SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,
screen_w, screen_h,
SDL_WINDOW_OPENGL)
作用:弹出窗口
参数意义:留坑
其他函数留坑待填