mirror of
https://github.com/ZLMediaKit/ZLMediaKit.git
synced 2026-06-14 03:55:58 +08:00
rtsp/rtmp/mp4支持opus并整理代码
This commit is contained in:
@@ -21,41 +21,6 @@ string makeAacConfig(const uint8_t *hex, int length);
|
||||
int dumpAacConfig(const string &config, int length, uint8_t *out, int out_size);
|
||||
bool parseAacConfig(const string &config, int &samplerate, int &channels);
|
||||
|
||||
/**
|
||||
* aac帧,包含adts头
|
||||
*/
|
||||
class AACFrame : public FrameImp {
|
||||
public:
|
||||
typedef std::shared_ptr<AACFrame> Ptr;
|
||||
AACFrame(){
|
||||
_codecid = CodecAAC;
|
||||
}
|
||||
};
|
||||
|
||||
class AACFrameNoCacheAble : public FrameFromPtr {
|
||||
public:
|
||||
typedef std::shared_ptr<AACFrameNoCacheAble> Ptr;
|
||||
|
||||
AACFrameNoCacheAble(char *ptr,uint32_t size,uint32_t dts,uint32_t pts = 0,int prefix_size = ADTS_HEADER_LEN){
|
||||
_ptr = ptr;
|
||||
_size = size;
|
||||
_dts = dts;
|
||||
_prefix_size = prefix_size;
|
||||
}
|
||||
|
||||
CodecId getCodecId() const override{
|
||||
return CodecAAC;
|
||||
}
|
||||
|
||||
bool keyFrame() const override {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool configFrame() const override{
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* aac音频通道
|
||||
*/
|
||||
|
||||
@@ -43,7 +43,9 @@ bool AACRtmpDecoder::inputRtmp(const RtmpPacket::Ptr &pkt, bool) {
|
||||
}
|
||||
|
||||
void AACRtmpDecoder::onGetAAC(const char* data, int len, uint32_t stamp) {
|
||||
auto frame = ResourcePoolHelper<AACFrame>::obtainObj();
|
||||
auto frame = ResourcePoolHelper<FrameImp>::obtainObj();
|
||||
frame->_codec_id = CodecAAC;
|
||||
|
||||
//生成adts头
|
||||
char adts_header[32] = {0};
|
||||
auto size = dumpAacConfig(_aac_cfg, len, (uint8_t *) adts_header, sizeof(adts_header));
|
||||
|
||||
@@ -19,7 +19,7 @@ namespace mediakit{
|
||||
/**
|
||||
* aac Rtmp转adts类
|
||||
*/
|
||||
class AACRtmpDecoder : public RtmpCodec , public ResourcePoolHelper<AACFrame> {
|
||||
class AACRtmpDecoder : public RtmpCodec , public ResourcePoolHelper<FrameImp> {
|
||||
public:
|
||||
typedef std::shared_ptr<AACRtmpDecoder> Ptr;
|
||||
|
||||
|
||||
@@ -67,19 +67,19 @@ AACRtpDecoder::AACRtpDecoder(const Track::Ptr &track) {
|
||||
} else {
|
||||
_aac_cfg = aacTrack->getAacCfg();
|
||||
}
|
||||
_frame = obtainFrame();
|
||||
obtainFrame();
|
||||
}
|
||||
|
||||
AACRtpDecoder::AACRtpDecoder() {
|
||||
_frame = obtainFrame();
|
||||
obtainFrame();
|
||||
}
|
||||
|
||||
AACFrame::Ptr AACRtpDecoder::obtainFrame() {
|
||||
void AACRtpDecoder::obtainFrame() {
|
||||
//从缓存池重新申请对象,防止覆盖已经写入环形缓存的对象
|
||||
auto frame = ResourcePoolHelper<AACFrame>::obtainObj();
|
||||
frame->_prefix_size = 0;
|
||||
frame->_buffer.clear();
|
||||
return frame;
|
||||
_frame = ResourcePoolHelper<FrameImp>::obtainObj();
|
||||
_frame->_prefix_size = 0;
|
||||
_frame->_buffer.clear();
|
||||
_frame->_codec_id = CodecAAC;
|
||||
}
|
||||
|
||||
bool AACRtpDecoder::inputRtp(const RtpPacket::Ptr &rtppack, bool key_pos) {
|
||||
@@ -143,11 +143,7 @@ void AACRtpDecoder::flushData() {
|
||||
_frame->_prefix_size = size;
|
||||
}
|
||||
RtpCodec::inputFrame(_frame);
|
||||
_frame = obtainFrame();
|
||||
obtainFrame();
|
||||
}
|
||||
|
||||
|
||||
}//namespace mediakit
|
||||
|
||||
|
||||
|
||||
}//namespace mediakit
|
||||
@@ -17,7 +17,7 @@ namespace mediakit{
|
||||
/**
|
||||
* aac rtp转adts类
|
||||
*/
|
||||
class AACRtpDecoder : public RtpCodec , public ResourcePoolHelper<AACFrame> {
|
||||
class AACRtpDecoder : public RtpCodec , public ResourcePoolHelper<FrameImp> {
|
||||
public:
|
||||
typedef std::shared_ptr<AACRtpDecoder> Ptr;
|
||||
|
||||
@@ -39,11 +39,11 @@ protected:
|
||||
AACRtpDecoder();
|
||||
|
||||
private:
|
||||
AACFrame::Ptr obtainFrame();
|
||||
void obtainFrame();
|
||||
void flushData();
|
||||
|
||||
private:
|
||||
AACFrame::Ptr _frame;
|
||||
FrameImp::Ptr _frame;
|
||||
string _aac_cfg;
|
||||
uint32_t _last_dts = 0;
|
||||
};
|
||||
|
||||
67
src/Extension/CommonRtmp.cpp
Normal file
67
src/Extension/CommonRtmp.cpp
Normal file
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
|
||||
*
|
||||
* This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit).
|
||||
*
|
||||
* Use of this source code is governed by MIT license that can be found in the
|
||||
* LICENSE file in the root of the source tree. All contributing project authors
|
||||
* may be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "CommonRtmp.h"
|
||||
|
||||
namespace mediakit{
|
||||
|
||||
CommonRtmpDecoder::CommonRtmpDecoder(CodecId codec) {
|
||||
_codec = codec;
|
||||
obtainFrame();
|
||||
}
|
||||
|
||||
CodecId CommonRtmpDecoder::getCodecId() const {
|
||||
return _codec;
|
||||
}
|
||||
|
||||
void CommonRtmpDecoder::obtainFrame() {
|
||||
//从缓存池重新申请对象,防止覆盖已经写入环形缓存的对象
|
||||
_frame = ResourcePoolHelper<FrameImp>::obtainObj();
|
||||
_frame->_buffer.clear();
|
||||
_frame->_codec_id = _codec;
|
||||
_frame->_prefix_size = 0;
|
||||
}
|
||||
|
||||
bool CommonRtmpDecoder::inputRtmp(const RtmpPacket::Ptr &rtmp, bool) {
|
||||
//拷贝负载
|
||||
_frame->_buffer.assign(rtmp->strBuf.data() + 1, rtmp->strBuf.size() - 1);
|
||||
_frame->_dts = rtmp->timeStamp;
|
||||
//写入环形缓存
|
||||
RtmpCodec::inputFrame(_frame);
|
||||
//创建下一帧
|
||||
obtainFrame();
|
||||
return false;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
CommonRtmpEncoder::CommonRtmpEncoder(const Track::Ptr &track) : CommonRtmpDecoder(track->getCodecId()) {
|
||||
_audio_flv_flags = getAudioRtmpFlags(track);
|
||||
}
|
||||
|
||||
void CommonRtmpEncoder::inputFrame(const Frame::Ptr &frame) {
|
||||
if (!_audio_flv_flags) {
|
||||
return;
|
||||
}
|
||||
RtmpPacket::Ptr rtmp = ResourcePoolHelper<RtmpPacket>::obtainObj();
|
||||
rtmp->strBuf.clear();
|
||||
//header
|
||||
rtmp->strBuf.push_back(_audio_flv_flags);
|
||||
//data
|
||||
rtmp->strBuf.append(frame->data() + frame->prefixSize(), frame->size() - frame->prefixSize());
|
||||
rtmp->bodySize = rtmp->strBuf.size();
|
||||
rtmp->chunkId = CHUNK_AUDIO;
|
||||
rtmp->streamId = STREAM_MEDIA;
|
||||
rtmp->timeStamp = frame->dts();
|
||||
rtmp->typeId = MSG_AUDIO;
|
||||
RtmpCodec::inputRtmp(rtmp, false);
|
||||
}
|
||||
|
||||
}//namespace mediakit
|
||||
74
src/Extension/CommonRtmp.h
Normal file
74
src/Extension/CommonRtmp.h
Normal file
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
|
||||
*
|
||||
* This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit).
|
||||
*
|
||||
* Use of this source code is governed by MIT license that can be found in the
|
||||
* LICENSE file in the root of the source tree. All contributing project authors
|
||||
* may be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef ZLMEDIAKIT_COMMONRTMP_H
|
||||
#define ZLMEDIAKIT_COMMONRTMP_H
|
||||
|
||||
#include "Frame.h"
|
||||
#include "Rtmp/RtmpCodec.h"
|
||||
|
||||
namespace mediakit{
|
||||
|
||||
/**
|
||||
* 通用 rtmp解码类
|
||||
*/
|
||||
class CommonRtmpDecoder : public RtmpCodec , public ResourcePoolHelper<FrameImp> {
|
||||
public:
|
||||
typedef std::shared_ptr<CommonRtmpDecoder> Ptr;
|
||||
|
||||
~CommonRtmpDecoder() override {}
|
||||
|
||||
/**
|
||||
* 构造函数
|
||||
* @param codec 编码id
|
||||
*/
|
||||
CommonRtmpDecoder(CodecId codec);
|
||||
|
||||
/**
|
||||
* 返回编码类型ID
|
||||
*/
|
||||
CodecId getCodecId() const override;
|
||||
|
||||
/**
|
||||
* 输入Rtmp并解码
|
||||
* @param rtmp Rtmp数据包
|
||||
* @param key_pos 此参数内部强制转换为false,请忽略之
|
||||
*/
|
||||
bool inputRtmp(const RtmpPacket::Ptr &rtmp, bool key_pos = false) override;
|
||||
|
||||
private:
|
||||
void obtainFrame();
|
||||
|
||||
private:
|
||||
CodecId _codec;
|
||||
FrameImp::Ptr _frame;
|
||||
};
|
||||
|
||||
/**
|
||||
* 通用 rtmp编码类
|
||||
*/
|
||||
class CommonRtmpEncoder : public CommonRtmpDecoder , public ResourcePoolHelper<RtmpPacket> {
|
||||
public:
|
||||
typedef std::shared_ptr<CommonRtmpEncoder> Ptr;
|
||||
|
||||
CommonRtmpEncoder(const Track::Ptr &track);
|
||||
~CommonRtmpEncoder() override{}
|
||||
|
||||
/**
|
||||
* 输入帧数据
|
||||
*/
|
||||
void inputFrame(const Frame::Ptr &frame) override;
|
||||
|
||||
private:
|
||||
uint8_t _audio_flv_flags = 0;
|
||||
};
|
||||
|
||||
}//namespace mediakit
|
||||
#endif //ZLMEDIAKIT_COMMONRTMP_H
|
||||
87
src/Extension/CommonRtp.cpp
Normal file
87
src/Extension/CommonRtp.cpp
Normal file
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
|
||||
*
|
||||
* This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit).
|
||||
*
|
||||
* Use of this source code is governed by MIT license that can be found in the
|
||||
* LICENSE file in the root of the source tree. All contributing project authors
|
||||
* may be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "CommonRtp.h"
|
||||
|
||||
#define MAX_FRAME_SIZE 2 * 1024
|
||||
|
||||
CommonRtpDecoder::CommonRtpDecoder(CodecId codec){
|
||||
_codec = codec;
|
||||
obtainFrame();
|
||||
}
|
||||
|
||||
CodecId CommonRtpDecoder::getCodecId() const {
|
||||
return _codec;
|
||||
}
|
||||
|
||||
void CommonRtpDecoder::obtainFrame() {
|
||||
_frame = ResourcePoolHelper<FrameImp>::obtainObj();
|
||||
_frame->_buffer.clear();
|
||||
_frame->_prefix_size = 0;
|
||||
_frame->_dts = 0;
|
||||
_frame->_codec_id = _codec;
|
||||
}
|
||||
|
||||
bool CommonRtpDecoder::inputRtp(const RtpPacket::Ptr &rtp, bool){
|
||||
auto payload = rtp->data() + rtp->offset;
|
||||
auto size = rtp->size() - rtp->offset;
|
||||
if (size <= 0) {
|
||||
//无实际负载
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_frame->_dts != rtp->timeStamp || _frame->_buffer.size() > MAX_FRAME_SIZE) {
|
||||
//时间戳发生变化或者缓存超过MAX_FRAME_SIZE,则清空上帧数据
|
||||
if (!_frame->_buffer.empty()) {
|
||||
//有有效帧,则输出
|
||||
RtpCodec::inputFrame(_frame);
|
||||
}
|
||||
|
||||
//新的一帧数据
|
||||
obtainFrame();
|
||||
_frame->_dts = rtp->timeStamp;
|
||||
_drop_flag = false;
|
||||
} else if (_last_seq != 0 && _last_seq + (uint16_t) 1 != rtp->sequence) {
|
||||
//时间戳未发生变化,但是seq却不连续,说明中间rtp丢包了,那么整帧应该废弃
|
||||
WarnL << "rtp丢包:" << _last_seq << " -> " << rtp->sequence;
|
||||
_drop_flag = true;
|
||||
_frame->_buffer.clear();
|
||||
}
|
||||
|
||||
if (!_drop_flag) {
|
||||
_frame->_buffer.append(payload, size);
|
||||
}
|
||||
|
||||
_last_seq = rtp->sequence;
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
CommonRtpEncoder::CommonRtpEncoder(CodecId codec, uint32_t ssrc, uint32_t mtu_size,
|
||||
uint32_t sample_rate, uint8_t payload_type, uint8_t interleaved)
|
||||
: CommonRtpDecoder(codec), RtpInfo(ssrc, mtu_size, sample_rate, payload_type, interleaved) {
|
||||
}
|
||||
|
||||
void CommonRtpEncoder::inputFrame(const Frame::Ptr &frame){
|
||||
GET_CONFIG(uint32_t, cycleMS, Rtp::kCycleMS);
|
||||
auto stamp = frame->dts() % cycleMS;
|
||||
auto ptr = frame->data() + frame->prefixSize();
|
||||
auto len = frame->size() - frame->prefixSize();
|
||||
auto remain_size = len;
|
||||
const auto max_rtp_size = _ui32MtuSize - 20;
|
||||
|
||||
while (remain_size > 0) {
|
||||
auto rtp_size = remain_size > max_rtp_size ? max_rtp_size : remain_size;
|
||||
RtpCodec::inputRtp(makeRtp(getTrackType(), ptr, rtp_size, false, stamp), false);
|
||||
ptr += rtp_size;
|
||||
remain_size -= rtp_size;
|
||||
}
|
||||
}
|
||||
83
src/Extension/CommonRtp.h
Normal file
83
src/Extension/CommonRtp.h
Normal file
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
|
||||
*
|
||||
* This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit).
|
||||
*
|
||||
* Use of this source code is governed by MIT license that can be found in the
|
||||
* LICENSE file in the root of the source tree. All contributing project authors
|
||||
* may be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef ZLMEDIAKIT_COMMONRTP_H
|
||||
#define ZLMEDIAKIT_COMMONRTP_H
|
||||
|
||||
#include "Frame.h"
|
||||
#include "Rtsp/RtpCodec.h"
|
||||
|
||||
namespace mediakit{
|
||||
|
||||
/**
|
||||
* 通用 rtp解码类
|
||||
*/
|
||||
class CommonRtpDecoder : public RtpCodec, public ResourcePoolHelper<FrameImp> {
|
||||
public:
|
||||
typedef std::shared_ptr <CommonRtpDecoder> Ptr;
|
||||
|
||||
~CommonRtpDecoder() override {}
|
||||
|
||||
/**
|
||||
* 构造函数
|
||||
* @param codec 编码id
|
||||
*/
|
||||
CommonRtpDecoder(CodecId codec);
|
||||
|
||||
/**
|
||||
* 返回编码类型ID
|
||||
*/
|
||||
CodecId getCodecId() const override;
|
||||
|
||||
/**
|
||||
* 输入rtp并解码
|
||||
* @param rtp rtp数据包
|
||||
* @param key_pos 此参数内部强制转换为false,请忽略之
|
||||
*/
|
||||
bool inputRtp(const RtpPacket::Ptr &rtp, bool key_pos = false) override;
|
||||
|
||||
private:
|
||||
void obtainFrame();
|
||||
|
||||
private:
|
||||
CodecId _codec;
|
||||
FrameImp::Ptr _frame;
|
||||
uint16_t _last_seq = 0;
|
||||
bool _drop_flag = false;
|
||||
};
|
||||
|
||||
/**
|
||||
* 通用 rtp编码类
|
||||
*/
|
||||
class CommonRtpEncoder : public CommonRtpDecoder, public RtpInfo {
|
||||
public:
|
||||
typedef std::shared_ptr <CommonRtpEncoder> Ptr;
|
||||
|
||||
~CommonRtpEncoder() override {}
|
||||
|
||||
/**
|
||||
* 构造函数
|
||||
* @param codec 编码类型
|
||||
* @param ssrc ssrc
|
||||
* @param mtu_size mtu 大小
|
||||
* @param sample_rate 采样率
|
||||
* @param payload_type pt类型
|
||||
* @param interleaved rtsp interleaved 值
|
||||
*/
|
||||
CommonRtpEncoder(CodecId codec, uint32_t ssrc, uint32_t mtu_size, uint32_t sample_rate, uint8_t payload_type, uint8_t interleaved);
|
||||
|
||||
/**
|
||||
* 输入帧数据并编码成rtp
|
||||
*/
|
||||
void inputFrame(const Frame::Ptr &frame) override;
|
||||
};
|
||||
|
||||
}//namespace mediakit
|
||||
#endif //ZLMEDIAKIT_COMMONRTP_H
|
||||
@@ -13,11 +13,13 @@
|
||||
#include "H264Rtmp.h"
|
||||
#include "H265Rtmp.h"
|
||||
#include "AACRtmp.h"
|
||||
#include "G711Rtmp.h"
|
||||
#include "CommonRtmp.h"
|
||||
#include "H264Rtp.h"
|
||||
#include "AACRtp.h"
|
||||
#include "G711Rtp.h"
|
||||
#include "H265Rtp.h"
|
||||
#include "CommonRtp.h"
|
||||
#include "Opus.h"
|
||||
#include "G711.h"
|
||||
#include "Common/Parser.h"
|
||||
|
||||
namespace mediakit{
|
||||
@@ -42,6 +44,10 @@ Track::Ptr Factory::getTrackBySdp(const SdpTrack::Ptr &track) {
|
||||
return std::make_shared<AACTrack>(aac_cfg);
|
||||
}
|
||||
|
||||
if (strcasecmp(track->_codec.data(), "opus") == 0) {
|
||||
return std::make_shared<OpusTrack>();
|
||||
}
|
||||
|
||||
if (strcasecmp(track->_codec.data(), "PCMA") == 0) {
|
||||
return std::make_shared<G711Track>(CodecG711A, track->_samplerate, track->_channel, 16);
|
||||
}
|
||||
@@ -114,11 +120,12 @@ RtpCodec::Ptr Factory::getRtpEncoderBySdp(const Sdp::Ptr &sdp) {
|
||||
auto interleaved = sdp->getTrackType() * 2;
|
||||
auto codec_id = sdp->getCodecId();
|
||||
switch (codec_id){
|
||||
case CodecH264 : return std::make_shared<H264RtpEncoder>(ssrc,mtu,sample_rate,pt,interleaved);
|
||||
case CodecH265 : return std::make_shared<H265RtpEncoder>(ssrc,mtu,sample_rate,pt,interleaved);
|
||||
case CodecAAC : return std::make_shared<AACRtpEncoder>(ssrc,mtu,sample_rate,pt,interleaved);
|
||||
case CodecH264 : return std::make_shared<H264RtpEncoder>(ssrc, mtu, sample_rate, pt, interleaved);
|
||||
case CodecH265 : return std::make_shared<H265RtpEncoder>(ssrc, mtu, sample_rate, pt, interleaved);
|
||||
case CodecAAC : return std::make_shared<AACRtpEncoder>(ssrc, mtu, sample_rate, pt, interleaved);
|
||||
case CodecOpus :
|
||||
case CodecG711A :
|
||||
case CodecG711U : return std::make_shared<G711RtpEncoder>(codec_id, ssrc, mtu, sample_rate, pt, interleaved);
|
||||
case CodecG711U : return std::make_shared<CommonRtpEncoder>(codec_id, ssrc, mtu, sample_rate, pt, interleaved);
|
||||
default : WarnL << "暂不支持该CodecId:" << codec_id; return nullptr;
|
||||
}
|
||||
}
|
||||
@@ -128,8 +135,9 @@ RtpCodec::Ptr Factory::getRtpDecoderByTrack(const Track::Ptr &track) {
|
||||
case CodecH264 : return std::make_shared<H264RtpDecoder>();
|
||||
case CodecH265 : return std::make_shared<H265RtpDecoder>();
|
||||
case CodecAAC : return std::make_shared<AACRtpDecoder>(track->clone());
|
||||
case CodecOpus :
|
||||
case CodecG711A :
|
||||
case CodecG711U : return std::make_shared<G711RtpDecoder>(track->getCodecId());
|
||||
case CodecG711U : return std::make_shared<CommonRtpDecoder>(track->getCodecId());
|
||||
default : WarnL << "暂不支持该CodecId:" << track->getCodecName(); return nullptr;
|
||||
}
|
||||
}
|
||||
@@ -137,40 +145,35 @@ RtpCodec::Ptr Factory::getRtpDecoderByTrack(const Track::Ptr &track) {
|
||||
/////////////////////////////rtmp相关///////////////////////////////////////////
|
||||
|
||||
static CodecId getVideoCodecIdByAmf(const AMFValue &val){
|
||||
if (val.type() == AMF_STRING){
|
||||
if (val.type() == AMF_STRING) {
|
||||
auto str = val.as_string();
|
||||
if(str == "avc1"){
|
||||
if (str == "avc1") {
|
||||
return CodecH264;
|
||||
}
|
||||
if(str == "mp4a"){
|
||||
return CodecAAC;
|
||||
}
|
||||
if(str == "hev1" || str == "hvc1"){
|
||||
if (str == "hev1" || str == "hvc1") {
|
||||
return CodecH265;
|
||||
}
|
||||
WarnL << "暂不支持该Amf:" << str;
|
||||
WarnL << "暂不支持该视频Amf:" << str;
|
||||
return CodecInvalid;
|
||||
}
|
||||
|
||||
if (val.type() != AMF_NULL){
|
||||
if (val.type() != AMF_NULL) {
|
||||
auto type_id = val.as_integer();
|
||||
switch (type_id){
|
||||
case FLV_CODEC_H264: return CodecH264;
|
||||
case FLV_CODEC_AAC: return CodecAAC;
|
||||
case FLV_CODEC_H265: return CodecH265;
|
||||
default : WarnL << "暂不支持该Amf:" << type_id; return CodecInvalid;
|
||||
switch (type_id) {
|
||||
case FLV_CODEC_H264 : return CodecH264;
|
||||
case FLV_CODEC_H265 : return CodecH265;
|
||||
default : WarnL << "暂不支持该视频Amf:" << type_id; return CodecInvalid;
|
||||
}
|
||||
}
|
||||
|
||||
return CodecInvalid;
|
||||
}
|
||||
|
||||
|
||||
Track::Ptr getTrackByCodecId(CodecId codecId, int sample_rate = 0, int channels = 0, int sample_bit = 0) {
|
||||
switch (codecId){
|
||||
case CodecH264 : return std::make_shared<H264Track>();
|
||||
case CodecH265 : return std::make_shared<H265Track>();
|
||||
case CodecAAC : return std::make_shared<AACTrack>();
|
||||
case CodecOpus: return std::make_shared<OpusTrack>();
|
||||
case CodecG711A :
|
||||
case CodecG711U : return (sample_rate && channels && sample_bit) ? std::make_shared<G711Track>(codecId, sample_rate, channels, sample_bit) : nullptr;
|
||||
default : WarnL << "暂不支持该CodecId:" << codecId; return nullptr;
|
||||
@@ -191,7 +194,7 @@ static CodecId getAudioCodecIdByAmf(const AMFValue &val) {
|
||||
if (str == "mp4a") {
|
||||
return CodecAAC;
|
||||
}
|
||||
WarnL << "暂不支持该Amf:" << str;
|
||||
WarnL << "暂不支持该音频Amf:" << str;
|
||||
return CodecInvalid;
|
||||
}
|
||||
|
||||
@@ -201,7 +204,8 @@ static CodecId getAudioCodecIdByAmf(const AMFValue &val) {
|
||||
case FLV_CODEC_AAC : return CodecAAC;
|
||||
case FLV_CODEC_G711A : return CodecG711A;
|
||||
case FLV_CODEC_G711U : return CodecG711U;
|
||||
default : WarnL << "暂不支持该Amf:" << type_id; return CodecInvalid;
|
||||
case FLV_CODEC_OPUS : return CodecOpus;
|
||||
default : WarnL << "暂不支持该音频Amf:" << type_id; return CodecInvalid;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -221,6 +225,7 @@ RtmpCodec::Ptr Factory::getRtmpCodecByTrack(const Track::Ptr &track, bool is_enc
|
||||
case CodecH264 : return std::make_shared<H264RtmpEncoder>(track);
|
||||
case CodecAAC : return std::make_shared<AACRtmpEncoder>(track);
|
||||
case CodecH265 : return std::make_shared<H265RtmpEncoder>(track);
|
||||
case CodecOpus : return std::make_shared<CommonRtmpEncoder>(track);
|
||||
case CodecG711A :
|
||||
case CodecG711U : {
|
||||
auto audio_track = dynamic_pointer_cast<AudioTrack>(track);
|
||||
@@ -235,7 +240,7 @@ RtmpCodec::Ptr Factory::getRtmpCodecByTrack(const Track::Ptr &track, bool is_enc
|
||||
<< ",该音频已被忽略";
|
||||
return nullptr;
|
||||
}
|
||||
return std::make_shared<G711RtmpEncoder>(track);
|
||||
return std::make_shared<CommonRtmpEncoder>(track);
|
||||
}
|
||||
default : WarnL << "暂不支持该CodecId:" << track->getCodecName(); return nullptr;
|
||||
}
|
||||
@@ -248,6 +253,7 @@ AMFValue Factory::getAmfByCodecId(CodecId codecId) {
|
||||
case CodecH265: return AMFValue(FLV_CODEC_H265);
|
||||
case CodecG711A: return AMFValue(FLV_CODEC_G711A);
|
||||
case CodecG711U: return AMFValue(FLV_CODEC_G711U);
|
||||
case CodecOpus: return AMFValue(FLV_CODEC_OPUS);
|
||||
default: return AMFValue(AMF_NULL);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,12 +35,12 @@ public:
|
||||
_dts = frame->dts();
|
||||
_pts = frame->pts();
|
||||
_prefix_size = frame->prefixSize();
|
||||
_codecid = frame->getCodecId();
|
||||
_codec_id = frame->getCodecId();
|
||||
_key = frame->keyFrame();
|
||||
_config = frame->configFrame();
|
||||
}
|
||||
|
||||
virtual ~FrameCacheAble() = default;
|
||||
~FrameCacheAble() override = default;
|
||||
|
||||
/**
|
||||
* 可以被缓存
|
||||
@@ -49,10 +49,6 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
CodecId getCodecId() const override{
|
||||
return _codecid;
|
||||
}
|
||||
|
||||
bool keyFrame() const override{
|
||||
return _key;
|
||||
}
|
||||
@@ -60,10 +56,10 @@ public:
|
||||
bool configFrame() const override{
|
||||
return _config;
|
||||
}
|
||||
|
||||
private:
|
||||
Frame::Ptr _frame;
|
||||
BufferRaw::Ptr _buffer;
|
||||
CodecId _codecid;
|
||||
bool _key;
|
||||
bool _config;
|
||||
};
|
||||
|
||||
@@ -148,7 +148,7 @@ public:
|
||||
}
|
||||
|
||||
CodecId getCodecId() const override{
|
||||
return _codecid;
|
||||
return _codec_id;
|
||||
}
|
||||
|
||||
bool keyFrame() const override {
|
||||
@@ -160,7 +160,7 @@ public:
|
||||
}
|
||||
|
||||
public:
|
||||
CodecId _codecid = CodecInvalid;
|
||||
CodecId _codec_id = CodecInvalid;
|
||||
string _buffer;
|
||||
uint32_t _dts = 0;
|
||||
uint32_t _pts = 0;
|
||||
@@ -314,9 +314,19 @@ private:
|
||||
class FrameFromPtr : public Frame{
|
||||
public:
|
||||
typedef std::shared_ptr<FrameFromPtr> Ptr;
|
||||
FrameFromPtr(CodecId codec_id, char *ptr, uint32_t size, uint32_t dts, uint32_t pts = 0, int prefix_size = 0){
|
||||
_codec_id = codec_id;
|
||||
_ptr = ptr;
|
||||
_size = size;
|
||||
_dts = dts;
|
||||
_pts = pts;
|
||||
_prefix_size = prefix_size;
|
||||
}
|
||||
|
||||
char *data() const override{
|
||||
return _ptr;
|
||||
}
|
||||
|
||||
uint32_t size() const override {
|
||||
return _size;
|
||||
}
|
||||
@@ -336,12 +346,29 @@ public:
|
||||
bool cacheAble() const override {
|
||||
return false;
|
||||
}
|
||||
|
||||
CodecId getCodecId() const override{
|
||||
return _codec_id;
|
||||
}
|
||||
|
||||
bool keyFrame() const override {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool configFrame() const override{
|
||||
return false;
|
||||
}
|
||||
|
||||
protected:
|
||||
FrameFromPtr() {}
|
||||
|
||||
protected:
|
||||
char *_ptr;
|
||||
uint32_t _size;
|
||||
uint32_t _dts;
|
||||
uint32_t _pts = 0;
|
||||
uint32_t _prefix_size;
|
||||
CodecId _codec_id = CodecInvalid;
|
||||
};
|
||||
|
||||
}//namespace mediakit
|
||||
|
||||
@@ -16,47 +16,6 @@
|
||||
|
||||
namespace mediakit{
|
||||
|
||||
/**
|
||||
* G711帧
|
||||
*/
|
||||
class G711Frame : public FrameImp {
|
||||
public:
|
||||
G711Frame(){
|
||||
_codecid = CodecG711A;
|
||||
}
|
||||
};
|
||||
|
||||
class G711FrameNoCacheAble : public FrameFromPtr {
|
||||
public:
|
||||
typedef std::shared_ptr<G711FrameNoCacheAble> Ptr;
|
||||
|
||||
G711FrameNoCacheAble(char *ptr,uint32_t size,uint32_t dts, uint32_t pts = 0,int prefix_size = 0){
|
||||
_ptr = ptr;
|
||||
_size = size;
|
||||
_dts = dts;
|
||||
_prefix_size = prefix_size;
|
||||
}
|
||||
|
||||
void setCodec(CodecId codecId){
|
||||
_codecId = codecId;
|
||||
}
|
||||
|
||||
CodecId getCodecId() const override{
|
||||
return _codecId;
|
||||
}
|
||||
|
||||
bool keyFrame() const override {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool configFrame() const override{
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
CodecId _codecId;
|
||||
};
|
||||
|
||||
/**
|
||||
* G711音频通道
|
||||
*/
|
||||
|
||||
@@ -1,63 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
|
||||
*
|
||||
* This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit).
|
||||
*
|
||||
* Use of this source code is governed by MIT license that can be found in the
|
||||
* LICENSE file in the root of the source tree. All contributing project authors
|
||||
* may be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "G711Rtmp.h"
|
||||
|
||||
namespace mediakit{
|
||||
|
||||
G711RtmpDecoder::G711RtmpDecoder(CodecId codecId) {
|
||||
_frame = obtainFrame();
|
||||
_codecId = codecId;
|
||||
}
|
||||
|
||||
G711Frame::Ptr G711RtmpDecoder::obtainFrame() {
|
||||
//从缓存池重新申请对象,防止覆盖已经写入环形缓存的对象
|
||||
auto frame = ResourcePoolHelper<G711Frame>::obtainObj();
|
||||
frame->_buffer.clear();
|
||||
frame->_codecid = _codecId;
|
||||
return frame;
|
||||
}
|
||||
|
||||
bool G711RtmpDecoder::inputRtmp(const RtmpPacket::Ptr &pkt, bool) {
|
||||
//拷贝G711负载
|
||||
_frame->_buffer.assign(pkt->strBuf.data() + 1, pkt->strBuf.size() - 1);
|
||||
_frame->_dts = pkt->timeStamp;
|
||||
//写入环形缓存
|
||||
RtmpCodec::inputFrame(_frame);
|
||||
_frame = obtainFrame();
|
||||
return false;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
G711RtmpEncoder::G711RtmpEncoder(const Track::Ptr &track) : G711RtmpDecoder(track->getCodecId()) {
|
||||
_audio_flv_flags = getAudioRtmpFlags(track);
|
||||
}
|
||||
|
||||
void G711RtmpEncoder::inputFrame(const Frame::Ptr &frame) {
|
||||
if(!_audio_flv_flags){
|
||||
return;
|
||||
}
|
||||
RtmpPacket::Ptr rtmpPkt = ResourcePoolHelper<RtmpPacket>::obtainObj();
|
||||
rtmpPkt->strBuf.clear();
|
||||
//header
|
||||
rtmpPkt->strBuf.push_back(_audio_flv_flags);
|
||||
|
||||
//g711 data
|
||||
rtmpPkt->strBuf.append(frame->data() + frame->prefixSize(), frame->size() - frame->prefixSize());
|
||||
rtmpPkt->bodySize = rtmpPkt->strBuf.size();
|
||||
rtmpPkt->chunkId = CHUNK_AUDIO;
|
||||
rtmpPkt->streamId = STREAM_MEDIA;
|
||||
rtmpPkt->timeStamp = frame->dts();
|
||||
rtmpPkt->typeId = MSG_AUDIO;
|
||||
RtmpCodec::inputRtmp(rtmpPkt, false);
|
||||
}
|
||||
|
||||
}//namespace mediakit
|
||||
@@ -1,66 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
|
||||
*
|
||||
* This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit).
|
||||
*
|
||||
* Use of this source code is governed by MIT license that can be found in the
|
||||
* LICENSE file in the root of the source tree. All contributing project authors
|
||||
* may be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef ZLMEDIAKIT_G711RTMPCODEC_H
|
||||
#define ZLMEDIAKIT_G711RTMPCODEC_H
|
||||
|
||||
#include "Rtmp/RtmpCodec.h"
|
||||
#include "Extension/Track.h"
|
||||
#include "Extension/G711.h"
|
||||
|
||||
namespace mediakit{
|
||||
/**
|
||||
* G711 Rtmp转G711 Frame类
|
||||
*/
|
||||
class G711RtmpDecoder : public RtmpCodec , public ResourcePoolHelper<G711Frame> {
|
||||
public:
|
||||
typedef std::shared_ptr<G711RtmpDecoder> Ptr;
|
||||
|
||||
G711RtmpDecoder(CodecId codecId);
|
||||
~G711RtmpDecoder() {}
|
||||
|
||||
/**
|
||||
* 输入Rtmp并解码
|
||||
* @param Rtmp Rtmp数据包
|
||||
* @param key_pos 此参数内部强制转换为false,请忽略之
|
||||
*/
|
||||
bool inputRtmp(const RtmpPacket::Ptr &Rtmp, bool key_pos = false) override;
|
||||
|
||||
CodecId getCodecId() const override{
|
||||
return _codecId;
|
||||
}
|
||||
private:
|
||||
G711Frame::Ptr obtainFrame();
|
||||
private:
|
||||
G711Frame::Ptr _frame;
|
||||
CodecId _codecId;
|
||||
};
|
||||
|
||||
/**
|
||||
* G711 RTMP打包类
|
||||
*/
|
||||
class G711RtmpEncoder : public G711RtmpDecoder , public ResourcePoolHelper<RtmpPacket> {
|
||||
public:
|
||||
typedef std::shared_ptr<G711RtmpEncoder> Ptr;
|
||||
|
||||
G711RtmpEncoder(const Track::Ptr &track);
|
||||
~G711RtmpEncoder() {}
|
||||
|
||||
/**
|
||||
* 输入G711 数据
|
||||
*/
|
||||
void inputFrame(const Frame::Ptr &frame) override;
|
||||
private:
|
||||
uint8_t _audio_flv_flags = 0;
|
||||
};
|
||||
|
||||
}//namespace mediakit
|
||||
|
||||
#endif //ZLMEDIAKIT_G711RTMPCODEC_H
|
||||
@@ -1,92 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
|
||||
*
|
||||
* This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit).
|
||||
*
|
||||
* Use of this source code is governed by MIT license that can be found in the
|
||||
* LICENSE file in the root of the source tree. All contributing project authors
|
||||
* may be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "G711Rtp.h"
|
||||
|
||||
namespace mediakit{
|
||||
|
||||
G711RtpDecoder::G711RtpDecoder(CodecId codecid){
|
||||
_codecid = codecid;
|
||||
_frame = obtainFrame();
|
||||
}
|
||||
|
||||
G711Frame::Ptr G711RtpDecoder::obtainFrame() {
|
||||
//从缓存池重新申请对象,防止覆盖已经写入环形缓存的对象
|
||||
auto frame = ResourcePoolHelper<G711Frame>::obtainObj();
|
||||
frame->_buffer.clear();
|
||||
frame->_codecid = _codecid;
|
||||
frame->_dts = 0;
|
||||
return frame;
|
||||
}
|
||||
|
||||
bool G711RtpDecoder::inputRtp(const RtpPacket::Ptr &rtppack, bool) {
|
||||
// 获取rtp数据长度
|
||||
int length = rtppack->size() - rtppack->offset;
|
||||
// 获取rtp数据
|
||||
const char *rtp_packet_buf = rtppack->data() + rtppack->offset;
|
||||
|
||||
if (rtppack->timeStamp != _frame->_dts) {
|
||||
//时间戳变更,清空上一帧
|
||||
onGetG711(_frame);
|
||||
}
|
||||
|
||||
//追加数据
|
||||
_frame->_buffer.append(rtp_packet_buf, length);
|
||||
//赋值时间戳
|
||||
_frame->_dts = rtppack->timeStamp;
|
||||
|
||||
if (rtppack->mark || _frame->_buffer.size() > 10 * 1024) {
|
||||
//标记为mark时,或者内存快溢出时,我们认为这是该帧最后一个包
|
||||
onGetG711(_frame);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void G711RtpDecoder::onGetG711(const G711Frame::Ptr &frame) {
|
||||
if(!frame->_buffer.empty()){
|
||||
//写入环形缓存
|
||||
RtpCodec::inputFrame(frame);
|
||||
_frame = obtainFrame();
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
G711RtpEncoder::G711RtpEncoder(CodecId codecid, uint32_t ui32Ssrc, uint32_t ui32MtuSize,
|
||||
uint32_t ui32SampleRate, uint8_t ui8PayloadType, uint8_t ui8Interleaved) :
|
||||
G711RtpDecoder(codecid),
|
||||
RtpInfo(ui32Ssrc, ui32MtuSize, ui32SampleRate, ui8PayloadType, ui8Interleaved) {
|
||||
}
|
||||
|
||||
void G711RtpEncoder::inputFrame(const Frame::Ptr &frame) {
|
||||
GET_CONFIG(uint32_t, cycleMS, Rtp::kCycleMS);
|
||||
auto uiStamp = frame->dts();
|
||||
auto pcData = frame->data() + frame->prefixSize();
|
||||
auto iLen = frame->size() - frame->prefixSize();
|
||||
|
||||
uiStamp %= cycleMS;
|
||||
char *ptr = (char *) pcData;
|
||||
int iSize = iLen;
|
||||
while (iSize > 0) {
|
||||
if (iSize <= _ui32MtuSize - 20) {
|
||||
makeG711Rtp(ptr, iSize, true, uiStamp);
|
||||
break;
|
||||
}
|
||||
makeG711Rtp(ptr, _ui32MtuSize - 20, false, uiStamp);
|
||||
ptr += (_ui32MtuSize - 20);
|
||||
iSize -= (_ui32MtuSize - 20);
|
||||
}
|
||||
}
|
||||
|
||||
void G711RtpEncoder::makeG711Rtp(const void *data, unsigned int len, bool mark, uint32_t uiStamp) {
|
||||
RtpCodec::inputRtp(makeRtp(getTrackType(), data, len, mark, uiStamp), false);
|
||||
}
|
||||
|
||||
}//namespace mediakit
|
||||
@@ -1,79 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
|
||||
*
|
||||
* This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit).
|
||||
*
|
||||
* Use of this source code is governed by MIT license that can be found in the
|
||||
* LICENSE file in the root of the source tree. All contributing project authors
|
||||
* may be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef ZLMEDIAKIT_G711RTPCODEC_H
|
||||
#define ZLMEDIAKIT_G711RTPCODEC_H
|
||||
#include "Rtsp/RtpCodec.h"
|
||||
#include "Extension/G711.h"
|
||||
namespace mediakit{
|
||||
|
||||
/**
|
||||
* rtp转G711类
|
||||
*/
|
||||
class G711RtpDecoder : public RtpCodec , public ResourcePoolHelper<G711Frame> {
|
||||
public:
|
||||
typedef std::shared_ptr<G711RtpDecoder> Ptr;
|
||||
|
||||
G711RtpDecoder(CodecId codecid);
|
||||
~G711RtpDecoder() {}
|
||||
|
||||
/**
|
||||
* 输入rtp并解码
|
||||
* @param rtp rtp数据包
|
||||
* @param key_pos 此参数内部强制转换为false,请忽略之
|
||||
*/
|
||||
bool inputRtp(const RtpPacket::Ptr &rtp, bool key_pos = false) override;
|
||||
|
||||
CodecId getCodecId() const override{
|
||||
return _codecid;
|
||||
}
|
||||
|
||||
private:
|
||||
void onGetG711(const G711Frame::Ptr &frame);
|
||||
G711Frame::Ptr obtainFrame();
|
||||
|
||||
private:
|
||||
G711Frame::Ptr _frame;
|
||||
CodecId _codecid;
|
||||
};
|
||||
|
||||
/**
|
||||
* g711 转rtp类
|
||||
*/
|
||||
class G711RtpEncoder : public G711RtpDecoder , public RtpInfo {
|
||||
public:
|
||||
typedef std::shared_ptr<G711RtpEncoder> Ptr;
|
||||
|
||||
/**
|
||||
* @param ui32Ssrc ssrc
|
||||
* @param ui32MtuSize mtu 大小
|
||||
* @param ui32SampleRate 采样率
|
||||
* @param ui8PayloadType pt类型
|
||||
* @param ui8Interleaved rtsp interleaved 值
|
||||
*/
|
||||
G711RtpEncoder(CodecId codecid,
|
||||
uint32_t ui32Ssrc,
|
||||
uint32_t ui32MtuSize,
|
||||
uint32_t ui32SampleRate,
|
||||
uint8_t ui8PayloadType = 0,
|
||||
uint8_t ui8Interleaved = TrackAudio * 2);
|
||||
~G711RtpEncoder() {}
|
||||
|
||||
/**
|
||||
* @param frame g711数据
|
||||
*/
|
||||
void inputFrame(const Frame::Ptr &frame) override;
|
||||
private:
|
||||
void makeG711Rtp(const void *pData, unsigned int uiLen, bool bMark, uint32_t uiStamp);
|
||||
};
|
||||
|
||||
}//namespace mediakit
|
||||
|
||||
#endif //ZLMEDIAKIT_G711RTPCODEC_H
|
||||
@@ -37,7 +37,7 @@ public:
|
||||
} NalType;
|
||||
|
||||
H264Frame(){
|
||||
_codecid = CodecH264;
|
||||
_codec_id = CodecH264;
|
||||
}
|
||||
|
||||
bool keyFrame() const override {
|
||||
|
||||
@@ -61,7 +61,7 @@ public:
|
||||
} NaleType;
|
||||
|
||||
H265Frame(){
|
||||
_codecid = CodecH265;
|
||||
_codec_id = CodecH265;
|
||||
}
|
||||
|
||||
bool keyFrame() const override {
|
||||
|
||||
@@ -16,52 +16,13 @@
|
||||
|
||||
namespace mediakit{
|
||||
|
||||
/**
|
||||
* Opus帧
|
||||
*/
|
||||
class OpusFrame : public FrameImp {
|
||||
public:
|
||||
typedef std::shared_ptr<OpusFrame> Ptr;
|
||||
|
||||
OpusFrame(){
|
||||
_codecid = CodecOpus;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 不可缓存的Opus帧
|
||||
*/
|
||||
class OpusFrameNoCacheAble : public FrameFromPtr {
|
||||
public:
|
||||
typedef std::shared_ptr<OpusFrameNoCacheAble> Ptr;
|
||||
|
||||
OpusFrameNoCacheAble(char *ptr,uint32_t size,uint32_t dts, uint32_t pts = 0,int prefix_size = 0){
|
||||
_ptr = ptr;
|
||||
_size = size;
|
||||
_dts = dts;
|
||||
_prefix_size = prefix_size;
|
||||
}
|
||||
|
||||
CodecId getCodecId() const override{
|
||||
return CodecOpus;
|
||||
}
|
||||
|
||||
bool keyFrame() const override {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool configFrame() const override{
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Opus帧音频通道
|
||||
*/
|
||||
class OpusTrack : public AudioTrackImp{
|
||||
public:
|
||||
typedef std::shared_ptr<OpusTrack> Ptr;
|
||||
OpusTrack(int sample_rate, int channels, int sample_bit) : AudioTrackImp(CodecOpus,sample_rate,channels,sample_bit){}
|
||||
OpusTrack() : AudioTrackImp(CodecOpus,48000,2,16){}
|
||||
|
||||
private:
|
||||
//克隆该Track
|
||||
|
||||
Reference in New Issue
Block a user