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:
parent
3209ad29e0
commit
afbc3443f3
12 changed files with 1264 additions and 222 deletions
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
};
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
Loading…
Reference in a new issue