Add --audio-codec-options
Similar to --video-codec-options, but for audio. PR #3757 <https://github.com/Genymobile/scrcpy/pull/3757>
This commit is contained in:
parent
58cf8e5401
commit
b03c864c70
12 changed files with 68 additions and 4 deletions
|
@ -4,6 +4,7 @@ _scrcpy() {
|
|||
--always-on-top
|
||||
--audio-bit-rate=
|
||||
--audio-codec=
|
||||
--audio-codec-options=
|
||||
-b --video-bit-rate=
|
||||
--crop=
|
||||
-d --select-usb
|
||||
|
|
|
@ -11,6 +11,7 @@ arguments=(
|
|||
'--always-on-top[Make scrcpy window always on top \(above other windows\)]'
|
||||
'--audio-bit-rate=[Encode the audio at the given bit-rate]'
|
||||
'--audio-codec=[Select the audio codec]:codec:(opus aac)'
|
||||
'--audio-codec-options=[Set a list of comma-separated key\:type=value options for the device audio encoder]'
|
||||
{-b,--video-bit-rate=}'[Encode the video at the given bit-rate]'
|
||||
'--crop=[\[width\:height\:x\:y\] Crop the device screen on the server]'
|
||||
{-d,--select-usb}'[Use USB device]'
|
||||
|
|
10
app/scrcpy.1
10
app/scrcpy.1
|
@ -31,6 +31,16 @@ Select an audio codec (opus or aac).
|
|||
|
||||
Default is opus.
|
||||
|
||||
.TP
|
||||
.BI "\-\-audio\-codec\-options " key\fR[:\fItype\fR]=\fIvalue\fR[,...]
|
||||
Set a list of comma-separated key:type=value options for the device audio encoder.
|
||||
|
||||
The possible values for 'type' are 'int' (default), 'long', 'float' and 'string'.
|
||||
|
||||
The list of possible codec options is available in the Android documentation
|
||||
.UR https://d.android.com/reference/android/media/MediaFormat
|
||||
.UE .
|
||||
|
||||
.TP
|
||||
.BI "\-b, \-\-video\-bit\-rate " value
|
||||
Encode the video at the given bit\-rate, expressed in bits/s. Unit suffixes are supported: '\fBK\fR' (x1000) and '\fBM\fR' (x1000000).
|
||||
|
|
|
@ -66,6 +66,7 @@ enum {
|
|||
OPT_NO_AUDIO,
|
||||
OPT_AUDIO_BIT_RATE,
|
||||
OPT_AUDIO_CODEC,
|
||||
OPT_AUDIO_CODEC_OPTIONS,
|
||||
};
|
||||
|
||||
struct sc_option {
|
||||
|
@ -122,6 +123,18 @@ static const struct sc_option options[] = {
|
|||
.text = "Select an audio codec (opus or aac).\n"
|
||||
"Default is opus.",
|
||||
},
|
||||
{
|
||||
.longopt_id = OPT_AUDIO_CODEC_OPTIONS,
|
||||
.longopt = "audio-codec-options",
|
||||
.argdesc = "key[:type]=value[,...]",
|
||||
.text = "Set a list of comma-separated key:type=value options for the "
|
||||
"device audio encoder.\n"
|
||||
"The possible values for 'type' are 'int' (default), 'long', "
|
||||
"'float' and 'string'.\n"
|
||||
"The list of possible codec options is available in the "
|
||||
"Android documentation: "
|
||||
"<https://d.android.com/reference/android/media/MediaFormat>",
|
||||
},
|
||||
{
|
||||
.shortopt = 'b',
|
||||
.longopt = "video-bit-rate",
|
||||
|
@ -1672,6 +1685,9 @@ parse_args_with_getopt(struct scrcpy_cli_args *args, int argc, char *argv[],
|
|||
case OPT_VIDEO_CODEC_OPTIONS:
|
||||
opts->video_codec_options = optarg;
|
||||
break;
|
||||
case OPT_AUDIO_CODEC_OPTIONS:
|
||||
opts->audio_codec_options = optarg;
|
||||
break;
|
||||
case OPT_ENCODER:
|
||||
LOGW("--encoder is deprecated, use --video-encoder instead.");
|
||||
// fall through
|
||||
|
|
|
@ -8,6 +8,7 @@ const struct scrcpy_options scrcpy_options_default = {
|
|||
.push_target = NULL,
|
||||
.render_driver = NULL,
|
||||
.video_codec_options = NULL,
|
||||
.audio_codec_options = NULL,
|
||||
.video_encoder = NULL,
|
||||
#ifdef HAVE_V4L2
|
||||
.v4l2_device = NULL,
|
||||
|
|
|
@ -96,6 +96,7 @@ struct scrcpy_options {
|
|||
const char *push_target;
|
||||
const char *render_driver;
|
||||
const char *video_codec_options;
|
||||
const char *audio_codec_options;
|
||||
const char *video_encoder;
|
||||
#ifdef HAVE_V4L2
|
||||
const char *v4l2_device;
|
||||
|
|
|
@ -331,6 +331,7 @@ scrcpy(struct scrcpy_options *options) {
|
|||
.show_touches = options->show_touches,
|
||||
.stay_awake = options->stay_awake,
|
||||
.video_codec_options = options->video_codec_options,
|
||||
.audio_codec_options = options->audio_codec_options,
|
||||
.video_encoder = options->video_encoder,
|
||||
.force_adb_forward = options->force_adb_forward,
|
||||
.power_off_on_close = options->power_off_on_close,
|
||||
|
|
|
@ -72,6 +72,7 @@ sc_server_params_destroy(struct sc_server_params *params) {
|
|||
free((char *) params->req_serial);
|
||||
free((char *) params->crop);
|
||||
free((char *) params->video_codec_options);
|
||||
free((char *) params->audio_codec_options);
|
||||
free((char *) params->video_encoder);
|
||||
free((char *) params->tcpip_dst);
|
||||
}
|
||||
|
@ -96,6 +97,7 @@ sc_server_params_copy(struct sc_server_params *dst,
|
|||
COPY(req_serial);
|
||||
COPY(crop);
|
||||
COPY(video_codec_options);
|
||||
COPY(audio_codec_options);
|
||||
COPY(video_encoder);
|
||||
COPY(tcpip_dst);
|
||||
#undef COPY
|
||||
|
@ -268,6 +270,9 @@ execute_server(struct sc_server *server,
|
|||
if (params->video_codec_options) {
|
||||
ADD_PARAM("video_codec_options=%s", params->video_codec_options);
|
||||
}
|
||||
if (params->audio_codec_options) {
|
||||
ADD_PARAM("audio_codec_options=%s", params->audio_codec_options);
|
||||
}
|
||||
if (params->video_encoder) {
|
||||
ADD_PARAM("video_encoder=%s", params->video_encoder);
|
||||
}
|
||||
|
|
|
@ -29,6 +29,7 @@ struct sc_server_params {
|
|||
enum sc_codec audio_codec;
|
||||
const char *crop;
|
||||
const char *video_codec_options;
|
||||
const char *audio_codec_options;
|
||||
const char *video_encoder;
|
||||
struct sc_port_range port_range;
|
||||
uint32_t tunnel_host;
|
||||
|
|
|
@ -15,6 +15,7 @@ import android.os.Looper;
|
|||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ArrayBlockingQueue;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
|
||||
|
@ -49,6 +50,7 @@ public final class AudioEncoder {
|
|||
|
||||
private final Streamer streamer;
|
||||
private final int bitRate;
|
||||
private final List<CodecOption> codecOptions;
|
||||
|
||||
// Capacity of 64 is in practice "infinite" (it is limited by the number of available MediaCodec buffers, typically 4).
|
||||
// So many pending tasks would lead to an unacceptable delay anyway.
|
||||
|
@ -63,9 +65,10 @@ public final class AudioEncoder {
|
|||
|
||||
private boolean ended;
|
||||
|
||||
public AudioEncoder(Streamer streamer, int bitRate) {
|
||||
public AudioEncoder(Streamer streamer, int bitRate, List<CodecOption> codecOptions) {
|
||||
this.streamer = streamer;
|
||||
this.bitRate = bitRate;
|
||||
this.codecOptions = codecOptions;
|
||||
}
|
||||
|
||||
private static AudioFormat createAudioFormat() {
|
||||
|
@ -92,12 +95,22 @@ public final class AudioEncoder {
|
|||
return builder.build();
|
||||
}
|
||||
|
||||
private static MediaFormat createFormat(String mimeType, int bitRate) {
|
||||
private static MediaFormat createFormat(String mimeType, int bitRate, List<CodecOption> codecOptions) {
|
||||
MediaFormat format = new MediaFormat();
|
||||
format.setString(MediaFormat.KEY_MIME, mimeType);
|
||||
format.setInteger(MediaFormat.KEY_BIT_RATE, bitRate);
|
||||
format.setInteger(MediaFormat.KEY_CHANNEL_COUNT, CHANNELS);
|
||||
format.setInteger(MediaFormat.KEY_SAMPLE_RATE, SAMPLE_RATE);
|
||||
|
||||
if (codecOptions != null) {
|
||||
for (CodecOption option : codecOptions) {
|
||||
String key = option.getKey();
|
||||
Object value = option.getValue();
|
||||
CodecUtils.setCodecOption(format, key, value);
|
||||
Ln.d("Audio codec option set: " + key + " (" + value.getClass().getSimpleName() + ") = " + value);
|
||||
}
|
||||
}
|
||||
|
||||
return format;
|
||||
}
|
||||
|
||||
|
@ -221,7 +234,7 @@ public final class AudioEncoder {
|
|||
mediaCodecThread = new HandlerThread("AudioEncoder");
|
||||
mediaCodecThread.start();
|
||||
|
||||
MediaFormat format = createFormat(mimeType, bitRate);
|
||||
MediaFormat format = createFormat(mimeType, bitRate, codecOptions);
|
||||
mediaCodec.setCallback(new EncoderCallback(), new Handler(mediaCodecThread.getLooper()));
|
||||
mediaCodec.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
|
||||
|
||||
|
|
|
@ -23,6 +23,8 @@ public class Options {
|
|||
private boolean showTouches;
|
||||
private boolean stayAwake;
|
||||
private List<CodecOption> videoCodecOptions;
|
||||
private List<CodecOption> audioCodecOptions;
|
||||
|
||||
private String videoEncoder;
|
||||
private boolean powerOffScreenOnClose;
|
||||
private boolean clipboardAutosync = true;
|
||||
|
@ -172,6 +174,14 @@ public class Options {
|
|||
this.videoCodecOptions = videoCodecOptions;
|
||||
}
|
||||
|
||||
public List<CodecOption> getAudioCodecOptions() {
|
||||
return audioCodecOptions;
|
||||
}
|
||||
|
||||
public void setAudioCodecOptions(List<CodecOption> audioCodecOptions) {
|
||||
this.audioCodecOptions = audioCodecOptions;
|
||||
}
|
||||
|
||||
public String getVideoEncoder() {
|
||||
return videoEncoder;
|
||||
}
|
||||
|
|
|
@ -111,7 +111,7 @@ public final class Server {
|
|||
if (audio) {
|
||||
Streamer audioStreamer = new Streamer(connection.getAudioFd(), options.getAudioCodec(), options.getSendCodecId(),
|
||||
options.getSendFrameMeta());
|
||||
audioEncoder = new AudioEncoder(audioStreamer, options.getAudioBitRate());
|
||||
audioEncoder = new AudioEncoder(audioStreamer, options.getAudioBitRate(), options.getAudioCodecOptions());
|
||||
audioEncoder.start();
|
||||
}
|
||||
|
||||
|
@ -258,6 +258,10 @@ public final class Server {
|
|||
List<CodecOption> videoCodecOptions = CodecOption.parse(value);
|
||||
options.setVideoCodecOptions(videoCodecOptions);
|
||||
break;
|
||||
case "audio_codec_options":
|
||||
List<CodecOption> audioCodecOptions = CodecOption.parse(value);
|
||||
options.setAudioCodecOptions(audioCodecOptions);
|
||||
break;
|
||||
case "video_encoder":
|
||||
if (!value.isEmpty()) {
|
||||
options.setVideoEncoder(value);
|
||||
|
|
Loading…
Reference in a new issue