Use NV12 pixel format with VA-API

This gives better performance than yuv420p.

Signed-off-by: Park Ju Hyung <qkrwngud825@gmail.com>
This commit is contained in:
Park Ju Hyung 2020-11-09 20:28:49 +09:00
commit dbea82e362
5 changed files with 31 additions and 14 deletions

View file

@ -1,6 +1,7 @@
#include "decoder.h" #include "decoder.h"
#include <libavformat/avformat.h> #include <libavformat/avformat.h>
#include <libavutil/imgutils.h>
#include <libavutil/time.h> #include <libavutil/time.h>
#include <SDL2/SDL_events.h> #include <SDL2/SDL_events.h>
#include <SDL2/SDL_mutex.h> #include <SDL2/SDL_mutex.h>
@ -98,23 +99,29 @@ decoder_push(struct decoder *decoder, const AVPacket *packet) {
// the new decoding/encoding API has been introduced by: // the new decoding/encoding API has been introduced by:
// <http://git.videolan.org/?p=ffmpeg.git;a=commitdiff;h=7fc329e2dd6226dfecaa4a1d7adf353bf2773726> // <http://git.videolan.org/?p=ffmpeg.git;a=commitdiff;h=7fc329e2dd6226dfecaa4a1d7adf353bf2773726>
#ifdef SCRCPY_LAVF_HAS_NEW_ENCODING_DECODING_API #ifdef SCRCPY_LAVF_HAS_NEW_ENCODING_DECODING_API
struct video_buffer *vb = decoder->video_buffer;
AVFrame *rendering_frame = vb->rendering_frame;
int ret; int ret;
if ((ret = avcodec_send_packet(decoder->codec_ctx, packet)) < 0) { if ((ret = avcodec_send_packet(decoder->codec_ctx, packet)) < 0) {
LOGE("Could not send video packet: %d", ret); LOGE("Could not send video packet: %d", ret);
return false; return false;
} }
ret = avcodec_receive_frame(decoder->codec_ctx, ret = avcodec_receive_frame(decoder->codec_ctx,
decoder->video_buffer->hw_frame); vb->hw_frame);
if (!ret) { if (!ret) {
// a frame was received // a frame was received
ret = av_hwframe_transfer_data(decoder->video_buffer->decoding_frame, ret = av_hwframe_transfer_data(vb->decoding_frame,
decoder->video_buffer->hw_frame, 0); vb->hw_frame, 0);
if (ret < 0) { if (ret < 0) {
LOGE("Failed to transfer data to output frame: %d", ret); LOGE("Failed to transfer data to output frame: %d", ret);
goto fail; 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); push_frame(decoder);
} else if (ret != AVERROR(EAGAIN)) { } else if (ret != AVERROR(EAGAIN)) {
goto fail; goto fail;

View file

@ -361,7 +361,7 @@ scrcpy(const struct scrcpy_options *options) {
fps_counter_initialized = true; fps_counter_initialized = true;
if (!video_buffer_init(&video_buffer, &fps_counter, if (!video_buffer_init(&video_buffer, &fps_counter,
options->render_expired_frames)) { options->render_expired_frames, &frame_size)) {
goto end; goto end;
} }
video_buffer_initialized = true; video_buffer_initialized = true;

View file

@ -203,7 +203,7 @@ static inline SDL_Texture *
create_texture(struct screen *screen) { create_texture(struct screen *screen) {
SDL_Renderer *renderer = screen->renderer; SDL_Renderer *renderer = screen->renderer;
struct size size = screen->frame_size; 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, SDL_TEXTUREACCESS_STREAMING,
size.width, size.height); size.width, size.height);
if (!texture) { if (!texture) {
@ -442,10 +442,8 @@ prepare_for_frame(struct screen *screen, struct size new_frame_size) {
// write the frame into the texture // write the frame into the texture
static void static void
update_texture(struct screen *screen, const AVFrame *frame) { update_texture(struct screen *screen, const AVFrame *frame) {
SDL_UpdateYUVTexture(screen->texture, NULL, SDL_UpdateTexture(screen->texture, NULL,
frame->data[0], frame->linesize[0], frame->data[0], frame->linesize[0]);
frame->data[1], frame->linesize[1],
frame->data[2], frame->linesize[2]);
if (screen->mipmaps) { if (screen->mipmaps) {
assert(screen->use_opengl); assert(screen->use_opengl);

View file

@ -3,6 +3,7 @@
#include <assert.h> #include <assert.h>
#include <SDL2/SDL_mutex.h> #include <SDL2/SDL_mutex.h>
#include <libavutil/avutil.h> #include <libavutil/avutil.h>
#include <libavutil/imgutils.h>
#include <libavformat/avformat.h> #include <libavformat/avformat.h>
#include "config.h" #include "config.h"
@ -11,7 +12,7 @@
bool bool
video_buffer_init(struct video_buffer *vb, struct fps_counter *fps_counter, 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; vb->fps_counter = fps_counter;
if (!(vb->hw_frame = av_frame_alloc())) { 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())) { if (!(vb->decoding_frame = av_frame_alloc())) {
goto error_1; 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())) { if (!(vb->rendering_frame = av_frame_alloc())) {
goto error_2; 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())) { if (!(vb->mutex = SDL_CreateMutex())) {
goto error_3; goto error_4;
} }
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_3; goto error_4;
} }
// 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
@ -48,6 +55,8 @@ video_buffer_init(struct video_buffer *vb, struct fps_counter *fps_counter,
return true; return true;
error_4:
av_free(vb->out_buffer);
error_3: error_3:
av_frame_free(&vb->rendering_frame); av_frame_free(&vb->rendering_frame);
error_2: error_2:
@ -64,6 +73,7 @@ video_buffer_destroy(struct video_buffer *vb) {
SDL_DestroyCond(vb->rendering_frame_consumed_cond); SDL_DestroyCond(vb->rendering_frame_consumed_cond);
} }
SDL_DestroyMutex(vb->mutex); SDL_DestroyMutex(vb->mutex);
av_free(vb->out_buffer);
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); av_frame_free(&vb->hw_frame);

View file

@ -5,6 +5,7 @@
#include <SDL2/SDL_mutex.h> #include <SDL2/SDL_mutex.h>
#include "config.h" #include "config.h"
#include "common.h"
#include "fps_counter.h" #include "fps_counter.h"
// forward declarations // forward declarations
@ -14,6 +15,7 @@ struct video_buffer {
AVFrame *hw_frame; AVFrame *hw_frame;
AVFrame *decoding_frame; AVFrame *decoding_frame;
AVFrame *rendering_frame; AVFrame *rendering_frame;
void *out_buffer;
SDL_mutex *mutex; SDL_mutex *mutex;
bool render_expired_frames; bool render_expired_frames;
bool interrupted; bool interrupted;
@ -24,7 +26,7 @@ struct video_buffer {
bool bool
video_buffer_init(struct video_buffer *vb, struct fps_counter *fps_counter, video_buffer_init(struct video_buffer *vb, struct fps_counter *fps_counter,
bool render_expired_frames); bool render_expired_frames, struct size *size);
void void
video_buffer_destroy(struct video_buffer *vb); video_buffer_destroy(struct video_buffer *vb);