parsing sdp for rtsp control tracks and its codecs

This commit is contained in:
Castillo, Gerard
2014-01-16 14:39:26 +01:00
parent 20181ebca0
commit 75e2daa102
4 changed files with 638 additions and 260 deletions

View File

@@ -553,10 +553,56 @@ static void *audio_receiver_thread(void *arg)
}
pdb_iter_done(&it);
}else if(s->receiver == NET_STANDARD){
//TODO receive mulaw standard RTP (decode frame mulaw callback)
//TODO now expecting to receive mulaw standard RTP (decode frame mulaw callback) , next steps, to be dynamic...
gettimeofday(&curr_time, NULL);
ts = tv_diff(curr_time, s->start_time) * 90000;
rtp_update(s->audio_network_device, curr_time);
rtp_send_ctrl(s->audio_network_device, ts, 0, curr_time);
timeout.tv_sec = 0;
timeout.tv_usec = 999999 / 59.94; /* audio goes almost always at the same rate
as video frames */
rtp_recv_r(s->audio_network_device, &timeout, ts);
pdb_iter_t it;
cp = pdb_iter_init(s->audio_participants, &it);
while (cp != NULL) {
if (audio_pbuf_decode(cp->playout_buffer, curr_time, decode_audio_frame_mulaw, &pbuf_data)) {
bool failed = false;
if(s->echo_state) {
#ifdef HAVE_SPEEX
echo_play(s->echo_state, &pbuf_data.buffer);
#endif
}
struct audio_desc curr_desc;
curr_desc = audio_desc_from_audio_frame(&pbuf_data.buffer);
if(!audio_desc_eq(device_desc, curr_desc)) {
if(audio_reconfigure(s, curr_desc.bps * 8,
curr_desc.ch_count,
curr_desc.sample_rate) != TRUE) {
fprintf(stderr, "Audio reconfiguration failed!");
failed = true;
}
else {
fprintf(stderr, "Audio reconfiguration succeeded.");
device_desc = curr_desc;
rtp_flush_recv_buf(s->audio_network_device);
}
fprintf(stderr, " (%d channels, %d bps, %d Hz)\n",
curr_desc.ch_count,
curr_desc.bps, curr_desc.sample_rate);
}
if(!failed)
audio_playback_put_frame(s->audio_playback_device, &pbuf_data.buffer);
}
pbuf_remove(cp->playout_buffer, curr_time);
cp = pdb_iter_next(&it);
}
pdb_iter_done(&it);
}else { /* NET_JACK */
#ifdef HAVE_JACK_TRANS
jack_receive(s->jack_connection, &pbuf_data);

View File

@@ -564,4 +564,108 @@ cleanup:
return ret;
}
/*
* Second version that uses external audio configuration,
* now it uses a struct state_audio_decoder instead an audio_frame2.
* It does multi-channel handling.
*/
int decode_audio_frame_mulaw(struct coded_data *cdata, void *data)
{
struct pbuf_audio_data *s = (struct pbuf_audio_data *) data;
struct state_audio_decoder *audio = s->decoder;
//struct state_audio_decoder *audio = (struct state_audio_decoder *)data;
if(!cdata) return false;
// Reconfiguration.
if (audio->received_frame->bps != audio->saved_desc.bps ||
audio->received_frame->sample_rate != audio->saved_desc.sample_rate ||
audio->received_frame->ch_count != audio->saved_desc.ch_count ||
audio->received_frame->codec != audio->saved_desc.codec)
{
audio_frame2_allocate(audio->received_frame, audio->saved_desc.ch_count, audio->saved_desc.sample_rate * audio->saved_desc.bps);
audio->received_frame->bps = audio->saved_desc.bps;
audio->received_frame->sample_rate = audio->saved_desc.sample_rate;
audio->received_frame->ch_count = audio->saved_desc.ch_count;
audio->received_frame->codec = audio->saved_desc.codec;
}
// Initial setup
for (int ch = 0 ; ch < audio->received_frame->ch_count ; ch ++) {
audio->received_frame->data_len[ch] = 0;
}
// Check-if-there-is-only-one-channel optimization.
if (audio->received_frame->ch_count == 1) {
char *to = audio->received_frame->data[0];
while (cdata != NULL) {
// Get the data to copy into the received_frame.
char *from = cdata->data->data;
// See if the data fits.
if (cdata->data->data_len <= (int)(audio->received_frame->max_size - audio->received_frame->data_len[0])) {
// Copy the data
memcpy(to, from, cdata->data->data_len);
// Update the pointer and the counter.
to += cdata->data->data_len;
audio->received_frame->data_len[0] += cdata->data->data_len;
} else {
// Filled it out, exit now.
return true;
}
cdata = cdata->nxt;
}
} else { // Multi-channel case.
/*
* Unoptimized version of the multi-channel handling.
* TODO: Optimize it! It's a matrix transpose.
* Take a look at http://stackoverflow.com/questions/1777901/array-interleaving-problem
*/
char *to;
int bytes_copied = 0;
while (cdata != NULL) {
// Check that the amount of data on cdata->data->data is congruent with 0 modulus audio->received_frame->ch_count.
if (cdata->data->data_len % audio->received_frame->ch_count != 0) {
// printf something?
return false;
}
// If there is space on the current audio_frame2 buffer.
if ((cdata->data->data_len / audio->received_frame->ch_count) <= (int)(audio->received_frame->max_size - bytes_copied)) {
char *from = cdata->data->data;
// For each group of samples.
for (int g = 0 ; g < (cdata->data->data_len / audio->received_frame->ch_count) ; g++) {
// Iterate throught each channel.
for (int ch = 0 ; ch < audio->received_frame->ch_count ; ch ++) {
// Copy the current sample from the RTP packet to the audio_frame2.
to = audio->received_frame->data[ch];
to += bytes_copied;
memcpy(to, from, audio->received_frame->bps);
from += audio->received_frame->bps;
audio->received_frame->data_len[ch] += audio->received_frame->bps;
}
bytes_copied += audio->received_frame->bps;
}
} else {
// Filled audio_frame2 out, exit now.
return true;
}
cdata = cdata->nxt;
}
}
return true;
}

View File

@@ -54,6 +54,7 @@
struct coded_data;
int decode_audio_frame(struct coded_data *cdata, void *data);
int decode_audio_frame_mulaw(struct coded_data *cdata, void *data);
void *audio_decoder_init(char *audio_channel_map, const char *audio_scale,
const char *encryption);
void audio_decoder_destroy(void *state);

View File

@@ -81,17 +81,17 @@
/* error handling macros */
#define my_curl_easy_setopt(A, B, C) \
if ((res = curl_easy_setopt((A), (B), (C))) != CURLE_OK){ \
fprintf(stderr, "[rtsp error] curl_easy_setopt(%s, %s, %s) failed: %d\n", #A, #B, #C, res); \
printf("[rtsp error] could not configure rtsp capture properly, \n\t\tplease check your parameters. \nExiting...\n\n"); \
exit(0); \
}
fprintf(stderr, "[rtsp error] curl_easy_setopt(%s, %s, %s) failed: %d\n", #A, #B, #C, res); \
printf("[rtsp error] could not configure rtsp capture properly, \n\t\tplease check your parameters. \nExiting...\n\n"); \
exit(0); \
}
#define my_curl_easy_perform(A) \
if ((res = curl_easy_perform((A))) != CURLE_OK){ \
fprintf(stderr, "[rtsp error] curl_easy_perform(%s) failed: %d\n", #A, res); \
printf("[rtsp error] could not configure rtsp capture properly, \n\t\tplease check your parameters. \nExiting...\n\n"); \
exit(0); \
}
fprintf(stderr, "[rtsp error] curl_easy_perform(%s) failed: %d\n", #A, res); \
printf("[rtsp error] could not configure rtsp capture properly, \n\t\tplease check your parameters. \nExiting...\n\n"); \
exit(0); \
}
/* send RTSP GET_PARAMETERS request */
static void
@@ -126,7 +126,7 @@ static void
get_media_control_attribute(const char *sdp_filename, char *control);
/* scan sdp file for incoming codec */
static int
static char *
set_codec_attribute_from_incoming_media(const char *sdp_filename, void *state);
static int
@@ -151,17 +151,18 @@ FILE *F_video_rtsp = NULL;
/**
* @struct rtsp_state
*/
struct rtsp_state {
struct video_rtsp_state {
char *nals;
int nals_size;
char *data; //nals + data
uint32_t *in_codec;
char *codec;
struct timeval t0, t;
int frames;
struct video_frame *frame;
struct tile *tile;
struct audio_frame audio;
int width;
int height;
@@ -170,12 +171,19 @@ struct rtsp_state {
bool decompress;
bool grab;
struct state_decompress *sd;
struct video_desc des;
char * out_frame;
int port;
float fps;
char *control;
struct rtp *device;
struct pdb *participants;
struct pdb_e *cp;
double rtcp_bw;
int ttl;
char *addr;
char *mcast_if;
struct timeval curr_time;
struct timeval timeout;
@@ -184,28 +192,59 @@ struct rtsp_state {
int required_connections;
uint32_t timestamp;
int play_audio_frame;
struct timeval last_audio_time;
unsigned int grab_audio:1;
pthread_t rtsp_thread_id; //the worker_id
pthread_t vrtsp_thread_id; //the worker_id
pthread_mutex_t lock;
pthread_cond_t worker_cv;
volatile bool worker_waiting;
pthread_cond_t boss_cv;
volatile bool boss_waiting;
};
volatile bool should_exit;
struct audio_rtsp_state {
struct audio_frame audio;
int play_audio_frame;
struct state_decompress *sd;
struct video_desc des;
char * out_frame;
char *codec;
struct timeval last_audio_time;
unsigned int grab_audio:1;
CURL *curl;
char *uri;
int port;
float fps;
char *control;
struct rtp *device;
struct pdb *participants;
struct pdb_e *cp;
double rtcp_bw;
int ttl;
char *mcast_if;
struct timeval curr_time;
struct timeval timeout;
struct timeval prev_time;
struct timeval start_time;
int required_connections;
uint32_t timestamp;
pthread_t artsp_thread_id; //the worker_id
pthread_mutex_t lock;
pthread_cond_t worker_cv;
volatile bool worker_waiting;
pthread_cond_t boss_cv;
volatile bool boss_waiting;
};
struct rtsp_state {
CURL *curl;
char *uri;
uint avType;
char *addr;
char *sdp;
volatile bool should_exit;
struct audio_rtsp_state *artsp_state;
struct video_rtsp_state *vrtsp_state;
};
static void
@@ -226,9 +265,9 @@ rtsp_keepalive(void *state) {
s = (struct rtsp_state *) state;
struct timeval now;
gettimeofday(&now, NULL);
if (tv_diff(now, s->prev_time) >= 20) {
if (tv_diff(now, s->vrtsp_state->prev_time) >= 20) {
rtsp_get_parameters(s->curl, s->uri);
gettimeofday(&s->prev_time, NULL);
gettimeofday(&s->vrtsp_state->prev_time, NULL);
}
}
@@ -237,54 +276,54 @@ vidcap_rtsp_thread(void *arg) {
struct rtsp_state *s;
s = (struct rtsp_state *) arg;
gettimeofday(&s->start_time, NULL);
gettimeofday(&s->prev_time, NULL);
gettimeofday(&s->vrtsp_state->start_time, NULL);
gettimeofday(&s->vrtsp_state->prev_time, NULL);
while (!s->should_exit) {
gettimeofday(&s->curr_time, NULL);
s->timestamp = tv_diff(s->curr_time, s->start_time) * 90000;
rtsp_keepalive(s);
rtp_update(s->device, s->curr_time);
//TODO no need of rtcp communication between ug and rtsp server?
//rtp_send_ctrl(s->device, s->timestamp, 0, s->curr_time);
s->timeout.tv_sec = 0;
s->timeout.tv_usec = 10000;
if (!rtp_recv_r(s->device, &s->timeout, s->timestamp)) {
pdb_iter_t it;
s->cp = pdb_iter_init(s->participants, &it);
while (s->cp != NULL) {
if (pthread_mutex_trylock(&s->lock) == 0) {
{
if(s->grab){
while (s->new_frame && !s->should_exit) {
s->worker_waiting = true;
pthread_cond_wait(&s->worker_cv, &s->lock);
s->worker_waiting = false;
}
if (pbuf_decode(s->cp->playout_buffer, s->curr_time,
decode_frame_h264, s->rx_data))
{
s->new_frame = true;
}
if (s->boss_waiting)
pthread_cond_signal(&s->boss_cv);
}
}
pthread_mutex_unlock(&s->lock);
}
pbuf_remove(s->cp->playout_buffer, s->curr_time);
s->cp = pdb_iter_next(&it);
}
pdb_iter_done(&it);
}
// gettimeofday(&s->curr_time, NULL);
// s->timestamp = tv_diff(s->curr_time, s->start_time) * 90000;
//
// rtsp_keepalive(s);
//
// rtp_update(s->device, s->curr_time);
// //TODO no need of rtcp communication between ug and rtsp server?
// //rtp_send_ctrl(s->device, s->timestamp, 0, s->curr_time);
//
// s->timeout.tv_sec = 0;
// s->timeout.tv_usec = 10000;
//
// if (!rtp_recv_r(s->device, &s->timeout, s->timestamp)) {
// pdb_iter_t it;
// s->cp = pdb_iter_init(s->participants, &it);
//
// while (s->cp != NULL) {
// if (pthread_mutex_trylock(&s->lock) == 0) {
// {
// if(s->grab){
//
// while (s->new_frame && !s->should_exit) {
// s->worker_waiting = true;
// pthread_cond_wait(&s->worker_cv, &s->lock);
// s->worker_waiting = false;
// }
//
// if (pbuf_decode(s->cp->playout_buffer, s->curr_time,
// decode_frame_h264, s->rx_data))
// {
// s->new_frame = true;
// }
// if (s->boss_waiting)
// pthread_cond_signal(&s->boss_cv);
// }
// }
// pthread_mutex_unlock(&s->lock);
// }
// pbuf_remove(s->cp->playout_buffer, s->curr_time);
// s->cp = pdb_iter_next(&it);
// }
//
// pdb_iter_done(&it);
// }
}
return NULL;
}
@@ -296,63 +335,63 @@ vidcap_rtsp_grab(void *state, struct audio_frame **audio) {
*audio = NULL;
if(pthread_mutex_trylock(&s->lock)==0){
{
s->grab = true;
// if(pthread_mutex_trylock(&s->lock)==0){
// {
// s->grab = true;
//
// while (!s->new_frame) {
// s->boss_waiting = true;
// pthread_cond_wait(&s->boss_cv, &s->lock);
// s->boss_waiting = false;
// }
//
// gettimeofday(&s->curr_time, NULL);
// s->frame->h264_iframe = s->rx_data->iframe;
// s->frame->h264_iframe = s->rx_data->iframe;
// s->frame->tiles[0].data_len = s->rx_data->buffer_len;
// memcpy(s->data + s->nals_size, s->rx_data->frame_buffer,
// s->rx_data->buffer_len);
// memcpy(s->frame->tiles[0].data, s->data,
// s->rx_data->buffer_len + s->nals_size);
// s->frame->tiles[0].data_len += s->nals_size;
//
// if (s->decompress) {
// decompress_frame(s->sd, (unsigned char *) s->out_frame,
// (unsigned char *) s->frame->tiles[0].data,
// s->rx_data->buffer_len + s->nals_size, 0);
// s->frame->tiles[0].data = s->out_frame; //TODO memcpy?
// s->frame->tiles[0].data_len = vc_get_linesize(s->des.width, UYVY)
// * s->des.height; //TODO reconfigurable?
// }
// s->new_frame = false;
//
// if (s->worker_waiting) {
// pthread_cond_signal(&s->worker_cv);
// }
// }
// pthread_mutex_unlock(&s->lock);
//
// gettimeofday(&s->t, NULL);
// double seconds = tv_diff(s->t, s->t0);
// if (seconds >= 5) {
// float fps = s->frames / seconds;
// fprintf(stderr, "[rtsp capture] %d frames in %g seconds = %g FPS\n",
// s->frames, seconds, fps);
// s->t0 = s->t;
// s->frames = 0;
// //TODO: Threshold of ¿1fps? in order to update fps parameter. Now a higher fps is fixed to 30fps...
// //if (fps > s->fps + 1 || fps < s->fps - 1) {
// // debug_msg(
// // "\n[rtsp] updating fps from rtsp server stream... now = %f , before = %f\n",fps,s->fps);
// // s->frame->fps = fps;
// // s->fps = fps;
// // }
// }
// s->frames++;
// s->grab = false;
// }
while (!s->new_frame) {
s->boss_waiting = true;
pthread_cond_wait(&s->boss_cv, &s->lock);
s->boss_waiting = false;
}
gettimeofday(&s->curr_time, NULL);
s->frame->h264_iframe = s->rx_data->iframe;
s->frame->h264_iframe = s->rx_data->iframe;
s->frame->tiles[0].data_len = s->rx_data->buffer_len;
memcpy(s->data + s->nals_size, s->rx_data->frame_buffer,
s->rx_data->buffer_len);
memcpy(s->frame->tiles[0].data, s->data,
s->rx_data->buffer_len + s->nals_size);
s->frame->tiles[0].data_len += s->nals_size;
if (s->decompress) {
decompress_frame(s->sd, (unsigned char *) s->out_frame,
(unsigned char *) s->frame->tiles[0].data,
s->rx_data->buffer_len + s->nals_size, 0);
s->frame->tiles[0].data = s->out_frame; //TODO memcpy?
s->frame->tiles[0].data_len = vc_get_linesize(s->des.width, UYVY)
* s->des.height; //TODO reconfigurable?
}
s->new_frame = false;
if (s->worker_waiting) {
pthread_cond_signal(&s->worker_cv);
}
}
pthread_mutex_unlock(&s->lock);
gettimeofday(&s->t, NULL);
double seconds = tv_diff(s->t, s->t0);
if (seconds >= 5) {
float fps = s->frames / seconds;
fprintf(stderr, "[rtsp capture] %d frames in %g seconds = %g FPS\n",
s->frames, seconds, fps);
s->t0 = s->t;
s->frames = 0;
//TODO: Threshold of ¿1fps? in order to update fps parameter. Now a higher fps is fixed to 30fps...
//if (fps > s->fps + 1 || fps < s->fps - 1) {
// debug_msg(
// "\n[rtsp] updating fps from rtsp server stream... now = %f , before = %f\n",fps,s->fps);
// s->frame->fps = fps;
// s->fps = fps;
// }
}
s->frames++;
s->grab = false;
}
return s->frame;
return s->vrtsp_state->frame;
}
void *
@@ -364,32 +403,42 @@ vidcap_rtsp_init(const struct vidcap_params *params) {
if (!s)
return NULL;
char *save_ptr = NULL;
s->artsp_state = calloc(1,sizeof(struct audio_rtsp_state));
s->vrtsp_state = calloc(1,sizeof(struct video_rtsp_state));
gettimeofday(&s->t0, NULL);
s->frames = 0;
s->nals = malloc(1024);
s->grab = false;
//TODO now static codec assignment, to be dynamic as a function of supported codecs
s->vrtsp_state->codec = "";
s->artsp_state->codec = "";
s->artsp_state->control = "";
s->artsp_state->control = "";
char *save_ptr = NULL;
s->avType = -1; //-1 none, 0 a&v, 1 v, 2 a
gettimeofday(&s->vrtsp_state->t0, NULL);
s->vrtsp_state->frames = 0;
s->vrtsp_state->nals = malloc(1024);
s->vrtsp_state->grab = false;
s->addr = "127.0.0.1";
s->device = NULL;
s->rtcp_bw = 5 * 1024 * 1024; /* FIXME */
s->ttl = 255;
s->vrtsp_state->device = NULL;
s->vrtsp_state->rtcp_bw = 5 * 1024 * 1024; /* FIXME */
s->vrtsp_state->ttl = 255;
s->mcast_if = NULL;
s->required_connections = 1;
s->vrtsp_state->mcast_if = NULL;
s->vrtsp_state->required_connections = 1;
s->timeout.tv_sec = 0;
s->timeout.tv_usec = 10000;
s->vrtsp_state->timeout.tv_sec = 0;
s->vrtsp_state->timeout.tv_usec = 10000;
s->device = (struct rtp *) malloc(
(s->required_connections) * sizeof(struct rtp *));
s->participants = pdb_init();
s->vrtsp_state->device = (struct rtp *) malloc(
(s->vrtsp_state->required_connections) * sizeof(struct rtp *));
s->vrtsp_state->participants = pdb_init();
s->rx_data = malloc(sizeof(struct std_frame_received));
s->new_frame = false;
s->vrtsp_state->rx_data = malloc(sizeof(struct std_frame_received));
s->vrtsp_state->new_frame = false;
s->in_codec = malloc(sizeof(uint32_t *) * 10);
s->vrtsp_state->in_codec = malloc(sizeof(uint32_t *) * 10);
s->uri = NULL;
s->curl = NULL;
@@ -427,7 +476,7 @@ vidcap_rtsp_init(const struct vidcap_params *params) {
break;
case 1:
if (tmp) { //TODO check if it's a number
s->port = atoi(tmp);
s->vrtsp_state->port = atoi(tmp);
} else {
printf("\n[rtsp] Wrong format for port! \n");
show_help();
@@ -436,7 +485,7 @@ vidcap_rtsp_init(const struct vidcap_params *params) {
break;
case 2:
if (tmp) { //TODO check if it's a number
s->width = atoi(tmp);
s->vrtsp_state->width = atoi(tmp);
} else {
printf("\n[rtsp] Wrong format for width! \n");
show_help();
@@ -445,20 +494,20 @@ vidcap_rtsp_init(const struct vidcap_params *params) {
break;
case 3:
if (tmp) { //TODO check if it's a number
s->height = atoi(tmp);
s->vrtsp_state->height = atoi(tmp);
//Now checking if we have user and password parameters...
if (s->height == 0) {
if (s->vrtsp_state->height == 0) {
int ntmp = 0;
ntmp = s->width;
s->width = s->port;
s->height = ntmp;
ntmp = s->vrtsp_state->width;
s->vrtsp_state->width = s->vrtsp_state->port;
s->vrtsp_state->height = ntmp;
sprintf(s->uri, "rtsp:%s", uri_tmp1);
s->port = atoi(uri_tmp2);
s->vrtsp_state->port = atoi(uri_tmp2);
if (tmp) {
if (strcmp(tmp, "true") == 0)
s->decompress = true;
s->vrtsp_state->decompress = true;
else if (strcmp(tmp, "false") == 0)
s->decompress = false;
s->vrtsp_state->decompress = false;
else {
printf(
"\n[rtsp] Wrong format for boolean decompress flag! \n");
@@ -477,9 +526,9 @@ vidcap_rtsp_init(const struct vidcap_params *params) {
case 4:
if (tmp) {
if (strcmp(tmp, "true") == 0)
s->decompress = true;
s->vrtsp_state->decompress = true;
else if (strcmp(tmp, "false") == 0)
s->decompress = false;
s->vrtsp_state->decompress = false;
else {
printf(
"\n[rtsp] Wrong format for boolean decompress flag! \n");
@@ -497,96 +546,98 @@ vidcap_rtsp_init(const struct vidcap_params *params) {
}
}
//re-check parameters
if (s->height == 0) {
if (s->vrtsp_state->height == 0) {
int ntmp = 0;
ntmp = s->width;
s->width = (int) s->port;
s->height = (int) ntmp;
ntmp = s->vrtsp_state->width;
s->vrtsp_state->width = (int) s->vrtsp_state->port;
s->vrtsp_state->height = (int) ntmp;
sprintf(s->uri, "rtsp:%s", uri_tmp1);
s->port = (int) atoi(uri_tmp2);
s->vrtsp_state->port = (int) atoi(uri_tmp2);
}
debug_msg("[rtsp] selected flags:\n");
debug_msg("\t uri: %s\n",s->uri);
debug_msg("\t port: %d\n", s->port);
debug_msg("\t width: %d\n",s->width);
debug_msg("\t height: %d\n",s->height);
debug_msg("\t decompress: %d\n\n",s->decompress);
debug_msg("\t port: %d\n", s->vrtsp_state->port);
debug_msg("\t width: %d\n",s->vrtsp_state->width);
debug_msg("\t height: %d\n",s->vrtsp_state->height);
debug_msg("\t decompress: %d\n\n",s->vrtsp_state->decompress);
if (uri_tmp1 != NULL)
free(uri_tmp1);
if (uri_tmp2 != NULL)
free(uri_tmp2);
s->rx_data->frame_buffer = malloc(4 * s->width * s->height);
s->data = malloc(4 * s->width * s->height + s->nals_size);
s->vrtsp_state->rx_data->frame_buffer = malloc(4 * s->vrtsp_state->width * s->vrtsp_state->height);
s->vrtsp_state->data = malloc(4 * s->vrtsp_state->width * s->vrtsp_state->height + s->vrtsp_state->nals_size);
s->frame = vf_alloc(1);
s->frame->isStd = TRUE;
s->frame->h264_bframe = FALSE;
s->frame->h264_iframe = FALSE;
s->tile = vf_get_tile(s->frame, 0);
vf_get_tile(s->frame, 0)->width = s->width;
vf_get_tile(s->frame, 0)->height = s->height;
s->vrtsp_state->frame = vf_alloc(1);
s->vrtsp_state->frame->isStd = TRUE;
s->vrtsp_state->frame->h264_bframe = FALSE;
s->vrtsp_state->frame->h264_iframe = FALSE;
s->vrtsp_state->tile = vf_get_tile(s->vrtsp_state->frame, 0);
vf_get_tile(s->vrtsp_state->frame, 0)->width = s->vrtsp_state->width;
vf_get_tile(s->vrtsp_state->frame, 0)->height = s->vrtsp_state->height;
//TODO fps should be autodetected, now reset and controlled at vidcap_grab function
s->frame->fps = 30;
s->fps = 30;
s->frame->interlacing = PROGRESSIVE;
s->vrtsp_state->frame->fps = 30;
s->vrtsp_state->fps = 30;
s->vrtsp_state->frame->interlacing = PROGRESSIVE;
s->frame->tiles[0].data = calloc(1, s->width * s->height);
s->vrtsp_state->frame->tiles[0].data = calloc(1, s->vrtsp_state->width * s->vrtsp_state->height);
s->should_exit = false;
s->device = rtp_init_if(NULL, s->mcast_if, s->port, 0, s->ttl, s->rtcp_bw,
0, rtp_recv_callback, (void *) s->participants, 0);
s->vrtsp_state->nals_size = init_rtsp(s->uri, s->vrtsp_state->port, s, s->vrtsp_state->nals);
if (s->device != NULL) {
if (!rtp_set_option(s->device, RTP_OPT_WEAK_VALIDATION, 1)) {
debug_msg("[rtsp] RTP INIT - set option\n");
return NULL;
}
if (!rtp_set_sdes(s->device, rtp_my_ssrc(s->device),
RTCP_SDES_TOOL, PACKAGE_STRING, strlen(PACKAGE_STRING))) {
debug_msg("[rtsp] RTP INIT - set sdes\n");
return NULL;
}
int ret = rtp_set_recv_buf(s->device, INITIAL_VIDEO_RECV_BUFFER_SIZE);
if (!ret) {
debug_msg("[rtsp] RTP INIT - set recv buf \nset command: sudo sysctl -w net.core.rmem_max=9123840\n");
return NULL;
}
if (!rtp_set_send_buf(s->device, 1024 * 56)) {
debug_msg("[rtsp] RTP INIT - set send buf\n");
return NULL;
}
ret=pdb_add(s->participants, rtp_my_ssrc(s->device));
}
// s->device = rtp_init_if(NULL, s->mcast_if, s->port, 0, s->ttl, s->rtcp_bw,
// 0, rtp_recv_callback, (void *) s->participants, 0);
//
// if (s->device != NULL) {
// if (!rtp_set_option(s->device, RTP_OPT_WEAK_VALIDATION, 1)) {
// debug_msg("[rtsp] RTP INIT - set option\n");
// return NULL;
// }
// if (!rtp_set_sdes(s->device, rtp_my_ssrc(s->device),
// RTCP_SDES_TOOL, PACKAGE_STRING, strlen(PACKAGE_STRING))) {
// debug_msg("[rtsp] RTP INIT - set sdes\n");
// return NULL;
// }
//
// int ret = rtp_set_recv_buf(s->device, INITIAL_VIDEO_RECV_BUFFER_SIZE);
// if (!ret) {
// debug_msg("[rtsp] RTP INIT - set recv buf \nset command: sudo sysctl -w net.core.rmem_max=9123840\n");
// return NULL;
// }
//
// if (!rtp_set_send_buf(s->device, 1024 * 56)) {
// debug_msg("[rtsp] RTP INIT - set send buf\n");
// return NULL;
// }
// ret=pdb_add(s->participants, rtp_my_ssrc(s->device));
// }
debug_msg("[rtsp] rtp receiver init done\n");
pthread_mutex_init(&s->lock, NULL);
pthread_cond_init(&s->boss_cv, NULL);
pthread_cond_init(&s->worker_cv, NULL);
pthread_mutex_init(&s->vrtsp_state->lock, NULL);
pthread_cond_init(&s->vrtsp_state->boss_cv, NULL);
pthread_cond_init(&s->vrtsp_state->worker_cv, NULL);
s->boss_waiting = false;
s->worker_waiting = false;
s->vrtsp_state->boss_waiting = false;
s->vrtsp_state->worker_waiting = false;
s->nals_size = init_rtsp(s->uri, s->port, s, s->nals);
if (s->nals_size >= 0)
memcpy(s->data, s->nals, s->nals_size);
if (s->vrtsp_state->nals_size >= 0)
memcpy(s->vrtsp_state->data, s->vrtsp_state->nals, s->vrtsp_state->nals_size);
else
return NULL;
if (s->decompress) {
if (init_decompressor(s) == 0)
if (s->vrtsp_state->decompress) {
if (init_decompressor(s->vrtsp_state) == 0)
return NULL;
s->frame->color_spec = UYVY;
s->vrtsp_state->frame->color_spec = UYVY;
}
pthread_create(&s->rtsp_thread_id, NULL, vidcap_rtsp_thread, s);
pthread_create(&s->vrtsp_state->vrtsp_thread_id, NULL, vidcap_rtsp_thread, s);
debug_msg("[rtsp] rtsp capture init done\n");
@@ -611,11 +662,18 @@ init_rtsp(char* rtsp_uri, int rtsp_port, void *state, char* nals) {
char *sdp_filename = malloc(strlen(url) + 32);
char *control = malloc(150 * sizeof(char *));
memset(control, 0, 150 * sizeof(char *));
char transport[256];
bzero(transport, 256);
char Atransport[256];
char Vtransport[256];
bzero(Atransport, 256);
bzero(Vtransport, 256);
int port = rtsp_port;
get_sdp_filename(url, sdp_filename);
sprintf(transport, "RTP/AVP;unicast;client_port=%d-%d", port, port + 1);
sprintf(Vtransport, "RTP/AVP;unicast;client_port=%d-%d", port, port + 1);
//THIS AUDIO PORTS ARE AS DEFAULT UG AUDIO PORTS BUT AREN'T RELATED...
sprintf(Atransport, "RTP/AVP;unicast;client_port=%d-%d", port+2, port + 3);
/* initialize curl */
res = curl_global_init(CURL_GLOBAL_ALL);
@@ -645,24 +703,51 @@ init_rtsp(char* rtsp_uri, int rtsp_port, void *state, char* nals) {
/* request server options */
rtsp_options(curl, uri);
debug_msg("sdp_file: %s\n", sdp_filename);
printf("sdp_file: %s\n", sdp_filename);
/* request session description and write response to sdp file */
rtsp_describe(curl, uri, sdp_filename);
debug_msg("sdp_file!!!!: %s\n", sdp_filename);
/* get media control attribute from sdp file */
get_media_control_attribute(sdp_filename, control);
// printf("sdp_file name: %s\n", sdp_filename);
/* set incoming media codec attribute from sdp file */
if (set_codec_attribute_from_incoming_media(sdp_filename, s) == 0)
setup_codecs_and_controls_from_sdp(sdp_filename, s);
if (s->vrtsp_state->codec == "H264"){
sprintf(uri, "%s/%s", url, s->vrtsp_state->control);
printf("\n V URI = %s\n",uri);
rtsp_setup(curl, uri, Vtransport);
//rtsp_play(curl, uri, range);
sprintf(uri, "%s", url);
}
if (s->artsp_state->codec == "PCMU"){
sprintf(uri, "%s/%s", url, s->artsp_state->control);
printf("\n A URI = %s\n",uri);
rtsp_setup(curl, uri, Atransport);
//rtsp_play(curl, uri, range);
sprintf(uri, "%s", url);
}
if (s->artsp_state->codec == "" && s->vrtsp_state->codec == ""){
return -1;
}else rtsp_play(curl, uri, range);
/* setup media stream */
sprintf(uri, "%s/%s", url, control);
rtsp_setup(curl, uri, transport);
/* start playing media stream */
sprintf(uri, "%s", url);
rtsp_play(curl, uri, range);
// /* set incoming media codec attribute from sdp file */
// //FIND VIDEO TRACK (NOW ONLY H264 IS ACCEPTED)
// char * codec1 = set_codec_attribute_from_incoming_media(sdp_filename, s); //AQUÍ ACTIVAR VIDEO H264 SI EXISTEIX I/O AUDIO ULAW SI EXISTEIX
// if (codec1 == NULL)
// return -1;
// else { /* get media control attribute from sdp file */
// get_media_control_attribute(sdp_filename, control);
// printf("\nmedia control attribute: %s\n\n", control);
// /* setup media stream */
// sprintf(uri, "%s/%s", url, control);
// printf("setup: %s\n", uri);
// rtsp_setup(curl, uri, Vtransport);
//
// // exit(0);
// /* start playing media stream */
// sprintf(uri, "%s", url);
//
//
// }
// rtsp_play(curl, uri, range);
/* get start nal size attribute from sdp file */
len_nals = get_nals(sdp_filename, nals);
@@ -682,6 +767,108 @@ init_rtsp(char* rtsp_uri, int rtsp_port, void *state, char* nals) {
return len_nals;
}
void setup_codecs_and_controls_from_sdp(const char *sdp_filename, void *state) {
struct rtsp_state *rtspState;
rtspState = (struct rtsp_state *) state;
int n=0;
char *line = (char*) malloc(1024);
char* tmpBuff;
int countT = 0;
int countC = 0;
char* codecs[2];
char* tracks[2];
for(int q=0; q<2 ; q++){
codecs[q] = (char*) malloc(10);
tracks[q] = (char*) malloc(10);
}
FILE* fp;
fp = fopen(sdp_filename, "r");
if(fp == 0){
printf("unable to open asset %s", sdp_filename);
fclose(fp);
return -1;
}
fseek(fp, 0, SEEK_END);
unsigned long fileSize = ftell(fp);
rewind(fp);
char* buffer = (char*) malloc(fileSize+1);
unsigned long readResult = fread(buffer, sizeof(char), fileSize, fp);
if(readResult != fileSize){
printf("something bad happens, read result != file size");
return -1;
}
buffer[fileSize] = '\0';
while (buffer[n] != '\0'){
newLine(buffer,&n,line);
sscanf(line, " a = control: %s", tmpBuff);
tmpBuff = strstr(line, "track");
if(tmpBuff!=NULL){
//printf("track = %s\n",tmpBuff);
strncpy(tracks[countT],tmpBuff,strlen(tmpBuff));
tracks[countT][strlen(tmpBuff)] = '\0';
countT++;
}
tmpBuff='\0';
sscanf(line, " a=rtpmap:96 %s", tmpBuff);
tmpBuff = strstr(line, "H264");
if(tmpBuff!=NULL){
//printf("codec = %s\n",tmpBuff);
strncpy(codecs[countC],tmpBuff,4);
codecs[countC][4] = '\0';
countC++;
}
tmpBuff='\0';
sscanf(line, " a=rtpmap:97 %s", tmpBuff);
tmpBuff = strstr(line, "PCMU");
if(tmpBuff!=NULL){
//printf("codec = %s\n",tmpBuff);
strncpy(codecs[countC],tmpBuff,4);
codecs[countC][4] = '\0';
countC++;
}
tmpBuff='\0';
if(countT > 1 && countC > 1) break;
}
printf("\nTRACK = %s FOR CODEC = %s",tracks[0],codecs[0]);
printf("\nTRACK = %s FOR CODEC = %s\n",tracks[1],codecs[1]);
for(int p=0;p<2;p++){
if(strncmp(codecs[p],"H264",4)==0){
rtspState->vrtsp_state->codec = "H264";
rtspState->vrtsp_state->control = tracks[p];
}if(strncmp(codecs[p],"PCMU",4)==0){
rtspState->artsp_state->codec = "PCMU";
rtspState->artsp_state->control = tracks[p];
}
}
free(line);
free(buffer);
fclose(fp);
}
void newLine(const char* buffer, int* i, char* line){
int j=0;
while(buffer[*i] != '\n' && buffer[*i] != '\0'){
j++;
(*i)++;
}
if(buffer[*i] == '\n'){
j++;
(*i)++;
}
if(j>0){
memcpy(line,buffer+(*i)-j,j);
line[j] = '\0';
}
}
/**
* Initializes decompressor if required by decompress flag
*/
@@ -690,24 +877,24 @@ init_decompressor(void *state) {
struct rtsp_state *sr;
sr = (struct rtsp_state *) state;
sr->sd = (struct state_decompress *) calloc(2,
sr->vrtsp_state->sd = (struct state_decompress *) calloc(2,
sizeof(struct state_decompress *));
initialize_video_decompress();
if (decompress_is_available(LIBAVCODEC_MAGIC)) {
sr->sd = decompress_init(LIBAVCODEC_MAGIC);
sr->vrtsp_state->sd = decompress_init(LIBAVCODEC_MAGIC);
sr->des.width = sr->width;
sr->des.height = sr->height;
sr->des.color_spec = sr->frame->color_spec;
sr->des.tile_count = 0;
sr->des.interlacing = PROGRESSIVE;
sr->vrtsp_state->des.width = sr->vrtsp_state->width;
sr->vrtsp_state->des.height = sr->vrtsp_state->height;
sr->vrtsp_state->des.color_spec = sr->vrtsp_state->frame->color_spec;
sr->vrtsp_state->des.tile_count = 0;
sr->vrtsp_state->des.interlacing = PROGRESSIVE;
decompress_reconfigure(sr->sd, sr->des, 16, 8, 0,
vc_get_linesize(sr->des.width, UYVY), UYVY);
decompress_reconfigure(sr->vrtsp_state->sd, sr->vrtsp_state->des, 16, 8, 0,
vc_get_linesize(sr->vrtsp_state->des.width, UYVY), UYVY);
} else
return 0;
sr->out_frame = malloc(sr->width * sr->height * 4);
sr->vrtsp_state->out_frame = malloc(sr->vrtsp_state->width * sr->vrtsp_state->height * 4);
return 1;
}
@@ -838,17 +1025,21 @@ get_sdp_filename(const char *url, char *sdp_filename) {
* scan sdp file for media control attribute
*/
static void
get_media_control_attribute(const char *sdp_filename, char *control) {
check_and_set_media_control_attribute(const char *sdp_filename, void *state) {
struct rtsp_state *rtspState;
rtspState = (struct rtsp_state *) state;
int max_len = 1256;
char *s = malloc(max_len);
char *track = malloc(max_len);
char *track_ant = malloc(max_len);
printf("\n\n");
FILE *sdp_fp = fopen(sdp_filename, "rt");
//control[0] = '\0';
if (sdp_fp != NULL) {
while (fgets(s, max_len - 2, sdp_fp) != NULL) {
printf("\nSDP: %s\n",s);
sscanf(s, " a = control: %s", track_ant);
if (strcmp(track_ant, "") != 0) {
track = strstr(track_ant, "track");
@@ -856,7 +1047,34 @@ get_media_control_attribute(const char *sdp_filename, char *control) {
break;
}
}
printf("\n\n");
fclose(sdp_fp);
}
free(s);
memcpy(rtspState->vrtsp_state->control, track, strlen(track));
}
static void
get_media_control_attribute(const char *sdp_filename, char *control) {
int max_len = 1256;
char *s = malloc(max_len);
char *track = malloc(max_len);
char *track_ant = malloc(max_len);
printf("\n\n");
FILE *sdp_fp = fopen(sdp_filename, "rt");
//control[0] = '\0';
if (sdp_fp != NULL) {
while (fgets(s, max_len - 2, sdp_fp) != NULL) {
printf("\nSDP: %s\n",s);
sscanf(s, " a = control: %s", track_ant);
if (strcmp(track_ant, "") != 0) {
track = strstr(track_ant, "track");
if (track != NULL)
break;
}
}
printf("\n\n");
fclose(sdp_fp);
}
free(s);
@@ -866,7 +1084,7 @@ get_media_control_attribute(const char *sdp_filename, char *control) {
/**
* scan sdp file for incoming codec and set it
*/
static int
static char *
set_codec_attribute_from_incoming_media(const char *sdp_filename, void *state) {
struct rtsp_state *sr;
sr = (struct rtsp_state *) state;
@@ -901,17 +1119,26 @@ set_codec_attribute_from_incoming_media(const char *sdp_filename, void *state) {
tmp = strtok_r(codec, "/", &save_ptr);
if (!tmp) {
fprintf(stderr, "[rtsp] no codec atribute found into sdp file...\n");
return 0;
return NULL;
}
sprintf((char *) sr->in_codec, "%s", tmp);
if (memcmp(sr->in_codec, "H264", 4) == 0)
sr->frame->color_spec = H264;
else if (memcmp(sr->in_codec, "VP8", 3) == 0)
sr->frame->color_spec = VP8;
else
sr->frame->color_spec = RGBA;
return 1;
printf("\n\nCODEC = %s\n\n",tmp);
sprintf((char *) sr->vrtsp_state->in_codec, "%s", tmp);
if (memcmp(sr->vrtsp_state->in_codec, "H264", 4) == 0){
sr->vrtsp_state->frame->color_spec = H264;
return "H264";
}
else if (memcmp(sr->vrtsp_state->in_codec, "VP8", 3) == 0){
sr->vrtsp_state->frame->color_spec = VP8;
return "VP8";
}
else{
sr->vrtsp_state->frame->color_spec = RGBA;
return "RGBA";
}
return NULL;
}
struct vidcap_type *
@@ -932,19 +1159,19 @@ vidcap_rtsp_done(void *state) {
struct rtsp_state *s = state;
s->should_exit = true;
pthread_join(s->rtsp_thread_id, NULL);
pthread_join(s->vrtsp_state->vrtsp_thread_id, NULL);
free(s->rx_data->frame_buffer);
free(s->data);
free(s->vrtsp_state->rx_data->frame_buffer);
free(s->vrtsp_state->data);
rtsp_teardown(s->curl, s->uri);
curl_easy_cleanup(s->curl);
s->curl = NULL;
if (s->decompress)
decompress_done(s->sd);
rtp_done(s->device);
if (s->vrtsp_state->decompress)
decompress_done(s->vrtsp_state->sd);
rtp_done(s->vrtsp_state->device);
free(s);
}