rtmp_amf_flv.c 86.2 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
/*****************************************************************************
 * rtmp_amf_flv.c: RTMP, AMF and FLV over RTMP implementation.
 *****************************************************************************
 * Copyright (C) URJC - LADyR - Luis Lopez Fernandez
 *
 * Author: Miguel Angel Cabrera Moya
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
18 19 20
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
21 22 23 24 25 26 27 28 29
 *****************************************************************************/

/*****************************************************************************
 * RTMP header:
 ******************************************************************************/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

30
#include <vlc_common.h>
31 32 33 34 35
#include <vlc_access.h>

#include <vlc_network.h> /* DOWN: #include <network.h> */
#include <vlc_url.h>
#include <vlc_block.h>
36
#include <vlc_rand.h>
37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101

#include <stdlib.h>
#include <stdint.h>
#include <string.h>

#include "rtmp_amf_flv.h"

/* header length (including itself) */
const uint8_t RTMP_HEADER_SIZE_MASK = 0xC0;
const uint8_t RTMP_HEADER_SIZE_12 = 0x00; 
const uint8_t RTMP_HEADER_SIZE_8 = 0x40;
const uint8_t RTMP_HEADER_SIZE_4 = 0x80;
const uint8_t RTMP_HEADER_SIZE_1 = 0xC0;

/* streams */
const uint8_t RTMP_HEADER_STREAM_MAX = 64;
const uint8_t RTMP_HEADER_STREAM_INDEX_MASK = 0x3F;

/* handshake */
const uint8_t RTMP_HANDSHAKE = 0x03;
const uint16_t RTMP_HANDSHAKE_BODY_SIZE = 1536;

/* content types */
const uint8_t RTMP_CONTENT_TYPE_CHUNK_SIZE = 0x01;
const uint8_t RTMP_CONTENT_TYPE_UNKNOWN_02 = 0x02;
const uint8_t RTMP_CONTENT_TYPE_BYTES_READ = 0x03;
const uint8_t RTMP_CONTENT_TYPE_PING = 0x04;
const uint8_t RTMP_CONTENT_TYPE_SERVER_BW = 0x05;
const uint8_t RTMP_CONTENT_TYPE_CLIENT_BW = 0x06;
const uint8_t RTMP_CONTENT_TYPE_UNKNOWN_07 = 0x07;
const uint8_t RTMP_CONTENT_TYPE_AUDIO_DATA = 0x08;
const uint8_t RTMP_CONTENT_TYPE_VIDEO_DATA = 0x09;
const uint8_t RTMP_CONTENT_TYPE_UNKNOWN_0A_0E = 0x0A;
const uint8_t RTMP_CONTENT_TYPE_FLEX_STREAM = 0x0F;
const uint8_t RTMP_CONTENT_TYPE_FLEX_SHARED_OBJECT = 0x10;
const uint8_t RTMP_CONTENT_TYPE_MESSAGE = 0x11;
const uint8_t RTMP_CONTENT_TYPE_NOTIFY = 0x12;
const uint8_t RTMP_CONTENT_TYPE_SHARED_OBJECT = 0x13;
const uint8_t RTMP_CONTENT_TYPE_INVOKE = 0x14;

/* shared object datatypes */
const uint8_t RTMP_SHARED_OBJECT_DATATYPE_CONNECT = 0x01;
const uint8_t RTMP_SHARED_OBJECT_DATATYPE_DISCONNECT = 0x02;
const uint8_t RTMP_SHARED_OBJECT_DATATYPE_SET_ATTRIBUTE = 0x03;
const uint8_t RTMP_SHARED_OBJECT_DATATYPE_UPDATE_DATA = 0x04;
const uint8_t RTMP_SHARED_OBJECT_DATATYPE_UPDATE_ATTRIBUTE = 0x05;
const uint8_t RTMP_SHARED_OBJECT_DATATYPE_SEND_MESSAGE = 0x06;
const uint8_t RTMP_SHARED_OBJECT_DATATYPE_STATUS = 0x07;
const uint8_t RTMP_SHARED_OBJECT_DATATYPE_CLEAR_DATA = 0x08;
const uint8_t RTMP_SHARED_OBJECT_DATATYPE_DELETE_DATA = 0x09;
const uint8_t RTMP_SHARED_OBJECT_DATATYPE_DELETE_ATTRIBUTE = 0x0A;
const uint8_t RTMP_SHARED_OBJECT_DATATYPE_INITIAL_DATA = 0x0B;

/* pings */
const uint16_t RTMP_PING_CLEAR_STREAM = 0x0000;
const uint16_t RTMP_PING_CLEAR_PLAYING_BUFFER = 0x0001;
const uint16_t RTMP_PING_BUFFER_TIME_CLIENT = 0x0003;
const uint16_t RTMP_PING_RESET_STREAM = 0x0004;
const uint16_t RTMP_PING_CLIENT_FROM_SERVER = 0x0006;
const uint16_t RTMP_PING_PONG_FROM_CLIENT = 0x0007;

/* pings sizes */
const uint8_t RTMP_PING_SIZE_CLEAR_STREAM = 6;
const uint8_t RTMP_PING_SIZE_CLEAR_PLAYING_BUFFER = 6;
const uint8_t RTMP_PING_SIZE_BUFFER_TIME_CLIENT = 10;
102 103
const uint8_t RTMP_PING_SIZE_RESET_STREAM = 6;
/*const uint8_t RTMP_PING_SIZE_CLIENT_FROM_SERVER = 0x0006; TODO
104 105 106
const uint8_t RTMP_PING_SIZE_PONG_FROM_CLIENT = 0x0007;
*/

107 108 109 110 111 112 113 114 115 116
/* default values */
const uint8_t RTMP_DEFAULT_STREAM_INDEX_CONTROL = 0x02;
const uint8_t RTMP_DEFAULT_STREAM_INDEX_INVOKE = 0x03;
const uint8_t RTMP_DEFAULT_STREAM_INDEX_NOTIFY = 0x04;
const uint8_t RTMP_DEFAULT_STREAM_INDEX_VIDEO_DATA = 0x05;
const uint8_t RTMP_DEFAULT_STREAM_INDEX_AUDIO_DATA = 0x06;
const uint32_t RTMP_DEFAULT_CHUNK_SIZE = 128;
const double RTMP_DEFAULT_STREAM_CLIENT_ID = 1.0;
const double RTMP_DEFAULT_STREAM_SERVER_ID = 1.0;

117
/* misc */
118
const uint16_t MAX_EMPTY_BLOCKS = 200; /* empty blocks in fifo for media*/
119
const uint16_t RTMP_BODY_SIZE_ALLOC = 1024;
Pavlov Konstantin's avatar
Pavlov Konstantin committed
120
const uint32_t RTMP_TIME_CLIENT_BUFFER = 2000; /* milliseconds */
121
const uint32_t RTMP_SERVER_BW = 0x00000200;
122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172
const uint32_t RTMP_SRC_DST_CONNECT_OBJECT = 0x00000000;
const uint32_t RTMP_SRC_DST_CONNECT_OBJECT2 = 0x00000001;
const uint32_t RTMP_SRC_DST_DEFAULT = 0x01000000;
const uint64_t RTMP_AUDIOCODECS = 0x4083380000000000;
const uint64_t RTMP_VIDEOCODECS = 0x405f000000000000;
const uint64_t RTMP_VIDEOFUNCTION = 0x3ff0000000000000;
/*****************************************************************************
 * AMF header:
 ******************************************************************************/

/* boolean constants */
const uint8_t AMF_BOOLEAN_FALSE = 0x00;
const uint8_t AMF_BOOLEAN_TRUE = 0x01;

/* datatypes */
const uint8_t AMF_DATATYPE_NUMBER = 0x00;
const uint8_t AMF_DATATYPE_BOOLEAN = 0x01;
const uint8_t AMF_DATATYPE_STRING = 0x02;
const uint8_t AMF_DATATYPE_OBJECT = 0x03;
const uint8_t AMF_DATATYPE_MOVIE_CLIP = 0x04;
const uint8_t AMF_DATATYPE_NULL = 0x05;
const uint8_t AMF_DATATYPE_UNDEFINED = 0x06;
const uint8_t AMF_DATATYPE_REFERENCE = 0x07;
const uint8_t AMF_DATATYPE_MIXED_ARRAY = 0x08;
const uint8_t AMF_DATATYPE_END_OF_OBJECT = 0x09;
const uint8_t AMF_DATATYPE_ARRAY = 0x0A;
const uint8_t AMF_DATATYPE_DATE = 0x0B;
const uint8_t AMF_DATATYPE_LONG_STRING = 0x0C;
const uint8_t AMF_DATATYPE_UNSUPPORTED = 0x0D;
const uint8_t AMF_DATATYPE_RECORDSET = 0x0E;
const uint8_t AMF_DATATYPE_XML = 0x0F;
const uint8_t AMF_DATATYPE_TYPED_OBJECT = 0x10;
const uint8_t AMF_DATATYPE_AMF3_DATA = 0x11;

/* datatypes sizes */
const uint8_t AMF_DATATYPE_SIZE_NUMBER = 9;
const uint8_t AMF_DATATYPE_SIZE_BOOLEAN = 2;
const uint8_t AMF_DATATYPE_SIZE_STRING = 3;
const uint8_t AMF_DATATYPE_SIZE_OBJECT = 1;
const uint8_t AMF_DATATYPE_SIZE_NULL = 1;
const uint8_t AMF_DATATYPE_SIZE_OBJECT_VARIABLE = 2;
const uint8_t AMF_DATATYPE_SIZE_MIXED_ARRAY = 5;
const uint8_t AMF_DATATYPE_SIZE_END_OF_OBJECT = 3;

/* amf remote calls */
const uint64_t AMF_CALL_NETCONNECTION_CONNECT = 0x3FF0000000000000;
const uint64_t AMF_CALL_NETCONNECTION_CONNECT_AUDIOCODECS = 0x4083380000000000;
const uint64_t AMF_CALL_NETCONNECTION_CONNECT_VIDEOCODECS = 0x405F000000000000;
const uint64_t AMF_CALL_NETCONNECTION_CONNECT_VIDEOFUNCTION = 0x3FF0000000000000;
const uint64_t AMF_CALL_NETCONNECTION_CONNECT_OBJECTENCODING = 0x0;
const double AMF_CALL_STREAM_CLIENT_NUMBER = 3.0;
173
const double AMF_CALL_ONBWDONE = 2.0; 
174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226
const uint64_t AMF_CALL_NETSTREAM_PLAY = 0x0;

/*****************************************************************************
 * FLV header:
 ******************************************************************************/
const uint8_t FLV_HEADER_SIGNATURE[3] = { 0x46, 0x4C, 0x56 }; /* always "FLV" */
const uint8_t FLV_HEADER_VERSION = 0x01;
const uint8_t FLV_HEADER_AUDIO = 0x04;
const uint8_t FLV_HEADER_VIDEO = 0x01;
const uint32_t FLV_HEADER_SIZE = 0x00000009; /* always 9 for known FLV files */

const uint32_t FLV_TAG_FIRST_PREVIOUS_TAG_SIZE = 0x00000000;
const uint8_t FLV_TAG_PREVIOUS_TAG_SIZE = 4;
const uint8_t FLV_TAG_SIZE = 11;

/* audio stereo types */
const uint8_t FLV_AUDIO_STEREO_MASK = 0x01;
const uint8_t FLV_AUDIO_STEREO_MONO = 0x00;
const uint8_t FLV_AUDIO_STEREO_STEREO = 0x01;

/* audio size */
const uint8_t FLV_AUDIO_SIZE_MASK = 0x02;
const uint8_t FLV_AUDIO_SIZE_8_BIT = 0x00;
const uint8_t FLV_AUDIO_SIZE_16_BIT = 0x02;

/* audio rate */
const uint8_t FLV_AUDIO_RATE_MASK = 0x0C;
const uint8_t FLV_AUDIO_RATE_5_5_KHZ = 0x00;
const uint8_t FLV_AUDIO_RATE_11_KHZ = 0x04;
const uint8_t FLV_AUDIO_RATE_22_KHZ = 0x08;
const uint8_t FLV_AUDIO_RATE_44_KHZ = 0x0C;

/* audio codec types */
const uint8_t FLV_AUDIO_CODEC_ID_MASK = 0xF0;
const uint8_t FLV_AUDIO_CODEC_ID_UNCOMPRESSED = 0x00;
const uint8_t FLV_AUDIO_CODEC_ID_ADPCM = 0x10;
const uint8_t FLV_AUDIO_CODEC_ID_MP3 = 0x20;
const uint8_t FLV_AUDIO_CODEC_ID_NELLYMOSER_8KHZ_MONO = 0x50;
const uint8_t FLV_AUDIO_CODEC_ID_NELLYMOSER = 0x60;

/* video codec types */
const uint8_t FLV_VIDEO_CODEC_ID_MASK = 0x0F;
const uint8_t FLV_VIDEO_CODEC_ID_SORENSEN_H263 = 0x02;
const uint8_t FLV_VIDEO_CODEC_ID_SCREEN_VIDEO = 0x03;
const uint8_t FLV_VIDEO_CODEC_ID_ON2_VP6 = 0x04;
const uint8_t FLV_VIDEO_CODEC_ID_ON2_VP6_ALPHA = 0x05;
const uint8_t FLV_VIDEO_CODEC_ID_SCREEN_VIDEO_2 = 0x06;

/* video frame types */
const uint8_t FLV_VIDEO_FRAME_TYPE_MASK = 0xF0;
const uint8_t FLV_VIDEO_FRAME_TYPE_KEYFRAME = 0x10;
const uint8_t FLV_VIDEO_FRAME_TYPE_INTER_FRAME = 0x20;
const uint8_t FLV_VIDEO_FRAME_TYPE_DISPOSABLE_INTER_FRAME = 0x30;
227

228 229 230 231
/*****************************************************************************
 * static RTMP functions:
 ******************************************************************************/
static rtmp_packet_t *rtmp_new_packet( rtmp_control_thread_t *p_thread, uint8_t stream_index, uint32_t timestamp, uint8_t content_type, uint32_t src_dst, rtmp_body_t *body );
232 233 234 235 236 237 238 239 240 241 242
static block_t *rtmp_new_block( rtmp_control_thread_t *p_thread, uint8_t *buffer, int32_t length_buffer );

static rtmp_packet_t *rtmp_encode_onBWDone( rtmp_control_thread_t *p_thread, double number );
static rtmp_packet_t *rtmp_encode_server_bw( rtmp_control_thread_t *p_thread, uint32_t number );
static rtmp_packet_t *rtmp_encode_NetConnection_connect_result( rtmp_control_thread_t *p_thread, double number );
static rtmp_packet_t *rtmp_encode_createStream_result( rtmp_control_thread_t *p_thread, double stream_client, double stream_server );
static rtmp_packet_t *rtmp_encode_ping_reset_stream( rtmp_control_thread_t *p_thread );
static rtmp_packet_t *rtmp_encode_ping_clear_stream( rtmp_control_thread_t *p_thread, uint32_t src_dst );
static rtmp_packet_t *rtmp_encode_NetStream_play_reset_onStatus( rtmp_control_thread_t *p_thread, char *psz_media );
static rtmp_packet_t *rtmp_encode_NetStream_play_start_onStatus( rtmp_control_thread_t *p_thread, char *psz_media );
static uint8_t rtmp_encode_header_size( vlc_object_t *p_this, uint8_t header_size );
243
static uint8_t rtmp_decode_header_size( vlc_object_t *p_this, uint8_t header_size );
244
static uint8_t rtmp_get_stream_index( uint8_t content_type );
245

246
static void rtmp_body_append( rtmp_body_t *rtmp_body, uint8_t *buffer, uint32_t length );
247

248
static uint8_t *rtmp_encode_ping( uint16_t type, uint32_t src_dst, uint32_t third_arg, uint32_t fourth_arg );
249 250 251 252 253 254 255 256 257 258 259 260 261 262

/*****************************************************************************
 * static AMF functions:
 ******************************************************************************/
static uint8_t *amf_encode_element( uint8_t element, const void *value );
static uint8_t *amf_encode_object_variable( const char *key, uint8_t element, const void *value );
static double amf_decode_number( uint8_t **buffer );
static int amf_decode_boolean( uint8_t **buffer );
static char *amf_decode_string( uint8_t **buffer );
static char *amf_decode_object( uint8_t **buffer );

/*****************************************************************************
 * static FLV functions:
 ******************************************************************************/
263 264 265 266
static void flv_rebuild( rtmp_control_thread_t *p_thread, rtmp_packet_t *rtmp_packet );
static void flv_get_metadata_audio( rtmp_control_thread_t *p_thread, rtmp_packet_t *packet_audio, uint8_t *stereo, uint8_t *audiosamplesize, uint32_t *audiosamplerate, uint8_t *audiocodecid );
static void flv_get_metadata_video( rtmp_control_thread_t *p_thread, rtmp_packet_t *packet_video, uint8_t *videocodecid, uint8_t *frametype );
static rtmp_packet_t *flv_build_onMetaData( access_t *p_access, uint64_t duration, uint8_t stereo, uint8_t audiosamplesize, uint32_t audiosamplerate, uint8_t audiocodecid, uint8_t videocodecid );
267 268 269 270

/*****************************************************************************
 * RTMP implementation:
 ******************************************************************************/
271 272
int
rtmp_handshake_passive( vlc_object_t *p_this, int fd )
273 274 275 276 277 278 279
{
    uint8_t p_read[RTMP_HANDSHAKE_BODY_SIZE + 1];
    uint8_t p_write[RTMP_HANDSHAKE_BODY_SIZE * 2 + 1];
    ssize_t i_ret;
    int i;

    /* Receive handshake */
280
    i_ret = net_Read( p_this, fd, NULL, p_read, RTMP_HANDSHAKE_BODY_SIZE + 1, true );
281 282
    if( i_ret != RTMP_HANDSHAKE_BODY_SIZE + 1 )
    {
283
        msg_Err( p_this, "failed to receive handshake" );
284 285 286 287 288 289
        return -1;
    }

    /* Check handshake */
    if ( p_read[0] != RTMP_HANDSHAKE )
    {
290
        msg_Err( p_this, "first byte in handshake corrupt" );
291 292 293 294 295 296 297 298 299
        return -1;
    }

    /* Answer handshake */
    p_write[0] = RTMP_HANDSHAKE;
    memset( p_write + 1, 0, RTMP_HANDSHAKE_BODY_SIZE );
    memcpy( p_write + 1 + RTMP_HANDSHAKE_BODY_SIZE, p_read + 1, RTMP_HANDSHAKE_BODY_SIZE );

    /* Send handshake*/
300
    i_ret = net_Write( p_this, fd, NULL, p_write, RTMP_HANDSHAKE_BODY_SIZE * 2 + 1 );
301 302
    if( i_ret != RTMP_HANDSHAKE_BODY_SIZE * 2 + 1 )
    {
303
        msg_Err( p_this, "failed to send handshake" );
304 305 306 307
        return -1;
    }

    /* Receive acknowledge */
308
    i_ret = net_Read( p_this, fd, NULL, p_read, RTMP_HANDSHAKE_BODY_SIZE, true );
309 310
    if( i_ret != RTMP_HANDSHAKE_BODY_SIZE )
    {
311
        msg_Err( p_this, "failed to receive acknowledge" );
312 313 314 315 316 317 318
        return -1;
    }

    /* Check acknowledge */
    for(i = 8; i < RTMP_HANDSHAKE_BODY_SIZE; i++ )
        if( p_write[i + 1] != p_read[i] )
        {
319
            msg_Err( p_this, "body acknowledge received corrupt" );
320 321 322 323 324
            return -1;
        }

    return 0;
}
325 326 327

int
rtmp_handshake_active( vlc_object_t *p_this, int fd )
328 329 330 331 332 333 334
{
    uint8_t p_read[RTMP_HANDSHAKE_BODY_SIZE * 2 + 1];
    uint8_t p_write[RTMP_HANDSHAKE_BODY_SIZE + 1];
    ssize_t i_ret;
    int i;

    p_write[0] = RTMP_HANDSHAKE;
335 336 337 338 339

    for( i = 0; i < 8; i++ )
        p_write[i + 1] = 0x00;

    vlc_rand_bytes( p_write+1+8, RTMP_HANDSHAKE_BODY_SIZE-8 );
340 341

    /* Send handshake*/
342
    i_ret = net_Write( p_this, fd, NULL, p_write, RTMP_HANDSHAKE_BODY_SIZE+1 );
343 344
    if( i_ret != RTMP_HANDSHAKE_BODY_SIZE + 1 )
    {
345
        msg_Err( p_this, "failed to send handshake" );
346 347 348 349
        return -1;
    }

    /* Receive handshake */
350
    i_ret = net_Read( p_this, fd, NULL, p_read, RTMP_HANDSHAKE_BODY_SIZE * 2 + 1, true );
351 352
    if( i_ret != RTMP_HANDSHAKE_BODY_SIZE * 2 + 1 )
    {
353
        msg_Err( p_this, "failed to receive handshake" );
354 355 356 357 358 359
        return -1;
    }

    /* Check handshake */
    if( p_read[0] != RTMP_HANDSHAKE )
    {
360
        msg_Err( p_this, "first byte in handshake received corrupt" );
361 362 363
        return -1;
    }

364
    for(i = 8; i < RTMP_HANDSHAKE_BODY_SIZE; i++ )
365 366
        if( p_write[i + 1] != p_read[i + 1 + RTMP_HANDSHAKE_BODY_SIZE] )
        {
367
            msg_Err( p_this, "body handshake received corrupt" );
368 369 370 371
            return -1;
        }

    /* Acknowledge handshake */
372
    i_ret = net_Write( p_this, fd, NULL, p_read + 1, RTMP_HANDSHAKE_BODY_SIZE );
373 374
    if( i_ret != RTMP_HANDSHAKE_BODY_SIZE )
    {
375
        msg_Err( p_this, "failed to acknowledge handshake" );
376 377 378 379 380 381
        return -1;
    }

    return 0;
}

382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399
static int
write_rtmp( rtmp_control_thread_t *p_thread, uint8_t *buf,
            rtmp_packet_t *pkt, const char *errmsg )
{
    int32_t enclen = pkt->length_encoded;
    int ret = net_Write( p_thread, p_thread->fd, NULL, buf, enclen );
    free( pkt->body->body );
    free( pkt->body );
    free( pkt );
    free( buf );
    if( ret != enclen )
    {
        msg_Err( p_thread, errmsg );
        return 0;
    }
    return 1;
}

400 401
int
rtmp_connect_active( rtmp_control_thread_t *p_thread )
402 403 404 405 406 407 408
{
    rtmp_packet_t *rtmp_packet;
    rtmp_body_t *rtmp_body;
    uint8_t *tmp_buffer;
    char *tmp_url;

    /* Build NetConnection.connect call */
409
    rtmp_body = rtmp_body_new( -1 );
410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425

    tmp_buffer = amf_encode_element( AMF_DATATYPE_STRING, "connect" );
    rtmp_body_append( rtmp_body, tmp_buffer, 
        AMF_DATATYPE_SIZE_STRING + strlen( "connect" ) );
    free( tmp_buffer );

    tmp_buffer = amf_encode_element( AMF_DATATYPE_NUMBER,
        &AMF_CALL_NETCONNECTION_CONNECT );
    rtmp_body_append( rtmp_body, tmp_buffer, AMF_DATATYPE_SIZE_NUMBER );
    free( tmp_buffer );

    tmp_buffer = amf_encode_element( AMF_DATATYPE_OBJECT, NULL );
    rtmp_body_append( rtmp_body, tmp_buffer, AMF_DATATYPE_SIZE_OBJECT );
    free( tmp_buffer );

    tmp_buffer = amf_encode_object_variable( "app",
426
        AMF_DATATYPE_STRING, p_thread->psz_application );
427 428
    rtmp_body_append( rtmp_body, tmp_buffer,
        AMF_DATATYPE_SIZE_OBJECT_VARIABLE + strlen( "app" ) + 
429 430
        AMF_DATATYPE_SIZE_STRING + strlen( p_thread->psz_application ) );
    free( tmp_buffer );
431 432 433 434 435 436

    tmp_buffer = amf_encode_object_variable( "flashVer",
        AMF_DATATYPE_STRING, "LNX 9,0,48,0" );
    rtmp_body_append( rtmp_body, tmp_buffer,
        AMF_DATATYPE_SIZE_OBJECT_VARIABLE + strlen( "flashVer" ) +
        AMF_DATATYPE_SIZE_STRING + strlen( "LNX 9,0,48,0" ) );
437
    free( tmp_buffer );
438 439

    tmp_buffer = amf_encode_object_variable( "swfUrl",
440
         AMF_DATATYPE_STRING, p_thread->psz_swf_url );
441 442
    rtmp_body_append( rtmp_body, tmp_buffer,
        AMF_DATATYPE_SIZE_OBJECT_VARIABLE + strlen( "swfUrl" ) +
443
        AMF_DATATYPE_SIZE_STRING + strlen( p_thread->psz_swf_url ) );
444
    free( tmp_buffer );
445

446
    if( asprintf( &tmp_url, "rtmp://%s", p_thread->url.psz_buffer ) == -1 )
447 448 449 450 451
    {
        free( rtmp_body->body );
        free( rtmp_body );
        return -1;
    }
452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488
    tmp_buffer = amf_encode_object_variable( "tcUrl",
        AMF_DATATYPE_STRING, tmp_url );
    rtmp_body_append( rtmp_body, tmp_buffer,
        AMF_DATATYPE_SIZE_OBJECT_VARIABLE + strlen( "tcUrl" ) +
        AMF_DATATYPE_SIZE_STRING + strlen( tmp_url ) );
    free( tmp_url );
    free( tmp_buffer );

    tmp_buffer = amf_encode_object_variable( "fpad",
        AMF_DATATYPE_BOOLEAN, &AMF_BOOLEAN_FALSE );
    rtmp_body_append( rtmp_body, tmp_buffer,
        AMF_DATATYPE_SIZE_OBJECT_VARIABLE + strlen( "fpad" ) +
        AMF_DATATYPE_SIZE_BOOLEAN );
    free( tmp_buffer );

    tmp_buffer = amf_encode_object_variable( "audioCodecs",
        AMF_DATATYPE_NUMBER, &AMF_CALL_NETCONNECTION_CONNECT_AUDIOCODECS );
    rtmp_body_append( rtmp_body, tmp_buffer,
        AMF_DATATYPE_SIZE_OBJECT_VARIABLE + strlen( "audioCodecs" ) +
        AMF_DATATYPE_SIZE_NUMBER );
    free( tmp_buffer );

    tmp_buffer = amf_encode_object_variable( "videoCodecs",
        AMF_DATATYPE_NUMBER, &AMF_CALL_NETCONNECTION_CONNECT_VIDEOCODECS );
    rtmp_body_append( rtmp_body, tmp_buffer,
        AMF_DATATYPE_SIZE_OBJECT_VARIABLE + strlen( "videoCodecs" ) +
        AMF_DATATYPE_SIZE_NUMBER );
    free( tmp_buffer );

    tmp_buffer = amf_encode_object_variable( "videoFunction",
        AMF_DATATYPE_NUMBER, &AMF_CALL_NETCONNECTION_CONNECT_VIDEOFUNCTION );
    rtmp_body_append( rtmp_body, tmp_buffer,
        AMF_DATATYPE_SIZE_OBJECT_VARIABLE + strlen( "videoFunction" ) +
        AMF_DATATYPE_SIZE_NUMBER );
    free( tmp_buffer );

    tmp_buffer = amf_encode_object_variable( "pageUrl",
489
        AMF_DATATYPE_STRING, p_thread->psz_page_url );
490 491
    rtmp_body_append( rtmp_body, tmp_buffer,
        AMF_DATATYPE_SIZE_OBJECT_VARIABLE + strlen( "pageUrl" ) +
492
        AMF_DATATYPE_SIZE_STRING + strlen( p_thread->psz_page_url ) );
493 494 495 496 497 498 499 500 501 502 503 504 505
    free( tmp_buffer );

    tmp_buffer = amf_encode_object_variable( "objectEncoding",
        AMF_DATATYPE_NUMBER, &AMF_CALL_NETCONNECTION_CONNECT_OBJECTENCODING );
    rtmp_body_append( rtmp_body, tmp_buffer,
        AMF_DATATYPE_SIZE_OBJECT_VARIABLE + strlen( "objectEncoding" ) +
        AMF_DATATYPE_SIZE_NUMBER );
    free( tmp_buffer );

    tmp_buffer = amf_encode_element ( AMF_DATATYPE_END_OF_OBJECT, NULL );
    rtmp_body_append( rtmp_body, tmp_buffer, AMF_DATATYPE_SIZE_END_OF_OBJECT );
    free( tmp_buffer );

506
    rtmp_packet = rtmp_new_packet( p_thread, RTMP_DEFAULT_STREAM_INDEX_INVOKE,
507 508 509 510
        0, RTMP_CONTENT_TYPE_INVOKE, 0, rtmp_body );
    free( rtmp_body->body );
    free( rtmp_body );

511
    tmp_buffer = rtmp_encode_packet( p_thread, rtmp_packet );
512 513

    /* Call NetConnection.connect */
514 515
    if( !write_rtmp( p_thread, tmp_buffer, rtmp_packet,
                     "failed send call NetConnection.connect" ) )
516 517 518
        return -1;

    /* Wait for NetConnection.connect result */
519 520 521
    vlc_mutex_lock( &p_thread->lock );
    vlc_cond_wait( &p_thread->wait, &p_thread->lock );
    vlc_mutex_unlock( &p_thread->lock );
522

523
    if( p_thread->result_connect )
524
    {
525
        msg_Err( p_thread, "failed call NetConnection.connect" );
526 527 528 529
        return -1;
    }

    /* Force control thread to stop if receive NetStream.play call and wait is not ready */
530
    vlc_mutex_lock( &p_thread->lock );
531 532

    /* Build NetStream.createStream call */
533
    rtmp_body = rtmp_body_new( -1 );
534 535 536 537 538 539

    tmp_buffer = amf_encode_element( AMF_DATATYPE_STRING, "createStream" );
    rtmp_body_append( rtmp_body, tmp_buffer, 
        AMF_DATATYPE_SIZE_STRING + strlen( "createStream" ) );
    free( tmp_buffer );

540
    p_thread->stream_client_id = RTMP_DEFAULT_STREAM_CLIENT_ID;
541 542 543 544 545 546 547 548 549 550

    tmp_buffer = amf_encode_element( AMF_DATATYPE_NUMBER,
        &AMF_CALL_STREAM_CLIENT_NUMBER );
    rtmp_body_append( rtmp_body, tmp_buffer, AMF_DATATYPE_SIZE_NUMBER );
    free( tmp_buffer );

    tmp_buffer = amf_encode_element( AMF_DATATYPE_NULL, NULL );
    rtmp_body_append( rtmp_body, tmp_buffer, AMF_DATATYPE_SIZE_NULL );
    free( tmp_buffer );

551
    rtmp_packet = rtmp_new_packet( p_thread, RTMP_DEFAULT_STREAM_INDEX_INVOKE, 
552 553 554 555
        0, RTMP_CONTENT_TYPE_INVOKE, 0, rtmp_body );
    free( rtmp_body->body );
    free( rtmp_body );

556
    tmp_buffer = rtmp_encode_packet( p_thread, rtmp_packet );
557 558

    /* Call NetStream.createStream */
559 560
    if( !write_rtmp( p_thread, tmp_buffer, rtmp_packet,
                     "failed send call NetStream.createStream" ) )
561
        return -1;
562

563 564
/*TODO: read server stream number*/
    /* Build ping packet */
565
    rtmp_body = rtmp_body_new( -1 );
566

567
    tmp_buffer = rtmp_encode_ping( RTMP_PING_BUFFER_TIME_CLIENT, RTMP_SRC_DST_CONNECT_OBJECT, RTMP_TIME_CLIENT_BUFFER, 0 );
568 569 570
    rtmp_body_append( rtmp_body, tmp_buffer, RTMP_PING_SIZE_BUFFER_TIME_CLIENT );
    free( tmp_buffer );

571
    rtmp_packet = rtmp_new_packet( p_thread, RTMP_DEFAULT_STREAM_INDEX_CONTROL,
572 573 574 575
        0, RTMP_CONTENT_TYPE_PING, 0, rtmp_body );
    free( rtmp_body->body );
    free( rtmp_body );

576
    tmp_buffer = rtmp_encode_packet( p_thread, rtmp_packet );
577 578

    /* Send ping packet */
579 580
    if( !write_rtmp( p_thread, tmp_buffer, rtmp_packet,
                     "failed send ping BUFFER_TIME_CLIENT" ) )
581 582 583
        return -1;

    /* Build NetStream.play call */
584
    rtmp_body = rtmp_body_new( -1 );
585 586 587 588 589 590 591 592 593 594 595 596 597 598 599

    tmp_buffer = amf_encode_element( AMF_DATATYPE_STRING, "play" );
    rtmp_body_append( rtmp_body, tmp_buffer,
        AMF_DATATYPE_SIZE_STRING + strlen( "play" ) );
    free( tmp_buffer );

    tmp_buffer = amf_encode_element( AMF_DATATYPE_NUMBER,
        &AMF_CALL_NETSTREAM_PLAY );
    rtmp_body_append( rtmp_body, tmp_buffer, AMF_DATATYPE_SIZE_NUMBER );
    free( tmp_buffer );

    tmp_buffer = amf_encode_element( AMF_DATATYPE_NULL, NULL );
    rtmp_body_append( rtmp_body, tmp_buffer, AMF_DATATYPE_SIZE_NULL );
    free( tmp_buffer );

600
    tmp_buffer = amf_encode_element( AMF_DATATYPE_STRING, p_thread->psz_media );
601
    rtmp_body_append( rtmp_body, tmp_buffer,
602
        AMF_DATATYPE_SIZE_STRING + strlen( p_thread->psz_media ) );
603 604
    free( tmp_buffer );

605
    rtmp_packet = rtmp_new_packet( p_thread, RTMP_DEFAULT_STREAM_INDEX_INVOKE,
606 607 608 609
        0, RTMP_CONTENT_TYPE_INVOKE, RTMP_SRC_DST_DEFAULT, rtmp_body );
    free( rtmp_body->body );
    free( rtmp_body );

610
    tmp_buffer = rtmp_encode_packet( p_thread, rtmp_packet );
611 612

    /* Call NetStream.play */
613 614
    if( !write_rtmp( p_thread, tmp_buffer, rtmp_packet,
                     "failed send call NetStream.play" ) )
615
        return -1;
616

617 618

    /* Build ping packet */
619
    rtmp_body = rtmp_body_new( -1 );
620

621
    tmp_buffer = rtmp_encode_ping( RTMP_PING_BUFFER_TIME_CLIENT, RTMP_SRC_DST_CONNECT_OBJECT2, RTMP_TIME_CLIENT_BUFFER, 0 );
622 623 624
    rtmp_body_append( rtmp_body, tmp_buffer, RTMP_PING_SIZE_BUFFER_TIME_CLIENT );
    free( tmp_buffer );

625
    rtmp_packet = rtmp_new_packet( p_thread, RTMP_DEFAULT_STREAM_INDEX_CONTROL,
626 627 628 629
        0, RTMP_CONTENT_TYPE_PING, 0, rtmp_body );
    free( rtmp_body->body );
    free( rtmp_body );

630
    tmp_buffer = rtmp_encode_packet( p_thread, rtmp_packet );
631 632

    /* Send ping packet */
633 634
    if( !write_rtmp( p_thread, tmp_buffer, rtmp_packet,
                     "failed send ping BUFFER_TIME_CLIENT" ) )
635 636 637
        return -1;

    /* Wait for NetStream.play.start result */
638 639
    vlc_cond_wait( &p_thread->wait, &p_thread->lock );
    vlc_mutex_unlock( &p_thread->lock );
640

641
    if( p_thread->result_play )
642
    {
643
        msg_Err( p_thread, "failed call NetStream.play" );
644 645 646 647
        return -1;
    }

    /* Next packet is the beginning of flv stream */
648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667
    msg_Dbg( p_thread, "next packet is the beginning of flv stream" );

    return 0;
}

int
rtmp_connect_passive( rtmp_control_thread_t *p_thread )
{
    /* Force control thread to stop if receive NetStream.play call and wait is not ready */
    vlc_mutex_lock( &p_thread->lock );

    /* Wait for NetStream.play.start result */
    vlc_cond_wait( &p_thread->wait, &p_thread->lock );
    vlc_mutex_unlock( &p_thread->lock );

    if( p_thread->result_play )
    {
        msg_Err( p_thread, "failed call NetStream.play" );
        return -1;
    }
668 669 670

    return 0;
}
671

672 673 674 675 676 677 678 679
static void
rtmp_packet_free( rtmp_packet_t *pkt )
{
    free( pkt->body->body );
    free( pkt->body );
    free( pkt );
}

680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713
/* TODO
int
rtmp_seek( access_t *p_access, int64_t i_pos )
{
    access_sys_t *p_sys = p_access->p_sys;
    rtmp_packet_t *rtmp_packet;
    rtmp_body_t *rtmp_body;
    uint8_t *tmp_buffer;
    uint64_t tmp_number;
    ssize_t i_ret;
msg_Warn(p_access, "i_pos %lld", i_pos);
    // Build NetStream.seek call //
    rtmp_body = rtmp_body_new();

    tmp_buffer = amf_encode_element( AMF_DATATYPE_STRING, "seek" );
    rtmp_body_append( rtmp_body, tmp_buffer,
        AMF_DATATYPE_SIZE_STRING + strlen( "seek" ) );
    free( tmp_buffer );

    tmp_number = 0;
    tmp_buffer = amf_encode_element( AMF_DATATYPE_NUMBER,
        &tmp_number );
    rtmp_body_append( rtmp_body, tmp_buffer, AMF_DATATYPE_SIZE_NUMBER );
    free( tmp_buffer );

    tmp_buffer = amf_encode_element( AMF_DATATYPE_NULL, NULL );
    rtmp_body_append( rtmp_body, tmp_buffer, AMF_DATATYPE_SIZE_NULL );
    free( tmp_buffer );
//TODO: convert i_pos to double and see if they are milliseconds
    tmp_buffer = amf_encode_element( AMF_DATATYPE_NUMBER,
        &i_pos );
    rtmp_body_append( rtmp_body, tmp_buffer, AMF_DATATYPE_SIZE_NUMBER );
    free( tmp_buffer );

714
    rtmp_packet = rtmp_new_packet( p_sys->p_thread, RTMP_DEFAULT_STREAM_INDEX_INVOKE,
715 716 717 718 719 720 721
        0, RTMP_DATATYPE_INVOKE, RTMP_SRC_DST_DEFAULT, rtmp_body );
    free( rtmp_body->body );
    free( rtmp_body );

    tmp_buffer = rtmp_encode_packet( p_access, rtmp_packet ); 

    // Call NetStream.seek //
722 723
    if( !write_rtmp( p_thread, tmp_buffer, rtmp_packet,
                     "failed call NetStream.seek" ) )
724 725 726 727
        return -1;

    // Receive TODO: see what //
    rtmp_packet = rtmp_read_net_packet( p_access, p_sys->fd );
728
    rtmp_packet_free( rtmp_packet );
729 730 731 732

    return 0;
}
*/
733 734 735

rtmp_packet_t *
rtmp_build_bytes_read( rtmp_control_thread_t *p_thread, uint32_t reply )
736 737 738 739 740 741
{
    rtmp_packet_t *rtmp_packet;
    rtmp_body_t *rtmp_body;
    uint8_t *tmp_buffer;

    /* Build bytes read packet */
742
    rtmp_body = rtmp_body_new( -1 );
743 744

    tmp_buffer = (uint8_t *) malloc( sizeof( uint32_t ) * sizeof( uint8_t ) );
745 746
    if( !tmp_buffer ) return NULL;

747 748 749 750 751 752
    reply = hton32( reply );
    memcpy( tmp_buffer, &reply, sizeof( uint32_t ) );

    rtmp_body_append( rtmp_body, tmp_buffer, sizeof( uint32_t ) );
    free( tmp_buffer );

753
    rtmp_packet = rtmp_new_packet( p_thread, RTMP_DEFAULT_STREAM_INDEX_CONTROL,
754 755 756 757
        0, RTMP_CONTENT_TYPE_BYTES_READ, 0, rtmp_body );
    free( rtmp_body->body );
    free( rtmp_body );

758
    return rtmp_packet;
759 760
}

761 762
rtmp_packet_t *
rtmp_build_publish_start( rtmp_control_thread_t *p_thread )
763 764 765 766 767 768
{
    rtmp_packet_t *rtmp_packet;
    rtmp_body_t *rtmp_body;
    uint8_t *tmp_buffer;

    /* Build publish start event */
769
    rtmp_body = rtmp_body_new( -1 );
770 771 772 773 774 775 776

    tmp_buffer = amf_encode_element( AMF_DATATYPE_STRING, "onStatus" );
    rtmp_body_append( rtmp_body, tmp_buffer,
        AMF_DATATYPE_SIZE_STRING + strlen( "onStatus" ) );
    free( tmp_buffer );

    tmp_buffer = amf_encode_element( AMF_DATATYPE_NUMBER,
777
        &p_thread->stream_server_id );
778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810
    rtmp_body_append( rtmp_body, tmp_buffer, AMF_DATATYPE_SIZE_NUMBER );
    free( tmp_buffer );

    tmp_buffer = amf_encode_element( AMF_DATATYPE_NULL, NULL );
    rtmp_body_append( rtmp_body, tmp_buffer, AMF_DATATYPE_SIZE_NULL );
    free( tmp_buffer );

    tmp_buffer = amf_encode_element( AMF_DATATYPE_OBJECT, NULL );
    rtmp_body_append( rtmp_body, tmp_buffer, AMF_DATATYPE_SIZE_OBJECT );
    free( tmp_buffer );

    tmp_buffer = amf_encode_object_variable( "level",
        AMF_DATATYPE_STRING, "status" );
    rtmp_body_append( rtmp_body, tmp_buffer,
        AMF_DATATYPE_SIZE_OBJECT_VARIABLE + strlen( "level" ) +
        AMF_DATATYPE_SIZE_STRING + strlen( "status" ) );
    free ( tmp_buffer );

    tmp_buffer = amf_encode_object_variable( "code",
        AMF_DATATYPE_STRING, "NetStream.Publish.Start" );
    rtmp_body_append( rtmp_body, tmp_buffer,
        AMF_DATATYPE_SIZE_OBJECT_VARIABLE + strlen( "code" ) +
        AMF_DATATYPE_SIZE_STRING + strlen( "NetStream.Publish.Start" ) );
    free ( tmp_buffer );

    tmp_buffer = amf_encode_object_variable( "description",
        AMF_DATATYPE_STRING, "" );
    rtmp_body_append( rtmp_body, tmp_buffer,
        AMF_DATATYPE_SIZE_OBJECT_VARIABLE + strlen( "description" ) +
        AMF_DATATYPE_SIZE_STRING + strlen( "" ) );
    free ( tmp_buffer );

    tmp_buffer = amf_encode_object_variable( "details",
811
        AMF_DATATYPE_STRING, p_thread->psz_publish );
812 813
    rtmp_body_append( rtmp_body, tmp_buffer,
        AMF_DATATYPE_SIZE_OBJECT_VARIABLE + strlen( "details" ) +
814
        AMF_DATATYPE_SIZE_STRING + strlen( p_thread->psz_publish ) );
815 816 817
    free ( tmp_buffer );

    tmp_buffer = amf_encode_object_variable( "clientid",
818
        AMF_DATATYPE_NUMBER, &p_thread->stream_client_id );
819
    rtmp_body_append( rtmp_body, tmp_buffer,
820
        AMF_DATATYPE_SIZE_OBJECT_VARIABLE + strlen( "clientid" ) +
821 822 823 824 825 826 827
        AMF_DATATYPE_SIZE_NUMBER );
    free( tmp_buffer );

    tmp_buffer = amf_encode_element ( AMF_DATATYPE_END_OF_OBJECT, NULL );
    rtmp_body_append( rtmp_body, tmp_buffer, AMF_DATATYPE_SIZE_END_OF_OBJECT );
    free( tmp_buffer );

828
    rtmp_packet = rtmp_new_packet( p_thread, RTMP_DEFAULT_STREAM_INDEX_INVOKE,
829 830 831 832
        0, RTMP_CONTENT_TYPE_INVOKE, 0, rtmp_body );
    free( rtmp_body->body );
    free( rtmp_body );

833
    return rtmp_packet;
834 835 836
}

rtmp_packet_t *
837
rtmp_build_flv_over_rtmp( rtmp_control_thread_t *p_thread, block_t *p_buffer )
838 839 840
{
    rtmp_packet_t *rtmp_packet;

841
    if( p_thread->flv_length_body > 0 )
842
    {
843 844
        p_thread->flv_length_body -= p_buffer->i_buffer;
        rtmp_body_append( p_thread->flv_body, p_buffer->p_buffer, p_buffer->i_buffer );
845

846 847
        if( p_thread->flv_length_body > 0 )
            return NULL;
848 849 850 851

    }
    else
    {
852
        p_thread->flv_content_type = *p_buffer->p_buffer;
853

854 855 856 857 858
        p_buffer->p_buffer[0] = 0;
        p_thread->flv_length_body = ntoh32( *(uint32_t *) (p_buffer->p_buffer) );

        p_buffer->p_buffer[3] = 0;
        p_thread->flv_timestamp = ntoh32( *(uint32_t *) (p_buffer->p_buffer + 3) );
859 860
    }

861
    if( p_thread->flv_length_body > p_buffer->i_buffer - FLV_TAG_SIZE - FLV_TAG_PREVIOUS_TAG_SIZE )
862
    {
863 864
        p_thread->flv_length_body -= p_buffer->i_buffer - FLV_TAG_SIZE - FLV_TAG_PREVIOUS_TAG_SIZE;
        rtmp_body_append( p_thread->flv_body, p_buffer->p_buffer + FLV_TAG_SIZE, p_buffer->i_buffer - FLV_TAG_SIZE );
865

866
        return NULL;
867 868 869
    }
    else
    {
870 871
        rtmp_body_append( p_thread->flv_body, p_buffer->p_buffer + FLV_TAG_SIZE, p_thread->flv_length_body );
    }
872

873 874 875 876
    rtmp_packet = rtmp_new_packet( p_thread, rtmp_get_stream_index( p_thread->flv_content_type ),
        p_thread->flv_timestamp, p_thread->flv_content_type, RTMP_SRC_DST_DEFAULT, p_thread->flv_body );
    p_thread->flv_length_body = 0;
    rtmp_body_reset( p_thread->flv_body );
877

878 879
    return rtmp_packet;
}
880

881 882 883 884 885
rtmp_packet_t *
rtmp_read_net_packet( rtmp_control_thread_t *p_thread )
{
    int length_header;
    int stream_index;
886
    size_t bytes_left;
887
    uint8_t p_read[12];
888
    rtmp_packet_t *header;
889
    ssize_t i_ret;
890

891
    for(;;)
892
    {
893 894 895
        i_ret = net_Read( p_thread, p_thread->fd, NULL, p_read, 1, true );
        if( i_ret != 1 )
            goto error;
896

897 898
        length_header = rtmp_decode_header_size( (vlc_object_t *) p_thread,
                                          p_read[0] & RTMP_HEADER_SIZE_MASK );
899
        stream_index = p_read[0] & RTMP_HEADER_STREAM_INDEX_MASK;
900
        header = p_thread->rtmp_headers_recv+stream_index;
901

902 903 904 905 906
        i_ret = net_Read( p_thread, p_thread->fd, NULL, p_read + 1, length_header - 1, true );
        if( i_ret != length_header - 1 )
            goto error;

        /* Update timestamp if not is an interchunk packet */
907
        if( length_header == 1 && header->body == NULL )
908
        {
909
            header->timestamp += header->timestamp_relative;
910 911 912 913 914 915 916
        }

        /* Length 4 and 8 headers have relative timestamp */
        if( length_header == 4 || length_header == 8 )
        {
            p_read[0] = 0;

917 918
            header->timestamp_relative = ntoh32( *(uint32_t *) p_read );
            header->timestamp += header->timestamp_relative;
919 920 921 922 923 924
        }

        if( length_header >= 8 )
        {
            p_read[3] = 0;

925 926
            header->length_body = ntoh32( *(uint32_t *) (p_read + 3) );
            header->content_type = p_read[7];
927 928 929 930 931 932 933
        }

        /* Length 12 headers have absolute timestamp */
        if( length_header >= 12 )
        {
            p_read[0] = 0;

934 935
            header->timestamp = ntoh32( *(uint32_t *) p_read );
            header->src_dst = ntoh32( *(uint32_t *) (p_read + 8) );
936 937
        }

938
        if( header->body == NULL )
939
        {
940
            header->body = rtmp_body_new( header->length_body );
941 942
        }

943
        bytes_left = header->body->length_buffer - header->body->length_body;
944 945 946

        if( bytes_left > p_thread->chunk_size_recv )
            bytes_left = p_thread->chunk_size_recv;
947 948

        i_ret = net_Read( p_thread, p_thread->fd, NULL,
949 950
            header->body->body + header->body->length_body, bytes_left, true );

951
        if( i_ret != (ssize_t)bytes_left )
952
            goto error;
953

954
        header->body->length_body += bytes_left;
955

956
        if( header->length_body == header->body->length_body )
957
        {
958 959
            rtmp_packet_t *rpkt = (rtmp_packet_t*)malloc(sizeof(rtmp_packet_t));
            if( !rpkt ) goto error;
960

961 962 963 964 965 966 967
            rpkt->stream_index       = stream_index;
            rpkt->timestamp          = header->timestamp;
            rpkt->timestamp_relative = header->timestamp_relative;
            rpkt->content_type       = header->content_type;
            rpkt->src_dst            = header->src_dst;
            rpkt->length_body        = header->length_body;
            rpkt->body               = header->body;
968

969
            header->body = NULL;
970

971
            return rpkt;
972 973
        }
    }
974

975
error:
976 977 978 979 980 981
    msg_Err( p_thread, "rtmp_read_net_packet: net_Read error");
    return NULL;
}


static void
982 983
rtmp_handler_null( rtmp_control_thread_t *p_thread, rtmp_packet_t *rtmp_packet )
{
984
    VLC_UNUSED(p_thread);
985
    rtmp_packet_free( rtmp_packet );
986 987 988
}

static void
989 990
rtmp_handler_chunk_size( rtmp_control_thread_t *p_thread,
                         rtmp_packet_t *rtmp_packet )
991
{
992 993 994
    p_thread->chunk_size_recv =
                            ntoh32( *(uint32_t *) (rtmp_packet->body->body) );
    rtmp_packet_free( rtmp_packet );
995 996 997
}

static void
998
rtmp_handler_audio_data( rtmp_control_thread_t *p_thread, rtmp_packet_t *rtmp_packet )
999 1000 1001
{
    block_t *p_buffer;

1002
    if( !p_thread->has_audio )
1003
    {
1004
        p_thread->has_audio = 1;
1005

1006 1007 1008
        flv_get_metadata_audio( p_thread, rtmp_packet,
            &p_thread->metadata_stereo, &p_thread->metadata_samplesize,
            &p_thread->metadata_samplerate, &p_thread->metadata_audiocodecid );
1009 1010
    }

1011 1012 1013
    flv_rebuild( p_thread, rtmp_packet );
    p_buffer = rtmp_new_block( p_thread, rtmp_packet->body->body, rtmp_packet->body->length_body );
    block_FifoPut( p_thread->p_fifo_input, p_buffer );
1014

1015
    rtmp_packet_free( rtmp_packet );
1016 1017 1018
}

static void
1019
rtmp_handler_video_data( rtmp_control_thread_t *p_thread, rtmp_packet_t *rtmp_packet )
1020 1021 1022
{
    block_t *p_buffer;

1023
    if( !p_thread->has_video )
1024
    {
1025
        p_thread->has_video = 1;
1026

1027 1028
        flv_get_metadata_video( p_thread, rtmp_packet,
            &p_thread->metadata_videocodecid, &p_thread->metadata_frametype );
1029
    }
1030 1031 1032 1033

    flv_rebuild( p_thread, rtmp_packet );
    p_buffer = rtmp_new_block( p_thread, rtmp_packet->body->body, rtmp_packet->body->length_body );
    block_FifoPut( p_thread->p_fifo_input, p_buffer );
1034

1035
    rtmp_packet_free( rtmp_packet );
1036 1037 1038
}

static void
1039
rtmp_handler_notify( rtmp_control_thread_t *p_thread, rtmp_packet_t *rtmp_packet )
1040 1041 1042
{
    block_t *p_buffer;

1043
    p_thread->metadata_received = 1;