- 博客(0)
- 资源 (10)
- 收藏
- 关注
rtmp源文件代码 rtmp实现代码
int WriteStream(
CRTMP* rtmp,
char **buf, // target pointer, maybe preallocated
unsigned int len, // length of buffer if preallocated
uint32_t *tsm, // pointer to timestamp, will contain timestamp of last video packet returned
bool bNoHeader, // resuming mode, will not write FLV header and compare metaHeader and first kexframe
char *metaHeader, // pointer to meta header (if bNoHeader == TRUE)
uint32_t nMetaHeaderSize, // length of meta header, if zero meta header check omitted (if bNoHeader == TRUE)
char *initialFrame, // pointer to initial keyframe (no FLV header or tagSize, raw data) (if bNoHeader == TRUE)
uint8_t initialFrameType, // initial frame type (audio or video)
uint32_t nInitialFrameSize, // length of initial frame in bytes, if zero initial frame check omitted (if bNoHeader == TRUE)
uint8_t *dataType // whenever we get a video/audio packet we set an appropriate flag here, this will be later written to the FLV header
)
{
char flvHeader[] = { 'F', 'L', 'V', 0x01,
0x00,//5, // video + audio
0x00, 0x00, 0x00, 0x09,
0x00, 0x00, 0x00, 0x00 // first prevTagSize=0
};
static bool bStopIgnoring = false;
static bool bSentHeader = false;
static bool bFoundKeyframe = false;
static bool bFoundFlvKeyframe = false;
uint32_t prevTagSize = 0;
RTMPPacket packet;
if(rtmp->GetNextMediaPacket(packet))
{
char *packetBody = packet.m_body;
unsigned int nPacketLen = packet.m_nBodySize;
// skip video info/command packets
if(packet.m_packetType == 0x09 &&
nPacketLen == 2 &&
((*packetBody & 0xf0) == 0x50)) {
return 0;
}
if(packet.m_packetType == 0x09 && nPacketLen <= 5) {
Log(LOGWARNING, "ignoring too small video packet: size: %d", nPacketLen);
return 0;
}
if(packet.m_packetType == 0x08 && nPacketLen <= 1) {
Log(LOGWARNING, "ignoring too small audio packet: size: %d", nPacketLen);
return 0;
}
#ifdef _DEBUG
debugTS += packet.m_nInfoField1;
Log(LOGDEBUG, "type: %02X, size: %d, TS: %d ms, sent TS: %d ms", packet.m_packetType, nPacketLen, debugTS, packet.m_nInfoField1);
if(packet.m_packetType == 0x09)
Log(LOGDEBUG, "frametype: %02X", (*packetBody & 0xf0));
#endif
// check the header if we get one
if(bNoHeader && packet.m_nInfoField1 == 0) {
if(nMetaHeaderSize > 0 && packet.m_packetType == 0x12) {
RTMP_LIB::AMFObject metaObj;
int nRes = metaObj.Decode(packetBody, nPacketLen);
if(nRes >= 0) {
std::string metastring = metaObj.GetProperty(0).GetString();
if(metastring == "onMetaData") {
// comapre
if((nMetaHeaderSize != nPacketLen) ||
(memcmp(metaHeader, packetBody, nMetaHeaderSize) != 0)) {
return -2;
}
}
}
}
// check first keyframe to make sure we got the right position in the stream!
// (the first non ignored frame)
if(nInitialFrameSize > 0) {
// video or audio data
if(packet.m_packetType == initialFrameType && nInitialFrameSize == nPacketLen) {
// we don't compare the sizes since the packet can contain several FLV packets, just make
// sure the first frame is our keyframe (which we are going to rewrite)
if(memcmp(initialFrame, packetBody, nInitialFrameSize) == 0) {
Log(LOGDEBUG, "Checked keyframe successfully!");
bFoundKeyframe = true;
return 0; // ignore it! (what about audio data after it? it is handled by ignoring all 0ms frames, see below)
}
}
// hande FLV streams, even though the server resends the keyframe as an extra video packet
// it is also included in the first FLV stream chunk and we have to compare it and
// filter it out !!
//
if(packet.m_packetType == 0x16) {
// basically we have to find the keyframe with the correct TS being nTimeStamp
unsigned int pos=0;
uint32_t ts = 0;
while(pos+11 < nPacketLen) {
uint32_t dataSize = CRTMP::ReadInt24(packetBody+pos+1); // size without header (11) and prevTagSize (4)
ts = CRTMP::ReadInt24(packetBody+pos+4);
ts |= (packetBody[pos+7]<<24);
#ifdef _DEBUG
Log(LOGDEBUG, "keyframe search: FLV Packet: type %02X, dataSize: %d, timeStamp: %d ms",
packetBody[pos], dataSize, ts);
#endif
// ok, is it a keyframe!!!: well doesn't work for audio!
if(packetBody[0] == initialFrameType /* && (packetBody[11]&0xf0) == 0x10*/) {
if(ts == nTimeStamp) {
Log(LOGDEBUG, "Found keyframe with resume-keyframe timestamp!");
if(nInitialFrameSize != dataSize || memcmp(initialFrame, packetBody+pos+11, nInitialFrameSize) != 0) {
Log(LOGERROR, "FLV Stream: Keyframe doesn't match!");
return -2;
}
bFoundFlvKeyframe = true;
// ok, skip this packet
// check whether skipable:
if(pos+11+dataSize+4 > nPacketLen) {
Log(LOGWARNING, "Non skipable packet since it doesn't end with chunk, stream corrupt!");
return -2;
}
packetBody += (pos+11+dataSize+4);
nPacketLen -= (pos+11+dataSize+4);
goto stopKeyframeSearch;
} else if(nTimeStamp < ts) {
goto stopKeyframeSearch; // the timestamp ts will only increase with further packets, wait for seek
}
}
pos += (11+dataSize+4);
}
if(ts < nTimeStamp) {
Log(LOGERROR, "First packet does not contain keyframe, all timestamps are smaller than the keyframe timestamp, so probably the resume seek failed?");
}
stopKeyframeSearch:
;
//*
if(!bFoundFlvKeyframe) {
Log(LOGERROR, "Couldn't find the seeked keyframe in this chunk!");
return 0;//-2;
}//*/
}
}
}
if(bNoHeader && packet.m_nInfoField1 > 0 && (bFoundFlvKeyframe || bFoundKeyframe)) {
// another problem is that the server can actually change from 09/08 video/audio packets to an FLV stream
// or vice versa and our keyframe check will prevent us from going along with the new stream if we resumed
//
// in this case set the 'found keyframe' variables to true
// We assume that if we found one keyframe somewhere and were already beyond TS > 0 we have written
// data to the output which means we can accept all forthcoming data inclusing the change between 08/09 <-> FLV
// packets
bFoundFlvKeyframe = true;
bFoundKeyframe = true;
}
// skip till we find out keyframe (seeking might put us somewhere before it)
if(bNoHeader && !bFoundKeyframe && packet.m_packetType != 0x16) {
Log(LOGWARNING, "Stream does not start with requested frame, ignoring data... ");
nIgnoredFrameCounter++;
if(nIgnoredFrameCounter > MAX_IGNORED_FRAMES)
return -2;
return 0;
}
// ok, do the same for FLV streams
if(bNoHeader && !bFoundFlvKeyframe && packet.m_packetType == 0x16) {
Log(LOGWARNING, "Stream does not start with requested FLV frame, ignoring data... ");
nIgnoredFlvFrameCounter++;
if(nIgnoredFlvFrameCounter > MAX_IGNORED_FRAMES)
return -2;
return 0;
}
// if bNoHeader, we continue a stream, we have to ignore the 0ms frames since these are the first keyframes, we've got these
// so don't mess around with multiple copies sent by the server to us! (if the keyframe is found at a later position
// there is only one copy and it will be ignored by the preceding if clause)
if(!bStopIgnoring && bNoHeader && packet.m_packetType != 0x16) { // exclude type 0x16 (FLV) since it can conatin several FLV packets
if(packet.m_nInfoField1 == 0) {
return 0;
} else {
bStopIgnoring = true; // stop ignoring packets
}
}
// calculate packet size and reallocate buffer if necessary
unsigned int size = nPacketLen
+ ((bSentHeader || bNoHeader) ? 0 : sizeof(flvHeader))
+ ((packet.m_packetType == 0x08 || packet.m_packetType == 0x09 || packet.m_packetType == 0x12) ? 11 : 0)
+ (packet.m_packetType != 0x16 ? 4 : 0);
if(size+4 > len) { // the extra 4 is for the case of an FLV stream without a last prevTagSize (we need extra 4 bytes to append it)
*buf = (char *)realloc(*buf, size+4);
if(*buf == 0) {
Log(LOGERROR, "Couldn't reallocate memory!");
return -1; // fatal error
}
}
char *ptr = *buf;
if(!bSentHeader && !bNoHeader)
{
memcpy(ptr, flvHeader, sizeof(flvHeader));
ptr+=sizeof(flvHeader);
bSentHeader = true;
}
// audio (0x08), video (0x09) or metadata (0x12) packets :
// construct 11 byte header then add rtmp packet's data
if(packet.m_packetType == 0x08 || packet.m_packetType == 0x09 || packet.m_packetType == 0x12)
{
// set data type
*dataType |= (((packet.m_packetType == 0x08)<<2)|(packet.m_packetType == 0x09));
nTimeStamp += packet.m_nInfoField1;
prevTagSize = 11 + nPacketLen;
//nTimeStamp += packet.m_nInfoField1;
//Log(LOGDEBUG, "%02X: Added TS: %d ms, TS: %d", packet.m_packetType, packet.m_nInfoField1, nTimeStamp);
*ptr = packet.m_packetType;
ptr++;
ptr += CRTMP::EncodeInt24(ptr, nPacketLen);
/*if(packet.m_packetType == 0x09) { // video
// H264 fix:
if((packetBody[0] & 0x0f) == 7) { // CodecId = H264
uint8_t packetType = *(packetBody+1);
uint32_t ts = CRTMP::ReadInt24(packetBody+2); // composition time
int32_t cts = (ts+0xff800000)^0xff800000;
Log(LOGDEBUG, "cts : %d\n", cts);
nTimeStamp -= cts;
// get rid of the composition time
CRTMP::EncodeInt24(packetBody+2, 0);
}
Log(LOGDEBUG, "VIDEO: nTimeStamp: 0x%08X (%d)\n", nTimeStamp, nTimeStamp);
}*/
ptr += CRTMP::EncodeInt24(ptr, nTimeStamp);
*ptr = (char)((nTimeStamp & 0xFF000000) >> 24);
ptr++;
// stream id
ptr += CRTMP::EncodeInt24(ptr, 0);
}
memcpy(ptr, packetBody, nPacketLen);
unsigned int len = nPacketLen;
// correct tagSize and obtain timestamp if we have an FLV stream
if(packet.m_packetType == 0x16)
{
unsigned int pos=0;
while(pos+11 < nPacketLen) {
uint32_t dataSize = CRTMP::ReadInt24(packetBody+pos+1); // size without header (11) or prevTagSize (4)
nTimeStamp = CRTMP::ReadInt24(packetBody+pos+4);
nTimeStamp |= (packetBody[pos+7]<<24);
// set data type
*dataType |= (((*(packetBody+pos) == 0x08)<<2)|(*(packetBody+pos) == 0x09));
if(pos+11+dataSize+4 > nPacketLen) {
Log(LOGWARNING, "No tagSize found, appending!");
// we have to append a last tagSize!
prevTagSize = dataSize+11;
CRTMP::EncodeInt32(ptr+pos+11+dataSize, prevTagSize);
size+=4; len+=4;
} else {
prevTagSize = CRTMP::ReadInt32(packetBody+pos+11+dataSize);
#ifdef _DEBUG
Log(LOGDEBUG, "FLV Packet: type %02X, dataSize: %d, tagSize: %d, timeStamp: %d ms",
packetBody[pos], dataSize, prevTagSize, nTimeStamp);
#endif
if(prevTagSize != (dataSize+11)) {
#ifdef _DEBUG
Log(LOGWARNING, "tag size and data size are not consitent, writing tag size according to data size %d", dataSize+11);
#endif
prevTagSize = dataSize+11;
CRTMP::EncodeInt32(ptr+pos+11+dataSize, prevTagSize);
}
}
pos += (11+dataSize+4);
}
}
ptr += len;
if(packet.m_packetType != 0x16) { // FLV tag packets contain their own prevTagSize
CRTMP::EncodeInt32(ptr, prevTagSize);
//ptr += 4;
}
if(tsm)
*tsm = nTimeStamp;
return size;
}
return -1; // no more media packets
}
2010-12-27
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人