diff --git a/app/src/decoder.c b/app/src/decoder.c index 49d4ce86..49ec29c0 100644 --- a/app/src/decoder.c +++ b/app/src/decoder.c @@ -15,6 +15,37 @@ #include "util/buffer_util.h" #include "util/log.h" +static int hw_decoder_init(struct decoder *decoder) +{ + int ret; + + ret = av_hwdevice_ctx_create(&decoder->hw_device_ctx, + AV_HWDEVICE_TYPE_VAAPI, + NULL, NULL, 0); + if (ret < 0) { + LOGE("Failed to create specified HW device"); + return ret; + } + + decoder->codec_ctx->hw_device_ctx = av_buffer_ref(decoder->hw_device_ctx); + + return ret; +} + +static enum AVPixelFormat get_vaapi_format(__attribute__((unused)) AVCodecContext *ctx, + const enum AVPixelFormat *pix_fmts) +{ + const enum AVPixelFormat *p; + + for (p = pix_fmts; *p != AV_PIX_FMT_NONE; p++) { + if (*p == AV_PIX_FMT_VAAPI) + return *p; + } + + LOGE("Unable to decode using VA-API"); + return AV_PIX_FMT_NONE; +} + // set the decoded frame as ready for rendering, and notify static void push_frame(struct decoder *decoder) { @@ -44,6 +75,9 @@ decoder_open(struct decoder *decoder, const AVCodec *codec) { return false; } + hw_decoder_init(decoder); + decoder->codec_ctx->get_format = get_vaapi_format; + if (avcodec_open2(decoder->codec_ctx, codec, NULL) < 0) { LOGE("Could not open codec"); avcodec_free_context(&decoder->codec_ctx); @@ -70,13 +104,20 @@ decoder_push(struct decoder *decoder, const AVPacket *packet) { return false; } ret = avcodec_receive_frame(decoder->codec_ctx, - decoder->video_buffer->decoding_frame); + decoder->video_buffer->hw_frame); if (!ret) { // a frame was received + + ret = av_hwframe_transfer_data(decoder->video_buffer->decoding_frame, + decoder->video_buffer->hw_frame, 0); + if (ret < 0) { + LOGE("Failed to transfer data to output frame: %d", ret); + goto fail; + } + push_frame(decoder); } else if (ret != AVERROR(EAGAIN)) { - LOGE("Could not receive video frame: %d", ret); - return false; + goto fail; } #else int got_picture; @@ -93,6 +134,10 @@ decoder_push(struct decoder *decoder, const AVPacket *packet) { } #endif return true; + +fail: + LOGE("Could not receive video frame: %d", ret); + return false; } void diff --git a/app/src/decoder.h b/app/src/decoder.h index f243812c..ae9cc6a0 100644 --- a/app/src/decoder.h +++ b/app/src/decoder.h @@ -10,6 +10,7 @@ struct video_buffer; struct decoder { struct video_buffer *video_buffer; + AVBufferRef *hw_device_ctx; AVCodecContext *codec_ctx; }; diff --git a/app/src/video_buffer.c b/app/src/video_buffer.c index 629680d9..b62a9fdd 100644 --- a/app/src/video_buffer.c +++ b/app/src/video_buffer.c @@ -14,23 +14,28 @@ video_buffer_init(struct video_buffer *vb, struct fps_counter *fps_counter, bool render_expired_frames) { vb->fps_counter = fps_counter; - if (!(vb->decoding_frame = av_frame_alloc())) { + if (!(vb->hw_frame = av_frame_alloc())) { goto error_0; } - if (!(vb->rendering_frame = av_frame_alloc())) { + if (!(vb->decoding_frame = av_frame_alloc())) { goto error_1; } + vb->decoding_frame->format = AV_PIX_FMT_YUV420P; + + if (!(vb->rendering_frame = av_frame_alloc())) { + goto error_2; + } if (!(vb->mutex = SDL_CreateMutex())) { - goto error_2; + goto error_3; } vb->render_expired_frames = render_expired_frames; if (render_expired_frames) { if (!(vb->rendering_frame_consumed_cond = SDL_CreateCond())) { SDL_DestroyMutex(vb->mutex); - goto error_2; + goto error_3; } // interrupted is not used if expired frames are not rendered // since offering a frame will never block @@ -43,10 +48,12 @@ video_buffer_init(struct video_buffer *vb, struct fps_counter *fps_counter, return true; -error_2: +error_3: av_frame_free(&vb->rendering_frame); -error_1: +error_2: av_frame_free(&vb->decoding_frame); +error_1: + av_frame_free(&vb->hw_frame); error_0: return false; } @@ -59,6 +66,7 @@ video_buffer_destroy(struct video_buffer *vb) { SDL_DestroyMutex(vb->mutex); av_frame_free(&vb->rendering_frame); av_frame_free(&vb->decoding_frame); + av_frame_free(&vb->hw_frame); } static void diff --git a/app/src/video_buffer.h b/app/src/video_buffer.h index 303b3fc2..4424f3ac 100644 --- a/app/src/video_buffer.h +++ b/app/src/video_buffer.h @@ -11,6 +11,7 @@ typedef struct AVFrame AVFrame; struct video_buffer { + AVFrame *hw_frame; AVFrame *decoding_frame; AVFrame *rendering_frame; SDL_mutex *mutex;