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")
이치에 맞지 않다: 이 말은nullptr
VA-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
'programing' 카테고리의 다른 글
Vue2 - Vanilla ONKEYPRESS 함수를 메서드로 변환 (0) | 2022.07.02 |
---|---|
VueJS 줄바꿈 문자가 올바르게 렌더링되지 않음 (0) | 2022.07.02 |
getAttribute()와 getParameter()의 차이점 (0) | 2022.07.02 |
다른 구성 요소의 하위 구성 요소로 Vue 구성 요소 (0) | 2022.07.02 |
각각에 대해 내부에서 vue 데이터 개체에 액세스합니다. (0) | 2022.07.02 |