Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e93fd94842 | ||
|
|
e131b9c667 | ||
|
|
e1a009de5d | ||
|
|
7d4aedc29a |
@@ -28,6 +28,7 @@ sc_demuxer_recv_codec_id(struct sc_demuxer *demuxer) {
|
|||||||
#define SC_CODEC_ID_H264 UINT32_C(0x68323634) // "h264" in ASCII
|
#define SC_CODEC_ID_H264 UINT32_C(0x68323634) // "h264" in ASCII
|
||||||
#define SC_CODEC_ID_H265 UINT32_C(0x68323635) // "h265" in ASCII
|
#define SC_CODEC_ID_H265 UINT32_C(0x68323635) // "h265" in ASCII
|
||||||
#define SC_CODEC_ID_AV1 UINT32_C(0x00617631) // "av1" in ASCII
|
#define SC_CODEC_ID_AV1 UINT32_C(0x00617631) // "av1" in ASCII
|
||||||
|
#define SC_CODEC_ID_OPUS UINT32_C(0x6f707573) // "opus" in ASCII
|
||||||
uint32_t codec_id = sc_read32be(data);
|
uint32_t codec_id = sc_read32be(data);
|
||||||
switch (codec_id) {
|
switch (codec_id) {
|
||||||
case SC_CODEC_ID_H264:
|
case SC_CODEC_ID_H264:
|
||||||
@@ -36,6 +37,8 @@ sc_demuxer_recv_codec_id(struct sc_demuxer *demuxer) {
|
|||||||
return AV_CODEC_ID_HEVC;
|
return AV_CODEC_ID_HEVC;
|
||||||
case SC_CODEC_ID_AV1:
|
case SC_CODEC_ID_AV1:
|
||||||
return AV_CODEC_ID_AV1;
|
return AV_CODEC_ID_AV1;
|
||||||
|
case SC_CODEC_ID_OPUS:
|
||||||
|
return AV_CODEC_ID_OPUS;
|
||||||
default:
|
default:
|
||||||
LOGE("Unknown codec id 0x%08" PRIx32, codec_id);
|
LOGE("Unknown codec id 0x%08" PRIx32, codec_id);
|
||||||
return AV_CODEC_ID_NONE;
|
return AV_CODEC_ID_NONE;
|
||||||
@@ -270,10 +273,12 @@ end:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
sc_demuxer_init(struct sc_demuxer *demuxer, sc_socket socket,
|
sc_demuxer_init(struct sc_demuxer *demuxer, enum sc_stream_id stream_id,
|
||||||
const struct sc_demuxer_callbacks *cbs, void *cbs_userdata) {
|
sc_socket socket, const struct sc_demuxer_callbacks *cbs,
|
||||||
|
void *cbs_userdata) {
|
||||||
assert(socket != SC_SOCKET_NONE);
|
assert(socket != SC_SOCKET_NONE);
|
||||||
|
|
||||||
|
demuxer->stream_id = stream_id;
|
||||||
demuxer->socket = socket;
|
demuxer->socket = socket;
|
||||||
demuxer->pending = NULL;
|
demuxer->pending = NULL;
|
||||||
demuxer->sink_count = 0;
|
demuxer->sink_count = 0;
|
||||||
|
|||||||
@@ -14,7 +14,13 @@
|
|||||||
|
|
||||||
#define SC_DEMUXER_MAX_SINKS 2
|
#define SC_DEMUXER_MAX_SINKS 2
|
||||||
|
|
||||||
|
enum sc_stream_id {
|
||||||
|
SC_STREAM_ID_VIDEO,
|
||||||
|
SC_STREAM_ID_AUDIO,
|
||||||
|
};
|
||||||
|
|
||||||
struct sc_demuxer {
|
struct sc_demuxer {
|
||||||
|
enum sc_stream_id stream_id;
|
||||||
sc_socket socket;
|
sc_socket socket;
|
||||||
sc_thread thread;
|
sc_thread thread;
|
||||||
|
|
||||||
@@ -36,8 +42,9 @@ struct sc_demuxer_callbacks {
|
|||||||
};
|
};
|
||||||
|
|
||||||
void
|
void
|
||||||
sc_demuxer_init(struct sc_demuxer *demuxer, sc_socket socket,
|
sc_demuxer_init(struct sc_demuxer *demuxer, enum sc_stream_id stream_id,
|
||||||
const struct sc_demuxer_callbacks *cbs, void *cbs_userdata);
|
sc_socket socket, const struct sc_demuxer_callbacks *cbs,
|
||||||
|
void *cbs_userdata);
|
||||||
|
|
||||||
void
|
void
|
||||||
sc_demuxer_add_sink(struct sc_demuxer *demuxer, struct sc_packet_sink *sink);
|
sc_demuxer_add_sink(struct sc_demuxer *demuxer, struct sc_packet_sink *sink);
|
||||||
|
|||||||
@@ -434,15 +434,15 @@ scrcpy(struct scrcpy_options *options) {
|
|||||||
static const struct sc_demuxer_callbacks video_demuxer_cbs = {
|
static const struct sc_demuxer_callbacks video_demuxer_cbs = {
|
||||||
.on_eos = sc_video_demuxer_on_eos,
|
.on_eos = sc_video_demuxer_on_eos,
|
||||||
};
|
};
|
||||||
sc_demuxer_init(&s->video_demuxer, s->server.video_socket,
|
sc_demuxer_init(&s->video_demuxer, SC_STREAM_ID_VIDEO,
|
||||||
&video_demuxer_cbs, NULL);
|
s->server.video_socket, &video_demuxer_cbs, NULL);
|
||||||
|
|
||||||
if (options->audio) {
|
if (options->audio) {
|
||||||
static const struct sc_demuxer_callbacks audio_demuxer_cbs = {
|
static const struct sc_demuxer_callbacks audio_demuxer_cbs = {
|
||||||
.on_eos = sc_audio_demuxer_on_eos,
|
.on_eos = sc_audio_demuxer_on_eos,
|
||||||
};
|
};
|
||||||
sc_demuxer_init(&s->audio_demuxer, s->server.audio_socket,
|
sc_demuxer_init(&s->audio_demuxer, SC_STREAM_ID_AUDIO,
|
||||||
&audio_demuxer_cbs, NULL);
|
s->server.audio_socket, &audio_demuxer_cbs, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dec) {
|
if (dec) {
|
||||||
|
|||||||
@@ -47,11 +47,11 @@ public final class AudioEncoder {
|
|||||||
private static int BUFFER_MS = 15; // milliseconds
|
private static int BUFFER_MS = 15; // milliseconds
|
||||||
private static final int BUFFER_SIZE = SAMPLE_RATE * CHANNELS * BUFFER_MS / 1000;
|
private static final int BUFFER_SIZE = SAMPLE_RATE * CHANNELS * BUFFER_MS / 1000;
|
||||||
|
|
||||||
|
private final Streamer streamer;
|
||||||
|
|
||||||
private AudioRecord recorder;
|
private AudioRecord recorder;
|
||||||
private MediaCodec mediaCodec;
|
private MediaCodec mediaCodec;
|
||||||
|
|
||||||
private final AtomicBoolean cleanUpDone = new AtomicBoolean(false);
|
|
||||||
|
|
||||||
// Capacity of 64 is in practice "infinite" (it is limited by the number of available MediaCodec buffers, typically 4).
|
// 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.
|
// So many pending tasks would lead to an unacceptable delay anyway.
|
||||||
private final BlockingQueue<InputTask> inputTasks = new ArrayBlockingQueue<>(64);
|
private final BlockingQueue<InputTask> inputTasks = new ArrayBlockingQueue<>(64);
|
||||||
@@ -65,6 +65,10 @@ public final class AudioEncoder {
|
|||||||
|
|
||||||
private boolean ended;
|
private boolean ended;
|
||||||
|
|
||||||
|
public AudioEncoder(Streamer streamer) {
|
||||||
|
this.streamer = streamer;
|
||||||
|
}
|
||||||
|
|
||||||
private static AudioFormat createAudioFormat() {
|
private static AudioFormat createAudioFormat() {
|
||||||
AudioFormat.Builder builder = new AudioFormat.Builder();
|
AudioFormat.Builder builder = new AudioFormat.Builder();
|
||||||
builder.setEncoding(AudioFormat.ENCODING_PCM_16BIT);
|
builder.setEncoding(AudioFormat.ENCODING_PCM_16BIT);
|
||||||
@@ -142,11 +146,13 @@ public final class AudioEncoder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void outputThread() throws IOException, InterruptedException {
|
private void outputThread() throws IOException, InterruptedException {
|
||||||
|
streamer.writeHeader();
|
||||||
|
|
||||||
while (!Thread.currentThread().isInterrupted()) {
|
while (!Thread.currentThread().isInterrupted()) {
|
||||||
OutputTask task = outputTasks.take();
|
OutputTask task = outputTasks.take();
|
||||||
ByteBuffer buffer = mediaCodec.getOutputBuffer(task.index);
|
ByteBuffer buffer = mediaCodec.getOutputBuffer(task.index);
|
||||||
try {
|
try {
|
||||||
Ln.i("Audio packet [pts=" + task.bufferInfo.presentationTimeUs + "] " + buffer.remaining() + " bytes");
|
streamer.writePacket(buffer, task.bufferInfo);
|
||||||
} finally {
|
} finally {
|
||||||
mediaCodec.releaseOutputBuffer(task.index, false);
|
mediaCodec.releaseOutputBuffer(task.index, false);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -111,7 +111,8 @@ public final class Server {
|
|||||||
|
|
||||||
AudioEncoder audioEncoder = null;
|
AudioEncoder audioEncoder = null;
|
||||||
if (audio) {
|
if (audio) {
|
||||||
audioEncoder = new AudioEncoder();
|
Streamer audioStreamer = new Streamer(connection.getAudioFd(), AudioCodec.OPUS, options.getSendCodecId(), options.getSendFrameMeta());
|
||||||
|
audioEncoder = new AudioEncoder(audioStreamer);
|
||||||
audioEncoder.start();
|
audioEncoder.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user