尝试修复时间戳回环或乱序导致的问题

This commit is contained in:
xiongziliang 2019-08-02 18:06:37 +08:00
parent 6a9eb8d54b
commit f9426c2cfb
6 changed files with 165 additions and 50 deletions

View File

@ -104,41 +104,15 @@ void MP4Muxer::onTrackFrame(const Frame::Ptr &frame) {
//mp4文件时间戳需要从0开始 //mp4文件时间戳需要从0开始
auto &track_info = it->second; auto &track_info = it->second;
if(!track_info.start_dts){ int64_t dts_out, pts_out;
track_info.start_dts = frame->dts(); track_info.stamp.revise(frame->dts(),frame->pts(),dts_out,pts_out);
}
//相对时间戳
int64_t dts_inc = frame->dts() - track_info.start_dts;
//pts和dts的差值
int pts_dts_diff = frame->pts() - frame->dts();
if(pts_dts_diff > 200 || pts_dts_diff < -200){
//如果差值大于200毫秒则认为由于回环导致时间戳错乱了
pts_dts_diff = 0;
}
if(dts_inc < track_info.dts_inc){
//本次相对时间戳竟然小于上次?
if(dts_inc < 0){
//时间戳回环,保证下次相对时间戳与本次相对合理增长
track_info.start_dts = frame->dts() - track_info.dts_inc;
//本次时间戳强制等于上次时间戳+10
dts_inc = track_info.dts_inc + 10;
}else{
//时间戳变小了?,那么取上次时间戳+10
dts_inc = track_info.dts_inc + 10;
}
}
//保留上次相对时间戳
track_info.dts_inc = dts_inc;
mov_writer_write_l(_mov_writter.get(), mov_writer_write_l(_mov_writter.get(),
track_info.track_id, track_info.track_id,
frame->data() + frame->prefixSize(), frame->data() + frame->prefixSize(),
frame->size() - frame->prefixSize(), frame->size() - frame->prefixSize(),
pts_dts_diff + dts_inc, pts_out,
dts_inc, dts_out,
frame->keyFrame() ? MOV_AV_FLAG_KEYFREAME : 0, frame->keyFrame() ? MOV_AV_FLAG_KEYFREAME : 0,
with_nalu_size); with_nalu_size);
} }

View File

@ -39,6 +39,7 @@
#include "Extension/AAC.h" #include "Extension/AAC.h"
#include "Extension/H264.h" #include "Extension/H264.h"
#include "Extension/H265.h" #include "Extension/H265.h"
#include "Stamp.h"
namespace mediakit{ namespace mediakit{
@ -76,10 +77,9 @@ protected:
private: private:
struct track_info{ struct track_info{
int track_id = -1; int track_id = -1;
int64_t start_dts = 0; Stamp stamp;
int64_t dts_inc = 0;
}; };
map<CodecId,track_info> _codec_to_trackid; unordered_map<int,track_info> _codec_to_trackid;
bool _started = false; bool _started = false;
}; };

74
src/MediaFile/Stamp.cpp Normal file
View File

@ -0,0 +1,74 @@
/*
* MIT License
*
* Copyright (c) 2016-2019 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.
*/
#include "Stamp.h"
namespace mediakit {
void Stamp::revise(uint32_t dts, uint32_t pts, int64_t &dts_out, int64_t &pts_out) {
if(_first){
//记录第一次时间戳,后面好计算时间戳增量
_start_dts = dts;
_first = false;
}
//相对时间戳
dts_out = dts - _start_dts;
if(dts_out < _dts_inc){
//本次相对时间戳竟然小于上次?
if(dts_out < 0 || _dts_inc - dts_out > 0xFFFF){
//时间戳回环,保证下次相对时间戳与本次相对合理增长
_start_dts = dts - _dts_inc;
//本次时间戳强制等于上次时间戳
dts_out = _dts_inc;
}else{
//时间戳变小了?,那么取上次时间戳
dts_out = _dts_inc;
}
}
//保留这次相对时间戳,以便下次对比是否回环或乱序
_dts_inc = dts_out;
//////////////以下是播放时间戳的计算//////////////////
if(!pts){
//没有播放时间戳
pts = dts;
}
//pts和dts的差值
int pts_dts_diff = pts - dts;
if(pts_dts_diff > 200 || pts_dts_diff < -200){
//如果差值大于200毫秒则认为由于回环导致时间戳错乱了
pts_dts_diff = 0;
}
pts_out = dts_out + pts_dts_diff;
if(pts_out < 0){
//时间戳不能小于0
pts_out = 0;
}
}
}//namespace mediakit

48
src/MediaFile/Stamp.h Normal file
View File

@ -0,0 +1,48 @@
/*
* MIT License
*
* Copyright (c) 2016-2019 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.
*/
#ifndef ZLMEDIAKIT_STAMP_H
#define ZLMEDIAKIT_STAMP_H
#include <cstdint>
namespace mediakit {
class Stamp {
public:
Stamp() = default;
~Stamp() = default;
void revise(uint32_t dts, uint32_t pts, int64_t &dts_out, int64_t &pts_out);
private:
int64_t _start_dts = 0;
int64_t _dts_inc = 0;
bool _first = true;
};
}//namespace mediakit
#endif //ZLMEDIAKIT_STAMP_H

View File

@ -41,25 +41,35 @@ TsMuxer::~TsMuxer() {
void TsMuxer::addTrack(const Track::Ptr &track) { void TsMuxer::addTrack(const Track::Ptr &track) {
switch (track->getCodecId()){ switch (track->getCodecId()){
case CodecH264: case CodecH264: {
_codecid_to_stream_id[CodecH264] = mpeg_ts_add_stream(_context,PSI_STREAM_H264, nullptr,0); track_info info;
break; info.track_id = mpeg_ts_add_stream(_context, PSI_STREAM_H264, nullptr, 0);
case CodecH265: _codec_to_trackid[track->getCodecId()] = info;
_codecid_to_stream_id[CodecH265] = mpeg_ts_add_stream(_context,PSI_STREAM_H265, nullptr,0); } break;
break; case CodecH265: {
case CodecAAC: track_info info;
_codecid_to_stream_id[CodecAAC] = mpeg_ts_add_stream(_context,PSI_STREAM_AAC, nullptr,0); info.track_id = mpeg_ts_add_stream(_context, PSI_STREAM_H265, nullptr, 0);
break; _codec_to_trackid[track->getCodecId()] = info;
}break;
case CodecAAC: {
track_info info;
info.track_id = mpeg_ts_add_stream(_context, PSI_STREAM_AAC, nullptr, 0);
_codec_to_trackid[track->getCodecId()] = info;
}break;
default: default:
break; break;
} }
} }
void TsMuxer::inputFrame(const Frame::Ptr &frame) { void TsMuxer::inputFrame(const Frame::Ptr &frame) {
auto it = _codecid_to_stream_id.find(frame->getCodecId()); auto it = _codec_to_trackid.find(frame->getCodecId());
if(it == _codecid_to_stream_id.end()){ if(it == _codec_to_trackid.end()){
return; return;
} }
//mp4文件时间戳需要从0开始
auto &track_info = it->second;
int64_t dts_out, pts_out;
switch (frame->getCodecId()){ switch (frame->getCodecId()){
case CodecH265: case CodecH265:
case CodecH264: { case CodecH264: {
@ -79,16 +89,18 @@ void TsMuxer::inputFrame(const Frame::Ptr &frame) {
}); });
merged_frame = std::make_shared<BufferString>(std::move(merged)); merged_frame = std::make_shared<BufferString>(std::move(merged));
} }
_timestamp = back->dts(); track_info.stamp.revise(back->dts(),back->pts(),dts_out,pts_out);
mpeg_ts_write(_context, it->second, back->keyFrame() ? 0x0001 : 0, back->pts() * 90LL, back->dts() * 90LL, merged_frame->data(), merged_frame->size()); _timestamp = dts_out;
mpeg_ts_write(_context, track_info.track_id, back->keyFrame() ? 0x0001 : 0, pts_out * 90LL, dts_out * 90LL, merged_frame->data(), merged_frame->size());
_frameCached.clear(); _frameCached.clear();
} }
_frameCached.emplace_back(Frame::getCacheAbleFrame(frame)); _frameCached.emplace_back(Frame::getCacheAbleFrame(frame));
} }
break; break;
default: { default: {
_timestamp = frame->dts(); track_info.stamp.revise(frame->dts(),frame->pts(),dts_out,pts_out);
mpeg_ts_write(_context, it->second, frame->keyFrame() ? 0x0001 : 0, frame->pts() * 90LL, frame->dts() * 90LL, frame->data(), frame->size()); _timestamp = dts_out;
mpeg_ts_write(_context, track_info.track_id, frame->keyFrame() ? 0x0001 : 0, pts_out * 90LL, dts_out * 90LL, frame->data(), frame->size());
} }
break; break;
} }
@ -124,7 +136,7 @@ void TsMuxer::uninit() {
mpeg_ts_destroy(_context); mpeg_ts_destroy(_context);
_context = nullptr; _context = nullptr;
} }
_codecid_to_stream_id.clear(); _codec_to_trackid.clear();
} }
}//namespace mediakit }//namespace mediakit

View File

@ -32,6 +32,8 @@
#include "Extension/Track.h" #include "Extension/Track.h"
#include "Util/File.h" #include "Util/File.h"
#include "Common/MediaSink.h" #include "Common/MediaSink.h"
#include "Stamp.h"
using namespace toolkit; using namespace toolkit;
namespace mediakit { namespace mediakit {
@ -52,7 +54,12 @@ private:
void *_context = nullptr; void *_context = nullptr;
char *_tsbuf[188]; char *_tsbuf[188];
uint32_t _timestamp = 0; uint32_t _timestamp = 0;
unordered_map<int,int > _codecid_to_stream_id;
struct track_info{
int track_id = -1;
Stamp stamp;
};
unordered_map<int,track_info> _codec_to_trackid;
List<Frame::Ptr> _frameCached; List<Frame::Ptr> _frameCached;
}; };