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

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开始
auto &track_info = it->second;
if(!track_info.start_dts){
track_info.start_dts = frame->dts();
}
//相对时间戳
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;
int64_t dts_out, pts_out;
track_info.stamp.revise(frame->dts(),frame->pts(),dts_out,pts_out);
mov_writer_write_l(_mov_writter.get(),
track_info.track_id,
frame->data() + frame->prefixSize(),
frame->size() - frame->prefixSize(),
pts_dts_diff + dts_inc,
dts_inc,
pts_out,
dts_out,
frame->keyFrame() ? MOV_AV_FLAG_KEYFREAME : 0,
with_nalu_size);
}

View File

@ -39,6 +39,7 @@
#include "Extension/AAC.h"
#include "Extension/H264.h"
#include "Extension/H265.h"
#include "Stamp.h"
namespace mediakit{
@ -76,10 +77,9 @@ protected:
private:
struct track_info{
int track_id = -1;
int64_t start_dts = 0;
int64_t dts_inc = 0;
Stamp stamp;
};
map<CodecId,track_info> _codec_to_trackid;
unordered_map<int,track_info> _codec_to_trackid;
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) {
switch (track->getCodecId()){
case CodecH264:
_codecid_to_stream_id[CodecH264] = mpeg_ts_add_stream(_context,PSI_STREAM_H264, nullptr,0);
break;
case CodecH265:
_codecid_to_stream_id[CodecH265] = mpeg_ts_add_stream(_context,PSI_STREAM_H265, nullptr,0);
break;
case CodecAAC:
_codecid_to_stream_id[CodecAAC] = mpeg_ts_add_stream(_context,PSI_STREAM_AAC, nullptr,0);
break;
case CodecH264: {
track_info info;
info.track_id = mpeg_ts_add_stream(_context, PSI_STREAM_H264, nullptr, 0);
_codec_to_trackid[track->getCodecId()] = info;
} break;
case CodecH265: {
track_info info;
info.track_id = mpeg_ts_add_stream(_context, PSI_STREAM_H265, nullptr, 0);
_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:
break;
}
}
void TsMuxer::inputFrame(const Frame::Ptr &frame) {
auto it = _codecid_to_stream_id.find(frame->getCodecId());
if(it == _codecid_to_stream_id.end()){
auto it = _codec_to_trackid.find(frame->getCodecId());
if(it == _codec_to_trackid.end()){
return;
}
//mp4文件时间戳需要从0开始
auto &track_info = it->second;
int64_t dts_out, pts_out;
switch (frame->getCodecId()){
case CodecH265:
case CodecH264: {
@ -79,16 +89,18 @@ void TsMuxer::inputFrame(const Frame::Ptr &frame) {
});
merged_frame = std::make_shared<BufferString>(std::move(merged));
}
_timestamp = back->dts();
mpeg_ts_write(_context, it->second, back->keyFrame() ? 0x0001 : 0, back->pts() * 90LL, back->dts() * 90LL, merged_frame->data(), merged_frame->size());
track_info.stamp.revise(back->dts(),back->pts(),dts_out,pts_out);
_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.emplace_back(Frame::getCacheAbleFrame(frame));
}
break;
default: {
_timestamp = frame->dts();
mpeg_ts_write(_context, it->second, frame->keyFrame() ? 0x0001 : 0, frame->pts() * 90LL, frame->dts() * 90LL, frame->data(), frame->size());
track_info.stamp.revise(frame->dts(),frame->pts(),dts_out,pts_out);
_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;
}
@ -124,7 +136,7 @@ void TsMuxer::uninit() {
mpeg_ts_destroy(_context);
_context = nullptr;
}
_codecid_to_stream_id.clear();
_codec_to_trackid.clear();
}
}//namespace mediakit

View File

@ -32,6 +32,8 @@
#include "Extension/Track.h"
#include "Util/File.h"
#include "Common/MediaSink.h"
#include "Stamp.h"
using namespace toolkit;
namespace mediakit {
@ -52,7 +54,12 @@ private:
void *_context = nullptr;
char *_tsbuf[188];
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;
};