ffmpeg解码器使用

目录

      • 1、确定解码器类型
      • 2、获取解码器
      • 3、打开解码器
      • 4、进行解码

1、确定解码器类型

单解封装后得到视频流信息,我们可以从第一帧视频(音频)流信息中获取编码格式,从而确定解码器类型。

(1)定位第一帧音视频流信息
使用循环的方式查找,找到后break退出,代码如下:

    int videoStream = -1;
    int audioStream = -1;
    for (int i = 0; i < pFormatCtx->nb_streams; i++)    //循环查找视频中包含的流信息,
    {
        if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)	//视频流
        {
            videoStream = i;
            break;
        }
        if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO  && audioStream < 0)	//音频流
        {
            audioStream = i;
            break;
        }
    }

pFormatCtx:描述一个媒体文件或媒体流的构成和基本信息结构,代码中解封装得到的变量。
(2)得到音视频流编码信息

    if (videoStream >= 0)
        pCodecCtx = pFormatCtx->streams[videoStream]->codec;  	//查找视频解码器类型
    if (audioStream >= 0)
        aCodecCtx = pFormatCtx->streams[audioStream]->codec;	///查找音频解码器类型

2、获取解码器

使用AVCodecID枚举(代码中使用codec_id变量) 获取码流对应的标准,进而选择对应的解码器。

(1)软件解码器 ,使用函数:avcodec_find_decoder,代码如下:

codec_id = pCodecCtx->codec_id;
pCodec = avcodec_find_decoder(codec_id);

(2)硬件解码器(英伟达、英特尔),使用函数:avcodec_find_decoder_by_name,代码如下:

-------- 英伟达 --------:

	codec_id = pCodecCtx->codec_id;
    char hardWareDecoderName[32] = {0};
    if (AV_CODEC_ID_H264 == codec_id)
        sprintf(hardWareDecoderName, "h264_cuvid");
    else if (AV_CODEC_ID_HEVC == codec_id)
        sprintf(hardWareDecoderName, "hevc_cuvid");
    else if (AV_CODEC_ID_MPEG1VIDEO == codec_id)
        sprintf(hardWareDecoderName, "mpeg1_cuvid");
    else if (AV_CODEC_ID_MPEG2VIDEO == codec_id)
        sprintf(hardWareDecoderName, "mpeg2_cuvid");
    else if (AV_CODEC_ID_MPEG4 == codec_id)
        sprintf(hardWareDecoderName, "mpeg4_cuvid");

-------- 英特尔 --------:

	codec_id = pCodecCtx->codec_id;
    char hardWareDecoderName[32] = {0};
    if (AV_CODEC_ID_H264 == codec_id)
        sprintf(hardWareDecoderName, "h264_qsv");
    else if (AV_CODEC_ID_HEVC == codec_id)
        sprintf(hardWareDecoderName, "hevc_qsv");
    else if (AV_CODEC_ID_MPEG1VIDEO == codec_id)
        sprintf(hardWareDecoderName, "mpeg1_qsv");
    else if (AV_CODEC_ID_MPEG2VIDEO == codec_id)
        sprintf(hardWareDecoderName, "mpeg2_qsv");
    else if (AV_CODEC_ID_MPEG4 == codec_id)
        sprintf(hardWareDecoderName, "mpeg4_qsv");
    if (strlen(hardWareDecoderName) > 0)
        pCodec = avcodec_find_decoder_by_name(hardWareDecoderName);

3、打开解码器

使用avcodec_alloc_context3函数创建编码器,avcodec_open2函数打开编码器,代码如下:

		// 配置解码器
        pCodecCtx = avcodec_alloc_context3(pCodec);		  //得到的解码器
        pCodecCtx->thread_count = 8;		//只有软件解码需要配置,解码线程数
        pCodecCtx->pix_fmt = AV_PIX_FMT_YUV420P;	 //指明像素格式
         //打开解码器
        if (avcodec_open2(pCodecCtx, pCodec, nullptr) < 0)
        {
        	//返回参数小于0表示编码器打开失败
            avcodec_close(pCodecCtx);
            avcodec_free_context(&pCodecCtx);
            pCodecCtx = nullptr;
        }

4、进行解码

解码函数如下,参数输入解码前的码流数据,输出为解码后视频帧pFrame(格式为yuv420p,之前解码器配置的类型),以及放回解码结果。

bool decode(uint8_t *inputbuf, int frame_size)
{
    AVPacket pkt;
    av_init_packet(&pkt);
    pkt.data = inputbuf;
    pkt.size = frame_size;
    if (avcodec_send_packet(pCodecCtx, &pkt) != 0)
    {
       av_packet_unref(&pkt);
       return false;
    }
    while (0 == avcodec_receive_frame(pCodecCtx, pFrame));
    
	av_packet_unref(&pkt);
	return true;
}

补充:
前面初始化配置解码器的时候,并没有设置视频的宽高信息。因为h264的每一帧数据都带有编码的信息,当然也包括这些宽高信息了,因此解码完之后,使用pCodecCtx->width, pCodecCtx->height便可以知道视频的宽高是多少。

你可能感兴趣的:(ffmpeg,ffmpeg,H264,编解码,视频解码)