Add --record-orientation
Add an option to store the orientation to apply in a recorded file. Only rotations are supported (not flips). PR #4441 <https://github.com/Genymobile/scrcpy/pull/4441>
This commit is contained in:
parent
2f92686930
commit
a9d6cb5837
@ -62,6 +62,7 @@ _scrcpy() {
|
|||||||
-r --record=
|
-r --record=
|
||||||
--raw-key-events
|
--raw-key-events
|
||||||
--record-format=
|
--record-format=
|
||||||
|
--record-orientation=
|
||||||
--render-driver=
|
--render-driver=
|
||||||
--require-audio
|
--require-audio
|
||||||
--rotation=
|
--rotation=
|
||||||
@ -117,6 +118,10 @@ _scrcpy() {
|
|||||||
COMPREPLY=($(compgen -> '0 90 180 270 flip0 flip90 flip180 flip270' -- "$cur"))
|
COMPREPLY=($(compgen -> '0 90 180 270 flip0 flip90 flip180 flip270' -- "$cur"))
|
||||||
return
|
return
|
||||||
;;
|
;;
|
||||||
|
--record-orientation)
|
||||||
|
COMPREPLY=($(compgen -> '0 90 180 270' -- "$cur"))
|
||||||
|
return
|
||||||
|
;;
|
||||||
--lock-video-orientation)
|
--lock-video-orientation)
|
||||||
COMPREPLY=($(compgen -W 'unlocked initial 0 90 180 270' -- "$cur"))
|
COMPREPLY=($(compgen -W 'unlocked initial 0 90 180 270' -- "$cur"))
|
||||||
return
|
return
|
||||||
|
@ -67,6 +67,7 @@ arguments=(
|
|||||||
{-r,--record=}'[Record screen to file]:record file:_files'
|
{-r,--record=}'[Record screen to file]:record file:_files'
|
||||||
'--raw-key-events[Inject key events for all input keys, and ignore text events]'
|
'--raw-key-events[Inject key events for all input keys, and ignore text events]'
|
||||||
'--record-format=[Force recording format]:format:(mp4 mkv m4a mka opus aac flac wav)'
|
'--record-format=[Force recording format]:format:(mp4 mkv m4a mka opus aac flac wav)'
|
||||||
|
'--record-orientation=[Set the record orientation]:orientation values:(0 90 180 270)'
|
||||||
'--render-driver=[Request SDL to use the given render driver]:driver name:(direct3d opengl opengles2 opengles metal software)'
|
'--render-driver=[Request SDL to use the given render driver]:driver name:(direct3d opengl opengles2 opengles metal software)'
|
||||||
'--require-audio=[Make scrcpy fail if audio is enabled but does not work]'
|
'--require-audio=[Make scrcpy fail if audio is enabled but does not work]'
|
||||||
{-s,--serial=}'[The device serial number \(mandatory for multiple devices only\)]:serial:($("${ADB-adb}" devices | awk '\''$2 == "device" {print $1}'\''))'
|
{-s,--serial=}'[The device serial number \(mandatory for multiple devices only\)]:serial:($("${ADB-adb}" devices | awk '\''$2 == "device" {print $1}'\''))'
|
||||||
|
@ -367,6 +367,14 @@ Inject key events for all input keys, and ignore text events.
|
|||||||
.BI "\-\-record\-format " format
|
.BI "\-\-record\-format " format
|
||||||
Force recording format (mp4, mkv, m4a, mka, opus, aac, flac or wav).
|
Force recording format (mp4, mkv, m4a, mka, opus, aac, flac or wav).
|
||||||
|
|
||||||
|
.TP
|
||||||
|
.BI "\-\-record\-orientation " value
|
||||||
|
Set the record orientation.
|
||||||
|
|
||||||
|
Possible values are 0, 90, 180 and 270. The number represents the clockwise rotation in degrees.
|
||||||
|
|
||||||
|
Default is 0.
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.BI "\-\-render\-driver " name
|
.BI "\-\-render\-driver " name
|
||||||
Request SDL to use the given render driver (this is just a hint).
|
Request SDL to use the given render driver (this is just a hint).
|
||||||
|
@ -91,6 +91,7 @@ enum {
|
|||||||
OPT_CAMERA_FPS,
|
OPT_CAMERA_FPS,
|
||||||
OPT_CAMERA_HIGH_SPEED,
|
OPT_CAMERA_HIGH_SPEED,
|
||||||
OPT_DISPLAY_ORIENTATION,
|
OPT_DISPLAY_ORIENTATION,
|
||||||
|
OPT_RECORD_ORIENTATION,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct sc_option {
|
struct sc_option {
|
||||||
@ -609,6 +610,15 @@ static const struct sc_option options[] = {
|
|||||||
.text = "Force recording format (mp4, mkv, m4a, mka, opus, aac, flac "
|
.text = "Force recording format (mp4, mkv, m4a, mka, opus, aac, flac "
|
||||||
"or wav).",
|
"or wav).",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
.longopt_id = OPT_RECORD_ORIENTATION,
|
||||||
|
.longopt = "record-orientation",
|
||||||
|
.argdesc = "value",
|
||||||
|
.text = "Set the record orientation.\n"
|
||||||
|
"Possible values are 0, 90, 180 and 270. The number represents "
|
||||||
|
"the clockwise rotation in degrees.\n"
|
||||||
|
"Default is 0.",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
.longopt_id = OPT_RENDER_DRIVER,
|
.longopt_id = OPT_RENDER_DRIVER,
|
||||||
.longopt = "render-driver",
|
.longopt = "render-driver",
|
||||||
@ -2131,6 +2141,11 @@ parse_args_with_getopt(struct scrcpy_cli_args *args, int argc, char *argv[],
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case OPT_RECORD_ORIENTATION:
|
||||||
|
if (!parse_orientation(optarg, &opts->record_orientation)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
case OPT_RENDER_DRIVER:
|
case OPT_RENDER_DRIVER:
|
||||||
opts->render_driver = optarg;
|
opts->render_driver = optarg;
|
||||||
break;
|
break;
|
||||||
@ -2497,6 +2512,15 @@ parse_args_with_getopt(struct scrcpy_cli_args *args, int argc, char *argv[],
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (opts->record_orientation != SC_ORIENTATION_0) {
|
||||||
|
if (sc_orientation_is_mirror(opts->record_orientation)) {
|
||||||
|
LOGE("Record orientation only supports rotation, not "
|
||||||
|
"flipping: %s",
|
||||||
|
sc_orientation_get_name(opts->record_orientation));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (opts->video
|
if (opts->video
|
||||||
&& sc_record_format_is_audio_only(opts->record_format)) {
|
&& sc_record_format_is_audio_only(opts->record_format)) {
|
||||||
LOGE("Audio container does not support video stream");
|
LOGE("Audio container does not support video stream");
|
||||||
|
@ -3,7 +3,9 @@
|
|||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
|
#include <libavcodec/version.h>
|
||||||
#include <libavformat/version.h>
|
#include <libavformat/version.h>
|
||||||
|
#include <libavutil/version.h>
|
||||||
#include <SDL2/SDL_version.h>
|
#include <SDL2/SDL_version.h>
|
||||||
|
|
||||||
#ifndef __WIN32
|
#ifndef __WIN32
|
||||||
@ -50,6 +52,15 @@
|
|||||||
# define SCRCPY_LAVU_HAS_CHLAYOUT
|
# define SCRCPY_LAVU_HAS_CHLAYOUT
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// In ffmpeg/doc/APIchanges:
|
||||||
|
// 2023-10-06 - 5432d2aacad - lavc 60.15.100 - avformat.h
|
||||||
|
// Deprecate AVFormatContext.{nb_,}side_data, av_stream_add_side_data(),
|
||||||
|
// av_stream_new_side_data(), and av_stream_get_side_data(). Side data fields
|
||||||
|
// from AVFormatContext.codecpar should be used from now on.
|
||||||
|
#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(60, 15, 100)
|
||||||
|
# define SCRCPY_LAVC_HAS_CODECPAR_CODEC_SIDEDATA
|
||||||
|
#endif
|
||||||
|
|
||||||
#if SDL_VERSION_ATLEAST(2, 0, 6)
|
#if SDL_VERSION_ATLEAST(2, 0, 6)
|
||||||
// <https://github.com/libsdl-org/SDL/commit/d7a318de563125e5bb465b1000d6bc9576fbc6fc>
|
// <https://github.com/libsdl-org/SDL/commit/d7a318de563125e5bb465b1000d6bc9576fbc6fc>
|
||||||
# define SCRCPY_SDL_HAS_HINT_TOUCH_MOUSE_EVENTS
|
# define SCRCPY_SDL_HAS_HINT_TOUCH_MOUSE_EVENTS
|
||||||
|
@ -40,6 +40,7 @@ const struct scrcpy_options scrcpy_options_default = {
|
|||||||
.max_fps = 0,
|
.max_fps = 0,
|
||||||
.lock_video_orientation = SC_LOCK_VIDEO_ORIENTATION_UNLOCKED,
|
.lock_video_orientation = SC_LOCK_VIDEO_ORIENTATION_UNLOCKED,
|
||||||
.display_orientation = SC_ORIENTATION_0,
|
.display_orientation = SC_ORIENTATION_0,
|
||||||
|
.record_orientation = SC_ORIENTATION_0,
|
||||||
.window_x = SC_WINDOW_POSITION_UNDEFINED,
|
.window_x = SC_WINDOW_POSITION_UNDEFINED,
|
||||||
.window_y = SC_WINDOW_POSITION_UNDEFINED,
|
.window_y = SC_WINDOW_POSITION_UNDEFINED,
|
||||||
.window_width = 0,
|
.window_width = 0,
|
||||||
|
@ -220,6 +220,7 @@ struct scrcpy_options {
|
|||||||
uint16_t max_fps;
|
uint16_t max_fps;
|
||||||
enum sc_lock_video_orientation lock_video_orientation;
|
enum sc_lock_video_orientation lock_video_orientation;
|
||||||
enum sc_orientation display_orientation;
|
enum sc_orientation display_orientation;
|
||||||
|
enum sc_orientation record_orientation;
|
||||||
int16_t window_x; // SC_WINDOW_POSITION_UNDEFINED for "auto"
|
int16_t window_x; // SC_WINDOW_POSITION_UNDEFINED for "auto"
|
||||||
int16_t window_y; // SC_WINDOW_POSITION_UNDEFINED for "auto"
|
int16_t window_y; // SC_WINDOW_POSITION_UNDEFINED for "auto"
|
||||||
uint16_t window_width;
|
uint16_t window_width;
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
#include <libavcodec/avcodec.h>
|
#include <libavcodec/avcodec.h>
|
||||||
#include <libavformat/avformat.h>
|
#include <libavformat/avformat.h>
|
||||||
#include <libavutil/time.h>
|
#include <libavutil/time.h>
|
||||||
|
#include <libavutil/display.h>
|
||||||
|
|
||||||
#include "util/log.h"
|
#include "util/log.h"
|
||||||
#include "util/str.h"
|
#include "util/str.h"
|
||||||
@ -493,6 +494,42 @@ run_recorder(void *data) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
sc_recorder_set_orientation(AVStream *stream, enum sc_orientation orientation) {
|
||||||
|
assert(!sc_orientation_is_mirror(orientation));
|
||||||
|
|
||||||
|
uint8_t *raw_data;
|
||||||
|
#ifdef SCRCPY_LAVC_HAS_CODECPAR_CODEC_SIDEDATA
|
||||||
|
AVPacketSideData *sd =
|
||||||
|
av_packet_side_data_new(&stream->codecpar->coded_side_data,
|
||||||
|
&stream->codecpar->nb_coded_side_data,
|
||||||
|
AV_PKT_DATA_DISPLAYMATRIX,
|
||||||
|
sizeof(int32_t) * 9, 0);
|
||||||
|
if (!sd) {
|
||||||
|
LOG_OOM();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
raw_data = sd->data;
|
||||||
|
#else
|
||||||
|
raw_data = av_stream_new_side_data(stream, AV_PKT_DATA_DISPLAYMATRIX,
|
||||||
|
sizeof(int32_t) * 9);
|
||||||
|
if (!raw_data) {
|
||||||
|
LOG_OOM();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int32_t *matrix = (int32_t *) raw_data;
|
||||||
|
|
||||||
|
unsigned rotation = orientation;
|
||||||
|
unsigned angle = rotation * 90;
|
||||||
|
|
||||||
|
av_display_rotation_set(matrix, angle);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
sc_recorder_video_packet_sink_open(struct sc_packet_sink *sink,
|
sc_recorder_video_packet_sink_open(struct sc_packet_sink *sink,
|
||||||
AVCodecContext *ctx) {
|
AVCodecContext *ctx) {
|
||||||
@ -520,6 +557,16 @@ sc_recorder_video_packet_sink_open(struct sc_packet_sink *sink,
|
|||||||
|
|
||||||
recorder->video_stream.index = stream->index;
|
recorder->video_stream.index = stream->index;
|
||||||
|
|
||||||
|
if (recorder->orientation != SC_ORIENTATION_0) {
|
||||||
|
if (!sc_recorder_set_orientation(stream, recorder->orientation)) {
|
||||||
|
sc_mutex_unlock(&recorder->mutex);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOGI("Record orientation set to %s",
|
||||||
|
sc_orientation_get_name(recorder->orientation));
|
||||||
|
}
|
||||||
|
|
||||||
recorder->video_init = true;
|
recorder->video_init = true;
|
||||||
sc_cond_signal(&recorder->cond);
|
sc_cond_signal(&recorder->cond);
|
||||||
sc_mutex_unlock(&recorder->mutex);
|
sc_mutex_unlock(&recorder->mutex);
|
||||||
@ -689,7 +736,10 @@ sc_recorder_stream_init(struct sc_recorder_stream *stream) {
|
|||||||
bool
|
bool
|
||||||
sc_recorder_init(struct sc_recorder *recorder, const char *filename,
|
sc_recorder_init(struct sc_recorder *recorder, const char *filename,
|
||||||
enum sc_record_format format, bool video, bool audio,
|
enum sc_record_format format, bool video, bool audio,
|
||||||
|
enum sc_orientation orientation,
|
||||||
const struct sc_recorder_callbacks *cbs, void *cbs_userdata) {
|
const struct sc_recorder_callbacks *cbs, void *cbs_userdata) {
|
||||||
|
assert(!sc_orientation_is_mirror(orientation));
|
||||||
|
|
||||||
recorder->filename = strdup(filename);
|
recorder->filename = strdup(filename);
|
||||||
if (!recorder->filename) {
|
if (!recorder->filename) {
|
||||||
LOG_OOM();
|
LOG_OOM();
|
||||||
@ -710,6 +760,8 @@ sc_recorder_init(struct sc_recorder *recorder, const char *filename,
|
|||||||
recorder->video = video;
|
recorder->video = video;
|
||||||
recorder->audio = audio;
|
recorder->audio = audio;
|
||||||
|
|
||||||
|
recorder->orientation = orientation;
|
||||||
|
|
||||||
sc_vecdeque_init(&recorder->video_queue);
|
sc_vecdeque_init(&recorder->video_queue);
|
||||||
sc_vecdeque_init(&recorder->audio_queue);
|
sc_vecdeque_init(&recorder->audio_queue);
|
||||||
recorder->stopped = false;
|
recorder->stopped = false;
|
||||||
|
@ -34,6 +34,8 @@ struct sc_recorder {
|
|||||||
bool audio;
|
bool audio;
|
||||||
bool video;
|
bool video;
|
||||||
|
|
||||||
|
enum sc_orientation orientation;
|
||||||
|
|
||||||
char *filename;
|
char *filename;
|
||||||
enum sc_record_format format;
|
enum sc_record_format format;
|
||||||
AVFormatContext *ctx;
|
AVFormatContext *ctx;
|
||||||
@ -67,6 +69,7 @@ struct sc_recorder_callbacks {
|
|||||||
bool
|
bool
|
||||||
sc_recorder_init(struct sc_recorder *recorder, const char *filename,
|
sc_recorder_init(struct sc_recorder *recorder, const char *filename,
|
||||||
enum sc_record_format format, bool video, bool audio,
|
enum sc_record_format format, bool video, bool audio,
|
||||||
|
enum sc_orientation orientation,
|
||||||
const struct sc_recorder_callbacks *cbs, void *cbs_userdata);
|
const struct sc_recorder_callbacks *cbs, void *cbs_userdata);
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
@ -507,7 +507,8 @@ scrcpy(struct scrcpy_options *options) {
|
|||||||
};
|
};
|
||||||
if (!sc_recorder_init(&s->recorder, options->record_filename,
|
if (!sc_recorder_init(&s->recorder, options->record_filename,
|
||||||
options->record_format, options->video,
|
options->record_format, options->video,
|
||||||
options->audio, &recorder_cbs, NULL)) {
|
options->audio, options->record_orientation,
|
||||||
|
&recorder_cbs, NULL)) {
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
recorder_initialized = true;
|
recorder_initialized = true;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user