Example #1
0
/*****************************************************************************
 * output_Flush
 *****************************************************************************/
static void output_Flush( output_t *p_output )
{
    packet_t *p_packet = p_output->p_packets;
    int i_block_cnt = output_BlockCount( p_output );
    struct iovec p_iov[i_block_cnt + 2];
    uint8_t p_rtp_hdr[RTP_HEADER_SIZE];
    int i_iov = 0, i_payload_len, i_block;

    if ( (p_output->config.i_config & OUTPUT_RAW) )
    {
        p_iov[i_iov].iov_base = &p_output->raw_pkt_header;
        p_iov[i_iov].iov_len = sizeof(struct udprawpkt);
        i_iov++;
    }

    if ( !(p_output->config.i_config & OUTPUT_UDP) )
    {
        p_iov[i_iov].iov_base = p_rtp_hdr;
        p_iov[i_iov].iov_len = sizeof(p_rtp_hdr);

        rtp_set_hdr( p_rtp_hdr );
        rtp_set_type( p_rtp_hdr, RTP_TYPE_TS );
        rtp_set_seqnum( p_rtp_hdr, p_output->i_seqnum++ );
        rtp_set_timestamp( p_rtp_hdr,
                           p_output->i_ref_timestamp
                            + (p_packet->i_dts - p_output->i_ref_wallclock)
                               * 9 / 100 );
        rtp_set_ssrc( p_rtp_hdr, p_output->config.pi_ssrc );

        i_iov++;
    }

    for ( i_block = 0; i_block < p_packet->i_depth; i_block++ )
    {
        /* Do pid mapping here if needed.
         * save the original pid in the block.
         * set the pid to the new pid
         * later we re-instate the old pid for the next output
         */
        if ( b_do_remap || p_output->b_do_remap ) {
            block_t *p_block = p_packet->pp_blocks[i_block];
            uint16_t i_pid = ts_get_pid( p_block->p_ts );
            p_block->tmp_pid = UNUSED_PID;
            if ( p_output->pi_newpids[i_pid] != UNUSED_PID )
            {
                uint16_t i_newpid = p_output->pi_newpids[i_pid];
                /* Need to map this pid to the new pid */
                ts_set_pid( p_block->p_ts, i_newpid );
                p_block->tmp_pid = i_pid;
            }
        }

        p_iov[i_iov].iov_base = p_packet->pp_blocks[i_block]->p_ts;
        p_iov[i_iov].iov_len = TS_SIZE;
        i_iov++;
    }

    for ( ; i_block < i_block_cnt; i_block++ )
    {
        p_iov[i_iov].iov_base = p_pad_ts;
        p_iov[i_iov].iov_len = TS_SIZE;
        i_iov++;
    }

    
    if ( (p_output->config.i_config & OUTPUT_RAW) )
    {
        i_payload_len = 0;
        for ( i_block = 1; i_block < i_iov; i_block++ ) {
            i_payload_len += p_iov[i_block].iov_len; 
        }
        p_output->raw_pkt_header.udph.len = htons(sizeof(struct udpheader) + i_payload_len);
    }

    if ( writev( p_output->i_handle, p_iov, i_iov ) < 0 )
    {
        msg_Err( NULL, "couldn't writev to %s (%s)",
                 p_output->config.psz_displayname, strerror(errno) );
    }
    /* Update the wallclock because writev() can take some time. */
    i_wallclock = mdate();

    for ( i_block = 0; i_block < p_packet->i_depth; i_block++ )
    {
        p_packet->pp_blocks[i_block]->i_refcount--;
        if ( !p_packet->pp_blocks[i_block]->i_refcount )
            block_Delete( p_packet->pp_blocks[i_block] );
        else if ( b_do_remap || p_output->b_do_remap ) {
            /* still referenced so re-instate the orignial pid if remapped */
            block_t * p_block = p_packet->pp_blocks[i_block];
            if (p_block->tmp_pid != UNUSED_PID)
                ts_set_pid( p_block->p_ts, p_block->tmp_pid );
        }
    }
    p_output->p_packets = p_packet->p_next;
    free( p_packet );
    if ( p_output->p_packets == NULL )
        p_output->p_last_packet = NULL;
}
Example #2
0
/*****************************************************************************
 * Entry point
 *****************************************************************************/
int main( int i_argc, char **pp_argv )
{
    int c;
    int i_priority = -1;
    int i_ttl = 0;
    bool b_udp = false;
    struct pollfd pfd[2];

    while ( (c = getopt( i_argc, pp_argv, "i:t:wo:x:X:Um:R:h" )) != -1 )
    {
        switch ( c )
        {
        case 'i':
            i_priority = strtol( optarg, NULL, 0 );
            break;

        case 't':
            i_ttl = strtol( optarg, NULL, 0 );
            break;

        case 'w':
            b_overwrite_timestamps = true;
            break;

        case 'o':
        {
            struct in_addr maddr;
            if ( !inet_aton( optarg, &maddr ) )
                usage();
            i_ssrc = maddr.s_addr;
            b_overwrite_ssrc = true;
            break;
        }

        case 'x':
            i_retx_buffer = strtoll( optarg, NULL, 0 ) * 27000;
            break;

        case 'X':
            i_retx_fd = OpenSocket( optarg, 0, 0, 0, NULL, &b_retx_tcp, NULL );
            if ( i_retx_fd == -1 )
            {
                msg_Err( NULL, "unable to set up retx with %s\n", optarg );
                exit(EXIT_FAILURE);
            }
            pfd[1].fd = i_retx_fd;
            pfd[1].events = POLLIN | POLLERR | POLLRDHUP | POLLHUP;

            p_retx_block = malloc( sizeof(block_t) + RETX_HEADER_SIZE );
            p_retx_block->p_data = (uint8_t *)p_retx_block + sizeof(block_t);
            p_retx_block->i_size = 0;
            break;

        case 'U':
            b_udp = true;
            break;

        case 'm':
            i_asked_payload_size = strtol( optarg, NULL, 0 );
            break;

        case 'R':
            i_rtp_header_size = strtol( optarg, NULL, 0 );
            break;

        case 'h':
        default:
            usage();
            break;
        }
    }
    if ( optind >= i_argc - 1 )
        usage();

    i_input_fd = OpenSocket( pp_argv[optind], 0, DEFAULT_PORT, 0, NULL,
                             &b_input_tcp, NULL );
    if ( i_input_fd == -1 )
    {
        msg_Err( NULL, "unable to open input socket" );
        exit(EXIT_FAILURE);
    }

    optind++;
    pfd[0].fd = i_input_fd;
    pfd[0].events = POLLIN | POLLERR | POLLRDHUP | POLLHUP;

    while ( optind < i_argc )
    {
        p_outputs = realloc( p_outputs, ++i_nb_outputs * sizeof(output_t) );
        p_outputs[i_nb_outputs - 1].i_fd =
            OpenSocket( pp_argv[optind++], i_ttl, 0, DEFAULT_PORT,
                        &p_outputs[i_nb_outputs - 1].i_weight, NULL, NULL );
        if ( p_outputs[i_nb_outputs - 1].i_fd == -1 )
        {
            msg_Err( NULL, "unable to open output socket" );
            exit(EXIT_FAILURE);
        }

        p_outputs[i_nb_outputs - 1].i_weighted_size =
            p_outputs[i_nb_outputs - 1].i_remainder = 0;
        i_max_weight += p_outputs[i_nb_outputs - 1].i_weight;
    }
    msg_Dbg( NULL, "%d outputs weight %u%s", i_nb_outputs, i_max_weight,
             i_retx_fd != -1 ? ", with retx" : "" );

    if ( i_priority > 0 )
    {
        struct sched_param param;
        int i_error;

        memset( &param, 0, sizeof(struct sched_param) );
        param.sched_priority = i_priority;
        if ( (i_error = pthread_setschedparam( pthread_self(), SCHED_RR,
                                               &param )) )
        {
            msg_Warn( NULL, "couldn't set thread priority: %s",
                      strerror(i_error) );
        }
    }

    for ( ; ; )
    {
        uint64_t i_current_date;
        if ( poll( pfd, i_retx_fd == -1 ? 1 : 2, -1 ) < 0 )
        {
            int saved_errno = errno;
            msg_Warn( NULL, "couldn't poll(): %s", strerror(errno) );
            if ( saved_errno == EINTR ) continue;
            exit(EXIT_FAILURE);
        }
        i_current_date = wall_Date();

        if ( (pfd[0].revents & (POLLERR | POLLRDHUP | POLLHUP)) ||
             (i_retx_fd != -1 &&
              (pfd[1].revents & (POLLERR | POLLRDHUP | POLLHUP))))
        {
            msg_Err( NULL, "poll error\n" );
            exit(EXIT_FAILURE);
        }

        if ( pfd[0].revents & POLLIN )
        {
            /* Read input block */
            ssize_t i_size, i_wanted_size;
            uint8_t *p_read_buffer;

            if ( b_udp )
                i_wanted_size = i_asked_payload_size + RTP_HEADER_SIZE;
            else
                i_wanted_size = i_asked_payload_size + i_rtp_header_size;

            if ( p_input_block == NULL )
            {
                if ( b_udp )
                {
                    p_input_block = malloc( sizeof(block_t) +
                                            i_asked_payload_size +
                                            RTP_HEADER_SIZE );
                    p_input_block->i_size = RTP_HEADER_SIZE;
                }
                else
                {
                    p_input_block = malloc( sizeof(block_t) +
                                            i_asked_payload_size +
                                            i_rtp_header_size );
                    p_input_block->p_data = (uint8_t *)p_input_block +
                                            sizeof(block_t);
                    p_input_block->i_size = 0;
                }
                p_input_block->p_data = (uint8_t *)p_input_block +
                                        sizeof(block_t);
            }

            p_read_buffer = p_input_block->p_data + p_input_block->i_size;
            i_wanted_size -= p_input_block->i_size;
            i_size = read( i_input_fd, p_read_buffer, i_wanted_size );

            if ( i_size < 0 && errno != EAGAIN && errno != EINTR )
            {
                msg_Err( NULL, "unrecoverable read error, dying (%s)",
                         strerror(errno) );
                exit(EXIT_FAILURE);
            }
            if ( i_size <= 0 ) continue;

            p_input_block->i_size += i_size;

            if ( b_input_tcp && i_size != i_wanted_size )
                continue;

            if ( b_udp )
            {
                rtp_set_hdr( p_input_block->p_data );
                rtp_set_type( p_input_block->p_data, RTP_TYPE_TS );
                rtp_set_seqnum( p_input_block->p_data, i_rtp_seqnum );
                i_rtp_seqnum++;
                rtp_set_ssrc( p_input_block->p_data, (uint8_t *)&i_ssrc );
                /* this isn't RFC-compliant, but we assume that at the other
                 * end, the RTP header will be stripped */
                rtp_set_timestamp( p_input_block->p_data,
                                   i_current_date / 300 );
            }
            else
            {
                if ( b_overwrite_ssrc )
                    rtp_set_ssrc( p_input_block->p_data,
                                  (uint8_t *)&i_ssrc );
                if ( b_overwrite_timestamps )
                    rtp_set_timestamp( p_input_block->p_data,
                                       i_current_date / 300 );
            }

            /* Output block */
            output_t *p_output = NextOutput();
            SendBlock( p_output->i_fd, NULL, 0, p_input_block );

            p_output->i_weighted_size += (i_size + p_output->i_remainder)
                                           / p_output->i_weight;
            p_output->i_remainder = (i_size + p_output->i_remainder)
                                           % p_output->i_weight;

            if ( i_retx_fd != -1 )
                RetxQueue( p_input_block, i_current_date );
            else
                free( p_input_block );

            p_input_block = NULL;
        }

        if ( i_retx_fd != -1 && (pfd[1].revents & POLLIN) )
            RetxHandle();
    }

    return EXIT_SUCCESS;
}