129 lines
3.7 KiB
C++
129 lines
3.7 KiB
C++
#include "rtmp-internal.h"
|
|
#include "rtmp-msgtypeid.h"
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <assert.h>
|
|
|
|
#define RTMP_MESSAGE_HEADER_LENGTH 11 // RTMP 6.1.1
|
|
|
|
static int rtmp_audio(struct rtmp_t* rtmp, const uint8_t* payload, uint32_t bytes, uint32_t timestamp)
|
|
{
|
|
return rtmp->onaudio(rtmp->param, payload, bytes, timestamp);
|
|
}
|
|
|
|
static int rtmp_video(struct rtmp_t* rtmp, const uint8_t* payload, uint32_t bytes, uint32_t timestamp)
|
|
{
|
|
return rtmp->onvideo(rtmp->param, payload, bytes, timestamp);
|
|
}
|
|
|
|
static int rtmp_script(struct rtmp_t* rtmp, const uint8_t* payload, uint32_t bytes, uint32_t timestamp)
|
|
{
|
|
// filter @setDataFrame
|
|
const static uint8_t s_setFrameData[] = { 0x02, 0x00, 0x0d, 0x40, 0x73, 0x65, 0x74, 0x44, 0x61, 0x74, 0x61, 0x46, 0x72, 0x61, 0x6d, 0x65 };
|
|
if (bytes > sizeof(s_setFrameData) && 0 == memcmp(s_setFrameData, payload, sizeof(s_setFrameData)))
|
|
return rtmp->onscript(rtmp->param, payload + sizeof(s_setFrameData), bytes - sizeof(s_setFrameData), timestamp);
|
|
|
|
return rtmp->onscript(rtmp->param, payload, bytes, timestamp);
|
|
}
|
|
|
|
static int rtmp_aggregate(struct rtmp_t* rtmp, struct rtmp_chunk_header_t* header, const uint8_t* payload)
|
|
{
|
|
int r;
|
|
uint32_t i;
|
|
uint32_t n;
|
|
uint32_t t, t0, timestamp;
|
|
|
|
timestamp = header->timestamp;
|
|
for (t0 = i = r = 0; i + RTMP_MESSAGE_HEADER_LENGTH + 4 /*previous tag size*/ < header->length && 0 == r; i+= n + RTMP_MESSAGE_HEADER_LENGTH + 4)
|
|
{
|
|
n = ((uint32_t)payload[i + 1] << 16) | ((uint32_t)payload[i + 2] << 8) | payload[i + 3];
|
|
t = ((uint32_t)payload[i + 4] << 16) | ((uint32_t)payload[i + 5] << 8) | payload[i + 6] | ((uint32_t)payload[i + 7] << 24);
|
|
if (i + n + RTMP_MESSAGE_HEADER_LENGTH + 4 > header->length)
|
|
{
|
|
assert(0);
|
|
return 0; // ignore
|
|
}
|
|
|
|
if (0 != i)
|
|
timestamp += t - t0;
|
|
t0 = t;
|
|
|
|
switch (payload[i])
|
|
{
|
|
case RTMP_TYPE_AUDIO:
|
|
r = rtmp_audio(rtmp, payload + i + RTMP_MESSAGE_HEADER_LENGTH, n, timestamp);
|
|
break;
|
|
|
|
case RTMP_TYPE_VIDEO:
|
|
r = rtmp_video(rtmp, payload + i + RTMP_MESSAGE_HEADER_LENGTH, n, timestamp);
|
|
break;
|
|
|
|
case RTMP_TYPE_DATA:
|
|
r = rtmp_script(rtmp, payload + i + RTMP_MESSAGE_HEADER_LENGTH, n, timestamp);
|
|
break;
|
|
|
|
default:
|
|
assert(0);
|
|
r = 0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
assert(r || i == header->length);
|
|
return r;
|
|
}
|
|
|
|
int rtmp_handler(struct rtmp_t* rtmp, struct rtmp_chunk_header_t* header, const uint8_t* payload)
|
|
{
|
|
switch (header->type)
|
|
{
|
|
case RTMP_TYPE_FLEX_MESSAGE:
|
|
// filter AMF3 0x00
|
|
payload += (header->length > 0) ? 1 : 0; // fix header->length = 0
|
|
header->length -= (header->length > 0) ? 1 : 0;
|
|
return rtmp_invoke_handler(rtmp, header, payload);
|
|
|
|
case RTMP_TYPE_INVOKE:
|
|
return rtmp_invoke_handler(rtmp, header, payload);
|
|
|
|
case RTMP_TYPE_VIDEO:
|
|
return rtmp_video(rtmp, payload, header->length, header->timestamp);
|
|
|
|
case RTMP_TYPE_AUDIO:
|
|
return rtmp_audio(rtmp, payload, header->length, header->timestamp);
|
|
|
|
case RTMP_TYPE_EVENT:
|
|
// User Control Message Events
|
|
return 0 == rtmp_event_handler(rtmp, header, payload) ? -1 : 0;
|
|
|
|
// Protocol Control Messages
|
|
case RTMP_TYPE_SET_CHUNK_SIZE:
|
|
case RTMP_TYPE_ABORT:
|
|
case RTMP_TYPE_ACKNOWLEDGEMENT:
|
|
case RTMP_TYPE_WINDOW_ACKNOWLEDGEMENT_SIZE:
|
|
case RTMP_TYPE_SET_PEER_BANDWIDTH:
|
|
return 0 == rtmp_control_handler(rtmp, header, payload) ? -1 : 0;
|
|
|
|
case RTMP_TYPE_DATA:
|
|
case RTMP_TYPE_FLEX_STREAM:
|
|
// play -> RtmpSampleAccess
|
|
// finish -> onPlayStatus("NetStream.Play.Complete")
|
|
return rtmp_script(rtmp, payload, header->length, header->timestamp);
|
|
|
|
case RTMP_TYPE_SHARED_OBJECT:
|
|
case RTMP_TYPE_FLEX_OBJECT:
|
|
break;
|
|
|
|
case RTMP_TYPE_METADATA:
|
|
return rtmp_aggregate(rtmp, header, payload);
|
|
|
|
default:
|
|
assert(0);
|
|
printf("%s: unknown rtmp header type: %d\n", __FUNCTION__, (int)header->type);
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|