下载 >  开发技术 >  C > rtmp源文件代码 rtmp实现代码
3分

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) c har *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 上传大小:141KB
立即下载 开通VIP
分享
收藏 举报

评论 共13条

meteorite91 资料还可以吧
2015-12-21
回复
ars_txy 代码有点用,但是编译不过啊
2015-10-21
回复
jackmfq 资源有点深度,学习中
2015-01-04
回复

热点文章

  • nginx-rtmp源码概述

    2017-05-19 wu5215080
  • C版本的RTMP服务端

    2014-01-15 mmnn888666
  • RTMP推流器和拉流器源码

    2017-01-04 qq_22329511
  • videojs播放rtmp流,测试代码

    2017-09-18 cmqwan
  • 开发实现C++ RTMP直播拉流播放器

    2017-06-24 m0_37826678
  • RTMP直播例子--基于FLASH/FLEX(含源代码) 下载

    2017-06-22 theskyto166
  • 基于RTMP协议的Flash流媒体网页播放器

    2015-03-25 aoshilang2249
  • nginx rtmp代码架构1 hook点总结

    2015-07-25 liwf616
  • 搭建rtmp直播流服务之3:java开发ffmpeg实现rtsp转rtmp并实现ffmpeg命令的接口化管理架构设计及代码实现

    2016-06-30 eguid_1
  • 实时RTMP流媒体直播APP+服务端源码

    2018-04-02 wo0123456789wo
关闭
img

spring mvc+mybatis+mysql+maven+bootstrap 整合实现增删查改简单实例.zip

资源所需积分/C币 当前拥有积分 当前拥有C币
5 0 0
点击完成任务获取下载码
输入下载码
为了良好体验,不建议使用迅雷下载
img

rtmp源文件代码 rtmp实现代码

会员到期时间: 剩余下载个数: 剩余C币: 剩余积分:0
为了良好体验,不建议使用迅雷下载
VIP下载
您今日下载次数已达上限(为了良好下载体验及使用,每位用户24小时之内最多可下载20个资源)

积分不足!

资源所需积分/C币 当前拥有积分
您可以选择
开通VIP
4000万
程序员的必选
600万
绿色安全资源
现在开通
立省522元
或者
购买C币兑换积分 C币抽奖
img

资源所需积分/C币 当前拥有积分 当前拥有C币
5 4 45
为了良好体验,不建议使用迅雷下载
确认下载
img

资源所需积分/C币 当前拥有积分 当前拥有C币
5 0 0
为了良好体验,不建议使用迅雷下载
VIP和C币套餐优惠
img

资源所需积分/C币 当前拥有积分 当前拥有C币
5 4 45
您的积分不足,将扣除 10 C币
为了良好体验,不建议使用迅雷下载
确认下载
下载
无法举报自己的资源

兑换成功

你当前的下载分为234开始下载资源
你还不是VIP会员
开通VIP会员权限,免积分下载
立即开通

你下载资源过于频繁,请输入验证码

您因违反CSDN下载频道规则而被锁定帐户,如有疑问,请联络:webmaster@csdn.net!

举报

若举报审核通过,可返还被扣除的积分

  • 举报人:
  • 被举报人:
  • *类型:
    • *投诉人姓名:
    • *投诉人联系方式:
    • *版权证明:
  • *详细原因: