2020-03-06 13:00:06 +08:00
|
|
|
|
/*
|
2020-04-04 20:30:09 +08:00
|
|
|
|
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
|
2020-03-06 13:00:06 +08:00
|
|
|
|
*
|
2021-01-17 18:31:50 +08:00
|
|
|
|
* This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit).
|
2020-03-06 13:00:06 +08:00
|
|
|
|
*
|
2020-04-04 20:30:09 +08:00
|
|
|
|
* 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.
|
2020-03-06 13:00:06 +08:00
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include "Decoder.h"
|
|
|
|
|
#include "PSDecoder.h"
|
|
|
|
|
#include "TSDecoder.h"
|
2020-05-17 18:00:23 +08:00
|
|
|
|
#include "Extension/H264.h"
|
|
|
|
|
#include "Extension/H265.h"
|
|
|
|
|
#include "Extension/AAC.h"
|
|
|
|
|
#include "Extension/G711.h"
|
2020-08-01 20:56:34 +08:00
|
|
|
|
#include "Extension/Opus.h"
|
2020-05-17 18:00:23 +08:00
|
|
|
|
|
2020-06-12 18:17:49 +08:00
|
|
|
|
#if defined(ENABLE_RTPPROXY) || defined(ENABLE_HLS)
|
|
|
|
|
#include "mpeg-ts-proto.h"
|
|
|
|
|
#endif
|
|
|
|
|
|
2020-03-06 13:00:06 +08:00
|
|
|
|
namespace mediakit {
|
2020-05-17 18:00:23 +08:00
|
|
|
|
static Decoder::Ptr createDecoder_l(DecoderImp::Type type) {
|
2020-03-06 13:00:06 +08:00
|
|
|
|
switch (type){
|
2020-05-17 18:00:23 +08:00
|
|
|
|
case DecoderImp::decoder_ps:
|
|
|
|
|
#ifdef ENABLE_RTPPROXY
|
|
|
|
|
return std::make_shared<PSDecoder>();
|
|
|
|
|
#else
|
|
|
|
|
WarnL << "创建ps解复用器失败,请打开ENABLE_RTPPROXY然后重新编译";
|
|
|
|
|
return nullptr;
|
|
|
|
|
#endif//ENABLE_RTPPROXY
|
|
|
|
|
|
|
|
|
|
case DecoderImp::decoder_ts:
|
|
|
|
|
#ifdef ENABLE_HLS
|
|
|
|
|
return std::make_shared<TSDecoder>();
|
|
|
|
|
#else
|
|
|
|
|
WarnL << "创建mpegts解复用器失败,请打开ENABLE_HLS然后重新编译";
|
|
|
|
|
return nullptr;
|
|
|
|
|
#endif//ENABLE_HLS
|
|
|
|
|
|
|
|
|
|
default: return nullptr;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////
|
|
|
|
|
|
2020-05-21 11:44:57 +08:00
|
|
|
|
DecoderImp::Ptr DecoderImp::createDecoder(Type type, MediaSinkInterface *sink){
|
2020-05-17 18:00:23 +08:00
|
|
|
|
auto decoder = createDecoder_l(type);
|
|
|
|
|
if(!decoder){
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
return DecoderImp::Ptr(new DecoderImp(decoder, sink));
|
|
|
|
|
}
|
|
|
|
|
|
2021-01-17 18:31:50 +08:00
|
|
|
|
size_t DecoderImp::input(const uint8_t *data, size_t bytes){
|
2020-05-17 18:00:23 +08:00
|
|
|
|
return _decoder->input(data, bytes);
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-21 11:44:57 +08:00
|
|
|
|
DecoderImp::DecoderImp(const Decoder::Ptr &decoder, MediaSinkInterface *sink){
|
2020-05-17 18:00:23 +08:00
|
|
|
|
_decoder = decoder;
|
|
|
|
|
_sink = sink;
|
2021-01-17 18:31:50 +08:00
|
|
|
|
_decoder->setOnDecode([this](int stream, int codecid, int flags, int64_t pts, int64_t dts, const void *data, size_t bytes) {
|
2020-11-29 09:38:04 +08:00
|
|
|
|
onDecode(stream, codecid, flags, pts, dts, data, bytes);
|
|
|
|
|
});
|
2021-01-17 18:31:50 +08:00
|
|
|
|
_decoder->setOnStream([this](int stream, int codecid, const void *extra, size_t bytes, int finish) {
|
2020-11-29 09:38:04 +08:00
|
|
|
|
onStream(stream, codecid, extra, bytes, finish);
|
2020-05-17 18:00:23 +08:00
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2020-06-12 18:17:49 +08:00
|
|
|
|
#if defined(ENABLE_RTPPROXY) || defined(ENABLE_HLS)
|
2020-05-17 18:00:23 +08:00
|
|
|
|
#define SWITCH_CASE(codec_id) case codec_id : return #codec_id
|
|
|
|
|
static const char *getCodecName(int codec_id) {
|
|
|
|
|
switch (codec_id) {
|
|
|
|
|
SWITCH_CASE(PSI_STREAM_MPEG1);
|
|
|
|
|
SWITCH_CASE(PSI_STREAM_MPEG2);
|
|
|
|
|
SWITCH_CASE(PSI_STREAM_AUDIO_MPEG1);
|
|
|
|
|
SWITCH_CASE(PSI_STREAM_MP3);
|
|
|
|
|
SWITCH_CASE(PSI_STREAM_AAC);
|
|
|
|
|
SWITCH_CASE(PSI_STREAM_MPEG4);
|
|
|
|
|
SWITCH_CASE(PSI_STREAM_MPEG4_AAC_LATM);
|
|
|
|
|
SWITCH_CASE(PSI_STREAM_H264);
|
|
|
|
|
SWITCH_CASE(PSI_STREAM_MPEG4_AAC);
|
|
|
|
|
SWITCH_CASE(PSI_STREAM_H265);
|
|
|
|
|
SWITCH_CASE(PSI_STREAM_AUDIO_AC3);
|
|
|
|
|
SWITCH_CASE(PSI_STREAM_AUDIO_EAC3);
|
|
|
|
|
SWITCH_CASE(PSI_STREAM_AUDIO_DTS);
|
|
|
|
|
SWITCH_CASE(PSI_STREAM_VIDEO_DIRAC);
|
|
|
|
|
SWITCH_CASE(PSI_STREAM_VIDEO_VC1);
|
|
|
|
|
SWITCH_CASE(PSI_STREAM_VIDEO_SVAC);
|
|
|
|
|
SWITCH_CASE(PSI_STREAM_AUDIO_SVAC);
|
|
|
|
|
SWITCH_CASE(PSI_STREAM_AUDIO_G711A);
|
|
|
|
|
SWITCH_CASE(PSI_STREAM_AUDIO_G711U);
|
|
|
|
|
SWITCH_CASE(PSI_STREAM_AUDIO_G722);
|
|
|
|
|
SWITCH_CASE(PSI_STREAM_AUDIO_G723);
|
|
|
|
|
SWITCH_CASE(PSI_STREAM_AUDIO_G729);
|
2020-08-01 20:56:34 +08:00
|
|
|
|
SWITCH_CASE(PSI_STREAM_AUDIO_OPUS);
|
2020-05-17 18:00:23 +08:00
|
|
|
|
default : return "unknown codec";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void FrameMerger::inputFrame(const Frame::Ptr &frame,const function<void(uint32_t dts,uint32_t pts,const Buffer::Ptr &buffer)> &cb){
|
2021-02-04 18:14:53 +08:00
|
|
|
|
bool flush = false;
|
|
|
|
|
switch (frame->getCodecId()) {
|
|
|
|
|
case CodecH264:
|
|
|
|
|
case CodecH265:{
|
|
|
|
|
//如果是新的一帧,前面的缓存需要输出
|
|
|
|
|
flush = frame->prefixSize();
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
default: break;
|
|
|
|
|
}
|
|
|
|
|
if (!_frameCached.empty() && (flush || _frameCached.back()->dts() != frame->dts())) {
|
2020-05-17 18:00:23 +08:00
|
|
|
|
Frame::Ptr back = _frameCached.back();
|
|
|
|
|
Buffer::Ptr merged_frame = back;
|
|
|
|
|
if(_frameCached.size() != 1){
|
2020-11-01 03:41:35 +08:00
|
|
|
|
BufferLikeString merged;
|
|
|
|
|
merged.reserve(back->size() + 1024);
|
2020-05-17 18:00:23 +08:00
|
|
|
|
_frameCached.for_each([&](const Frame::Ptr &frame){
|
|
|
|
|
merged.append(frame->data(),frame->size());
|
|
|
|
|
});
|
2020-11-01 03:41:35 +08:00
|
|
|
|
merged_frame = std::make_shared<BufferOffset<BufferLikeString> >(std::move(merged));
|
2020-05-17 18:00:23 +08:00
|
|
|
|
}
|
|
|
|
|
cb(back->dts(),back->pts(),merged_frame);
|
|
|
|
|
_frameCached.clear();
|
|
|
|
|
}
|
|
|
|
|
_frameCached.emplace_back(Frame::getCacheAbleFrame(frame));
|
|
|
|
|
}
|
|
|
|
|
|
2021-01-17 18:31:50 +08:00
|
|
|
|
void DecoderImp::onStream(int stream, int codecid, const void *extra, size_t bytes, int finish){
|
2020-11-29 09:38:04 +08:00
|
|
|
|
switch (codecid) {
|
|
|
|
|
case PSI_STREAM_H264: {
|
|
|
|
|
InfoL << "got video track: H264";
|
|
|
|
|
auto track = std::make_shared<H264Track>();
|
|
|
|
|
onTrack(track);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case PSI_STREAM_H265: {
|
|
|
|
|
InfoL << "got video track: H265";
|
|
|
|
|
auto track = std::make_shared<H265Track>();
|
|
|
|
|
onTrack(track);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case PSI_STREAM_AAC: {
|
|
|
|
|
InfoL<< "got audio track: AAC";
|
|
|
|
|
auto track = std::make_shared<AACTrack>();
|
|
|
|
|
onTrack(track);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case PSI_STREAM_AUDIO_G711A:
|
|
|
|
|
case PSI_STREAM_AUDIO_G711U: {
|
|
|
|
|
auto codec = codecid == PSI_STREAM_AUDIO_G711A ? CodecG711A : CodecG711U;
|
|
|
|
|
InfoL << "got audio track: G711";
|
|
|
|
|
//G711传统只支持 8000/1/16的规格,FFmpeg貌似做了扩展,但是这里不管它了
|
|
|
|
|
auto track = std::make_shared<G711Track>(codec, 8000, 1, 16);
|
|
|
|
|
onTrack(track);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case PSI_STREAM_AUDIO_OPUS: {
|
|
|
|
|
InfoL << "got audio track: opus";
|
|
|
|
|
auto track = std::make_shared<OpusTrack>();
|
|
|
|
|
onTrack(track);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
if(codecid != 0){
|
|
|
|
|
WarnL<< "unsupported codec type:" << getCodecName(codecid) << " " << (int)codecid;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (finish) {
|
|
|
|
|
_sink->addTrackCompleted();
|
|
|
|
|
InfoL << "add track finished";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-01-17 18:31:50 +08:00
|
|
|
|
void DecoderImp::onDecode(int stream,int codecid,int flags,int64_t pts,int64_t dts,const void *data,size_t bytes) {
|
2020-05-17 18:00:23 +08:00
|
|
|
|
pts /= 90;
|
|
|
|
|
dts /= 90;
|
|
|
|
|
|
|
|
|
|
switch (codecid) {
|
|
|
|
|
case PSI_STREAM_H264: {
|
2021-02-04 18:14:53 +08:00
|
|
|
|
auto frame = std::make_shared<H264FrameNoCacheAble>((char *) data, bytes, (uint32_t)dts, (uint32_t)pts, prefixSize((char *) data, bytes));
|
2020-05-17 18:00:23 +08:00
|
|
|
|
_merger.inputFrame(frame,[this](uint32_t dts, uint32_t pts, const Buffer::Ptr &buffer) {
|
2020-09-21 14:56:58 +08:00
|
|
|
|
onFrame(std::make_shared<FrameWrapper<H264FrameNoCacheAble> >(buffer, dts, pts, prefixSize(buffer->data(), buffer->size()), 0));
|
2020-05-17 18:00:23 +08:00
|
|
|
|
});
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case PSI_STREAM_H265: {
|
2021-02-04 18:14:53 +08:00
|
|
|
|
auto frame = std::make_shared<H265FrameNoCacheAble>((char *) data, bytes, (uint32_t)dts, (uint32_t)pts, prefixSize((char *) data, bytes));
|
2020-05-17 18:00:23 +08:00
|
|
|
|
_merger.inputFrame(frame,[this](uint32_t dts, uint32_t pts, const Buffer::Ptr &buffer) {
|
2020-09-21 14:56:58 +08:00
|
|
|
|
onFrame(std::make_shared<FrameWrapper<H265FrameNoCacheAble> >(buffer, dts, pts, prefixSize(buffer->data(), buffer->size()), 0));
|
2020-05-17 18:00:23 +08:00
|
|
|
|
});
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case PSI_STREAM_AAC: {
|
2020-06-29 11:55:13 +08:00
|
|
|
|
uint8_t *ptr = (uint8_t *)data;
|
|
|
|
|
if(!(bytes > 7 && ptr[0] == 0xFF && (ptr[1] & 0xF0) == 0xF0)){
|
|
|
|
|
//这不是aac
|
|
|
|
|
break;
|
|
|
|
|
}
|
2021-01-17 18:31:50 +08:00
|
|
|
|
onFrame(std::make_shared<FrameFromPtr>(CodecAAC, (char *) data, bytes, (uint32_t)dts, 0, ADTS_HEADER_LEN));
|
2020-05-17 18:00:23 +08:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case PSI_STREAM_AUDIO_G711A:
|
|
|
|
|
case PSI_STREAM_AUDIO_G711U: {
|
|
|
|
|
auto codec = codecid == PSI_STREAM_AUDIO_G711A ? CodecG711A : CodecG711U;
|
2021-01-17 18:31:50 +08:00
|
|
|
|
onFrame(std::make_shared<FrameFromPtr>(codec, (char *) data, bytes, (uint32_t)dts));
|
2020-05-17 18:00:23 +08:00
|
|
|
|
break;
|
|
|
|
|
}
|
2020-08-01 20:56:34 +08:00
|
|
|
|
|
|
|
|
|
case PSI_STREAM_AUDIO_OPUS: {
|
2021-01-17 18:31:50 +08:00
|
|
|
|
onFrame(std::make_shared<FrameFromPtr>(CodecOpus, (char *) data, bytes, (uint32_t)dts));
|
2020-08-01 20:56:34 +08:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-17 18:00:23 +08:00
|
|
|
|
default:
|
2020-12-29 11:36:06 +08:00
|
|
|
|
if (codecid != 0) {
|
|
|
|
|
if (_last_unsported_print.elapsedTime() / 1000 > 5) {
|
|
|
|
|
_last_unsported_print.resetTime();
|
|
|
|
|
WarnL << "unsupported codec type:" << getCodecName(codecid) << " " << (int) codecid;
|
|
|
|
|
}
|
2020-05-17 18:00:23 +08:00
|
|
|
|
}
|
|
|
|
|
break;
|
2020-03-06 13:00:06 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
2020-06-12 18:17:49 +08:00
|
|
|
|
#else
|
2021-01-17 18:31:50 +08:00
|
|
|
|
void DecoderImp::onDecode(int stream,int codecid,int flags,int64_t pts,int64_t dts,const void *data,size_t bytes) {}
|
|
|
|
|
void DecoderImp::onStream(int stream,int codecid,const void *extra,size_t bytes,int finish) {}
|
2020-06-12 18:17:49 +08:00
|
|
|
|
#endif
|
2020-03-06 13:00:06 +08:00
|
|
|
|
|
2020-05-17 18:00:23 +08:00
|
|
|
|
void DecoderImp::onTrack(const Track::Ptr &track) {
|
|
|
|
|
_sink->addTrack(track);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DecoderImp::onFrame(const Frame::Ptr &frame) {
|
|
|
|
|
_sink->inputFrame(frame);
|
|
|
|
|
}
|
|
|
|
|
|
2020-03-06 13:00:06 +08:00
|
|
|
|
}//namespace mediakit
|
2020-06-12 18:17:49 +08:00
|
|
|
|
|