如何快速实现ffmpeg dxva2硬解码

9 篇文章 1 订阅
3 篇文章 0 订阅

首先,ffmpeg本身支持dxva2硬结解码,但解码器类型有限,并不是所有的都可以硬解。我使用的ffmpeg的版本是3.2,支持dxva2硬件加速的有以下几种文件格式: AV_CODEC_ID_MPEG2VIDEO、AV_CODEC_ID_H264、AV_CODEC_ID_VC1、AV_CODEC_ID_WMV3、AV_CODEC_ID_HEVC、AV_CODEC_ID_VP9

在正常软解代码的基础上,我们需要ffmpeg_dxva2.h和ffmpeg_dxva2.cpp。ffmpeg的源码里有ffmpeg_dxva2.c,前面的.h和.cpp就是从.c以及.c中包含的头文件中提取出来的,具体的下载地址为:http://download.csdn.net/detail/an505479313/9823407


下面说一下代码实现,直接贴代码:



static AVPixelFormat GetHwFormat(AVCodecContext *s, const AVPixelFormat *pix_fmts)
{
    InputStream* ist = (InputStream*)s->opaque;
    ist->active_hwaccel_id = HWACCEL_DXVA2;
    ist->hwaccel_pix_fmt = AV_PIX_FMT_DXVA2_VLD;
    return ist->hwaccel_pix_fmt;
}


int DecodeThread::stream_component_open(VideoState *is, int stream_index)
{
    AVFormatContext *ic = is->ic;
    AVCodecContext *avctx;
    AVCodec *codec = NULL;
    AVDictionary *opts = NULL;
    int ret = -1;
 
    if (stream_index < 0 || stream_index >= (int)ic->nb_streams)
        return -1;
    avctx = avcodec_alloc_context3(NULL);
    if (!avctx)
        return AVERROR(ENOMEM);
 
    ret = avcodec_parameters_to_context(avctx, ic->streams[stream_index]->codecpar);
    if (ret < 0)
        return -1;
    av_codec_set_pkt_timebase(avctx, ic->streams[stream_index]->time_base);
 
    codec = avcodec_find_decoder(avctx->codec_id);
 
    if(avctx->codec_id == AV_CODEC_ID_H264)
        avctx->thread_count = 1;
    else
    {
        if (!av_dict_get(opts, "threads", NULL, 0))
            av_dict_set(&opts, "threads", "auto", 0);
    }
    InputStream *ist = new InputStream();
 
    switch(avctx->codec_type){
    case AVMEDIA_TYPE_AUDIO:
        is->last_audio_stream = stream_index;
        break;
    case AVMEDIA_TYPE_VIDEO:
        is->last_video_stream = stream_index;
 
        ist->hwaccel_id     = HWACCEL_AUTO;
        ist->hwaccel_device = "dxva2";
        ist->dec            = codec;
        ist->dec_ctx        = avctx;
        avctx->coded_width  = avctx->width;
        avctx->coded_height = avctx->height;
 
        avctx->opaque = ist;
        dxva2_init(avctx);
        avctx->get_buffer2           = ist->hwaccel_get_buffer;
        avctx->get_format            = GetHwFormat;
        avctx->thread_safe_callbacks = 1;
        break;
    default:
        break;
    }
 
    if(!codec)
        return -1;
 
    avctx->lowres = lowres;
 
    if(avctx->lowres > codec->max_lowres){
        av_log(avctx, AV_LOG_WARNING, "The maximum value for lowres supported by the decoder is %d\n",
               codec->max_lowres);
        avctx->lowres= codec->max_lowres;
    }
 
    if(codec->capabilities & CODEC_CAP_DR1)
        avctx->flags |= CODEC_FLAG_EMU_EDGE;
 
 
 
    ret = avcodec_open2(avctx, codec, &opts);
    if (ret != 0) {
        return -1;
    }
 
    if (avctx->codec_type == AVMEDIA_TYPE_AUDIO && !is->playWithoutAudio) {
        int audio_hw_buf_size = audio_open(is, avctx->channel_layout, avctx->channels, avctx->sample_rate, &is->audio_src);
        if (audio_hw_buf_size < 0)
        {
            return -1;
        }
        is->audio_hw_buf_size = audio_hw_buf_size;
        is->audio_tgt = is->audio_src;
    }
 
    ic->streams[stream_index]->discard = AVDISCARD_DEFAULT;
    switch (avctx->codec_type) {
    case AVMEDIA_TYPE_AUDIO:
    if(!is->playWithoutAudio)
    {
        is->audio_stream = stream_index;
        is->audio_st = ic->streams[stream_index];
        is->audio_buf_size  = 0;
        is->audio_buf_index = 0;
 
        is->audio_diff_avg_coef  = exp(log(0.01) / AUDIO_DIFF_AVG_NB);
        is->audio_diff_avg_count = 0;
 
        is->audio_diff_threshold = 2.0 * is->audio_hw_buf_size / av_samples_get_buffer_size(NULL, is->audio_tgt.channels, is->audio_tgt.freq, is->audio_tgt.fmt, 1);
 
        memset(&is->audio_pkt, 0, sizeof(is->audio_pkt));
        memset(&is->audio_pkt_temp, 0, sizeof(is->audio_pkt_temp));
 
        packet_queue_start(&is->audioq);
        SDL_PauseAudioDevice(is->audiodeviceId,0);
        is->audioCtx = avctx;
    }
        break;
    case AVMEDIA_TYPE_VIDEO:
        is->video_stream = stream_index;
        is->video_st = ic->streams[stream_index];
        is->videoCtx = avctx;
        packet_queue_start(&is->videoq);
 
        start_event = new QEvent(Video_Event);
        QCoreApplication::postEvent(player,start_event);
        break;
    default:
        break;
    }
    return 0;
}
主要关于硬解的代码如下:

        ist->hwaccel_id     = HWACCEL_AUTO;
        ist->hwaccel_device = "dxva2";
        ist->dec            = codec;
        ist->dec_ctx        = avctx;
        avctx->coded_width  = avctx->width;
        avctx->coded_height = avctx->height;
 
        avctx->opaque = ist;
        dxva2_init(avctx);
        avctx->get_buffer2           = ist->hwaccel_get_buffer;
        avctx->get_format            = GetHwFormat;
        avctx->thread_safe_callbacks = 1;
其中ist是结构体InputStream的指针,该结构体存在于ffmpeg_dxva2.h中。

这里需要注意的是,如果要做硬解码,那么多线程解码的选项应该关掉,并设置线程数为1.我这里是为了支持其他不能用硬解的视频。

然后就是正常的打开解码器,使用_video2解码,并用dxva2_retrieve_data_call函数获取AVFrame。

FFmpeg是一种开源的多媒体处理工具,其中包含了dxva2解码功能。DXVA2是DirectX Video Acceleration 2的缩写,它是一种能够充分利用显卡件加速的视频解码技术。 使用FFmpeg进行dxva2解码时,可以获得以下几个优势: 1. 提高解码效率:dxva2解码能够使用显卡的件加速能力,从而大大提高视频解码的效率。相较于软解码,在相同的件条件下,dxva2解码可以更快地完成对视频的解码工作。 2. 减轻CPU负担:由于dxva2解码利用显卡进行解码,可以减轻CPU的负担,从而为其他任务提供更多的计算资源。这对于同时进行多任务处理的用户来说,尤其是一些对计算性能要求较高的场景,是非常有益的。 3. 优化视频播放体验:dxva2解码可以提供更平滑和流畅的视频播放体验。它能够更好地处理高分辨率、高比特率的视频文件,避免视频卡顿或者出现掉帧的情况。 然而,dxva2解码也存在一些限制和要求: 1. 件支持要求:要使用dxva2解码功能,需要具备支持DXVA2的显卡件。不同显卡型号和厂商支持的dxva2版本可能会有所不同,所以在使用前需要确认自己的显卡是否支持dxva2解码。 2. FFmpeg版本要求:为了能够使用dxva2解码功能,需要使用支持dxva2FFmpeg版本。更新的FFmpeg版本通常会修复一些bug并加入新的功能,所以建议使用最新版本的FFmpeg。 总结来说,通过FFmpegdxva2解码功能,我们可以提高解码效率、减轻CPU负担,并获得更好的视频播放体验。需要注意的是,确保件和软件环境支持dxva2解码,并及时更新FFmpeg版本可以保证最佳的使用效果。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值