2017-10-09 22:11:01 +08:00
|
|
|
|
/*
|
2017-09-27 16:20:30 +08:00
|
|
|
|
* MIT License
|
2017-04-01 16:35:56 +08:00
|
|
|
|
*
|
2017-09-27 16:20:30 +08:00
|
|
|
|
* Copyright (c) 2016 xiongziliang <771730766@qq.com>
|
|
|
|
|
*
|
|
|
|
|
* This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit).
|
|
|
|
|
*
|
|
|
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
|
|
|
* of this software and associated documentation files (the "Software"), to deal
|
|
|
|
|
* in the Software without restriction, including without limitation the rights
|
|
|
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
|
|
|
* copies of the Software, and to permit persons to whom the Software is
|
|
|
|
|
* furnished to do so, subject to the following conditions:
|
|
|
|
|
*
|
|
|
|
|
* The above copyright notice and this permission notice shall be included in all
|
|
|
|
|
* copies or substantial portions of the Software.
|
|
|
|
|
*
|
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
|
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
|
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
|
|
|
* SOFTWARE.
|
2017-04-01 16:35:56 +08:00
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include <string.h>
|
2017-05-02 17:15:12 +08:00
|
|
|
|
#include "Common/config.h"
|
2017-04-25 11:35:41 +08:00
|
|
|
|
#include "Rtmp/Rtmp.h"
|
|
|
|
|
#include "RtspToRtmpMediaSource.h"
|
|
|
|
|
#include "Util/util.h"
|
|
|
|
|
#include "Network/sockutil.h"
|
2017-04-01 16:35:56 +08:00
|
|
|
|
|
|
|
|
|
using namespace ZL::Util;
|
|
|
|
|
using namespace ZL::Network;
|
2017-04-25 11:35:41 +08:00
|
|
|
|
|
2017-04-01 16:35:56 +08:00
|
|
|
|
namespace ZL {
|
|
|
|
|
namespace Rtsp {
|
|
|
|
|
|
|
|
|
|
|
2018-02-07 11:16:43 +08:00
|
|
|
|
RtspToRtmpMediaSource::RtspToRtmpMediaSource(const string &vhost,
|
|
|
|
|
const string &app,
|
|
|
|
|
const string &id,
|
|
|
|
|
bool bEnableHls,
|
|
|
|
|
bool bEnableMp4) :
|
2018-10-24 15:43:52 +08:00
|
|
|
|
RtspMediaSource(vhost,app,id),_bEnableHls(bEnableHls),_bEnableMp4(bEnableMp4) {
|
2017-04-01 16:35:56 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RtspToRtmpMediaSource::~RtspToRtmpMediaSource() {
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void RtspToRtmpMediaSource::makeVideoConfigPkt() {
|
|
|
|
|
int8_t flags = 7; //h.264
|
|
|
|
|
flags |= (FLV_KEY_FRAME << 4);
|
|
|
|
|
bool is_config = true;
|
|
|
|
|
|
2017-12-04 23:55:09 +08:00
|
|
|
|
RtmpPacket::Ptr rtmpPkt(new RtmpPacket);
|
2017-04-01 16:35:56 +08:00
|
|
|
|
//////////header
|
2017-12-04 23:55:09 +08:00
|
|
|
|
rtmpPkt->strBuf.push_back(flags);
|
|
|
|
|
rtmpPkt->strBuf.push_back(!is_config);
|
|
|
|
|
rtmpPkt->strBuf.append("\x0\x0\x0", 3);
|
2017-04-01 16:35:56 +08:00
|
|
|
|
|
|
|
|
|
////////////sps
|
2017-12-04 23:55:09 +08:00
|
|
|
|
rtmpPkt->strBuf.push_back(1); // version
|
2018-10-23 16:41:25 +08:00
|
|
|
|
|
|
|
|
|
//todo(xzl) 修复此处
|
2018-10-24 15:43:52 +08:00
|
|
|
|
string _sps ;//= _pParser->getSps().substr(4);
|
|
|
|
|
string _pps ;//= _pParser->getPps().substr(4);
|
|
|
|
|
//DebugL<<hexdump(_sps.data(), _sps.size());
|
|
|
|
|
rtmpPkt->strBuf.push_back(_sps[1]); // profile
|
|
|
|
|
rtmpPkt->strBuf.push_back(_sps[2]); // compat
|
|
|
|
|
rtmpPkt->strBuf.push_back(_sps[3]); // level
|
2017-12-04 23:55:09 +08:00
|
|
|
|
rtmpPkt->strBuf.push_back(0xff); // 6 bits reserved + 2 bits nal size length - 1 (11)
|
|
|
|
|
rtmpPkt->strBuf.push_back(0xe1); // 3 bits reserved + 5 bits number of sps (00001)
|
2018-10-24 15:43:52 +08:00
|
|
|
|
uint16_t size = _sps.size();
|
2017-04-01 16:35:56 +08:00
|
|
|
|
size = htons(size);
|
2017-12-04 23:55:09 +08:00
|
|
|
|
rtmpPkt->strBuf.append((char *) &size, 2);
|
2018-10-24 15:43:52 +08:00
|
|
|
|
rtmpPkt->strBuf.append(_sps);
|
2017-04-01 16:35:56 +08:00
|
|
|
|
|
|
|
|
|
/////////////pps
|
2017-12-04 23:55:09 +08:00
|
|
|
|
rtmpPkt->strBuf.push_back(1); // version
|
2018-10-24 15:43:52 +08:00
|
|
|
|
size = _pps.size();
|
2017-04-01 16:35:56 +08:00
|
|
|
|
size = htons(size);
|
2017-12-04 23:55:09 +08:00
|
|
|
|
rtmpPkt->strBuf.append((char *) &size, 2);
|
2018-10-24 15:43:52 +08:00
|
|
|
|
rtmpPkt->strBuf.append(_pps);
|
2017-12-04 23:55:09 +08:00
|
|
|
|
|
|
|
|
|
rtmpPkt->bodySize = rtmpPkt->strBuf.size();
|
|
|
|
|
rtmpPkt->chunkId = CHUNK_VIDEO;
|
|
|
|
|
rtmpPkt->streamId = STREAM_MEDIA;
|
|
|
|
|
rtmpPkt->timeStamp = 0;
|
|
|
|
|
rtmpPkt->typeId = MSG_VIDEO;
|
2018-10-24 15:43:52 +08:00
|
|
|
|
_pRtmpSrc->onGetMedia(rtmpPkt);
|
2017-04-01 16:35:56 +08:00
|
|
|
|
}
|
2017-05-16 15:02:09 +08:00
|
|
|
|
void RtspToRtmpMediaSource::onGetH264(const H264Frame& frame) {
|
2018-10-24 15:43:52 +08:00
|
|
|
|
if(_pRecorder){
|
|
|
|
|
_pRecorder->inputH264((char *) frame.data(), frame.size(), frame.timeStamp, frame.type);
|
2017-05-16 15:02:09 +08:00
|
|
|
|
}
|
2018-10-18 23:48:00 +08:00
|
|
|
|
uint8_t nal_type = frame.data()[4] & 0x1F;
|
2017-05-16 15:02:09 +08:00
|
|
|
|
int8_t flags = 7; //h.264
|
|
|
|
|
bool is_config = false;
|
|
|
|
|
switch (nal_type) {
|
|
|
|
|
case 7:
|
|
|
|
|
case 8:
|
|
|
|
|
return;
|
|
|
|
|
case 5:
|
|
|
|
|
flags |= (FLV_KEY_FRAME << 4);
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
flags |= (FLV_INTER_FRAME << 4);
|
|
|
|
|
break;
|
|
|
|
|
}
|
2017-12-04 23:55:09 +08:00
|
|
|
|
RtmpPacket::Ptr rtmpPkt(new RtmpPacket);
|
|
|
|
|
rtmpPkt->strBuf.push_back(flags);
|
|
|
|
|
rtmpPkt->strBuf.push_back(!is_config);
|
|
|
|
|
rtmpPkt->strBuf.append("\x0\x0\x0", 3);
|
2018-10-18 23:48:00 +08:00
|
|
|
|
uint32_t size = frame.size() - 4;
|
2017-05-16 15:02:09 +08:00
|
|
|
|
size = htonl(size);
|
2017-12-04 23:55:09 +08:00
|
|
|
|
rtmpPkt->strBuf.append((char *) &size, 4);
|
2018-10-18 23:48:00 +08:00
|
|
|
|
rtmpPkt->strBuf.append(&frame.data()[4], frame.size() - 4);
|
2017-12-04 23:55:09 +08:00
|
|
|
|
|
|
|
|
|
rtmpPkt->bodySize = rtmpPkt->strBuf.size();
|
|
|
|
|
rtmpPkt->chunkId = CHUNK_VIDEO;
|
|
|
|
|
rtmpPkt->streamId = STREAM_MEDIA;
|
|
|
|
|
rtmpPkt->timeStamp = frame.timeStamp;
|
|
|
|
|
rtmpPkt->typeId = MSG_VIDEO;
|
2018-10-24 15:43:52 +08:00
|
|
|
|
_pRtmpSrc->onGetMedia(rtmpPkt);
|
2017-05-16 15:02:09 +08:00
|
|
|
|
}
|
2018-10-24 14:21:59 +08:00
|
|
|
|
void RtspToRtmpMediaSource::onGetAAC(const AACFrame& frame) {
|
2018-10-24 15:43:52 +08:00
|
|
|
|
if(_pRecorder){
|
|
|
|
|
_pRecorder->inputAAC((char *) frame.buffer, frame.aac_frame_length, frame.timeStamp);
|
2017-04-01 16:35:56 +08:00
|
|
|
|
}
|
|
|
|
|
|
2017-12-04 23:55:09 +08:00
|
|
|
|
RtmpPacket::Ptr rtmpPkt(new RtmpPacket);
|
2017-04-01 16:35:56 +08:00
|
|
|
|
//////////header
|
|
|
|
|
uint8_t is_config = false;
|
2018-10-24 15:43:52 +08:00
|
|
|
|
rtmpPkt->strBuf.push_back(_ui8AudioFlags);
|
2017-12-04 23:55:09 +08:00
|
|
|
|
rtmpPkt->strBuf.push_back(!is_config);
|
2018-10-18 23:48:00 +08:00
|
|
|
|
rtmpPkt->strBuf.append((char *) frame.buffer + 7, frame.aac_frame_length - 7);
|
2017-12-04 23:55:09 +08:00
|
|
|
|
|
|
|
|
|
rtmpPkt->bodySize = rtmpPkt->strBuf.size();
|
|
|
|
|
rtmpPkt->chunkId = CHUNK_AUDIO;
|
|
|
|
|
rtmpPkt->streamId = STREAM_MEDIA;
|
|
|
|
|
rtmpPkt->timeStamp = frame.timeStamp;
|
|
|
|
|
rtmpPkt->typeId = MSG_AUDIO;
|
2018-10-24 15:43:52 +08:00
|
|
|
|
_pRtmpSrc->onGetMedia(rtmpPkt);
|
2017-04-01 16:35:56 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void RtspToRtmpMediaSource::makeAudioConfigPkt() {
|
2018-10-23 16:41:25 +08:00
|
|
|
|
//todo(xzl) 修复此处
|
|
|
|
|
#if 0
|
2018-10-24 15:43:52 +08:00
|
|
|
|
uint8_t flvStereoOrMono = (_pParser->getAudioChannel() > 1);
|
2017-04-01 16:35:56 +08:00
|
|
|
|
uint8_t flvSampleRate;
|
2018-10-24 15:43:52 +08:00
|
|
|
|
switch (_pParser->getAudioSampleRate()) {
|
2017-04-01 16:35:56 +08:00
|
|
|
|
case 48000:
|
|
|
|
|
case 44100:
|
|
|
|
|
flvSampleRate = 3;
|
|
|
|
|
break;
|
|
|
|
|
case 24000:
|
|
|
|
|
case 22050:
|
|
|
|
|
flvSampleRate = 2;
|
|
|
|
|
break;
|
|
|
|
|
case 12000:
|
|
|
|
|
case 11025:
|
|
|
|
|
flvSampleRate = 1;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
flvSampleRate = 0;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2018-10-24 15:43:52 +08:00
|
|
|
|
uint8_t flvSampleBit = _pParser->getAudioSampleBit() == 16;
|
2017-04-01 16:35:56 +08:00
|
|
|
|
uint8_t flvAudioType = 10; //aac
|
|
|
|
|
|
2018-10-24 15:43:52 +08:00
|
|
|
|
_ui8AudioFlags = (flvAudioType << 4) | (flvSampleRate << 2) | (flvSampleBit << 1) | flvStereoOrMono;
|
2017-04-01 16:35:56 +08:00
|
|
|
|
|
2017-12-04 23:55:09 +08:00
|
|
|
|
RtmpPacket::Ptr rtmpPkt(new RtmpPacket);
|
2017-04-01 16:35:56 +08:00
|
|
|
|
//////////header
|
|
|
|
|
uint8_t is_config = true;
|
2018-10-24 15:43:52 +08:00
|
|
|
|
rtmpPkt->strBuf.push_back(_ui8AudioFlags);
|
2017-12-04 23:55:09 +08:00
|
|
|
|
rtmpPkt->strBuf.push_back(!is_config);
|
2018-10-24 15:43:52 +08:00
|
|
|
|
rtmpPkt->strBuf.append(_pParser->getAudioCfg());
|
2017-12-04 23:55:09 +08:00
|
|
|
|
|
|
|
|
|
rtmpPkt->bodySize = rtmpPkt->strBuf.size();
|
|
|
|
|
rtmpPkt->chunkId = CHUNK_AUDIO;
|
|
|
|
|
rtmpPkt->streamId = STREAM_MEDIA;
|
|
|
|
|
rtmpPkt->timeStamp = 0;
|
|
|
|
|
rtmpPkt->typeId = MSG_AUDIO;
|
2018-10-24 15:43:52 +08:00
|
|
|
|
_pRtmpSrc->onGetMedia(rtmpPkt);
|
2018-10-23 16:41:25 +08:00
|
|
|
|
|
|
|
|
|
#endif
|
2017-04-01 16:35:56 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void RtspToRtmpMediaSource::makeMetaData() {
|
2018-10-24 15:43:52 +08:00
|
|
|
|
_pRtmpSrc.reset(new RtmpMediaSource(getVhost(),getApp(),getId()));
|
|
|
|
|
_pRtmpSrc->setListener(_listener);
|
2017-05-13 17:25:31 +08:00
|
|
|
|
AMFValue metaData(AMF_OBJECT);
|
2018-10-24 15:43:52 +08:00
|
|
|
|
metaData.set("duration", _pParser->getDuration());
|
2017-04-01 16:35:56 +08:00
|
|
|
|
metaData.set("fileSize", 0);
|
2018-10-23 16:41:25 +08:00
|
|
|
|
//todo(xzl) 修复此处
|
|
|
|
|
#if 0
|
|
|
|
|
|
2018-10-24 15:43:52 +08:00
|
|
|
|
if (_pParser->containVideo()) {
|
|
|
|
|
metaData.set("width", _pParser->getVideoWidth());
|
|
|
|
|
metaData.set("height", _pParser->getVideoHeight());
|
2018-08-30 10:05:50 +08:00
|
|
|
|
metaData.set("videocodecid", "avc1"); //h.264
|
2017-04-01 16:35:56 +08:00
|
|
|
|
metaData.set("videodatarate", 5000);
|
2018-10-24 15:43:52 +08:00
|
|
|
|
metaData.set("framerate", _pParser->getVideoFps());
|
2017-04-01 16:35:56 +08:00
|
|
|
|
makeVideoConfigPkt();
|
|
|
|
|
}
|
2018-10-24 15:43:52 +08:00
|
|
|
|
if (_pParser->containAudio()) {
|
2018-08-30 10:05:50 +08:00
|
|
|
|
metaData.set("audiocodecid", "mp4a"); //aac
|
2017-04-01 16:35:56 +08:00
|
|
|
|
metaData.set("audiodatarate", 160);
|
2018-10-24 15:43:52 +08:00
|
|
|
|
metaData.set("audiosamplerate", _pParser->getAudioSampleRate());
|
|
|
|
|
metaData.set("audiosamplesize", _pParser->getAudioSampleBit());
|
|
|
|
|
metaData.set("audiochannels", _pParser->getAudioChannel());
|
|
|
|
|
metaData.set("stereo", _pParser->getAudioChannel() > 1);
|
2017-04-01 16:35:56 +08:00
|
|
|
|
makeAudioConfigPkt();
|
|
|
|
|
}
|
|
|
|
|
|
2018-10-23 16:41:25 +08:00
|
|
|
|
#endif
|
2018-10-24 15:43:52 +08:00
|
|
|
|
_pRtmpSrc->onGetMetaData(metaData);
|
2017-04-01 16:35:56 +08:00
|
|
|
|
}
|
|
|
|
|
} /* namespace Rtsp */
|
|
|
|
|
} /* namespace ZL */
|