programing

ffmpeg에서 하드웨어 액셀러레이션을 사용하는 방법

javaba 2022. 7. 2. 23:50
반응형

ffmpeg에서 하드웨어 액셀러레이션을 사용하는 방법

하드웨어 액셀러레이션을 사용하여 ffmpeg 비디오(h264 등)를 디코딩해야 합니다.프레임을 디코딩하는 일반적인 방법인 read packet -> decode frame을 사용하고 있습니다.그리고 ffmpeg의 디코딩 속도를 높이고 싶습니다.그래서 제가 만든 건--enable-vaapi그리고.--enable-hwaccel=h264근데 다음에 뭘 해야 될지 모르겠어요.사용하려고 했습니다.avcodec_find_decoder_by_name("h264_vaapi")nullptr을 반환합니다.어쨌든 저는 VA API뿐만 아니라 다른 API를 사용하고 싶을지도 모릅니다.ffmpeg 복호화 속도를 어떻게 높여야 하죠?

추신: ffmpeg with hwaccel을 사용하는 예는 인터넷에서 찾을 수 없었습니다.

조사를 실시한 결과, OS X(VDA) 및 Linux(VDPAU)에 필요한 하드웨어 액셀러레이션 디코딩을 실장할 수 있었습니다.Windows 의 실장도 입수하면, 답변을 갱신합니다.가장 쉬운 것부터 시작합시다.

Mac OS X

Mac OS에서 하드웨어 가속을 사용하려면 다음을 사용해야 합니다.avcodec_find_decoder_by_name("h264_vda");단, H264 비디오는 FFmpeg가 설치된 Mac OS에서만 가속할 수 있습니다.

Linux VDPAU

리눅스는 일이 훨씬 복잡하다.FFmpeg는 Linux에 VDPAU(Nvidia)와 VAAPI(Intel)의 2개의 하드웨어 액셀러레이터와 VDPAU의 1개의 하드웨어 디코더만 있습니다.위의 Mac OS 예시와 같이 VDPAU 디코더를 사용하는 것이 지극히 합리적이라고 생각됩니다.avcodec_find_decoder_by_name("h264_vdpau");

아무것도 변하지 않고 가속력이 전혀 없다는 것을 알게 되면 놀랄지도 모른다.왜냐하면 아직 시작 단계이기 때문에 가속이 작동하려면 훨씬 더 많은 코드를 작성해야 합니다.다행히, 독자적으로 해결책을 생각해 낼 필요는 없습니다.이를 실현하는 방법에는 libavg와 FFmpeg 그 자체라는 적어도2가지 좋은 예가 있습니다.libavg에는 VDPAUDecoder 클래스가 있습니다.이 클래스는 완전히 클리어되어 있으며, 실장에 근거하고 있습니다.비교할 다른 구현을 얻으려면 ffmpeg_vdpau.c를 참조할 수도 있습니다.내 생각에는 libavg 구현이 더 이해하기 쉽다.

위의 두 예에서 유일하게 부족한 것은 디코딩된 프레임을 메인 메모리에 올바르게 복사하는 것입니다.두 예 모두 다음을 사용합니다.VdpVideoSurfaceGetBitsYCbCr내 기계로 얻은 모든 퍼포먼스를 망쳤지따라서 다음 절차를 사용하여 GPU에서 데이터를 추출할 수 있습니다.

bool VdpauDecoder::fillFrameWithData(AVCodecContext* context,
    AVFrame* frame)
{
    VdpauDecoder* vdpauDecoder = static_cast<VdpauDecoder*>(context->opaque);
    VdpOutputSurface surface;
    vdp_output_surface_create(m_VdpDevice, VDP_RGBA_FORMAT_B8G8R8A8, frame->width, frame->height, &surface);
    auto renderState = reinterpret_cast<vdpau_render_state*>(frame->data[0]);
    VdpVideoSurface videoSurface = renderState->surface;

    auto status = vdp_video_mixer_render(vdpauDecoder->m_VdpMixer,
        VDP_INVALID_HANDLE,
        nullptr,
        VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME,
        0, nullptr,
        videoSurface,
        0, nullptr,
        nullptr,
        surface,
        nullptr, nullptr, 0, nullptr);
    if(status == VDP_STATUS_OK)
    {
        auto tmframe = av_frame_alloc();
        tmframe->format = AV_PIX_FMT_BGRA;
        tmframe->width = frame->width;
        tmframe->height = frame->height;
        if(av_frame_get_buffer(tmframe, 32) >= 0)
        {
            VdpStatus status = vdp_output_surface_get_bits_native(surface, nullptr,
                reinterpret_cast<void * const *>(tmframe->data),
                reinterpret_cast<const uint32_t *>(tmframe->linesize));
            if(status == VDP_STATUS_OK && av_frame_copy_props(tmframe, frame) == 0)
            {
                av_frame_unref(frame);
                av_frame_move_ref(frame, tmframe);
                return;
            }
        }
        av_frame_unref(tmframe);
    }
    vdp_output_surface_destroy(surface);
    return 0;
}

내부에 사용되고 있는 「외부」오브젝트가 몇개 있습니다만, 「get buffer」부분을 실장하면 이해할 수 있을 것입니다(앞의 예는 큰 도움이 됩니다).그리고 저는BGRA제 필요에 맞는 포맷을 선택해주실 수도 있습니다.

이 모든 것의 문제는 FFmpeg에서만 동작할 수 있는 것이 아니라 최소한 VDPAU API의 기본을 이해해야 한다는 것입니다.그리고 제 답변이 Linux에서 하드웨어 액셀러레이션을 구현하는 데 도움이 되기를 바랍니다.Linux에서 하드웨어 가속 디코딩을 구현하는 단순한 한 줄 방식이 없다는 것을 깨닫기 전까지 저는 많은 시간을 들여 이 문제에 임했습니다.

Linux VA-API

원래 VA-API에 대한 질문이었기 때문에 대답하지 않을 수 없습니다.우선 FFmpeg에는 VA-API 디코더가 없기 때문에avcodec_find_decoder_by_name("h264_vaapi")이치에 맞지 않다: 이 말은nullptrVA-API를 통한 디코딩이 얼마나 어려운지(혹은 더 간단한지) 모릅니다.지금까지 본 예들은 모두 매우 위협적이었습니다.그래서 저는 VA-API를 전혀 사용하지 않기로 선택했고 인텔 카드용 액셀러레이션을 구현해야 했습니다.다행히 VA-API 상에서 동작하는 VDPAU 라이브러리(드라이버?)가 있습니다.Intel 카드로 VDPAU를 사용할 수 있습니다.

다음 링크를 사용하여 Ubuntu에서 셋업했습니다.

또, @Timothy_G가 VA-API에 관한 링크도 언급하고 있는 원래의 질문에 대한 코멘트를 확인해 주세요.

언급URL : https://stackoverflow.com/questions/23289157/how-to-use-hardware-acceleration-with-ffmpeg

반응형