1
0
Fork 0
mirror of https://github.com/ossrs/srs.git synced 2025-03-09 15:49:59 +00:00

For #299, write fMP4 for DASH.

This commit is contained in:
winlin 2017-06-04 15:10:35 +08:00
parent baed1cc043
commit 0e9e1792fe
12 changed files with 834 additions and 381 deletions

View file

@ -6013,7 +6013,7 @@ bool SrsConfig::get_dash_enabled(string vhost)
int SrsConfig::get_dash_fragment(string vhost)
{
static int DEFAULT = 10 * 1000;
static int DEFAULT = 3 * 1000;
SrsConfDirective* conf = get_dash(vhost);
if (!conf) {

View file

@ -40,10 +40,12 @@ using namespace std;
SrsInitMp4::SrsInitMp4()
{
fw = new SrsFileWriter();
init = new SrsMp4M2tsInitEncoder();
}
SrsInitMp4::~SrsInitMp4()
{
srs_freep(init);
srs_freep(fw);
}
@ -57,228 +59,11 @@ int SrsInitMp4::write(SrsFormat* format, bool video, int tid)
return ret;
}
// Write ftyp box.
SrsMp4FileTypeBox* ftyp = new SrsMp4FileTypeBox();
SrsAutoFree(SrsMp4FileTypeBox, ftyp);
if (true) {
ftyp->major_brand = SrsMp4BoxBrandISO5;
ftyp->minor_version = 0;
ftyp->set_compatible_brands(SrsMp4BoxBrandISOM, SrsMp4BoxBrandISO5, SrsMp4BoxBrandDASH, SrsMp4BoxBrandMP42);
}
// Write moov.
SrsMp4MovieBox* moov = new SrsMp4MovieBox();
SrsAutoFree(SrsMp4MovieBox, moov);
if (true) {
SrsMp4MovieHeaderBox* mvhd = new SrsMp4MovieHeaderBox();
moov->set_mvhd(mvhd);
mvhd->timescale = 1000; // Use tbn ms.
mvhd->duration_in_tbn = 0;
mvhd->next_track_ID = tid;
if (video) {
SrsMp4TrackBox* trak = new SrsMp4TrackBox();
moov->add_trak(trak);
SrsMp4TrackHeaderBox* tkhd = new SrsMp4TrackHeaderBox();
trak->set_tkhd(tkhd);
tkhd->track_ID = mvhd->next_track_ID++;
tkhd->duration = 0;
tkhd->width = (format->vcodec->width << 16);
tkhd->height = (format->vcodec->height << 16);
SrsMp4MediaBox* mdia = new SrsMp4MediaBox();
trak->set_mdia(mdia);
SrsMp4MediaHeaderBox* mdhd = new SrsMp4MediaHeaderBox();
mdia->set_mdhd(mdhd);
mdhd->timescale = 1000;
mdhd->duration = 0;
mdhd->set_language0('u');
mdhd->set_language1('n');
mdhd->set_language2('d');
SrsMp4HandlerReferenceBox* hdlr = new SrsMp4HandlerReferenceBox();
mdia->set_hdlr(hdlr);
hdlr->handler_type = SrsMp4HandlerTypeVIDE;
hdlr->name = "VideoHandler";
SrsMp4MediaInformationBox* minf = new SrsMp4MediaInformationBox();
mdia->set_minf(minf);
SrsMp4VideoMeidaHeaderBox* vmhd = new SrsMp4VideoMeidaHeaderBox();
minf->set_vmhd(vmhd);
SrsMp4DataInformationBox* dinf = new SrsMp4DataInformationBox();
minf->set_dinf(dinf);
SrsMp4DataReferenceBox* dref = new SrsMp4DataReferenceBox();
dinf->set_dref(dref);
SrsMp4DataEntryBox* url = new SrsMp4DataEntryUrlBox();
dref->append(url);
SrsMp4SampleTableBox* stbl = new SrsMp4SampleTableBox();
minf->set_stbl(stbl);
SrsMp4SampleDescriptionBox* stsd = new SrsMp4SampleDescriptionBox();
stbl->set_stsd(stsd);
SrsMp4VisualSampleEntry* avc1 = new SrsMp4VisualSampleEntry();
stsd->append(avc1);
avc1->width = format->vcodec->width;
avc1->height = format->vcodec->height;
SrsMp4AvccBox* avcC = new SrsMp4AvccBox();
avc1->set_avcC(avcC);
avcC->avc_config = format->vcodec->avc_extra_data;
SrsMp4DecodingTime2SampleBox* stts = new SrsMp4DecodingTime2SampleBox();
stbl->set_stts(stts);
SrsMp4Sample2ChunkBox* stsc = new SrsMp4Sample2ChunkBox();
stbl->set_stsc(stsc);
SrsMp4SampleSizeBox* stsz = new SrsMp4SampleSizeBox();
stbl->set_stsz(stsz);
SrsMp4ChunkOffsetBox* stco = new SrsMp4ChunkOffsetBox();
stbl->set_stco(stco);
SrsMp4MovieExtendsBox* mvex = new SrsMp4MovieExtendsBox();
moov->set_mvex(mvex);
SrsMp4TrackExtendsBox* trex = new SrsMp4TrackExtendsBox();
mvex->set_trex(trex);
trex->track_ID = tid;
trex->default_sample_description_index = 1;
} else {
SrsMp4TrackBox* trak = new SrsMp4TrackBox();
moov->add_trak(trak);
SrsMp4TrackHeaderBox* tkhd = new SrsMp4TrackHeaderBox();
tkhd->volume = 0x0100;
trak->set_tkhd(tkhd);
tkhd->track_ID = mvhd->next_track_ID++;
tkhd->duration = 0;
SrsMp4MediaBox* mdia = new SrsMp4MediaBox();
trak->set_mdia(mdia);
SrsMp4MediaHeaderBox* mdhd = new SrsMp4MediaHeaderBox();
mdia->set_mdhd(mdhd);
mdhd->timescale = 1000;
mdhd->duration = 0;
mdhd->set_language0('u');
mdhd->set_language1('n');
mdhd->set_language2('d');
SrsMp4HandlerReferenceBox* hdlr = new SrsMp4HandlerReferenceBox();
mdia->set_hdlr(hdlr);
hdlr->handler_type = SrsMp4HandlerTypeSOUN;
hdlr->name = "SoundHandler";
SrsMp4MediaInformationBox* minf = new SrsMp4MediaInformationBox();
mdia->set_minf(minf);
SrsMp4SoundMeidaHeaderBox* smhd = new SrsMp4SoundMeidaHeaderBox();
minf->set_smhd(smhd);
SrsMp4DataInformationBox* dinf = new SrsMp4DataInformationBox();
minf->set_dinf(dinf);
SrsMp4DataReferenceBox* dref = new SrsMp4DataReferenceBox();
dinf->set_dref(dref);
SrsMp4DataEntryBox* url = new SrsMp4DataEntryUrlBox();
dref->append(url);
SrsMp4SampleTableBox* stbl = new SrsMp4SampleTableBox();
minf->set_stbl(stbl);
SrsMp4SampleDescriptionBox* stsd = new SrsMp4SampleDescriptionBox();
stbl->set_stsd(stsd);
SrsMp4AudioSampleEntry* mp4a = new SrsMp4AudioSampleEntry();
mp4a->samplerate = uint32_t(srs_flv_srates[format->acodec->sound_rate]) << 16;
if (format->acodec->sound_size == SrsAudioSampleBits16bit) {
mp4a->samplesize = 16;
} else {
mp4a->samplesize = 8;
}
if (format->acodec->sound_type == SrsAudioChannelsStereo) {
mp4a->channelcount = 2;
} else {
mp4a->channelcount = 1;
}
stsd->append(mp4a);
SrsMp4EsdsBox* esds = new SrsMp4EsdsBox();
mp4a->set_esds(esds);
SrsMp4ES_Descriptor* es = esds->es;
es->ES_ID = 0x02;
SrsMp4DecoderConfigDescriptor& desc = es->decConfigDescr;
desc.objectTypeIndication = SrsMp4ObjectTypeAac;
desc.streamType = SrsMp4StreamTypeAudioStream;
srs_freep(desc.decSpecificInfo);
SrsMp4DecoderSpecificInfo* asc = new SrsMp4DecoderSpecificInfo();
desc.decSpecificInfo = asc;
asc->asc = format->acodec->aac_extra_data;
SrsMp4DecodingTime2SampleBox* stts = new SrsMp4DecodingTime2SampleBox();
stbl->set_stts(stts);
SrsMp4Sample2ChunkBox* stsc = new SrsMp4Sample2ChunkBox();
stbl->set_stsc(stsc);
SrsMp4SampleSizeBox* stsz = new SrsMp4SampleSizeBox();
stbl->set_stsz(stsz);
SrsMp4ChunkOffsetBox* stco = new SrsMp4ChunkOffsetBox();
stbl->set_stco(stco);
SrsMp4MovieExtendsBox* mvex = new SrsMp4MovieExtendsBox();
moov->set_mvex(mvex);
SrsMp4TrackExtendsBox* trex = new SrsMp4TrackExtendsBox();
mvex->set_trex(trex);
trex->track_ID = tid;
trex->default_sample_description_index = 1;
}
}
int nb_data = ftyp->nb_bytes() + moov->nb_bytes();
uint8_t* data = new uint8_t[nb_data];
SrsAutoFreeA(uint8_t, data);
SrsBuffer* buffer = new SrsBuffer();
SrsAutoFree(SrsBuffer, buffer);
if ((ret = buffer->initialize((char*)data, nb_data)) != ERROR_SUCCESS) {
if ((ret = init->initialize(fw)) != ERROR_SUCCESS) {
return ret;
}
if ((ret = ftyp->encode(buffer)) != ERROR_SUCCESS) {
return ret;
}
if ((ret = moov->encode(buffer)) != ERROR_SUCCESS) {
return ret;
}
if ((ret = fw->write(data, nb_data, NULL)) != ERROR_SUCCESS) {
if ((ret = init->write(format, video, tid)) != ERROR_SUCCESS) {
return ret;
}
@ -288,21 +73,24 @@ int SrsInitMp4::write(SrsFormat* format, bool video, int tid)
SrsFragmentedMp4::SrsFragmentedMp4()
{
fw = new SrsFileWriter();
enc = new SrsMp4M2tsSegmentEncoder();
}
SrsFragmentedMp4::~SrsFragmentedMp4()
{
srs_freep(enc);
srs_freep(fw);
}
int SrsFragmentedMp4::initialize(SrsRequest* r, bool video, SrsMpdWriter* mpd)
int SrsFragmentedMp4::initialize(SrsRequest* r, bool video, SrsMpdWriter* mpd, uint32_t tid)
{
int ret = ERROR_SUCCESS;
string file_home;
string file_name;
if ((ret = mpd->get_fragment(video, file_home, file_name)) != ERROR_SUCCESS) {
int64_t sequence_number;
uint64_t basetime;
if ((ret = mpd->get_fragment(video, file_home, file_name, sequence_number, basetime)) != ERROR_SUCCESS) {
return ret;
}
@ -319,6 +107,10 @@ int SrsFragmentedMp4::initialize(SrsRequest* r, bool video, SrsMpdWriter* mpd)
return ret;
}
if ((ret = enc->initialize(fw, (uint32_t)sequence_number, basetime, tid)) != ERROR_SUCCESS) {
return ret;
}
return ret;
}
@ -326,15 +118,40 @@ int SrsFragmentedMp4::write(SrsSharedPtrMessage* shared_msg, SrsFormat* format)
{
int ret = ERROR_SUCCESS;
if (shared_msg->is_audio()) {
uint8_t* sample = (uint8_t*)format->raw;
uint32_t nb_sample = (uint32_t)format->nb_raw;
uint32_t dts = (uint32_t)shared_msg->timestamp;
ret = enc->write_sample(SrsMp4HandlerTypeSOUN, 0x00, dts, dts, sample, nb_sample);
} else if (shared_msg->is_video()) {
SrsVideoAvcFrameType frame_type = format->video->frame_type;
uint32_t cts = (uint32_t)format->video->cts;
uint32_t dts = (uint32_t)shared_msg->timestamp;
uint32_t pts = dts + cts;
uint8_t* sample = (uint8_t*)format->raw;
uint32_t nb_sample = (uint32_t)format->nb_raw;
ret = enc->write_sample(SrsMp4HandlerTypeVIDE, frame_type, dts, pts, sample, nb_sample);
} else {
return ret;
}
append(shared_msg->timestamp);
return ret;
}
int SrsFragmentedMp4::reap()
int SrsFragmentedMp4::reap(uint64_t& dts)
{
int ret = ERROR_SUCCESS;
if ((ret = enc->flush(dts)) != ERROR_SUCCESS) {
srs_error("DASH: Flush encoder failed, ret=%d", ret);
return ret;
}
srs_freep(fw);
if ((ret = rename()) != ERROR_SUCCESS) {
@ -369,6 +186,8 @@ int SrsMpdWriter::initialize(SrsRequest* r)
string mpd_path = srs_path_build_stream(mpd_file, req->vhost, req->app, req->stream);
fragment_home = srs_path_dirname(mpd_path) + "/" + req->stream;
srs_trace("DASH: Config fragment=%d, period=%d", fragment, update_period);
return ret;
}
@ -451,17 +270,19 @@ int SrsMpdWriter::write(SrsFormat* format)
return ret;
}
int SrsMpdWriter::get_fragment(bool video, std::string& home, std::string& file_name)
int SrsMpdWriter::get_fragment(bool video, std::string& home, std::string& file_name, int64_t& sn, uint64_t& basetime)
{
int ret = ERROR_SUCCESS;
home = fragment_home;
int64_t sequence_number = srs_update_system_time_ms() / fragment;
sn = srs_update_system_time_ms() / fragment;
basetime = sn * fragment;
if (video) {
file_name = "video-" + srs_int2str(sequence_number) + ".m4s";
file_name = "video-" + srs_int2str(sn) + ".m4s";
} else {
file_name = "audio-" + srs_int2str(sequence_number) + ".m4s";
file_name = "audio-" + srs_int2str(sn) + ".m4s";
}
return ret;
@ -476,6 +297,7 @@ SrsDashController::SrsDashController()
vcurrent = acurrent = NULL;
vfragments = new SrsFragmentWindow();
afragments = new SrsFragmentWindow();
audio_dts = video_dts = 0;
}
SrsDashController::~SrsDashController()
@ -503,14 +325,14 @@ int SrsDashController::initialize(SrsRequest* r)
srs_freep(vcurrent);
vcurrent = new SrsFragmentedMp4();
if ((ret = vcurrent->initialize(req, true, mpd)) != ERROR_SUCCESS) {
if ((ret = vcurrent->initialize(req, true, mpd, video_tack_id)) != ERROR_SUCCESS) {
srs_error("DASH: Initialize the video fragment failed, ret=%d", ret);
return ret;
}
srs_freep(acurrent);
acurrent = new SrsFragmentedMp4();
if ((ret = acurrent->initialize(req, false, mpd)) != ERROR_SUCCESS) {
if ((ret = acurrent->initialize(req, false, mpd, audio_track_id)) != ERROR_SUCCESS) {
srs_error("DASH: Initialize the audio fragment failed, ret=%d", ret);
return ret;
}
@ -527,14 +349,14 @@ int SrsDashController::on_audio(SrsSharedPtrMessage* shared_audio, SrsFormat* fo
}
if (acurrent->duration() >= fragment) {
if ((ret = acurrent->reap()) != ERROR_SUCCESS) {
if ((ret = acurrent->reap(audio_dts)) != ERROR_SUCCESS) {
return ret;
}
afragments->append(acurrent);
acurrent = new SrsFragmentedMp4();
if ((ret = acurrent->initialize(req, false, mpd)) != ERROR_SUCCESS) {
if ((ret = acurrent->initialize(req, false, mpd, audio_track_id)) != ERROR_SUCCESS) {
srs_error("DASH: Initialize the audio fragment failed, ret=%d", ret);
return ret;
}
@ -564,14 +386,14 @@ int SrsDashController::on_video(SrsSharedPtrMessage* shared_video, SrsFormat* fo
bool reopen = format->video->frame_type == SrsVideoAvcFrameTypeKeyFrame
&& vcurrent->duration() >= fragment;
if (reopen) {
if ((ret = vcurrent->reap()) != ERROR_SUCCESS) {
if ((ret = vcurrent->reap(video_dts)) != ERROR_SUCCESS) {
return ret;
}
vfragments->append(vcurrent);
vcurrent = new SrsFragmentedMp4();
if ((ret = vcurrent->initialize(req, true, mpd)) != ERROR_SUCCESS) {
if ((ret = vcurrent->initialize(req, true, mpd, video_tack_id)) != ERROR_SUCCESS) {
srs_error("DASH: Initialize the video fragment failed, ret=%d", ret);
return ret;
}
@ -610,8 +432,8 @@ int SrsDashController::refresh_init_mp4(SrsSharedPtrMessage* msg, SrsFormat* for
{
int ret = ERROR_SUCCESS;
if (msg->size <= 0 || (msg->is_video() && format->vcodec->is_avc_codec_ok())
|| (msg->is_audio() && format->acodec->is_aac_codec_ok())) {
if (msg->size <= 0 || (msg->is_video() && !format->vcodec->is_avc_codec_ok())
|| (msg->is_audio() && !format->acodec->is_aac_codec_ok())) {
srs_warn("DASH: Ignore empty sequence header.");
return ret;
}

View file

@ -37,6 +37,8 @@ class SrsSharedPtrMessage;
class SrsFormat;
class SrsFileWriter;
class SrsMpdWriter;
class SrsMp4M2tsInitEncoder;
class SrsMp4M2tsSegmentEncoder;
/**
* The init mp4 for FMP4.
@ -45,6 +47,7 @@ class SrsInitMp4 : public SrsFragment
{
private:
SrsFileWriter* fw;
SrsMp4M2tsInitEncoder* init;
public:
SrsInitMp4();
virtual ~SrsInitMp4();
@ -60,16 +63,17 @@ class SrsFragmentedMp4 : public SrsFragment
{
private:
SrsFileWriter* fw;
SrsMp4M2tsSegmentEncoder* enc;
public:
SrsFragmentedMp4();
virtual ~SrsFragmentedMp4();
public:
// Initialize the fragment, create the home dir, open the file.
virtual int initialize(SrsRequest* r, bool video, SrsMpdWriter* mpd);
virtual int initialize(SrsRequest* r, bool video, SrsMpdWriter* mpd, uint32_t tid);
// Write media message to fragment.
virtual int write(SrsSharedPtrMessage* shared_msg, SrsFormat* format);
// Reap the fragment, close the fd and rename tmp to official file.
virtual int reap();
virtual int reap(uint64_t& dts);
};
/**
@ -103,7 +107,8 @@ public:
virtual int write(SrsFormat* format);
public:
// Get the fragment relative home and filename.
virtual int get_fragment(bool video, std::string& home, std::string& filename);
// The basetime is the absolute time in ms, while the sn(sequence number) is basetime/fragment.
virtual int get_fragment(bool video, std::string& home, std::string& filename, int64_t& sn, uint64_t& basetime);
};
/**
@ -119,6 +124,8 @@ private:
SrsFragmentWindow* vfragments;
SrsFragmentedMp4* acurrent;
SrsFragmentWindow* afragments;
uint64_t audio_dts;
uint64_t video_dts;
private:
// The fragment duration in ms to reap it.
int fragment;

View file

@ -132,7 +132,7 @@ int SrsDvrSegmenter::write_metadata(SrsSharedPtrMessage* metadata)
return encode_metadata(metadata);
}
int SrsDvrSegmenter::write_audio(SrsSharedPtrMessage* shared_audio)
int SrsDvrSegmenter::write_audio(SrsSharedPtrMessage* shared_audio, SrsFormat* format)
{
int ret = ERROR_SUCCESS;
@ -147,14 +147,14 @@ int SrsDvrSegmenter::write_audio(SrsSharedPtrMessage* shared_audio)
return ret;
}
if ((ret = encode_audio(audio)) != ERROR_SUCCESS) {
if ((ret = encode_audio(audio, format)) != ERROR_SUCCESS) {
return ret;
}
return ret;
}
int SrsDvrSegmenter::write_video(SrsSharedPtrMessage* shared_video)
int SrsDvrSegmenter::write_video(SrsSharedPtrMessage* shared_video, SrsFormat* format)
{
int ret = ERROR_SUCCESS;
@ -165,7 +165,7 @@ int SrsDvrSegmenter::write_video(SrsSharedPtrMessage* shared_video)
return ret;
}
if ((ret = encode_video(video)) != ERROR_SUCCESS) {
if ((ret = encode_video(video, format)) != ERROR_SUCCESS) {
return ret;
}
@ -409,7 +409,7 @@ int SrsDvrFlvSegmenter::encode_metadata(SrsSharedPtrMessage* metadata)
return ret;
}
int SrsDvrFlvSegmenter::encode_audio(SrsSharedPtrMessage* audio)
int SrsDvrFlvSegmenter::encode_audio(SrsSharedPtrMessage* audio, SrsFormat* format)
{
int ret = ERROR_SUCCESS;
@ -422,15 +422,14 @@ int SrsDvrFlvSegmenter::encode_audio(SrsSharedPtrMessage* audio)
return ret;
}
int SrsDvrFlvSegmenter::encode_video(SrsSharedPtrMessage* video)
int SrsDvrFlvSegmenter::encode_video(SrsSharedPtrMessage* video, SrsFormat* format)
{
int ret = ERROR_SUCCESS;
char* payload = video->payload;
int size = video->size;
bool sh = SrsFlvVideo::sh(payload, size);
bool keyframe = SrsFlvVideo::h264(payload, size)
&& SrsFlvVideo::keyframe(payload, size) && !sh;
bool sh = (format->video->avc_packet_type == SrsVideoAvcFrameTraitSequenceHeader);
bool keyframe = (!sh && format->video->frame_type == SrsVideoAvcFrameTypeKeyFrame);
if (keyframe) {
has_keyframe = true;
@ -460,13 +459,11 @@ int SrsDvrFlvSegmenter::close_encoder()
SrsDvrMp4Segmenter::SrsDvrMp4Segmenter()
{
enc = new SrsMp4Encoder();
buffer = new SrsBuffer();
}
SrsDvrMp4Segmenter::~SrsDvrMp4Segmenter()
{
srs_freep(enc);
srs_freep(buffer);
}
int SrsDvrMp4Segmenter::refresh_metadata()
@ -493,37 +490,14 @@ int SrsDvrMp4Segmenter::encode_metadata(SrsSharedPtrMessage* /*metadata*/)
return ERROR_SUCCESS;
}
int SrsDvrMp4Segmenter::encode_audio(SrsSharedPtrMessage* audio)
int SrsDvrMp4Segmenter::encode_audio(SrsSharedPtrMessage* audio, SrsFormat* format)
{
int ret = ERROR_SUCCESS;
if ((ret = buffer->initialize(audio->payload, audio->size)) != ERROR_SUCCESS) {
return ret;
}
// E.4.2.1 AUDIODATA, flv_v10_1.pdf, page 3
if (!buffer->require(1)) {
ret = ERROR_FLV_REQUIRE_SPACE;
srs_error("DVR require flva 1 byte space. ret=%d", ret);
return ret;
}
uint8_t v = buffer->read_1bytes();
SrsAudioCodecId sound_format = (SrsAudioCodecId)((v >> 4) & 0x0f);
SrsAudioSampleRate sound_rate = (SrsAudioSampleRate)((v >> 2) & 0x03);
SrsAudioSampleBits sound_size = (SrsAudioSampleBits)((v >> 1) & 0x01);
SrsAudioChannels channels = (SrsAudioChannels)(v&0x01);
uint16_t ct = 0x00;
if (sound_format == SrsAudioCodecIdAAC) {
if (!buffer->require(1)) {
ret = ERROR_FLV_REQUIRE_SPACE;
srs_error("DVR require flva 1 byte space, format=%d. ret=%d", sound_format, ret);
return ret;
}
v = buffer->read_1bytes();
ct = (v == 0? SrsAudioAacFrameTraitSequenceHeader:SrsAudioAacFrameTraitRawData);
}
SrsAudioCodecId sound_format = format->acodec->id;
SrsAudioSampleRate sound_rate = format->acodec->sound_rate;
SrsAudioSampleBits sound_size = format->acodec->sound_size;
SrsAudioChannels channels = format->acodec->sound_type;
SrsAudioAacFrameTrait ct = format->audio->aac_packet_type;
if (ct == SrsAudioAacFrameTraitSequenceHeader) {
enc->acodec = sound_format;
enc->sample_rate = sound_rate;
@ -531,38 +505,20 @@ int SrsDvrMp4Segmenter::encode_audio(SrsSharedPtrMessage* audio)
enc->channels = channels;
}
uint8_t* sample = (uint8_t*)(buffer->data() + buffer->pos());
uint32_t nb_sample = (uint32_t)(buffer->size() - buffer->pos());
uint8_t* sample = (uint8_t*)format->raw;
uint32_t nb_sample = (uint32_t)format->nb_raw;
uint32_t dts = (uint32_t)audio->timestamp;
return enc->write_sample(SrsMp4HandlerTypeSOUN, 0x00, ct, dts, dts, sample, nb_sample);
}
int SrsDvrMp4Segmenter::encode_video(SrsSharedPtrMessage* video)
int SrsDvrMp4Segmenter::encode_video(SrsSharedPtrMessage* video, SrsFormat* format)
{
int ret = ERROR_SUCCESS;
SrsVideoAvcFrameType frame_type = format->video->frame_type;
SrsVideoCodecId codec_id = format->vcodec->id;
if ((ret = buffer->initialize(video->payload, video->size)) != ERROR_SUCCESS) {
return ret;
}
// E.4.3.1 VIDEODATA, flv_v10_1.pdf, page 5
if (!buffer->require(1)) {
ret = ERROR_FLV_REQUIRE_SPACE;
srs_error("DVR require flvv 1 byte space. ret=%d", ret);
return ret;
}
uint8_t v = buffer->read_1bytes();
SrsVideoAvcFrameType frame_type = (SrsVideoAvcFrameType)((v>>4)&0x0f);
SrsVideoCodecId codec_id = (SrsVideoCodecId)(v&0x0f);
if (!buffer->require(4)) {
ret = ERROR_FLV_REQUIRE_SPACE;
srs_error("DVR require flvv 4 bytes space, codec=%d. ret=%d", codec_id, ret);
return ret;
}
SrsVideoAvcFrameTrait ct = (SrsVideoAvcFrameTrait)buffer->read_1bytes();
uint32_t cts = (uint32_t)buffer->read_3bytes();
SrsVideoAvcFrameTrait ct = format->video->avc_packet_type;
uint32_t cts = (uint32_t)format->video->cts;
if (ct == SrsVideoAvcFrameTraitSequenceHeader) {
enc->vcodec = codec_id;
@ -571,8 +527,8 @@ int SrsDvrMp4Segmenter::encode_video(SrsSharedPtrMessage* video)
uint32_t dts = (uint32_t)video->timestamp;
uint32_t pts = dts + cts;
uint8_t* sample = (uint8_t*)(buffer->data() + buffer->pos());
uint32_t nb_sample = (uint32_t)(buffer->size() - buffer->pos());
uint8_t* sample = (uint8_t*)format->raw;
uint32_t nb_sample = (uint32_t)format->nb_raw;
return enc->write_sample(SrsMp4HandlerTypeVIDE, frame_type, ct, dts, pts, sample, nb_sample);
}
@ -686,7 +642,7 @@ int SrsDvrPlan::on_meta_data(SrsSharedPtrMessage* shared_metadata)
return segment->write_metadata(shared_metadata);
}
int SrsDvrPlan::on_audio(SrsSharedPtrMessage* shared_audio)
int SrsDvrPlan::on_audio(SrsSharedPtrMessage* shared_audio, SrsFormat* format)
{
int ret = ERROR_SUCCESS;
@ -694,14 +650,14 @@ int SrsDvrPlan::on_audio(SrsSharedPtrMessage* shared_audio)
return ret;
}
if ((ret = segment->write_audio(shared_audio)) != ERROR_SUCCESS) {
if ((ret = segment->write_audio(shared_audio, format)) != ERROR_SUCCESS) {
return ret;
}
return ret;
}
int SrsDvrPlan::on_video(SrsSharedPtrMessage* shared_video)
int SrsDvrPlan::on_video(SrsSharedPtrMessage* shared_video, SrsFormat* format)
{
int ret = ERROR_SUCCESS;
@ -709,7 +665,7 @@ int SrsDvrPlan::on_video(SrsSharedPtrMessage* shared_video)
return ret;
}
if ((ret = segment->write_video(shared_video)) != ERROR_SUCCESS) {
if ((ret = segment->write_video(shared_video, format)) != ERROR_SUCCESS) {
return ret;
}
@ -857,7 +813,7 @@ void SrsDvrSegmentPlan::on_unpublish()
{
}
int SrsDvrSegmentPlan::on_audio(SrsSharedPtrMessage* shared_audio)
int SrsDvrSegmentPlan::on_audio(SrsSharedPtrMessage* shared_audio, SrsFormat* format)
{
int ret = ERROR_SUCCESS;
@ -865,14 +821,14 @@ int SrsDvrSegmentPlan::on_audio(SrsSharedPtrMessage* shared_audio)
return ret;
}
if ((ret = SrsDvrPlan::on_audio(shared_audio)) != ERROR_SUCCESS) {
if ((ret = SrsDvrPlan::on_audio(shared_audio, format)) != ERROR_SUCCESS) {
return ret;
}
return ret;
}
int SrsDvrSegmentPlan::on_video(SrsSharedPtrMessage* shared_video)
int SrsDvrSegmentPlan::on_video(SrsSharedPtrMessage* shared_video, SrsFormat* format)
{
int ret = ERROR_SUCCESS;
@ -880,7 +836,7 @@ int SrsDvrSegmentPlan::on_video(SrsSharedPtrMessage* shared_video)
return ret;
}
if ((ret = SrsDvrPlan::on_video(shared_video)) != ERROR_SUCCESS) {
if ((ret = SrsDvrPlan::on_video(shared_video, format)) != ERROR_SUCCESS) {
return ret;
}
@ -1035,24 +991,24 @@ int SrsDvr::on_meta_data(SrsSharedPtrMessage* metadata)
return ret;
}
int SrsDvr::on_audio(SrsSharedPtrMessage* shared_audio)
int SrsDvr::on_audio(SrsSharedPtrMessage* shared_audio, SrsFormat* format)
{
// the dvr for this stream is not actived.
if (!actived) {
return ERROR_SUCCESS;
}
return plan->on_audio(shared_audio);
return plan->on_audio(shared_audio, format);
}
int SrsDvr::on_video(SrsSharedPtrMessage* shared_video)
int SrsDvr::on_video(SrsSharedPtrMessage* shared_video, SrsFormat* format)
{
// the dvr for this stream is not actived.
if (!actived) {
return ERROR_SUCCESS;
}
return plan->on_video(shared_video);
return plan->on_video(shared_video, format);
}
int SrsDvr::on_reload_vhost_dvr_apply(string vhost)

View file

@ -43,6 +43,7 @@ class SrsJsonObject;
class SrsThread;
class SrsMp4Encoder;
class SrsFragment;
class SrsFormat;
#include <srs_app_source.hpp>
#include <srs_app_reload.hpp>
@ -82,10 +83,10 @@ public:
virtual int write_metadata(SrsSharedPtrMessage* metadata);
// Write audio packet.
// @param shared_audio, directly ptr, copy it if need to save it.
virtual int write_audio(SrsSharedPtrMessage* shared_audio);
virtual int write_audio(SrsSharedPtrMessage* shared_audio, SrsFormat* format);
// Write video packet.
// @param shared_video, directly ptr, copy it if need to save it.
virtual int write_video(SrsSharedPtrMessage* shared_video);
virtual int write_video(SrsSharedPtrMessage* shared_video, SrsFormat* format);
// Refresh the metadata. For example, there is duration in flv metadata,
// when DVR in append mode, the duration must be update every some seconds.
// @remark Maybe ignored by concreate segmenter.
@ -96,8 +97,8 @@ public:
protected:
virtual int open_encoder() = 0;
virtual int encode_metadata(SrsSharedPtrMessage* metadata) = 0;
virtual int encode_audio(SrsSharedPtrMessage* audio) = 0;
virtual int encode_video(SrsSharedPtrMessage* video) = 0;
virtual int encode_audio(SrsSharedPtrMessage* audio, SrsFormat* format) = 0;
virtual int encode_video(SrsSharedPtrMessage* video, SrsFormat* format) = 0;
virtual int close_encoder() = 0;
private:
// Generate the flv segment path.
@ -134,8 +135,8 @@ public:
protected:
virtual int open_encoder();
virtual int encode_metadata(SrsSharedPtrMessage* metadata);
virtual int encode_audio(SrsSharedPtrMessage* audio);
virtual int encode_video(SrsSharedPtrMessage* video);
virtual int encode_audio(SrsSharedPtrMessage* audio, SrsFormat* format);
virtual int encode_video(SrsSharedPtrMessage* video, SrsFormat* format);
virtual int close_encoder();
};
@ -147,8 +148,6 @@ class SrsDvrMp4Segmenter : public SrsDvrSegmenter
private:
// The MP4 encoder, for MP4 target.
SrsMp4Encoder* enc;
// The buffer to demux the packet to mp4 sample.
SrsBuffer* buffer;
public:
SrsDvrMp4Segmenter();
virtual ~SrsDvrMp4Segmenter();
@ -157,8 +156,8 @@ public:
protected:
virtual int open_encoder();
virtual int encode_metadata(SrsSharedPtrMessage* metadata);
virtual int encode_audio(SrsSharedPtrMessage* audio);
virtual int encode_video(SrsSharedPtrMessage* video);
virtual int encode_audio(SrsSharedPtrMessage* audio, SrsFormat* format);
virtual int encode_video(SrsSharedPtrMessage* video, SrsFormat* format);
virtual int close_encoder();
};
@ -199,8 +198,8 @@ public:
virtual int on_publish() = 0;
virtual void on_unpublish() = 0;
virtual int on_meta_data(SrsSharedPtrMessage* shared_metadata);
virtual int on_audio(SrsSharedPtrMessage* shared_audio);
virtual int on_video(SrsSharedPtrMessage* shared_video);
virtual int on_audio(SrsSharedPtrMessage* shared_audio, SrsFormat* format);
virtual int on_video(SrsSharedPtrMessage* shared_video, SrsFormat* format);
// Internal interface for segmenter.
public:
// When segmenter close a segment.
@ -238,8 +237,8 @@ public:
virtual int initialize(SrsOriginHub* h, SrsDvrSegmenter* s, SrsRequest* r);
virtual int on_publish();
virtual void on_unpublish();
virtual int on_audio(SrsSharedPtrMessage* shared_audio);
virtual int on_video(SrsSharedPtrMessage* shared_video);
virtual int on_audio(SrsSharedPtrMessage* shared_audio, SrsFormat* format);
virtual int on_video(SrsSharedPtrMessage* shared_video, SrsFormat* format);
private:
virtual int update_duration(SrsSharedPtrMessage* msg);
// interface ISrsReloadHandler
@ -290,12 +289,12 @@ public:
* mux the audio packets to dvr.
* @param shared_audio, directly ptr, copy it if need to save it.
*/
virtual int on_audio(SrsSharedPtrMessage* shared_audio);
virtual int on_audio(SrsSharedPtrMessage* shared_audio, SrsFormat* foramt);
/**
* mux the video packets to dvr.
* @param shared_video, directly ptr, copy it if need to save it.
*/
virtual int on_video(SrsSharedPtrMessage* shared_video);
virtual int on_video(SrsSharedPtrMessage* shared_video, SrsFormat* format);
// interface ISrsReloadHandler
public:
virtual int on_reload_vhost_dvr_apply(std::string vhost);

View file

@ -1024,7 +1024,7 @@ int SrsOriginHub::on_audio(SrsSharedPtrMessage* shared_audio)
ret = ERROR_SUCCESS;
}
if ((ret = dvr->on_audio(msg)) != ERROR_SUCCESS) {
if ((ret = dvr->on_audio(msg, format)) != ERROR_SUCCESS) {
srs_warn("dvr process audio message failed, ignore and disable dvr. ret=%d", ret);
// unpublish, ignore ret.
@ -1126,7 +1126,7 @@ int SrsOriginHub::on_video(SrsSharedPtrMessage* shared_video, bool is_sequence_h
ret = ERROR_SUCCESS;
}
if ((ret = dvr->on_video(msg)) != ERROR_SUCCESS) {
if ((ret = dvr->on_video(msg, format)) != ERROR_SUCCESS) {
srs_warn("dvr process video message failed, ignore and disable dvr. ret=%d", ret);
// unpublish, ignore ret.
@ -1278,13 +1278,28 @@ int SrsOriginHub::on_dvr_request_sh()
return ret;
}
if (cache_sh_video && (ret = dvr->on_video(cache_sh_video)) != ERROR_SUCCESS) {
srs_error("dvr process video sequence header message failed. ret=%d", ret);
return ret;
if (cache_sh_video) {
// TODO: Use cached format for sh.
if ((ret = format->on_video(cache_sh_video)) != ERROR_SUCCESS) {
return ret;
}
if ((ret = dvr->on_video(cache_sh_video, format)) != ERROR_SUCCESS) {
srs_error("dvr process video sequence header message failed. ret=%d", ret);
return ret;
}
}
if (cache_sh_audio && (ret = dvr->on_audio(cache_sh_audio)) != ERROR_SUCCESS) {
srs_error("dvr process audio sequence header message failed. ret=%d", ret);
return ret;
if (cache_sh_audio) {
// TODO: Use cached format for sh.
if ((ret = format->on_audio(cache_sh_audio)) != ERROR_SUCCESS) {
return ret;
}
if ((ret = dvr->on_audio(cache_sh_audio, format)) != ERROR_SUCCESS) {
srs_error("dvr process audio sequence header message failed. ret=%d", ret);
return ret;
}
}
return ret;