mirror of
https://github.com/Genymobile/scrcpy.git
synced 2025-08-02 22:29:25 +00:00
Decode video using VA-API
Signed-off-by: Park Ju Hyung <qkrwngud825@gmail.com>
This commit is contained in:
parent
25aff00935
commit
d9224e15d0
4 changed files with 64 additions and 9 deletions
|
@ -15,6 +15,37 @@
|
||||||
#include "util/buffer_util.h"
|
#include "util/buffer_util.h"
|
||||||
#include "util/log.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
|
// set the decoded frame as ready for rendering, and notify
|
||||||
static void
|
static void
|
||||||
push_frame(struct decoder *decoder) {
|
push_frame(struct decoder *decoder) {
|
||||||
|
@ -44,6 +75,9 @@ decoder_open(struct decoder *decoder, const AVCodec *codec) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hw_decoder_init(decoder);
|
||||||
|
decoder->codec_ctx->get_format = get_vaapi_format;
|
||||||
|
|
||||||
if (avcodec_open2(decoder->codec_ctx, codec, NULL) < 0) {
|
if (avcodec_open2(decoder->codec_ctx, codec, NULL) < 0) {
|
||||||
LOGE("Could not open codec");
|
LOGE("Could not open codec");
|
||||||
avcodec_free_context(&decoder->codec_ctx);
|
avcodec_free_context(&decoder->codec_ctx);
|
||||||
|
@ -70,13 +104,20 @@ decoder_push(struct decoder *decoder, const AVPacket *packet) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
ret = avcodec_receive_frame(decoder->codec_ctx,
|
ret = avcodec_receive_frame(decoder->codec_ctx,
|
||||||
decoder->video_buffer->decoding_frame);
|
decoder->video_buffer->hw_frame);
|
||||||
if (!ret) {
|
if (!ret) {
|
||||||
// a frame was received
|
// 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);
|
push_frame(decoder);
|
||||||
} else if (ret != AVERROR(EAGAIN)) {
|
} else if (ret != AVERROR(EAGAIN)) {
|
||||||
LOGE("Could not receive video frame: %d", ret);
|
goto fail;
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
int got_picture;
|
int got_picture;
|
||||||
|
@ -93,6 +134,10 @@ decoder_push(struct decoder *decoder, const AVPacket *packet) {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
LOGE("Could not receive video frame: %d", ret);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -10,6 +10,7 @@ struct video_buffer;
|
||||||
|
|
||||||
struct decoder {
|
struct decoder {
|
||||||
struct video_buffer *video_buffer;
|
struct video_buffer *video_buffer;
|
||||||
|
AVBufferRef *hw_device_ctx;
|
||||||
AVCodecContext *codec_ctx;
|
AVCodecContext *codec_ctx;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -14,23 +14,28 @@ video_buffer_init(struct video_buffer *vb, struct fps_counter *fps_counter,
|
||||||
bool render_expired_frames) {
|
bool render_expired_frames) {
|
||||||
vb->fps_counter = fps_counter;
|
vb->fps_counter = fps_counter;
|
||||||
|
|
||||||
if (!(vb->decoding_frame = av_frame_alloc())) {
|
if (!(vb->hw_frame = av_frame_alloc())) {
|
||||||
goto error_0;
|
goto error_0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(vb->rendering_frame = av_frame_alloc())) {
|
if (!(vb->decoding_frame = av_frame_alloc())) {
|
||||||
goto error_1;
|
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())) {
|
if (!(vb->mutex = SDL_CreateMutex())) {
|
||||||
goto error_2;
|
goto error_3;
|
||||||
}
|
}
|
||||||
|
|
||||||
vb->render_expired_frames = render_expired_frames;
|
vb->render_expired_frames = render_expired_frames;
|
||||||
if (render_expired_frames) {
|
if (render_expired_frames) {
|
||||||
if (!(vb->rendering_frame_consumed_cond = SDL_CreateCond())) {
|
if (!(vb->rendering_frame_consumed_cond = SDL_CreateCond())) {
|
||||||
SDL_DestroyMutex(vb->mutex);
|
SDL_DestroyMutex(vb->mutex);
|
||||||
goto error_2;
|
goto error_3;
|
||||||
}
|
}
|
||||||
// interrupted is not used if expired frames are not rendered
|
// interrupted is not used if expired frames are not rendered
|
||||||
// since offering a frame will never block
|
// 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;
|
return true;
|
||||||
|
|
||||||
error_2:
|
error_3:
|
||||||
av_frame_free(&vb->rendering_frame);
|
av_frame_free(&vb->rendering_frame);
|
||||||
error_1:
|
error_2:
|
||||||
av_frame_free(&vb->decoding_frame);
|
av_frame_free(&vb->decoding_frame);
|
||||||
|
error_1:
|
||||||
|
av_frame_free(&vb->hw_frame);
|
||||||
error_0:
|
error_0:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -59,6 +66,7 @@ video_buffer_destroy(struct video_buffer *vb) {
|
||||||
SDL_DestroyMutex(vb->mutex);
|
SDL_DestroyMutex(vb->mutex);
|
||||||
av_frame_free(&vb->rendering_frame);
|
av_frame_free(&vb->rendering_frame);
|
||||||
av_frame_free(&vb->decoding_frame);
|
av_frame_free(&vb->decoding_frame);
|
||||||
|
av_frame_free(&vb->hw_frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
typedef struct AVFrame AVFrame;
|
typedef struct AVFrame AVFrame;
|
||||||
|
|
||||||
struct video_buffer {
|
struct video_buffer {
|
||||||
|
AVFrame *hw_frame;
|
||||||
AVFrame *decoding_frame;
|
AVFrame *decoding_frame;
|
||||||
AVFrame *rendering_frame;
|
AVFrame *rendering_frame;
|
||||||
SDL_mutex *mutex;
|
SDL_mutex *mutex;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue