1
0
Fork 0
mirror of https://github.com/ossrs/srs.git synced 2025-02-12 11:21:52 +00:00

fix #738, support DVR general mp4. 3.0.17

This commit is contained in:
winlin 2017-02-07 21:56:20 +08:00
parent 3209ad29e0
commit afbc3443f3
12 changed files with 1264 additions and 222 deletions

View file

@ -185,6 +185,7 @@ Please select your language:
### V3 changes
* v3.0, 2017-02-07, fix [#738][bug #738] support DVR general mp4. 3.0.17
* v3.0, 2017-01-19, for [#742][bug #742] refine source, meta and origin hub. 3.0.16
* v3.0, 2017-01-17, for [#742][bug #742] refine source, timeout, live cycle. 3.0.15
* v3.0, 2017-01-11, fix [#735][bug #735] config transform refer_publish invalid. 3.0.14
@ -1377,6 +1378,7 @@ Winlin
[bug #735]: https://github.com/ossrs/srs/issues/735
[bug #742]: https://github.com/ossrs/srs/issues/742
[bug #738]: https://github.com/ossrs/srs/issues/738
[bug #xxxxxxxxxxxxx]: https://github.com/ossrs/srs/issues/xxxxxxxxxxxxx
[exo #828]: https://github.com/google/ExoPlayer/pull/828

View file

@ -50,6 +50,7 @@ SrsDvrSegmenter::SrsDvrSegmenter()
jitter = NULL;
plan = NULL;
duration = 0;
stream_previous_pkt_time = -1;
path = "";
fs = new SrsFileWriter();
@ -120,6 +121,9 @@ int SrsDvrSegmenter::open()
jitter = new SrsRtmpJitter();
duration = 0;
// fresh stream starting.
stream_previous_pkt_time = -1;
// open file writer, in append or create mode.
if ((ret = fs->open(tmp_dvr_file)) != ERROR_SUCCESS) {
srs_error("open file stream for file %s failed. ret=%d", path.c_str(), ret);
@ -153,6 +157,10 @@ int SrsDvrSegmenter::write_audio(SrsSharedPtrMessage* shared_audio)
return ret;
}
if ((ret = on_update_duration(audio)) != ERROR_SUCCESS) {
return ret;
}
if ((ret = encode_audio(audio)) != ERROR_SUCCESS) {
return ret;
}
@ -171,13 +179,11 @@ int SrsDvrSegmenter::write_video(SrsSharedPtrMessage* shared_video)
return ret;
}
char* payload = video->payload;
int size = video->size;
if ((ret = encode_video(video)) != ERROR_SUCCESS) {
return ret;
}
bool is_sequence_header = SrsFlvCodec::video_is_sequence_header(payload, size);
bool is_key_frame = SrsFlvCodec::video_is_h264(payload, size)
&& SrsFlvCodec::video_is_keyframe(payload, size) && !is_sequence_header;
if ((ret = encode_video(video, is_sequence_header, is_key_frame)) != ERROR_SUCCESS) {
if ((ret = on_update_duration(video)) != ERROR_SUCCESS) {
return ret;
}
@ -220,6 +226,24 @@ int SrsDvrSegmenter::close()
return ret;
}
int SrsDvrSegmenter::on_update_duration(SrsSharedPtrMessage* msg)
{
int ret = ERROR_SUCCESS;
// no previous packet or timestamp overflow.
if (stream_previous_pkt_time < 0 || stream_previous_pkt_time > msg->timestamp) {
stream_previous_pkt_time = msg->timestamp;
}
// collect segment and stream duration, timestamp overflow is ok.
duration += msg->timestamp - stream_previous_pkt_time;
// update previous packet time
stream_previous_pkt_time = msg->timestamp;
return ret;
}
string SrsDvrSegmenter::generate_path()
{
// the path in config, for example,
@ -227,7 +251,7 @@ string SrsDvrSegmenter::generate_path()
std::string path_config = _srs_config->get_dvr_path(req->vhost);
// add [stream].[timestamp].flv as filename for dir
if (!srs_string_ends_with(path_config, ".flv")) {
if (!srs_string_ends_with(path_config, ".flv", ".mp4")) {
path_config += "/[stream].[timestamp].flv";
}
@ -261,11 +285,6 @@ SrsDvrFlvSegmenter::SrsDvrFlvSegmenter()
filesize_offset = 0;
has_keyframe = false;
starttime = -1;
stream_starttime = 0;
stream_previous_pkt_time = -1;
stream_duration = 0;
}
SrsDvrFlvSegmenter::~SrsDvrFlvSegmenter()
@ -335,16 +354,13 @@ int SrsDvrFlvSegmenter::open_encoder()
has_keyframe = false;
// fresh stream starting.
starttime = -1;
stream_previous_pkt_time = -1;
stream_starttime = srs_update_system_time_ms();
stream_duration = 0;
// update the duration and filesize offset.
duration_offset = 0;
filesize_offset = 0;
srs_freep(enc);
enc = new SrsFlvEncoder();
if ((ret = enc->initialize(fs)) != ERROR_SUCCESS) {
return ret;
}
@ -431,17 +447,19 @@ int SrsDvrFlvSegmenter::encode_audio(SrsSharedPtrMessage* audio)
return ret;
}
if ((ret = on_update_duration(audio)) != ERROR_SUCCESS) {
return ret;
}
return ret;
}
int SrsDvrFlvSegmenter::encode_video(SrsSharedPtrMessage* video, bool sh, bool keyframe)
int SrsDvrFlvSegmenter::encode_video(SrsSharedPtrMessage* video)
{
int ret = ERROR_SUCCESS;
char* payload = video->payload;
int size = video->size;
bool sh = SrsFlvCodec::video_is_sequence_header(payload, size);
bool keyframe = SrsFlvCodec::video_is_h264(payload, size)
&& SrsFlvCodec::video_is_keyframe(payload, size) && !sh;
if (keyframe) {
has_keyframe = true;
}
@ -455,14 +473,6 @@ int SrsDvrFlvSegmenter::encode_video(SrsSharedPtrMessage* video, bool sh, bool k
}
}
// update segment duration, session plan just update the duration,
// the segment plan will reap segment if exceed, this video will write to next segment.
if ((ret = on_update_duration(video)) != ERROR_SUCCESS) {
return ret;
}
char* payload = video->payload;
int size = video->size;
if ((ret = enc->write_video(video->timestamp, payload, size)) != ERROR_SUCCESS) {
return ret;
}
@ -475,77 +485,133 @@ int SrsDvrFlvSegmenter::close_encoder()
return refresh_metadata();
}
int SrsDvrFlvSegmenter::on_update_duration(SrsSharedPtrMessage* msg)
{
int ret = ERROR_SUCCESS;
// we must assumpt that the stream timestamp is monotonically increase,
// that is, always use time jitter to correct the timestamp.
// except the time jitter is disabled in config.
// set the segment starttime at first time
if (starttime < 0) {
starttime = msg->timestamp;
}
// no previous packet or timestamp overflow.
if (stream_previous_pkt_time < 0 || stream_previous_pkt_time > msg->timestamp) {
stream_previous_pkt_time = msg->timestamp;
}
// collect segment and stream duration, timestamp overflow is ok.
duration += msg->timestamp - stream_previous_pkt_time;
stream_duration += msg->timestamp - stream_previous_pkt_time;
// update previous packet time
stream_previous_pkt_time = msg->timestamp;
return ret;
}
SrsDvrMp4Segmenter::SrsDvrMp4Segmenter()
{
enc = new SrsMp4Encoder();
buffer = new SrsBuffer();
}
SrsDvrMp4Segmenter::~SrsDvrMp4Segmenter()
{
srs_freep(enc);
srs_freep(buffer);
}
int SrsDvrMp4Segmenter::refresh_metadata()
{
int ret = ERROR_SUCCESS;
return ret;
return ERROR_SUCCESS;
}
int SrsDvrMp4Segmenter::open_encoder()
{
int ret = ERROR_SUCCESS;
srs_freep(enc);
enc = new SrsMp4Encoder();
if ((ret = enc->initialize(fs)) != ERROR_SUCCESS) {
return ret;
}
return ret;
}
int SrsDvrMp4Segmenter::encode_metadata(SrsSharedPtrMessage* metadata)
int SrsDvrMp4Segmenter::encode_metadata(SrsSharedPtrMessage* /*metadata*/)
{
int ret = ERROR_SUCCESS;
return ret;
return ERROR_SUCCESS;
}
int SrsDvrMp4Segmenter::encode_audio(SrsSharedPtrMessage* audio)
{
int ret = ERROR_SUCCESS;
return ret;
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();
SrsCodecAudio sound_format = (SrsCodecAudio)((v >> 4) & 0x0f);
SrsCodecAudioSampleRate sound_rate = (SrsCodecAudioSampleRate)((v >> 2) & 0x03);
SrsCodecAudioSampleSize sound_size = (SrsCodecAudioSampleSize)((v >> 1) & 0x01);
SrsCodecAudioSoundType channels = (SrsCodecAudioSoundType)(v&0x01);
uint16_t ct = 0x00;
if (sound_format == SrsCodecAudioAAC) {
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? SrsCodecAudioTypeSequenceHeader:SrsCodecAudioTypeRawData);
}
if (ct == SrsCodecAudioTypeSequenceHeader) {
enc->acodec = sound_format;
enc->sample_rate = sound_rate;
enc->sound_bits = sound_size;
enc->channels = channels;
}
uint8_t* sample = (uint8_t*)(buffer->data() + buffer->pos());
uint32_t nb_sample = (uint32_t)(buffer->size() - buffer->pos());
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, bool sh, bool keyframe)
int SrsDvrMp4Segmenter::encode_video(SrsSharedPtrMessage* video)
{
int ret = ERROR_SUCCESS;
return ret;
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();
SrsCodecVideoAVCFrame frame_type = (SrsCodecVideoAVCFrame)((v>>4)&0x0f);
SrsCodecVideo codec_id = (SrsCodecVideo)(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;
}
SrsCodecVideoAVCType ct = (SrsCodecVideoAVCType)buffer->read_1bytes();
uint32_t cts = (uint32_t)buffer->read_3bytes();
if (ct == SrsCodecVideoAVCTypeSequenceHeader) {
enc->vcodec = codec_id;
}
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());
return enc->write_sample(SrsMp4HandlerTypeVIDE, frame_type, ct, dts, pts, sample, nb_sample);
}
int SrsDvrMp4Segmenter::close_encoder()
{
int ret = ERROR_SUCCESS;
if ((ret = enc->flush()) != ERROR_SUCCESS) {
return ret;
}
return ret;
}

View file

@ -60,10 +60,10 @@ class SrsDvrSegmenter : public ISrsReloadHandler
protected:
// The underlayer file object.
SrsFileWriter* fs;
// The duration in ms of current segment.
int64_t duration;
// Whether wait keyframe to reap segment.
bool wait_keyframe;
// The duration in ms of current segment.
int64_t duration;
private:
// The path of current segment flv file path.
std::string path;
@ -74,6 +74,11 @@ private:
private:
SrsRtmpJitter* jitter;
SrsRtmpJitterAlgorithm jitter_algorithm;
private:
// The previous stream RTMP pkt time in ms, used to calc the duration.
// for the RTMP timestamp will overflow.
// TODO: FIXME: Use utility object to calc it.
int64_t stream_previous_pkt_time;
public:
SrsDvrSegmenter();
virtual ~SrsDvrSegmenter();
@ -107,11 +112,13 @@ 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, bool sh, bool keyframe) = 0;
virtual int encode_video(SrsSharedPtrMessage* video) = 0;
virtual int close_encoder() = 0;
private:
// Generate the flv segment path.
virtual std::string generate_path();
// When update the duration of segment by rtmp msg.
virtual int on_update_duration(SrsSharedPtrMessage* msg);
// interface ISrsReloadHandler
public:
virtual int on_reload_vhost_dvr(std::string vhost);
@ -134,19 +141,6 @@ private:
int64_t filesize_offset;
// Whether current segment has keyframe.
bool has_keyframe;
private:
// The current segment starttime in ms, RTMP pkt time.
int64_t starttime;
// The stream start time in ms, to generate atc pts. abs time.
int64_t stream_starttime;
// The stream duration in ms, to generate atc segment.
int64_t stream_duration;
/**
* The previous stream RTMP pkt time in ms, used to calc the duration.
* for the RTMP timestamp will overflow.
*/
// TODO: FIXME: Use utility object to calc it.
int64_t stream_previous_pkt_time;
public:
SrsDvrFlvSegmenter();
virtual ~SrsDvrFlvSegmenter();
@ -156,11 +150,8 @@ protected:
virtual int open_encoder();
virtual int encode_metadata(SrsSharedPtrMessage* metadata);
virtual int encode_audio(SrsSharedPtrMessage* audio);
virtual int encode_video(SrsSharedPtrMessage* video, bool sh, bool keyframe);
virtual int encode_video(SrsSharedPtrMessage* video);
virtual int close_encoder();
private:
// When update the duration of segment by rtmp msg.
virtual int on_update_duration(SrsSharedPtrMessage* msg);
};
/**
@ -171,6 +162,8 @@ 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();
@ -180,7 +173,7 @@ protected:
virtual int open_encoder();
virtual int encode_metadata(SrsSharedPtrMessage* metadata);
virtual int encode_audio(SrsSharedPtrMessage* audio);
virtual int encode_video(SrsSharedPtrMessage* video, bool sh, bool keyframe);
virtual int encode_video(SrsSharedPtrMessage* video);
virtual int close_encoder();
};

View file

@ -31,7 +31,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// current release version
#define VERSION_MAJOR 3
#define VERSION_MINOR 0
#define VERSION_REVISION 16
#define VERSION_REVISION 17
// generated by configure, only macros.
#include <srs_auto_headers.hpp>

View file

@ -257,6 +257,9 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#define ERROR_MP4_ILLEGAL_TIMESTAMP 3081
#define ERROR_DVR_CANNOT_APPEND 3082
#define ERROR_DVR_ILLEGAL_PLAN 3083
#define ERROR_FLV_REQUIRE_SPACE 3084
#define ERROR_MP4_AVCC_CHANGE 3085
#define ERROR_MP4_ASC_CHANGE 3086
///////////////////////////////////////////////////////
// HTTP/StreamCaster/KAFKA protocol error.

File diff suppressed because it is too large Load diff

View file

@ -36,7 +36,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#include <vector>
#include <map>
class ISrsWriter;
class ISrsWriteSeeker;
class ISrsReadSeeker;
class SrsMp4TrackBox;
class SrsMp4MediaBox;
@ -59,6 +59,11 @@ class SrsMp4DecodingTime2SampleBox;
class SrsMp4CompositionTime2SampleBox;
class SrsMp4SyncSampleBox;
class SrsMp4MediaHeaderBox;
class SrsMp4HandlerReferenceBox;
class SrsMp4VideoMeidaHeaderBox;
class SrsMp4DataInformationBox;
class SrsMp4DataReferenceBox;
class SrsMp4SoundMeidaHeaderBox;
/**
* 4.2 Object Structure
@ -173,6 +178,9 @@ public:
// Get the contained box of specific type.
// @return The first matched box.
virtual SrsMp4Box* get(SrsMp4BoxType bt);
// Remove the contained box of specified type.
// @return The removed count.
virtual int remove(SrsMp4BoxType bt);
/**
* Discovery the box from buffer.
* @param ppbox Output the discoveried box, which user must free it.
@ -196,6 +204,13 @@ protected:
// It's not necessary to check the buffer, unless the box is not only determined by the verson.
// Generally, it's not necessary, that is, all boxes is determinated by version.
virtual int decode_header(SrsBuffer* buf);
protected:
// The actual size of this box, generally it must equal to nb_bytes,
// but for some special boxes, for instance mdat, the box encode actual size maybe large than
// the nb_bytes to write, because the data is written directly.
// That is, the actual size is used to encode the box size in header,
// while the nb_bytes is the bytes encoded the box.
virtual uint64_t encode_actual_size();
};
/**
@ -240,6 +255,8 @@ private:
public:
SrsMp4FileTypeBox();
virtual ~SrsMp4FileTypeBox();
public:
virtual void set_compatible_brands(SrsMp4BoxBrand b0, SrsMp4BoxBrand b1, SrsMp4BoxBrand b2, SrsMp4BoxBrand b3);
protected:
virtual int nb_header();
virtual int encode_header(SrsBuffer* buf);
@ -256,17 +273,19 @@ protected:
*/
class SrsMp4MediaDataBox : public SrsMp4Box
{
private:
public:
// the contained media data
// TODO: FIXME: Support 64bits size.
int nb_data;
// @remark User must alloc the data and codec it.
uint8_t* data;
public:
SrsMp4MediaDataBox();
virtual ~SrsMp4MediaDataBox();
protected:
virtual int nb_header();
virtual int encode_header(SrsBuffer* buf);
virtual int decode_header(SrsBuffer* buf);
virtual uint64_t encode_actual_size();
public:
virtual int decode(SrsBuffer* buf);
};
/**
@ -301,10 +320,13 @@ public:
public:
// Get the header of moov.
virtual SrsMp4MovieHeaderBox* mvhd();
virtual void set_mvhd(SrsMp4MovieHeaderBox* v);
// Get the first video track.
virtual SrsMp4TrackBox* video();
// Get the first audio track.
virtual SrsMp4TrackBox* audio();
// Add a new track.
virtual void add_trak(SrsMp4TrackBox* v);
// Get the number of video tracks.
virtual int nb_vide_tracks();
// Get the number of audio tracks.
@ -328,7 +350,7 @@ public:
// an integer that declares the most recent time the presentation was modified (in
// seconds since midnight, Jan. 1, 1904, in UTC time)
uint64_t modification_time;
private:
public:
// an integer that specifies the time-scale for the entire presentation; this is the number of
// time units that pass in one second. For example, a time coordinate system that measures time in
// sixtieths of a second has a time scale of 60.
@ -392,6 +414,7 @@ public:
virtual SrsMp4TrackType track_type();
// Get the track header box.
virtual SrsMp4TrackHeaderBox* tkhd();
virtual void set_tkhd(SrsMp4TrackHeaderBox* v);
public:
// Get the chunk offset box.
virtual SrsMp4ChunkOffsetBox* stco();
@ -416,9 +439,10 @@ public:
virtual SrsMp4AvccBox* avcc();
// For AAC codec, get the asc.
virtual SrsMp4DecoderSpecificInfo* asc();
private:
public:
// Get the media box.
virtual SrsMp4MediaBox* mdia();
virtual void set_mdia(SrsMp4MediaBox* v);
// Get the media info box.
virtual SrsMp4MediaInformationBox* minf();
// Get the sample table box.
@ -568,8 +592,13 @@ public:
virtual SrsMp4TrackType track_type();
// Get the media header box.
virtual SrsMp4MediaHeaderBox* mdhd();
virtual void set_mdhd(SrsMp4MediaHeaderBox* v);
// Get the hdlr box.
virtual SrsMp4HandlerReferenceBox* hdlr();
virtual void set_hdlr(SrsMp4HandlerReferenceBox* v);
// Get the media info box.
virtual SrsMp4MediaInformationBox* minf();
virtual void set_minf(SrsMp4MediaInformationBox* v);
};
/**
@ -608,12 +637,15 @@ public:
// the language code for this media. See ISO 639-2/T for the set of three character
// codes. Each character is packed as the difference between its ASCII value and 0x60. Since the code
// is confined to being three lower-case letters, these values are strictly positive.
virtual uint8_t language0();
virtual void set_language0(uint8_t v);
virtual uint8_t language1();
virtual void set_language1(uint8_t v);
virtual uint8_t language2();
virtual void set_language2(uint8_t v);
// @param v The ASCII, for example, 'u'.
virtual char language0();
virtual void set_language0(char v);
// @param v The ASCII, for example, 'n'.
virtual char language1();
virtual void set_language1(char v);
// @param v The ASCII, for example, 'd'.
virtual char language2();
virtual void set_language2(char v);
protected:
virtual int nb_header();
virtual int encode_header(SrsBuffer* buf);
@ -661,8 +693,18 @@ public:
SrsMp4MediaInformationBox();
virtual ~SrsMp4MediaInformationBox();
public:
// Get the vmhd box.
virtual SrsMp4VideoMeidaHeaderBox* vmhd();
virtual void set_vmhd(SrsMp4VideoMeidaHeaderBox* v);
// Get the smhd box.
virtual SrsMp4SoundMeidaHeaderBox* smhd();
virtual void set_smhd(SrsMp4SoundMeidaHeaderBox* v);
// Get the dinf box.
virtual SrsMp4DataInformationBox* dinf();
virtual void set_dinf(SrsMp4DataInformationBox* v);
// Get the sample table box.
virtual SrsMp4SampleTableBox* stbl();
virtual void set_stbl(SrsMp4SampleTableBox* v);
};
/**
@ -721,6 +763,10 @@ class SrsMp4DataInformationBox : public SrsMp4Box
public:
SrsMp4DataInformationBox();
virtual ~SrsMp4DataInformationBox();
public:
// Get the dref box.
virtual SrsMp4DataReferenceBox* dref();
virtual void set_dref(SrsMp4DataReferenceBox* v);
};
/**
@ -787,6 +833,7 @@ public:
public:
virtual uint32_t entry_count();
virtual SrsMp4DataEntryBox* entry_at(int index);
virtual SrsMp4DataReferenceBox* append(SrsMp4DataEntryBox* v);
protected:
virtual int nb_header();
virtual int encode_header(SrsBuffer* buf);
@ -808,18 +855,29 @@ public:
public:
// Get the sample description box
virtual SrsMp4SampleDescriptionBox* stsd();
virtual void set_stsd(SrsMp4SampleDescriptionBox* v);
// Get the chunk offset box.
virtual SrsMp4ChunkOffsetBox* stco();
virtual void set_stco(SrsMp4ChunkOffsetBox* v);
// Get the sample size box.
virtual SrsMp4SampleSizeBox* stsz();
virtual void set_stsz(SrsMp4SampleSizeBox* v);
// Get the sample to chunk box.
virtual SrsMp4Sample2ChunkBox* stsc();
virtual void set_stsc(SrsMp4Sample2ChunkBox* v);
// Get the dts box.
virtual SrsMp4DecodingTime2SampleBox* stts();
virtual void set_stts(SrsMp4DecodingTime2SampleBox* v);
// Get the cts/pts box.
virtual SrsMp4CompositionTime2SampleBox* ctts();
virtual void set_ctts(SrsMp4CompositionTime2SampleBox* v);
// Get the sync dts box.
virtual SrsMp4SyncSampleBox* stss();
virtual void set_stss(SrsMp4SyncSampleBox* v);
protected:
virtual int nb_header();
virtual int encode_header(SrsBuffer* buf);
virtual int decode_header(SrsBuffer* buf);
};
/**
@ -877,6 +935,7 @@ public:
public:
// For avc1, get the avcc box.
virtual SrsMp4AvccBox* avcC();
virtual void set_avcC(SrsMp4AvccBox* v);
protected:
virtual int nb_header();
virtual int encode_header(SrsBuffer* buf);
@ -920,6 +979,7 @@ public:
public:
// For AAC codec, get the esds.
virtual SrsMp4EsdsBox* esds();
virtual void set_esds(SrsMp4EsdsBox* v);
// For AAC codec, get the asc.
virtual SrsMp4DecoderSpecificInfo* asc();
protected:
@ -1020,7 +1080,7 @@ class SrsMp4DecoderConfigDescriptor : public SrsMp4BaseDescriptor
public:
// an indication of the object or scene description type that needs to be supported
// by the decoder for this elementary stream as per Table 5.
SrsMp4ObjectType objectTypeIndication;
SrsMp4ObjectType objectTypeIndication; // bit(8)
SrsMp4StreamType streamType; // bit(6)
uint8_t upStream; // bit(1)
uint8_t reserved; // bit(1)
@ -1127,6 +1187,7 @@ public:
public:
virtual uint32_t entry_count();
virtual SrsMp4SampleEntry* entrie_at(int index);
virtual SrsMp4SampleDescriptionBox* append(SrsMp4SampleEntry* v);
protected:
virtual int nb_header();
virtual int encode_header(SrsBuffer* buf);
@ -1417,7 +1478,7 @@ public:
// The type of sample, audio or video.
SrsCodecFlvTag type;
// The offset of sample in file.
uint64_t offset;
off_t offset;
// The index of sample with a track, start from 0.
uint32_t index;
// The dts in tbn.
@ -1463,17 +1524,19 @@ public:
SrsMp4SampleManager();
virtual ~SrsMp4SampleManager();
public:
/**
* Load the samples from moov.
* There must be atleast one track.
*/
// Load the samples from moov. There must be atleast one track.
virtual int load(SrsMp4MovieBox* moov);
/**
* Get the sample at index position.
* @remark NULL if exceed the max index.
*/
// Get the sample at index position.
// @remark NULL if exceed the max index.
virtual SrsMp4Sample* at(uint32_t index);
// Append the sample to the tail of manager.
virtual void append(SrsMp4Sample* sample);
// Write the samples info to moov.
virtual int write(SrsMp4MovieBox* moov);
private:
virtual int write_track(SrsCodecFlvTag track,
SrsMp4DecodingTime2SampleBox* stts, SrsMp4SyncSampleBox* stss, SrsMp4CompositionTime2SampleBox* ctts,
SrsMp4Sample2ChunkBox* stsc, SrsMp4SampleSizeBox* stsz, SrsMp4ChunkOffsetBox* stco);
virtual int do_load(std::map<uint64_t, SrsMp4Sample*>& tses, SrsMp4MovieBox* moov);
private:
// Load the samples of track from stco, stsz and stsc.
@ -1544,7 +1607,7 @@ public:
virtual int initialize(ISrsReadSeeker* rs);
/**
* Read a sample from mp4.
* @param pht The sample type, audio/soun or video/vide.
* @param pht The sample hanler type, audio/soun or video/vide.
* @param pft, The frame type. For video, it's SrsCodecVideoAVCFrame.
* @param pct, The codec type. For video, it's SrsCodecVideoAVCType. For audio, it's SrsCodecAudioType.
* @param pdts The output dts in milliseconds.
@ -1573,16 +1636,69 @@ private:
class SrsMp4Encoder
{
private:
ISrsWriter* writer;
ISrsWriteSeeker* wsio;
SrsBuffer* buffer;
// The mdat offset at file, we must update the header when flush.
off_t mdat_offset;
// The mdat size in bytes, we must update it to the mdat box header.
uint64_t mdat_bytes;
// The samples build from moov.
SrsMp4SampleManager* samples;
public:
// The audio codec of first track, generally there is zero or one track.
// Forbidden if no audio stream.
SrsCodecAudio acodec;
// The audio sample rate.
SrsCodecAudioSampleRate sample_rate;
// The audio sound bits.
SrsCodecAudioSampleSize sound_bits;
// The audio sound type.
SrsCodecAudioSoundType channels;
private:
// For AAC, the asc in esds box.
int nb_asc;
uint8_t* pasc;
// The number of audio samples.
int nb_audios;
// The duration of audio stream.
uint64_t aduration;
public:
// The video codec of first track, generally there is zero or one track.
// Forbidden if no video stream.
SrsCodecVideo vcodec;
private:
// For H.264/AVC, the avcc contains the sps/pps.
int nb_avcc;
uint8_t* pavcc;
// The number of video samples.
int nb_videos;
// The duration of video stream.
uint64_t vduration;
// The size width/height of video.
uint32_t width;
uint32_t height;
public:
SrsMp4Encoder();
virtual ~SrsMp4Encoder();
public:
/**
* Initialize the encoder with a writer w.
* @param w The underlayer io writer, user must manage it.
*/
virtual int initialize(ISrsWriter* w);
// Initialize the encoder with a writer w.
// @param w The underlayer io writer, user must manage it.
virtual int initialize(ISrsWriteSeeker* ws);
// Write a sampel to mp4.
// @param ht, The sample handler type, audio/soun or video/vide.
// @param ft, The frame type. For video, it's SrsCodecVideoAVCFrame.
// @param ct, The codec type. For video, it's SrsCodecVideoAVCType. For audio, it's SrsCodecAudioType.
// @param dts The output dts in milliseconds.
// @param pts The output pts in milliseconds.
// @param sample The output payload, user must free it.
// @param nb_sample The output size of payload.
virtual int write_sample(SrsMp4HandlerType ht, uint16_t ft, uint16_t ct,
uint32_t dts, uint32_t pts, uint8_t* sample, uint32_t nb_sample);
// Flush the encoder, to write the moov.
virtual int flush();
private:
virtual int copy_sequence_header(bool vsh, uint8_t* sample, uint32_t nb_sample);
virtual int do_write_sample(SrsMp4Sample* ps, uint8_t* sample, uint32_t nb_sample);
};
#endif

View file

@ -320,6 +320,21 @@ bool srs_string_ends_with(string str, string flag)
return str.rfind(flag) == str.length() - flag.length();
}
bool srs_string_ends_with(string str, string flag0, string flag1)
{
return srs_string_ends_with(str, flag0) || srs_string_ends_with(str, flag1);
}
bool srs_string_ends_with(string str, string flag0, string flag1, string flag2)
{
return srs_string_ends_with(str, flag0) || srs_string_ends_with(str, flag1) || srs_string_ends_with(str, flag2);
}
bool srs_string_ends_with(string str, string flag0, string flag1, string flag2, string flag3)
{
return srs_string_ends_with(str, flag0) || srs_string_ends_with(str, flag1) || srs_string_ends_with(str, flag2) || srs_string_ends_with(str, flag3);
}
bool srs_string_starts_with(string str, string flag)
{
return str.find(flag) == 0;
@ -471,6 +486,28 @@ int srs_do_create_dir_recursively(string dir)
return ret;
}
bool srs_bytes_equals(void* pa, void* pb, int size)
{
uint8_t* a = (uint8_t*)pa;
uint8_t* b = (uint8_t*)pb;
if (!a && !b) {
return true;
}
if (!a || !b) {
return false;
}
for(int i = 0; i < size; i++){
if(a[i] != b[i]){
return false;
}
}
return true;
}
int srs_create_dir_recursively(string dir)
{
int ret = ERROR_SUCCESS;

View file

@ -81,6 +81,9 @@ extern std::string srs_string_trim_start(std::string str, std::string trim_chars
extern std::string srs_string_remove(std::string str, std::string remove_chars);
// whether string end with
extern bool srs_string_ends_with(std::string str, std::string flag);
extern bool srs_string_ends_with(std::string str, std::string flag0, std::string flag1);
extern bool srs_string_ends_with(std::string str, std::string flag0, std::string flag1, std::string flag2);
extern bool srs_string_ends_with(std::string str, std::string flag0, std::string flag1, std::string flag2, std::string flag3);
// whether string starts with
extern bool srs_string_starts_with(std::string str, std::string flag);
extern bool srs_string_starts_with(std::string str, std::string flag0, std::string flag1);
@ -96,6 +99,12 @@ extern std::string srs_string_min_match(std::string str, std::vector<std::string
extern std::vector<std::string> srs_string_split(std::string str, std::string flag);
extern std::vector<std::string> srs_string_split(std::string str, std::vector<std::string> flags);
/**
* compare the memory in bytes.
* @return true if completely equal; otherwise, false.
*/
extern bool srs_bytes_equals(void* pa, void* pb, int size);
// create dir recursively
extern int srs_create_dir_recursively(std::string dir);

View file

@ -192,31 +192,6 @@ string srs_generate_vis_tc_url(string ip, string vhost, string app, int port)
return "rtmp://" + ip + ":" + srs_int2str(port) + "/" + app;
}
/**
* compare the memory in bytes.
*/
bool srs_bytes_equals(void* pa, void* pb, int size)
{
uint8_t* a = (uint8_t*)pa;
uint8_t* b = (uint8_t*)pb;
if (!a && !b) {
return true;
}
if (!a || !b) {
return false;
}
for(int i = 0; i < size; i++){
if(a[i] != b[i]){
return false;
}
}
return true;
}
template<typename T>
int srs_do_rtmp_create_msg(char type, uint32_t timestamp, char* data, int size, int stream_id, T** ppmsg)
{

View file

@ -89,25 +89,19 @@ extern std::string srs_generate_tc_url(
* srs_detect_tools generate the normal tcUrl
*/
extern std::string srs_generate_normal_tc_url(
std::string ip, std::string vhost, std::string app, int port);
std::string ip, std::string vhost, std::string app, int port);
/**
* srs_detect_tools generate the normal tcUrl
*/
extern std::string srs_generate_via_tc_url(
std::string ip, std::string vhost, std::string app, int port);
std::string ip, std::string vhost, std::string app, int port);
/**
* srs_detect_tools generate the vis/vis2 tcUrl
*/
extern std::string srs_generate_vis_tc_url(
std::string ip, std::string vhost, std::string app, int port);
/**
* compare the memory in bytes.
* @return true if completely equal; otherwise, false.
*/
extern bool srs_bytes_equals(void* pa, void* pb, int size);
std::string ip, std::string vhost, std::string app, int port);
/**
* create shared ptr message from bytes.

View file

@ -32,6 +32,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#include <srs_protocol_utility.hpp>
#include <srs_rtmp_stack.hpp>
#include <srs_kernel_buffer.hpp>
#include <srs_kernel_utility.hpp>
#ifdef SRS_AUTO_SSL