mirror of
https://github.com/morgan9e/UxPlay
synced 2026-04-14 00:04:13 +09:00
clean up SPS/PPS prepend code (for IDR frames) + cosmetic cleanups
This commit is contained in:
@@ -28,7 +28,6 @@
|
||||
#include <stdio.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
//#define DUMP_KEI_IV
|
||||
struct mirror_buffer_s {
|
||||
logger_t *logger;
|
||||
aes_ctx_t *aes_ctx;
|
||||
@@ -66,13 +65,6 @@ mirror_buffer_init_aes(mirror_buffer_t *mirror_buffer, const uint64_t *streamCon
|
||||
|
||||
// Need to be initialized externally
|
||||
mirror_buffer->aes_ctx = aes_ctr_init(aeskey_video, aesiv_video);
|
||||
|
||||
#ifdef DUMP_KEI_IV
|
||||
FILE* keyfile = fopen("/sdcard/111.keyiv", "wb");
|
||||
fwrite(aeskey_video, 16, 1, keyfile);
|
||||
fwrite(aesiv_video, 16, 1, keyfile);
|
||||
fclose(keyfile);
|
||||
#endif
|
||||
}
|
||||
|
||||
mirror_buffer_t *
|
||||
|
||||
@@ -79,14 +79,6 @@ raop_buffer_init(logger_t *logger,
|
||||
// Need to be initialized internally
|
||||
raop_buffer->aes_ctx = aes_cbc_init(aeskey, aesiv, AES_DECRYPT);
|
||||
|
||||
#ifdef DUMP_AUDIO
|
||||
if (file_keyiv != NULL) {
|
||||
fwrite(aeskey, 16, 1, file_keyiv);
|
||||
fwrite(aesiv, 16, 1, file_keyiv);
|
||||
fclose(file_keyiv);
|
||||
}
|
||||
#endif
|
||||
|
||||
for (int i = 0; i < RAOP_BUFFER_LENGTH; i++) {
|
||||
raop_buffer_entry_t *entry = &raop_buffer->entries[i];
|
||||
entry->payload_data = NULL;
|
||||
@@ -113,15 +105,6 @@ raop_buffer_destroy(raop_buffer_t *raop_buffer)
|
||||
free(raop_buffer);
|
||||
}
|
||||
|
||||
#ifdef DUMP_AUDIO
|
||||
if (file_aac != NULL) {
|
||||
fclose(file_aac);
|
||||
}
|
||||
if (file_source != NULL) {
|
||||
fclose(file_source);
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
static short
|
||||
@@ -130,32 +113,11 @@ seqnum_cmp(unsigned short s1, unsigned short s2)
|
||||
return (s1 - s2);
|
||||
}
|
||||
|
||||
//#define DUMP_AUDIO
|
||||
|
||||
#ifdef DUMP_AUDIO
|
||||
static FILE* file_aac = NULL;
|
||||
static FILE* file_source = NULL;
|
||||
static FILE* file_keyiv = NULL;
|
||||
#endif
|
||||
|
||||
|
||||
int
|
||||
raop_buffer_decrypt(raop_buffer_t *raop_buffer, unsigned char *data, unsigned char* output, unsigned int payload_size, unsigned int *outputlen)
|
||||
{
|
||||
assert(raop_buffer);
|
||||
int encryptedlen;
|
||||
#ifdef DUMP_AUDIO
|
||||
if (file_aac == NULL) {
|
||||
file_aac = fopen("/home/pi/Airplay.aac", "wb");
|
||||
file_source = fopen("/home/pi/Airplay.source", "wb");
|
||||
file_keyiv = fopen("/home/pi/Airplay.keyiv", "wb");
|
||||
}
|
||||
// Undecrypted file
|
||||
if (file_source != NULL) {
|
||||
fwrite(&data[12], payloadsize, 1, file_source);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (DECRYPTION_TEST) {
|
||||
char *str = utils_data_to_string(data,12,12);
|
||||
logger_log(raop_buffer->logger, LOGGER_INFO, "encrypted 12 byte header %s", str);
|
||||
@@ -199,13 +161,6 @@ raop_buffer_decrypt(raop_buffer_t *raop_buffer, unsigned char *data, unsigned ch
|
||||
free(str);
|
||||
}
|
||||
}
|
||||
#ifdef DUMP_AUDIO
|
||||
// Decrypted file
|
||||
if (file_aac != NULL) {
|
||||
fwrite(output, payloadsize, 1, file_aac);
|
||||
}
|
||||
#endif
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -104,12 +104,6 @@ struct raop_rtp_mirror_s {
|
||||
|
||||
/* switch for displaying client FPS data */
|
||||
uint8_t show_client_FPS_data;
|
||||
|
||||
/* SPS and PPS */
|
||||
int sps_pps_len;
|
||||
unsigned char* sps_pps;
|
||||
bool sps_pps_waiting;
|
||||
|
||||
};
|
||||
|
||||
static int
|
||||
@@ -154,9 +148,6 @@ raop_rtp_mirror_t *raop_rtp_mirror_init(logger_t *logger, raop_callbacks_t *call
|
||||
}
|
||||
raop_rtp_mirror->logger = logger;
|
||||
raop_rtp_mirror->ntp = ntp;
|
||||
raop_rtp_mirror->sps_pps_len = 0;
|
||||
raop_rtp_mirror->sps_pps = NULL;
|
||||
raop_rtp_mirror->sps_pps_waiting = false;
|
||||
|
||||
memcpy(&raop_rtp_mirror->callbacks, callbacks, sizeof(raop_callbacks_t));
|
||||
raop_rtp_mirror->buffer = mirror_buffer_init(logger, aeskey);
|
||||
@@ -182,8 +173,6 @@ raop_rtp_init_mirror_aes(raop_rtp_mirror_t *raop_rtp_mirror, uint64_t *streamCon
|
||||
mirror_buffer_init_aes(raop_rtp_mirror->buffer, streamConnectionID);
|
||||
}
|
||||
|
||||
//#define DUMP_H264
|
||||
|
||||
#define RAOP_PACKET_LEN 32768
|
||||
/**
|
||||
* Mirror
|
||||
@@ -197,6 +186,9 @@ raop_rtp_mirror_thread(void *arg)
|
||||
int stream_fd = -1;
|
||||
unsigned char packet[128];
|
||||
memset(packet, 0 , 128);
|
||||
unsigned char* sps_pps = NULL;
|
||||
bool prepend_sps_pps = false;
|
||||
int sps_pps_len = 0;
|
||||
unsigned char* payload = NULL;
|
||||
unsigned int readstart = 0;
|
||||
bool conn_reset = false;
|
||||
@@ -206,13 +198,6 @@ raop_rtp_mirror_thread(void *arg)
|
||||
uint64_t ntp_timestamp_local = 0;
|
||||
unsigned char nal_start_code[4] = { 0x00, 0x00, 0x00, 0x01 };
|
||||
bool logger_debug = (logger_get_level(raop_rtp_mirror->logger) >= LOGGER_DEBUG);
|
||||
#ifdef DUMP_H264
|
||||
// C decrypted
|
||||
FILE* file = fopen("/home/pi/Airplay.h264", "wb");
|
||||
// Encrypted source file
|
||||
FILE* file_source = fopen("/home/pi/Airplay.source", "wb");
|
||||
FILE* file_len = fopen("/home/pi/Airplay.len", "wb");
|
||||
#endif
|
||||
|
||||
while (1) {
|
||||
fd_set rfds;
|
||||
@@ -257,7 +242,8 @@ raop_rtp_mirror_thread(void *arg)
|
||||
saddrlen = sizeof(saddr);
|
||||
stream_fd = accept(raop_rtp_mirror->mirror_data_sock, (struct sockaddr *)&saddr, &saddrlen);
|
||||
if (stream_fd == -1) {
|
||||
logger_log(raop_rtp_mirror->logger, LOGGER_ERR, "raop_rtp_mirror error in accept %d %s", errno, strerror(errno));
|
||||
logger_log(raop_rtp_mirror->logger, LOGGER_ERR,
|
||||
"raop_rtp_mirror error in accept %d %s", errno, strerror(errno));
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -266,26 +252,31 @@ raop_rtp_mirror_thread(void *arg)
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = 5000;
|
||||
if (setsockopt(stream_fd, SOL_SOCKET, SO_RCVTIMEO, CAST &tv, sizeof(tv)) < 0) {
|
||||
logger_log(raop_rtp_mirror->logger, LOGGER_ERR, "raop_rtp_mirror could not set stream socket timeout %d %s", errno, strerror(errno));
|
||||
logger_log(raop_rtp_mirror->logger, LOGGER_ERR,
|
||||
"raop_rtp_mirror could not set stream socket timeout %d %s", errno, strerror(errno));
|
||||
break;
|
||||
}
|
||||
|
||||
int option;
|
||||
option = 1;
|
||||
if (setsockopt(stream_fd, SOL_SOCKET, SO_KEEPALIVE, CAST &option, sizeof(option)) < 0) {
|
||||
logger_log(raop_rtp_mirror->logger, LOGGER_WARNING, "raop_rtp_mirror could not set stream socket keepalive %d %s", errno, strerror(errno));
|
||||
logger_log(raop_rtp_mirror->logger, LOGGER_WARNING,
|
||||
"raop_rtp_mirror could not set stream socket keepalive %d %s", errno, strerror(errno));
|
||||
}
|
||||
option = 60;
|
||||
if (setsockopt(stream_fd, SOL_TCP, TCP_KEEPIDLE, CAST &option, sizeof(option)) < 0) {
|
||||
logger_log(raop_rtp_mirror->logger, LOGGER_WARNING, "raop_rtp_mirror could not set stream socket keepalive time %d %s", errno, strerror(errno));
|
||||
logger_log(raop_rtp_mirror->logger, LOGGER_WARNING,
|
||||
"raop_rtp_mirror could not set stream socket keepalive time %d %s", errno, strerror(errno));
|
||||
}
|
||||
option = 10;
|
||||
if (setsockopt(stream_fd, SOL_TCP, TCP_KEEPINTVL, CAST &option, sizeof(option)) < 0) {
|
||||
logger_log(raop_rtp_mirror->logger, LOGGER_WARNING, "raop_rtp_mirror could not set stream socket keepalive interval %d %s", errno, strerror(errno));
|
||||
logger_log(raop_rtp_mirror->logger, LOGGER_WARNING,
|
||||
"raop_rtp_mirror could not set stream socket keepalive interval %d %s", errno, strerror(errno));
|
||||
}
|
||||
option = 6;
|
||||
if (setsockopt(stream_fd, SOL_TCP, TCP_KEEPCNT, CAST &option, sizeof(option)) < 0) {
|
||||
logger_log(raop_rtp_mirror->logger, LOGGER_WARNING, "raop_rtp_mirror could not set stream socket keepalive probes %d %s", errno, strerror(errno));
|
||||
logger_log(raop_rtp_mirror->logger, LOGGER_WARNING,
|
||||
"raop_rtp_mirror could not set stream socket keepalive probes %d %s", errno, strerror(errno));
|
||||
}
|
||||
readstart = 0;
|
||||
}
|
||||
@@ -301,13 +292,15 @@ raop_rtp_mirror_thread(void *arg)
|
||||
}
|
||||
|
||||
if (payload == NULL && ret == 0) {
|
||||
logger_log(raop_rtp_mirror->logger, LOGGER_ERR, "raop_rtp_mirror tcp socket is closed, got %d bytes of 128 byte header",readstart);
|
||||
logger_log(raop_rtp_mirror->logger, LOGGER_ERR,
|
||||
"raop_rtp_mirror tcp socket is closed, got %d bytes of 128 byte header",readstart);
|
||||
FD_CLR(stream_fd, &rfds);
|
||||
stream_fd = -1;
|
||||
continue;
|
||||
} else if (payload == NULL && ret == -1) {
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK) continue; // Timeouts can happen even if the connection is fine
|
||||
logger_log(raop_rtp_mirror->logger, LOGGER_ERR, "raop_rtp_mirror error in header recv: %d %s", errno, strerror(errno));
|
||||
logger_log(raop_rtp_mirror->logger, LOGGER_ERR,
|
||||
"raop_rtp_mirror error in header recv: %d %s", errno, strerror(errno));
|
||||
if (errno == ECONNRESET) conn_reset = true;;
|
||||
break;
|
||||
}
|
||||
@@ -324,26 +317,28 @@ raop_rtp_mirror_thread(void *arg)
|
||||
}
|
||||
ntp_timestamp_raw = byteutils_get_long(packet, 8);
|
||||
ntp_timestamp_remote = raop_ntp_timestamp_to_nano_seconds(ntp_timestamp_raw, false);
|
||||
|
||||
/* packet[4] appears to have one of three possible values: *
|
||||
* 0x00 : encrypted packet *
|
||||
* 0x01 : unencrypted packet with a SPS and a PPS NAL, sent initially, and also when *
|
||||
* a change in video format (e.g., width, height) subsequently occurs *
|
||||
* 0x05 : unencrypted packet with a "streaming report", sent once per second */
|
||||
|
||||
/* encrypted packets have packet[5] = 0x00 or 0x10, and packet[6]= packet[7] = 0x00; *
|
||||
* encrypted packets immediately following an unencrypted SPS/PPS packet appear to *
|
||||
* be the only ones with packet[5] = 0x10, and almost always have packet[5] = 0x10, *
|
||||
* but occasionally have packet[5] = 0x00. */
|
||||
/* packet[4] + packet[5] identify the payload type: values seen are: *
|
||||
* 0x00 0x00: encrypted packet containing a non-IDR type 1 VCL NAL unit *
|
||||
* 0x00 0x10: encrypted packet containing an IDR type 5 VCL NAL unit *
|
||||
* 0x01 0x00 unencrypted packet containing a type 7 SPS NAL + a type 8 PPS NAL unit *
|
||||
* 0x05 0x00 unencrypted packet with a "streaming report", sent once per second. */
|
||||
|
||||
/* unencrypted SPS/PPS packets have packet[4:7] = 0x01 0x00 (0x16 or 0x56) 0x01 *
|
||||
* they are followed by an encrypted packet with the same timestamp in packet[8:15] */
|
||||
/* packet[6] + packet[7] may list a payload "option": values seen are: *
|
||||
* 0x00 0x00 : encrypted and "streaming report" packets *
|
||||
* 0x16 0x01 : seen in most unencrypted SPS+PPS packets *
|
||||
* 0x56 0x01 : occasionally seen in unencrypted SPS+PPS packets (why different?) */
|
||||
|
||||
/* "streaming report" packages have packet[4:7] = 0x05 0x00 0x00 0x00, and have no *
|
||||
* timestamp in packet[8:15] */
|
||||
/* unencrypted packets with a SPS and a PPS NAL are sent initially, and also when a *
|
||||
* change in video format (e.g. width, height) subsequently occurs. They seem always *
|
||||
* to be followed by a packet with a type 5 encrypted IDR VCL NAL, with an identical *
|
||||
* timestamp. On M1/M2 Mac clients, this type 5 NAL is prepended with a type 6 SEI *
|
||||
* NAL unit. Here we prepend the SPS+PPS NALs to the next encrypted packet, which *
|
||||
* always has the same timestamp, and is (almost?) always an IDR NAL unit. */
|
||||
|
||||
//unsigned short payload_type = byteutils_get_short(packet, 4) & 0xff;
|
||||
//unsigned short payload_option = byteutils_get_short(packet, 6);
|
||||
/* Unencrypted SPS/PPS packets also have image-size data in (parts of) packet[16:127] */
|
||||
|
||||
/* "streaming report" packets have no timestamp in packet[8:15] */
|
||||
|
||||
if (payload == NULL) {
|
||||
payload = malloc(payload_size);
|
||||
@@ -387,33 +382,36 @@ raop_rtp_mirror_thread(void *arg)
|
||||
(double) ntp_timestamp_remote / SEC, packet_description);
|
||||
}
|
||||
|
||||
#ifdef DUMP_H264
|
||||
fwrite(payload, payload_size, 1, file_source);
|
||||
fwrite(&readstart, sizeof(readstart), 1, file_len);
|
||||
#endif
|
||||
unsigned char* payload_out;
|
||||
unsigned char* payload_decrypted;
|
||||
if (!raop_rtp_mirror->sps_pps_waiting && packet[5] != 0x00) {
|
||||
logger_log(raop_rtp_mirror->logger, LOGGER_WARNING, "unexpected: packet[5] = %2.2x, but not preceded by SPS+PPS packet", packet[5]);
|
||||
}
|
||||
/* if a previous unencrypted packet contains an SPS (type 7) and PPS (type 8) NAL which has not
|
||||
* yet been sent, it should be prepended to the current NAL. In this case packet[5] is usually
|
||||
* 0x10; however, the M1 Macs have increased the h264 level, and now the encrypted packet after the
|
||||
* unencrypted SPS+PPS packet may contain a SEI (type 6) NAL prepended to the next VCL NAL, with
|
||||
* packet[5] = 0x00. Now the flag raop_rtp_mirror->sps_pps_waiting = true will signal that a
|
||||
* previous packet contained a SPS NAL + a PPS NAL, that has not yet been sent. This will trigger
|
||||
* prepending it to the current NAL, and the sps_pps_waiting flag will be set to false after
|
||||
* it has been prepended. It is not clear if the case packet[5] = 0x10 will occur when
|
||||
* raop_rtp_mirror->sps_pps = false, but if it does, the current code will prepend the stored
|
||||
* PPS + SPS NAL to the current encrypted NAL, and issue a warning message */
|
||||
/*
|
||||
* nal_types:1 Coded non-partitioned slice of a non-IDR picture
|
||||
* 5 Coded non-partitioned slice of an IDR picture
|
||||
* 6 Supplemental enhancement information (SEI)
|
||||
* 7 Sequence parameter set (SPS)
|
||||
* 8 Picture parameter set (PPS)
|
||||
*
|
||||
* if a previous unencrypted packet contains an SPS (type 7) and PPS (type 8) NAL which has not
|
||||
* yet been sent, it should be prepended to the current NAL. The M1 Macs have increased the h264 level,
|
||||
* and now the first encrypted packet after the unencrypted SPS+PPS packet may also contain a SEI (type 6) NAL
|
||||
* prepended to its VCL NAL.
|
||||
*
|
||||
* The flag prepend_sps_pps = true will signal that the previous packet contained a SPS NAL + a PPS NAL,
|
||||
* that has not yet been sent. This will trigger prepending it to the current NAL, and the prepend_sps_pps
|
||||
* flag will be set to false after it has been prepended. */
|
||||
|
||||
bool prepend_sps_pps = (raop_rtp_mirror->sps_pps_waiting || packet[5] != 0x00);
|
||||
if (prepend_sps_pps) {
|
||||
assert(raop_rtp_mirror->sps_pps);
|
||||
payload_out = (unsigned char*) malloc(payload_size + raop_rtp_mirror->sps_pps_len);
|
||||
payload_decrypted = payload_out + raop_rtp_mirror->sps_pps_len;
|
||||
memcpy(payload_out, raop_rtp_mirror->sps_pps, raop_rtp_mirror->sps_pps_len);
|
||||
raop_rtp_mirror->sps_pps_waiting = false;
|
||||
assert(sps_pps);
|
||||
payload_out = (unsigned char*) malloc(payload_size + sps_pps_len);
|
||||
payload_decrypted = payload_out + sps_pps_len;
|
||||
if (ntp_timestamp_raw != ntp_timestamp_nal) {
|
||||
logger_log(raop_rtp_mirror->logger, LOGGER_WARNING,
|
||||
"raop_rtp_mirror: prepended sps_pps timestamp does not match timestamp of "
|
||||
"video payload\n%llu\n%llu", ntp_timestamp_raw, ntp_timestamp_nal);
|
||||
}
|
||||
memcpy(payload_out, sps_pps, sps_pps_len);
|
||||
free (sps_pps);
|
||||
sps_pps = NULL;
|
||||
} else {
|
||||
payload_out = (unsigned char*) malloc(payload_size);
|
||||
payload_decrypted = payload_out;
|
||||
@@ -426,7 +424,6 @@ raop_rtp_mirror_thread(void *arg)
|
||||
bool valid_data = true;
|
||||
int nalu_size = 0;
|
||||
int nalus_count = 0;
|
||||
int nalu_type; /* 0x01 non-IDR VCL, 0x05 IDR VCL, 0x06 SEI 0x07 SPS, 0x08 PPS */
|
||||
while (nalu_size < payload_size) {
|
||||
int nc_len = byteutils_get_int_be(payload_decrypted, nalu_size);
|
||||
if (nc_len < 0 || nalu_size + 4 > payload_size) {
|
||||
@@ -436,22 +433,49 @@ raop_rtp_mirror_thread(void *arg)
|
||||
memcpy(payload_decrypted + nalu_size, nal_start_code, 4);
|
||||
nalu_size += 4;
|
||||
nalus_count++;
|
||||
if (payload_decrypted[nalu_size] & 0x80) valid_data = false; /* first bit of h264 nalu MUST be 0 ("forbidden_zero_bit") */
|
||||
nalu_type = payload_decrypted[nalu_size] & 0x1f;
|
||||
nalu_size += nc_len;
|
||||
if (nalu_type != 1) {
|
||||
logger_log(raop_rtp_mirror->logger, LOGGER_DEBUG, "nalu_type = %d, nalu_size = %d, processed bytes %d, payloadsize = %d nalus_count = %d",
|
||||
nalu_type, nc_len, nalu_size, payload_size, nalus_count);
|
||||
/* first bit of h264 nalu MUST be 0 ("forbidden_zero_bit") */
|
||||
if (payload_decrypted[nalu_size] & 0x80) {
|
||||
valid_data = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
int nalu_type = payload_decrypted[nalu_size] & 0x1f;
|
||||
int ref_idc = (payload_decrypted[nalu_size] >> 5);
|
||||
switch (nalu_type) {
|
||||
case 5: /*IDR, slice_layer_without_partitioning */
|
||||
case 1: /*non-IDR, slice_layer_without_partitioning */
|
||||
break;
|
||||
case 2: /* slice data partition A */
|
||||
case 3: /* slice data partition B */
|
||||
case 4: /* slice data partition C */
|
||||
logger_log(raop_rtp_mirror->logger, LOGGER_INFO,
|
||||
"unexpected partitioned VCL NAL unit: nalu_type = %d, ref_idc = %d, nalu_size = %d,"
|
||||
"processed bytes %d, payloadsize = %d nalus_count = %d",
|
||||
nalu_type, ref_idc, nc_len, nalu_size, payload_size, nalus_count);
|
||||
break;
|
||||
case 6:
|
||||
if (logger_debug) {
|
||||
char *str = utils_data_to_string(payload_decrypted + nalu_size, nc_len, 16);
|
||||
logger_log(raop_rtp_mirror->logger, LOGGER_DEBUG, "raop_rtp_mirror SEI NAL size = %d", nc_len);
|
||||
logger_log(raop_rtp_mirror->logger, LOGGER_DEBUG,
|
||||
"raop_rtp_mirror h264 Supplemental Enhancement Information:\n%s", str);
|
||||
free(str);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
logger_log(raop_rtp_mirror->logger, LOGGER_INFO,
|
||||
"unexpected non-VCL NAL unit: nalu_type = %d, ref_idc = %d, nalu_size = %d,"
|
||||
"processed bytes %d, payloadsize = %d nalus_count = %d",
|
||||
nalu_type, ref_idc, nc_len, nalu_size, payload_size, nalus_count);
|
||||
break;
|
||||
}
|
||||
nalu_size += nc_len;
|
||||
}
|
||||
if (nalu_size != payload_size) valid_data = false;
|
||||
if(!valid_data) {
|
||||
logger_log(raop_rtp_mirror->logger, LOGGER_DEBUG, "nalu marked as invalid");
|
||||
payload_out[0] = 1; /* mark video data as invalid h264 (failed decryption) */
|
||||
}
|
||||
#ifdef DUMP_H264
|
||||
fwrite(payload_decrypted, payload_size, 1, file);
|
||||
#endif
|
||||
|
||||
payload_decrypted = NULL;
|
||||
h264_decode_struct h264_data;
|
||||
h264_data.ntp_time_local = ntp_timestamp_local;
|
||||
@@ -460,11 +484,9 @@ raop_rtp_mirror_thread(void *arg)
|
||||
h264_data.data_len = payload_size;
|
||||
h264_data.data = payload_out;
|
||||
if (prepend_sps_pps) {
|
||||
h264_data.data_len += raop_rtp_mirror->sps_pps_len;
|
||||
h264_data.data_len += sps_pps_len;
|
||||
h264_data.nal_count += 2;
|
||||
if (ntp_timestamp_raw != ntp_timestamp_nal) {
|
||||
logger_log(raop_rtp_mirror->logger, LOGGER_WARNING, "raop_rtp_mirror: prepended sps_pps timestamp does not match that of video payload");
|
||||
}
|
||||
prepend_sps_pps = false;
|
||||
}
|
||||
raop_rtp_mirror->callbacks.video_process(raop_rtp_mirror->callbacks.cls, raop_rtp_mirror->ntp, &h264_data);
|
||||
free(payload_out);
|
||||
@@ -472,7 +494,8 @@ raop_rtp_mirror_thread(void *arg)
|
||||
case 0x01:
|
||||
// The information in the payload contains an SPS and a PPS NAL
|
||||
// The sps_pps is not encrypted
|
||||
logger_log(raop_rtp_mirror->logger, LOGGER_DEBUG, "\nReceived unencryted codec packet from client: payload_size %d header %s ts_client = %8.6f",
|
||||
logger_log(raop_rtp_mirror->logger, LOGGER_DEBUG, "\nReceived unencryted codec packet from client:"
|
||||
" payload_size %d header %s ts_client = %8.6f",
|
||||
payload_size, packet_description, (double) ntp_timestamp_remote / SEC);
|
||||
if (payload_size == 0) {
|
||||
logger_log(raop_rtp_mirror->logger, LOGGER_DEBUG, "raop_rtp_mirror, discard type 0x01 packet with no payload");
|
||||
@@ -484,8 +507,8 @@ raop_rtp_mirror_thread(void *arg)
|
||||
float width_source = byteutils_get_float(packet, 40);
|
||||
float height_source = byteutils_get_float(packet, 44);
|
||||
if (width != width_source || height != height_source) {
|
||||
logger_log(raop_rtp_mirror->logger, LOGGER_DEBUG, "raop_rtp_mirror: Unexpected : data %f, %f != width_source = %f, height_source = %f",
|
||||
width, height, width_source, height_source);
|
||||
logger_log(raop_rtp_mirror->logger, LOGGER_DEBUG, "raop_rtp_mirror: Unexpected : data %f,"
|
||||
" %f != width_source = %f, height_source = %f", width, height, width_source, height_source);
|
||||
}
|
||||
width = byteutils_get_float(packet, 48);
|
||||
height = byteutils_get_float(packet, 52);
|
||||
@@ -505,15 +528,15 @@ raop_rtp_mirror_thread(void *arg)
|
||||
int data_size = 6;
|
||||
if (logger_debug) {
|
||||
char *str = utils_data_to_string(payload, data_size, 16);
|
||||
logger_log(raop_rtp_mirror->logger, LOGGER_DEBUG, "raop_rtp_mirror: sps/pps header size = %d", data_size);
|
||||
logger_log(raop_rtp_mirror->logger, LOGGER_DEBUG, "raop_rtp_mirror h264 sps/pps header:\n%s", str);
|
||||
logger_log(raop_rtp_mirror->logger, LOGGER_DEBUG, "raop_rtp_mirror: SPS+PPS header size = %d", data_size);
|
||||
logger_log(raop_rtp_mirror->logger, LOGGER_DEBUG, "raop_rtp_mirror h264 SPS+PPS header:\n%s", str);
|
||||
free(str);
|
||||
str = utils_data_to_string(sequence_parameter_set, sps_size,16);
|
||||
logger_log(raop_rtp_mirror->logger, LOGGER_DEBUG, "raop_rtp_mirror sps size = %d", sps_size);
|
||||
logger_log(raop_rtp_mirror->logger, LOGGER_DEBUG, "raop_rtp_mirror SPS NAL size = %d", sps_size);
|
||||
logger_log(raop_rtp_mirror->logger, LOGGER_DEBUG, "raop_rtp_mirror h264 Sequence Parameter Set:\n%s", str);
|
||||
free(str);
|
||||
str = utils_data_to_string(picture_parameter_set, pps_size, 16);
|
||||
logger_log(raop_rtp_mirror->logger, LOGGER_DEBUG, "raop_rtp_mirror pps size = %d", pps_size);
|
||||
logger_log(raop_rtp_mirror->logger, LOGGER_DEBUG, "raop_rtp_mirror PPS NAL size = %d", pps_size);
|
||||
logger_log(raop_rtp_mirror->logger, LOGGER_DEBUG, "raop_rtp_mirror h264 Picture Parameter Set:\n%s", str);
|
||||
free(str);
|
||||
}
|
||||
@@ -521,27 +544,25 @@ raop_rtp_mirror_thread(void *arg)
|
||||
if (data_size > 0 && logger_debug) {
|
||||
char *str = utils_data_to_string (picture_parameter_set + pps_size, data_size, 16);
|
||||
logger_log(raop_rtp_mirror->logger, LOGGER_DEBUG, "remainder size = %d", data_size);
|
||||
logger_log(raop_rtp_mirror->logger, LOGGER_DEBUG, "remainder of sps+pps packet:\n%s", str);
|
||||
logger_log(raop_rtp_mirror->logger, LOGGER_DEBUG, "remainder of SPS+PPS packet:\n%s", str);
|
||||
free(str);
|
||||
} else if (data_size < 0) {
|
||||
logger_log(raop_rtp_mirror->logger, LOGGER_ERR, " pps_sps error: packet remainder size = %d < 0", data_size);
|
||||
}
|
||||
|
||||
// Copy the sps and pps into a buffer to prepend to the next NAL unit.
|
||||
raop_rtp_mirror->sps_pps_len = sps_size + pps_size + 8;
|
||||
if (raop_rtp_mirror->sps_pps) {
|
||||
free(raop_rtp_mirror->sps_pps);
|
||||
if (sps_pps) {
|
||||
free(sps_pps);
|
||||
sps_pps = NULL;
|
||||
}
|
||||
raop_rtp_mirror->sps_pps = (unsigned char*) malloc(raop_rtp_mirror->sps_pps_len);
|
||||
assert(raop_rtp_mirror->sps_pps);
|
||||
memcpy(raop_rtp_mirror->sps_pps, nal_start_code, 4);
|
||||
memcpy(raop_rtp_mirror->sps_pps + 4, sequence_parameter_set, sps_size);
|
||||
memcpy(raop_rtp_mirror->sps_pps + sps_size + 4, nal_start_code, 4);
|
||||
memcpy(raop_rtp_mirror->sps_pps + sps_size + 8, payload + sps_size + 11, pps_size);
|
||||
raop_rtp_mirror->sps_pps_waiting = true;
|
||||
#ifdef DUMP_H264
|
||||
fwrite(raop_rtp_mirror->sps_pps, raop_rtp_mirror->sps_pps_len, 1, file);
|
||||
#endif
|
||||
sps_pps_len = sps_size + pps_size + 8;
|
||||
sps_pps = (unsigned char*) malloc(sps_pps_len);
|
||||
assert(sps_pps);
|
||||
memcpy(sps_pps, nal_start_code, 4);
|
||||
memcpy(sps_pps + 4, sequence_parameter_set, sps_size);
|
||||
memcpy(sps_pps + sps_size + 4, nal_start_code, 4);
|
||||
memcpy(sps_pps + sps_size + 8, payload + sps_size + 11, pps_size);
|
||||
prepend_sps_pps = true;
|
||||
|
||||
// h264codec_t h264;
|
||||
// h264.version = payload[0];
|
||||
@@ -560,8 +581,8 @@ raop_rtp_mirror_thread(void *arg)
|
||||
|
||||
break;
|
||||
case 0x05:
|
||||
logger_log(raop_rtp_mirror->logger, LOGGER_DEBUG, "\nReceived video streaming performance info packet from client: payload_size %d header %s ts_raw = %llu",
|
||||
payload_size, packet_description, ntp_timestamp_raw);
|
||||
logger_log(raop_rtp_mirror->logger, LOGGER_DEBUG, "\nReceived video streaming performance info packet from client:"
|
||||
" payload_size %d header %s ts_raw = %llu", payload_size, packet_description, ntp_timestamp_raw);
|
||||
/* payloads with packet[4] = 0x05 have no timestamp, and carry video info from the client as a binary plist *
|
||||
* Sometimes (e.g, when the client has a locked screen), there is a 25kB trailer attached to the packet. *
|
||||
* This 25000 Byte trailer with unidentified content seems to be the same data each time it is sent. */
|
||||
@@ -576,7 +597,8 @@ raop_rtp_mirror_thread(void *arg)
|
||||
plist_size = payload_size - 25000;
|
||||
if (logger_debug) {
|
||||
char *str = utils_data_to_string(payload + plist_size, 16, 16);
|
||||
logger_log(raop_rtp_mirror->logger, LOGGER_DEBUG, "video_info packet had 25kB trailer; first 16 bytes are:\n%s", str);
|
||||
logger_log(raop_rtp_mirror->logger, LOGGER_DEBUG,
|
||||
"video_info packet had 25kB trailer; first 16 bytes are:\n%s", str);
|
||||
free(str);
|
||||
}
|
||||
}
|
||||
@@ -592,8 +614,8 @@ raop_rtp_mirror_thread(void *arg)
|
||||
}
|
||||
break;
|
||||
default:
|
||||
logger_log(raop_rtp_mirror->logger, LOGGER_WARNING, "\nReceived unexpected TCP packet from client, size %d, %s ts_raw = raw%llu",
|
||||
payload_size, packet_description, ntp_timestamp_raw);
|
||||
logger_log(raop_rtp_mirror->logger, LOGGER_WARNING, "\nReceived unexpected TCP packet from client, "
|
||||
"size %d, %s ts_raw = raw%llu", payload_size, packet_description, ntp_timestamp_raw);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -609,12 +631,6 @@ raop_rtp_mirror_thread(void *arg)
|
||||
closesocket(stream_fd);
|
||||
}
|
||||
|
||||
#ifdef DUMP_H264
|
||||
fclose(file);
|
||||
fclose(file_source);
|
||||
fclose(file_len);
|
||||
#endif
|
||||
|
||||
// Ensure running reflects the actual state
|
||||
MUTEX_LOCK(raop_rtp_mirror->run_mutex);
|
||||
raop_rtp_mirror->running = false;
|
||||
@@ -649,7 +665,8 @@ raop_rtp_init_mirror_sockets(raop_rtp_mirror_t *raop_rtp_mirror, int use_ipv6)
|
||||
|
||||
/* Set port values */
|
||||
raop_rtp_mirror->mirror_data_lport = dport;
|
||||
logger_log(raop_rtp_mirror->logger, LOGGER_DEBUG, "raop_rtp_mirror local data port socket %d port TCP %d", dsock, dport);
|
||||
logger_log(raop_rtp_mirror->logger, LOGGER_DEBUG, "raop_rtp_mirror local data port socket %d port TCP %d",
|
||||
dsock, dport);
|
||||
return 0;
|
||||
|
||||
sockets_cleanup:
|
||||
@@ -658,7 +675,8 @@ raop_rtp_init_mirror_sockets(raop_rtp_mirror_t *raop_rtp_mirror, int use_ipv6)
|
||||
}
|
||||
|
||||
void
|
||||
raop_rtp_start_mirror(raop_rtp_mirror_t *raop_rtp_mirror, int use_udp, unsigned short *mirror_data_lport, uint8_t show_client_FPS_data)
|
||||
raop_rtp_start_mirror(raop_rtp_mirror_t *raop_rtp_mirror, int use_udp, unsigned short *mirror_data_lport,
|
||||
uint8_t show_client_FPS_data)
|
||||
{
|
||||
logger_log(raop_rtp_mirror->logger, LOGGER_INFO, "raop_rtp_mirror starting mirroring");
|
||||
int use_ipv6 = 0;
|
||||
@@ -726,9 +744,6 @@ void raop_rtp_mirror_destroy(raop_rtp_mirror_t *raop_rtp_mirror) {
|
||||
raop_rtp_mirror_stop(raop_rtp_mirror);
|
||||
MUTEX_DESTROY(raop_rtp_mirror->run_mutex);
|
||||
mirror_buffer_destroy(raop_rtp_mirror->buffer);
|
||||
if (raop_rtp_mirror->sps_pps) {
|
||||
free(raop_rtp_mirror->sps_pps);
|
||||
}
|
||||
free(raop_rtp_mirror);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user