什么是AVHWAccel,我该如何使用它?

时间:2017-03-14 01:59:10

标签: c++ ffmpeg

我想利用硬件加速来解码h264编码的MP4文件。

我的计算环境:

Hardware: MacPro (2015 model)
Software: FFmpeg (installed by brew)

以下是FFmpeg命令的输出:

$ffmpeg -hwaccels
Hardware acceleration methods:
vda 
videotoolbox

根据this document,我的环境有两种选择,即VDAVideoToolBox。我在C ++中试过VDA

Codec = avcodec_find_decoder_by_name("h264_vda");

它有点工作,但像素格式的输出是UYVY422我无法处理(关于如何在UYVY422中呈现C++的任何建议?理想的格式是yuv420p

所以我想尝试VideotoolBox,但是没有这样简单的事情(虽然它可能适用于编码)

Codec = avcodec_find_decoder_by_name("h264_videotoolbox");

我似乎应该使用AVHWAccel,但AVHWAccel是什么以及如何使用它?

我的C ++代码的一部分:

for( unsigned int i = 0; i < pFormatCtx->nb_streams; i++ ){
        if(pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO){
            pCodecCtx = pFormatCtx->streams[i]->codec;
            video_stream = pFormatCtx->streams[i];
            if( pCodecCtx->codec_id == AV_CODEC_ID_H264 ){
                //pCodec = avcodec_find_decoder(pCodecCtx->codec_id);
                pCodec = avcodec_find_decoder_by_name("h264_vda");
                break;
            }
        }
    }
    // open codec
    if( pCodec ){
        if((ret=avcodec_open2(pCodecCtx, pCodec, NULL)) < 0) {
        ....

2 个答案:

答案 0 :(得分:3)

这与选择pix格式的解码器无关。

您的视频像素格式为UYVY422,因此您在解码帧后获得此格式。

与@halfelf提到的答案一样,您可以在解码帧后执行swscale,将pix格式转换为理想格式yuv420p,然后渲染它。

同时,如果您确定格式为UYVY422SDL2可以直接为您处理渲染。

在下面的示例中,我的格式为yuv420p,我使用swscale转换为UYVY422以呈现为SDL2

// prepare swscale context, AV_PIX_FMT_UYVY422 is my destination pix format
SwsContext *swsCtx = sws_getContext(codecCtx->width, codecCtx->height, codecCtx->pix_fmt,
                                    codecCtx->width, codecCtx->height, AV_PIX_FMT_UYVY422,
                                    SWS_FAST_BILINEAR, NULL, NULL, NULL);

SDL_Init(SDL_INIT_EVERYTHING);

SDL_Window *window;
SDL_Renderer *render;
SDL_Texture *texture;

SDL_CreateWindowAndRenderer(codecCtx->width,
                            codecCtx->height, SDL_WINDOW_OPENGL, &window, &render);

texture = SDL_CreateTexture(render, SDL_PIXELFORMAT_UYVY, SDL_TEXTUREACCESS_STREAMING,
                            codecCtx->width, codecCtx->height);

// ......
// decode the frame 
// ......
AVFrame *frameUYVY = av_frame_alloc();
av_image_alloc(frameUYVY->data, frameUYVY->linesize, codecCtx->width, codecCtx->height, AV_PIX_FMT_UYVY422, 32);

SDL_LockTexture(texture, NULL, (void **)frameUYVY->data, frameUYVY->linesize);

// convert the decoded frame to destination frameUYVY (yuv420p -> uyvy422)
sws_scale(swsCtx, frame->data, frame->linesize, 0, frame->height,
                      frameUYVY->data, frameUYVY->linesize);

SDL_UnlockTexture(texture);

// performa render
SDL_RenderClear(render);
SDL_RenderCopy(render, texture, NULL, NULL);
SDL_RenderPresent(render);

在您的示例中,如果您的pix格式为uyvy422,则可以跳过swscale部分,并在从ffmpeg解码后直接执行渲染。

答案 1 :(得分:2)

解码器不会选择输出的像素格式,它由视频本身决定。 swscale lib用于将一种像素格式转换为另一种像素格式。

auto sws_ctx = sws_getContext(src_width, src_height, AV_PIX_FMT_UYUV422, dst_width, dst_height, AV_PIX_FMT_YUV420P, 0,0,0,0);
av_image_alloc(new_data, new_linesize, dst_width, dst_height, AV_PIX_FMT_BGR24, FRAME_ALIGN);
sws_scale(sws_ctx, frame->data, frame->linesize, 0, src_height, new_data, new_linesize);

并且没有h264_videotoolbox解码器,只有编码器。列出可用的解码器/编码器:

ffmpeg -encoders
ffmpeg -decoders

解码器/编码器名称写在源中,例如,libavcodec/vda_h264_dec.clibavcodec/videotoolboxenc.c的末尾。