mirror of
https://github.com/ossrs/srs.git
synced 2025-03-09 15:49:59 +00:00
support write ts file
This commit is contained in:
parent
164392f6aa
commit
7ed20cc670
5 changed files with 143 additions and 19 deletions
|
@ -585,6 +585,7 @@ public:
|
||||||
|
|
||||||
int64_t pts; // 33bits
|
int64_t pts; // 33bits
|
||||||
int64_t dts; // 33bits
|
int64_t dts; // 33bits
|
||||||
|
int64_t pcr;
|
||||||
|
|
||||||
// header size.
|
// header size.
|
||||||
int packet_header_size;
|
int packet_header_size;
|
||||||
|
@ -596,6 +597,10 @@ public:
|
||||||
int packet_data_size;
|
int packet_data_size;
|
||||||
char* packet_data;
|
char* packet_data;
|
||||||
|
|
||||||
|
// for avc.
|
||||||
|
u_int8_t nal_ref_idc;
|
||||||
|
u_int8_t nal_unit_type;
|
||||||
|
|
||||||
TSMessage();
|
TSMessage();
|
||||||
virtual ~TSMessage();
|
virtual ~TSMessage();
|
||||||
|
|
||||||
|
@ -709,12 +714,15 @@ TSMessage::TSMessage()
|
||||||
stream_type = TSStreamTypeReserved;
|
stream_type = TSStreamTypeReserved;
|
||||||
stream_id = 0;
|
stream_id = 0;
|
||||||
packet_start_code_prefix = 0;
|
packet_start_code_prefix = 0;
|
||||||
pts = dts = 0;
|
pts = dts = pcr = 0;
|
||||||
PES_packet_length = 0;
|
PES_packet_length = 0;
|
||||||
packet_header_size = 0;
|
packet_header_size = 0;
|
||||||
parsed_packet_size = 0;
|
parsed_packet_size = 0;
|
||||||
packet_data_size = 0;
|
packet_data_size = 0;
|
||||||
packet_data = NULL;
|
packet_data = NULL;
|
||||||
|
|
||||||
|
nal_ref_idc = 0;
|
||||||
|
nal_unit_type = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
TSMessage::~TSMessage()
|
TSMessage::~TSMessage()
|
||||||
|
@ -1596,6 +1604,10 @@ int TSPayload::demux(TSContext* ctx, TSPacket* pkt, u_int8_t* start, u_int8_t* l
|
||||||
}
|
}
|
||||||
if (pid && (pid->type == TSPidTypeVideo || pid->type == TSPidTypeAudio)) {
|
if (pid && (pid->type == TSPidTypeVideo || pid->type == TSPidTypeAudio)) {
|
||||||
TSMessage* msg = ctx->get_msg(pkt->header->pid);
|
TSMessage* msg = ctx->get_msg(pkt->header->pid);
|
||||||
|
|
||||||
|
if (pkt->adaption_field->pcr > 0) {
|
||||||
|
msg->pcr = pkt->adaption_field->pcr;
|
||||||
|
}
|
||||||
|
|
||||||
// flush previous PES_packet_length(0) packets.
|
// flush previous PES_packet_length(0) packets.
|
||||||
if (msg->packet_start_code_prefix == 0x01
|
if (msg->packet_start_code_prefix == 0x01
|
||||||
|
@ -2135,6 +2147,10 @@ int consume(TSMessage* msg, AacMuxer* aac_muxer)
|
||||||
int8_t nal_unit_type = *pp++;
|
int8_t nal_unit_type = *pp++;
|
||||||
int8_t nal_ref_idc = (nal_unit_type >> 5) & 0x03;
|
int8_t nal_ref_idc = (nal_unit_type >> 5) & 0x03;
|
||||||
nal_unit_type &= 0x1f;
|
nal_unit_type &= 0x1f;
|
||||||
|
|
||||||
|
msg->nal_ref_idc = nal_ref_idc;
|
||||||
|
msg->nal_unit_type = nal_unit_type;
|
||||||
|
|
||||||
if (nal_ref_idc != 0) {
|
if (nal_ref_idc != 0) {
|
||||||
trace("ts+h264 got an SPS or PPS.");
|
trace("ts+h264 got an SPS or PPS.");
|
||||||
}
|
}
|
||||||
|
@ -2235,6 +2251,18 @@ int main(int argc, char** argv)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int64_t pts = msg->pts;
|
||||||
|
int64_t dts = (msg->dts == 0)? msg->pts : msg->dts;
|
||||||
|
int64_t pcr = msg->pcr;
|
||||||
|
static int64_t last_pcr_dts = 0;
|
||||||
|
trace("demuxer+report id=%d, type=%s, size=%d, dts=%d, pts=%d, cts=%d, pcr=%d, dts-pcr=%d, ref=%d, unit=%d, dts(diff-pcr)=%d",
|
||||||
|
ctx.ts_packet_count, (msg->type == TSPidTypeVideo)? "video":"audio",
|
||||||
|
msg->parsed_packet_size, dts, pts, pts - dts, pcr, pcr? dts - pcr : 0,
|
||||||
|
msg->nal_ref_idc, msg->nal_unit_type, pcr? dts - last_pcr_dts: 0);
|
||||||
|
if (pcr > 0) {
|
||||||
|
last_pcr_dts = dts;
|
||||||
|
}
|
||||||
|
|
||||||
srs_freep(msg);
|
srs_freep(msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -115,6 +115,10 @@ SrsCodec::SrsCodec()
|
||||||
avc_extra_data = NULL;
|
avc_extra_data = NULL;
|
||||||
aac_extra_size = 0;
|
aac_extra_size = 0;
|
||||||
aac_extra_data = NULL;
|
aac_extra_data = NULL;
|
||||||
|
sequenceParameterSetLength = 0;
|
||||||
|
sequenceParameterSetNALUnit = NULL;
|
||||||
|
pictureParameterSetLength = 0;
|
||||||
|
pictureParameterSetNALUnit = NULL;
|
||||||
|
|
||||||
stream = new SrsStream();
|
stream = new SrsStream();
|
||||||
}
|
}
|
||||||
|
@ -125,6 +129,8 @@ SrsCodec::~SrsCodec()
|
||||||
srs_freepa(aac_extra_data);
|
srs_freepa(aac_extra_data);
|
||||||
|
|
||||||
srs_freep(stream);
|
srs_freep(stream);
|
||||||
|
srs_freepa(sequenceParameterSetNALUnit);
|
||||||
|
srs_freepa(pictureParameterSetNALUnit);
|
||||||
}
|
}
|
||||||
|
|
||||||
int SrsCodec::audio_aac_demux(int8_t* data, int size, SrsCodecSample* sample)
|
int SrsCodec::audio_aac_demux(int8_t* data, int size, SrsCodecSample* sample)
|
||||||
|
@ -315,16 +321,67 @@ int SrsCodec::video_avc_demux(int8_t* data, int size, SrsCodecSample* sample)
|
||||||
int8_t lengthSizeMinusOne = stream->read_1bytes();
|
int8_t lengthSizeMinusOne = stream->read_1bytes();
|
||||||
lengthSizeMinusOne &= 0x03;
|
lengthSizeMinusOne &= 0x03;
|
||||||
NAL_unit_length = lengthSizeMinusOne;
|
NAL_unit_length = lengthSizeMinusOne;
|
||||||
/**
|
|
||||||
* skip the following:
|
// 1 sps
|
||||||
* numOfSequenceParameterSets
|
if (!stream->require(1)) {
|
||||||
* donot parse the following:
|
ret = ERROR_HLS_DECODE_ERROR;
|
||||||
* sequenceParameterSetLength
|
srs_error("hls decode video avc sequenc header sps failed. ret=%d", ret);
|
||||||
* sequenceParameterSetNALUnit
|
return ret;
|
||||||
* numOfPictureParameterSets
|
}
|
||||||
* pictureParameterSetLength
|
int8_t numOfSequenceParameterSets = stream->read_1bytes();
|
||||||
* pictureParameterSetNALUnit
|
numOfSequenceParameterSets &= 0x1f;
|
||||||
*/
|
if (numOfSequenceParameterSets != 1) {
|
||||||
|
ret = ERROR_HLS_DECODE_ERROR;
|
||||||
|
srs_error("hls decode video avc sequenc header sps failed. ret=%d", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
if (!stream->require(2)) {
|
||||||
|
ret = ERROR_HLS_DECODE_ERROR;
|
||||||
|
srs_error("hls decode video avc sequenc header sps size failed. ret=%d", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
sequenceParameterSetLength = stream->read_2bytes();
|
||||||
|
if (!stream->require(sequenceParameterSetLength)) {
|
||||||
|
ret = ERROR_HLS_DECODE_ERROR;
|
||||||
|
srs_error("hls decode video avc sequenc header sps data failed. ret=%d", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
if (sequenceParameterSetLength > 0) {
|
||||||
|
srs_freepa(sequenceParameterSetNALUnit);
|
||||||
|
sequenceParameterSetNALUnit = new char[sequenceParameterSetLength];
|
||||||
|
memcpy(sequenceParameterSetNALUnit, stream->current(), sequenceParameterSetLength);
|
||||||
|
stream->skip(sequenceParameterSetLength);
|
||||||
|
}
|
||||||
|
// 1 pps
|
||||||
|
if (!stream->require(1)) {
|
||||||
|
ret = ERROR_HLS_DECODE_ERROR;
|
||||||
|
srs_error("hls decode video avc sequenc header pps failed. ret=%d", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
int8_t numOfPictureParameterSets = stream->read_1bytes();
|
||||||
|
numOfPictureParameterSets &= 0x1f;
|
||||||
|
if (numOfPictureParameterSets != 1) {
|
||||||
|
ret = ERROR_HLS_DECODE_ERROR;
|
||||||
|
srs_error("hls decode video avc sequenc header pps failed. ret=%d", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
if (!stream->require(2)) {
|
||||||
|
ret = ERROR_HLS_DECODE_ERROR;
|
||||||
|
srs_error("hls decode video avc sequenc header pps size failed. ret=%d", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
pictureParameterSetLength = stream->read_2bytes();
|
||||||
|
if (!stream->require(pictureParameterSetLength)) {
|
||||||
|
ret = ERROR_HLS_DECODE_ERROR;
|
||||||
|
srs_error("hls decode video avc sequenc header pps data failed. ret=%d", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
if (pictureParameterSetLength > 0) {
|
||||||
|
srs_freepa(pictureParameterSetNALUnit);
|
||||||
|
pictureParameterSetNALUnit = new char[pictureParameterSetLength];
|
||||||
|
memcpy(pictureParameterSetNALUnit, stream->current(), pictureParameterSetLength);
|
||||||
|
stream->skip(pictureParameterSetLength);
|
||||||
|
}
|
||||||
} else if (avc_packet_type == SrsCodecVideoAVCTypeNALU){
|
} else if (avc_packet_type == SrsCodecVideoAVCTypeNALU){
|
||||||
// ensure the sequence header demuxed
|
// ensure the sequence header demuxed
|
||||||
if (avc_extra_size <= 0 || !avc_extra_data) {
|
if (avc_extra_size <= 0 || !avc_extra_data) {
|
||||||
|
|
|
@ -250,6 +250,10 @@ public:
|
||||||
int duration;
|
int duration;
|
||||||
// lengthSizeMinusOne, H.264-AVC-ISO_IEC_14496-15.pdf, page 16
|
// lengthSizeMinusOne, H.264-AVC-ISO_IEC_14496-15.pdf, page 16
|
||||||
int8_t NAL_unit_length;
|
int8_t NAL_unit_length;
|
||||||
|
u_int16_t sequenceParameterSetLength;
|
||||||
|
char* sequenceParameterSetNALUnit;
|
||||||
|
u_int16_t pictureParameterSetLength;
|
||||||
|
char* pictureParameterSetNALUnit;
|
||||||
/**
|
/**
|
||||||
* audio specified
|
* audio specified
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -512,8 +512,13 @@ SrsTSMuxer::SrsTSMuxer()
|
||||||
{
|
{
|
||||||
fd = -1;
|
fd = -1;
|
||||||
|
|
||||||
|
// ffmpeg set the start time to the delay time.
|
||||||
|
base_dts = SRS_HLS_DELAY;
|
||||||
|
|
||||||
audio_buffer = new SrsCodecBuffer();
|
audio_buffer = new SrsCodecBuffer();
|
||||||
video_buffer = new SrsCodecBuffer();
|
video_buffer = new SrsCodecBuffer();
|
||||||
|
|
||||||
|
got_iframe = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsTSMuxer::~SrsTSMuxer()
|
SrsTSMuxer::~SrsTSMuxer()
|
||||||
|
@ -555,7 +560,7 @@ int SrsTSMuxer::write_audio(u_int32_t time, SrsCodec* codec, SrsCodecSample* sam
|
||||||
{
|
{
|
||||||
int ret = ERROR_SUCCESS;
|
int ret = ERROR_SUCCESS;
|
||||||
|
|
||||||
audio_frame.dts = audio_frame.pts = time * 90;
|
audio_frame.dts = audio_frame.pts = base_dts + time * 90;
|
||||||
audio_frame.pid = TS_AUDIO_PID;
|
audio_frame.pid = TS_AUDIO_PID;
|
||||||
audio_frame.sid = TS_AUDIO_AAC;
|
audio_frame.sid = TS_AUDIO_AAC;
|
||||||
|
|
||||||
|
@ -626,12 +631,19 @@ int SrsTSMuxer::write_video(u_int32_t time, SrsCodec* codec, SrsCodecSample* sam
|
||||||
{
|
{
|
||||||
int ret = ERROR_SUCCESS;
|
int ret = ERROR_SUCCESS;
|
||||||
|
|
||||||
video_frame.dts = time * 90;
|
video_frame.dts = base_dts + time * 90;
|
||||||
video_frame.pts = video_frame.dts + sample->cts * 90;
|
video_frame.pts = video_frame.dts + sample->cts * 90;
|
||||||
video_frame.pid = TS_VIDEO_PID;
|
video_frame.pid = TS_VIDEO_PID;
|
||||||
video_frame.sid = TS_VIDEO_AVC;
|
video_frame.sid = TS_VIDEO_AVC;
|
||||||
video_frame.key = sample->frame_type == SrsCodecVideoAVCFrameKeyFrame;
|
video_frame.key = sample->frame_type == SrsCodecVideoAVCFrameKeyFrame;
|
||||||
|
|
||||||
|
if (video_frame.key) {
|
||||||
|
got_iframe = true;
|
||||||
|
}
|
||||||
|
if (!got_iframe) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static u_int8_t aud_nal[] = { 0x00, 0x00, 0x00, 0x01, 0x09, 0xf0 };
|
static u_int8_t aud_nal[] = { 0x00, 0x00, 0x00, 0x01, 0x09, 0xf0 };
|
||||||
video_buffer->append(aud_nal, sizeof(aud_nal));
|
video_buffer->append(aud_nal, sizeof(aud_nal));
|
||||||
|
|
||||||
|
@ -646,12 +658,33 @@ int SrsTSMuxer::write_video(u_int32_t time, SrsCodec* codec, SrsCodecSample* sam
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (false && video_frame.key && !sps_pps_sent) {
|
// 5bits, 7.3.1 NAL unit syntax,
|
||||||
// sample start prefix
|
// H.264-AVC-ISO_IEC_14496-10.pdf, page 44.
|
||||||
video_buffer->append(aud_nal, 4);
|
u_int8_t nal_unit_type;
|
||||||
// sps and pps
|
nal_unit_type = *buf->bytes;
|
||||||
// TODO: do in right way.
|
nal_unit_type &= 0x1f;
|
||||||
video_buffer->append(codec->avc_extra_data, codec->avc_extra_size);
|
|
||||||
|
// Table 7-1 – NAL unit type codes, page 61
|
||||||
|
// 1: Coded slice
|
||||||
|
if (nal_unit_type == 1) {
|
||||||
|
sps_pps_sent = false;
|
||||||
|
}
|
||||||
|
// 5: Coded slice of an IDR picture
|
||||||
|
if (nal_unit_type == 5 && !sps_pps_sent) {
|
||||||
|
// ngx_rtmp_hls_append_sps_pps
|
||||||
|
if (codec->sequenceParameterSetLength > 0) {
|
||||||
|
// AnnexB prefix
|
||||||
|
video_buffer->append(aud_nal, 4);
|
||||||
|
// sps
|
||||||
|
video_buffer->append(codec->sequenceParameterSetNALUnit, codec->sequenceParameterSetLength);
|
||||||
|
}
|
||||||
|
if (codec->pictureParameterSetLength > 0) {
|
||||||
|
// AnnexB prefix
|
||||||
|
video_buffer->append(aud_nal, 4);
|
||||||
|
// pps
|
||||||
|
video_buffer->append(codec->pictureParameterSetNALUnit, codec->pictureParameterSetLength);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// sample start prefix, '00 00 00 01' or '00 00 01'
|
// sample start prefix, '00 00 00 01' or '00 00 01'
|
||||||
|
|
|
@ -81,6 +81,8 @@ private:
|
||||||
int fd;
|
int fd;
|
||||||
std::string path;
|
std::string path;
|
||||||
private:
|
private:
|
||||||
|
bool got_iframe;
|
||||||
|
int64_t base_dts;
|
||||||
mpegts_frame audio_frame;
|
mpegts_frame audio_frame;
|
||||||
SrsCodecBuffer* audio_buffer;
|
SrsCodecBuffer* audio_buffer;
|
||||||
mpegts_frame video_frame;
|
mpegts_frame video_frame;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue