From dbea82e362af277ff4633fb792a494e38f686d87 Mon Sep 17 00:00:00 2001 From: Park Ju Hyung Date: Mon, 9 Nov 2020 20:28:49 +0900 Subject: [PATCH] Use NV12 pixel format with VA-API This gives better performance than yuv420p. Signed-off-by: Park Ju Hyung --- app/src/decoder.c | 13 ++++++++++--- app/src/scrcpy.c | 2 +- app/src/screen.c | 8 +++----- app/src/video_buffer.c | 18 ++++++++++++++---- app/src/video_buffer.h | 4 +++- 5 files changed, 31 insertions(+), 14 deletions(-) diff --git a/app/src/decoder.c b/app/src/decoder.c index 49ec29c0..ef805f05 100644 --- a/app/src/decoder.c +++ b/app/src/decoder.c @@ -1,6 +1,7 @@ #include "decoder.h" #include +#include #include #include #include @@ -98,23 +99,29 @@ decoder_push(struct decoder *decoder, const AVPacket *packet) { // the new decoding/encoding API has been introduced by: // #ifdef SCRCPY_LAVF_HAS_NEW_ENCODING_DECODING_API + struct video_buffer *vb = decoder->video_buffer; + AVFrame *rendering_frame = vb->rendering_frame; int ret; if ((ret = avcodec_send_packet(decoder->codec_ctx, packet)) < 0) { LOGE("Could not send video packet: %d", ret); return false; } ret = avcodec_receive_frame(decoder->codec_ctx, - decoder->video_buffer->hw_frame); + vb->hw_frame); if (!ret) { // a frame was received - ret = av_hwframe_transfer_data(decoder->video_buffer->decoding_frame, - decoder->video_buffer->hw_frame, 0); + ret = av_hwframe_transfer_data(vb->decoding_frame, + vb->hw_frame, 0); if (ret < 0) { LOGE("Failed to transfer data to output frame: %d", ret); goto fail; } + av_image_fill_arrays(rendering_frame->data, rendering_frame->linesize, + vb->out_buffer, AV_PIX_FMT_NV12, + rendering_frame->width, rendering_frame->height, 1); + push_frame(decoder); } else if (ret != AVERROR(EAGAIN)) { goto fail; diff --git a/app/src/scrcpy.c b/app/src/scrcpy.c index 45068cbb..7512b086 100644 --- a/app/src/scrcpy.c +++ b/app/src/scrcpy.c @@ -361,7 +361,7 @@ scrcpy(const struct scrcpy_options *options) { fps_counter_initialized = true; if (!video_buffer_init(&video_buffer, &fps_counter, - options->render_expired_frames)) { + options->render_expired_frames, &frame_size)) { goto end; } video_buffer_initialized = true; diff --git a/app/src/screen.c b/app/src/screen.c index fe2bc867..e4fc638f 100644 --- a/app/src/screen.c +++ b/app/src/screen.c @@ -203,7 +203,7 @@ static inline SDL_Texture * create_texture(struct screen *screen) { SDL_Renderer *renderer = screen->renderer; struct size size = screen->frame_size; - SDL_Texture *texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_YV12, + SDL_Texture *texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_NV12, SDL_TEXTUREACCESS_STREAMING, size.width, size.height); if (!texture) { @@ -442,10 +442,8 @@ prepare_for_frame(struct screen *screen, struct size new_frame_size) { // write the frame into the texture static void update_texture(struct screen *screen, const AVFrame *frame) { - SDL_UpdateYUVTexture(screen->texture, NULL, - frame->data[0], frame->linesize[0], - frame->data[1], frame->linesize[1], - frame->data[2], frame->linesize[2]); + SDL_UpdateTexture(screen->texture, NULL, + frame->data[0], frame->linesize[0]); if (screen->mipmaps) { assert(screen->use_opengl); diff --git a/app/src/video_buffer.c b/app/src/video_buffer.c index b62a9fdd..7401962b 100644 --- a/app/src/video_buffer.c +++ b/app/src/video_buffer.c @@ -3,6 +3,7 @@ #include #include #include +#include #include #include "config.h" @@ -11,7 +12,7 @@ bool video_buffer_init(struct video_buffer *vb, struct fps_counter *fps_counter, - bool render_expired_frames) { + bool render_expired_frames, struct size *size) { vb->fps_counter = fps_counter; if (!(vb->hw_frame = av_frame_alloc())) { @@ -21,21 +22,27 @@ video_buffer_init(struct video_buffer *vb, struct fps_counter *fps_counter, if (!(vb->decoding_frame = av_frame_alloc())) { goto error_1; } - vb->decoding_frame->format = AV_PIX_FMT_YUV420P; + vb->decoding_frame->format = AV_PIX_FMT_NV12; if (!(vb->rendering_frame = av_frame_alloc())) { goto error_2; } + vb->rendering_frame->format = AV_PIX_FMT_NV12; + + vb->out_buffer = av_malloc(av_image_get_buffer_size(AV_PIX_FMT_NV12, size->width, size->height, 1)); + if (!vb->out_buffer) { + goto error_3; + } if (!(vb->mutex = SDL_CreateMutex())) { - goto error_3; + goto error_4; } 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_3; + goto error_4; } // interrupted is not used if expired frames are not rendered // since offering a frame will never block @@ -48,6 +55,8 @@ video_buffer_init(struct video_buffer *vb, struct fps_counter *fps_counter, return true; +error_4: + av_free(vb->out_buffer); error_3: av_frame_free(&vb->rendering_frame); error_2: @@ -64,6 +73,7 @@ video_buffer_destroy(struct video_buffer *vb) { SDL_DestroyCond(vb->rendering_frame_consumed_cond); } SDL_DestroyMutex(vb->mutex); + av_free(vb->out_buffer); av_frame_free(&vb->rendering_frame); av_frame_free(&vb->decoding_frame); av_frame_free(&vb->hw_frame); diff --git a/app/src/video_buffer.h b/app/src/video_buffer.h index 4424f3ac..2121be36 100644 --- a/app/src/video_buffer.h +++ b/app/src/video_buffer.h @@ -5,6 +5,7 @@ #include #include "config.h" +#include "common.h" #include "fps_counter.h" // forward declarations @@ -14,6 +15,7 @@ struct video_buffer { AVFrame *hw_frame; AVFrame *decoding_frame; AVFrame *rendering_frame; + void *out_buffer; SDL_mutex *mutex; bool render_expired_frames; bool interrupted; @@ -24,7 +26,7 @@ struct video_buffer { bool video_buffer_init(struct video_buffer *vb, struct fps_counter *fps_counter, - bool render_expired_frames); + bool render_expired_frames, struct size *size); void video_buffer_destroy(struct video_buffer *vb);