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、数据结构图,我的字只有我能看懂系列

FFmpeg 入门[四] 解码函数及数据结构总结

 4、SDL流程

  • 初始化SDL显示图像需要的环境
  • 将解码得到的图像帧用SDL显示出来

5、又一张我的字只有我能看懂系列

FFmpeg 入门[四] 解码函数及数据结构总结 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)

作用:弹出窗口

参数意义:留坑

其他函数留坑待填