mirror of
https://github.com/Genymobile/scrcpy.git
synced 2025-04-21 03:55:05 +00:00
Merge dbea82e362
into d3d955f67b
This commit is contained in:
commit
687115a479
6 changed files with 89 additions and 17 deletions
|
@ -1,6 +1,7 @@
|
|||
#include "decoder.h"
|
||||
|
||||
#include <libavformat/avformat.h>
|
||||
#include <libavutil/imgutils.h>
|
||||
#include <libavutil/time.h>
|
||||
#include <SDL2/SDL_events.h>
|
||||
#include <SDL2/SDL_mutex.h>
|
||||
|
@ -15,6 +16,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 +76,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);
|
||||
|
@ -64,19 +99,32 @@ decoder_push(struct decoder *decoder, const AVPacket *packet) {
|
|||
// the new decoding/encoding API has been introduced by:
|
||||
// <http://git.videolan.org/?p=ffmpeg.git;a=commitdiff;h=7fc329e2dd6226dfecaa4a1d7adf353bf2773726>
|
||||
#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->decoding_frame);
|
||||
vb->hw_frame);
|
||||
if (!ret) {
|
||||
// a frame was received
|
||||
|
||||
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)) {
|
||||
LOGE("Could not receive video frame: %d", ret);
|
||||
return false;
|
||||
goto fail;
|
||||
}
|
||||
#else
|
||||
int got_picture;
|
||||
|
@ -93,6 +141,10 @@ decoder_push(struct decoder *decoder, const AVPacket *packet) {
|
|||
}
|
||||
#endif
|
||||
return true;
|
||||
|
||||
fail:
|
||||
LOGE("Could not receive video frame: %d", ret);
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -10,6 +10,7 @@ struct video_buffer;
|
|||
|
||||
struct decoder {
|
||||
struct video_buffer *video_buffer;
|
||||
AVBufferRef *hw_device_ctx;
|
||||
AVCodecContext *codec_ctx;
|
||||
};
|
||||
|
||||
|
|
|
@ -369,7 +369,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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include <assert.h>
|
||||
#include <SDL2/SDL_mutex.h>
|
||||
#include <libavutil/avutil.h>
|
||||
#include <libavutil/imgutils.h>
|
||||
#include <libavformat/avformat.h>
|
||||
|
||||
#include "config.h"
|
||||
|
@ -11,26 +12,37 @@
|
|||
|
||||
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->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_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_2;
|
||||
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_2;
|
||||
goto error_4;
|
||||
}
|
||||
// interrupted is not used if expired frames are not rendered
|
||||
// since offering a frame will never block
|
||||
|
@ -43,10 +55,14 @@ video_buffer_init(struct video_buffer *vb, struct fps_counter *fps_counter,
|
|||
|
||||
return true;
|
||||
|
||||
error_2:
|
||||
error_4:
|
||||
av_free(vb->out_buffer);
|
||||
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;
|
||||
}
|
||||
|
@ -57,8 +73,10 @@ 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);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
|
@ -5,14 +5,17 @@
|
|||
#include <SDL2/SDL_mutex.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "common.h"
|
||||
#include "fps_counter.h"
|
||||
|
||||
// forward declarations
|
||||
typedef struct AVFrame AVFrame;
|
||||
|
||||
struct video_buffer {
|
||||
AVFrame *hw_frame;
|
||||
AVFrame *decoding_frame;
|
||||
AVFrame *rendering_frame;
|
||||
void *out_buffer;
|
||||
SDL_mutex *mutex;
|
||||
bool render_expired_frames;
|
||||
bool interrupted;
|
||||
|
@ -23,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);
|
||||
|
|
Loading…
Add table
Reference in a new issue