mirror of
				https://github.com/ossrs/srs.git
				synced 2025-03-09 15:49:59 +00:00 
			
		
		
		
	for #738, remove the dvr plan append for it's no use
This commit is contained in:
		
							parent
							
								
									8c01f52372
								
							
						
					
					
						commit
						0a054cd6bd
					
				
					 5 changed files with 245 additions and 382 deletions
				
			
		| 
						 | 
					@ -1120,8 +1120,7 @@ vhost dvr.srs.com {
 | 
				
			||||||
        # the dvr plan. canbe:
 | 
					        # the dvr plan. canbe:
 | 
				
			||||||
        #       session reap flv/mp4 when session end(unpublish).
 | 
					        #       session reap flv/mp4 when session end(unpublish).
 | 
				
			||||||
        #       segment reap flv/mp4 when flv duration exceed the specified dvr_duration.
 | 
					        #       segment reap flv/mp4 when flv duration exceed the specified dvr_duration.
 | 
				
			||||||
        #       append always append to flv file, never reap it.
 | 
					        # @remark The plan append is removed in SRS3+, for it's no use.
 | 
				
			||||||
        # @remark MP4 only support session or segment plan, not suport append plan.
 | 
					 | 
				
			||||||
        # default: session
 | 
					        # default: session
 | 
				
			||||||
        dvr_plan        session;
 | 
					        dvr_plan        session;
 | 
				
			||||||
        # the dvr output path, *.flv or *.mp4.
 | 
					        # the dvr output path, *.flv or *.mp4.
 | 
				
			||||||
| 
						 | 
					@ -1159,8 +1158,8 @@ vhost dvr.srs.com {
 | 
				
			||||||
        #       dvr_path ./objs/nginx/html/[app]/[stream].[timestamp].mp4;
 | 
					        #       dvr_path ./objs/nginx/html/[app]/[stream].[timestamp].mp4;
 | 
				
			||||||
        #       =>
 | 
					        #       =>
 | 
				
			||||||
        #       dvr_path ./objs/nginx/html/live/livestream.1420254068776.mp4;
 | 
					        #       dvr_path ./objs/nginx/html/live/livestream.1420254068776.mp4;
 | 
				
			||||||
        # @see https://github.com/ossrs/srs/wiki/v2_CN_DVR#custom-path
 | 
					        # @see https://github.com/ossrs/srs/wiki/v3_CN_DVR#custom-path
 | 
				
			||||||
        # @see https://github.com/ossrs/srs/wiki/v2_EN_DVR#custom-path
 | 
					        # @see https://github.com/ossrs/srs/wiki/v3_EN_DVR#custom-path
 | 
				
			||||||
        #       segment,session apply it.
 | 
					        #       segment,session apply it.
 | 
				
			||||||
        # default: ./objs/nginx/html/[app]/[stream].[timestamp].flv
 | 
					        # default: ./objs/nginx/html/[app]/[stream].[timestamp].flv
 | 
				
			||||||
        dvr_path        ./objs/nginx/html/[app]/[stream].[timestamp].flv;
 | 
					        dvr_path        ./objs/nginx/html/[app]/[stream].[timestamp].flv;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -283,11 +283,6 @@ bool srs_config_dvr_is_plan_session(string plan)
 | 
				
			||||||
    return plan == "session";
 | 
					    return plan == "session";
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool srs_config_dvr_is_plan_append(string plan)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    return plan == "append";
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
bool srs_stream_caster_is_udp(string caster)
 | 
					bool srs_stream_caster_is_udp(string caster)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    return caster == "mpegts_over_udp";
 | 
					    return caster == "mpegts_over_udp";
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -99,7 +99,6 @@ extern bool srs_config_ingest_is_file(std::string type);
 | 
				
			||||||
extern bool srs_config_ingest_is_stream(std::string type);
 | 
					extern bool srs_config_ingest_is_stream(std::string type);
 | 
				
			||||||
extern bool srs_config_dvr_is_plan_segment(std::string plan);
 | 
					extern bool srs_config_dvr_is_plan_segment(std::string plan);
 | 
				
			||||||
extern bool srs_config_dvr_is_plan_session(std::string plan);
 | 
					extern bool srs_config_dvr_is_plan_session(std::string plan);
 | 
				
			||||||
extern bool srs_config_dvr_is_plan_append(std::string plan);
 | 
					 | 
				
			||||||
extern bool srs_stream_caster_is_udp(std::string caster);
 | 
					extern bool srs_stream_caster_is_udp(std::string caster);
 | 
				
			||||||
extern bool srs_stream_caster_is_rtsp(std::string caster);
 | 
					extern bool srs_stream_caster_is_rtsp(std::string caster);
 | 
				
			||||||
extern bool srs_stream_caster_is_flv(std::string caster);
 | 
					extern bool srs_stream_caster_is_flv(std::string caster);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -76,8 +76,8 @@ int SrsDvrSegmenter::initialize(SrsDvrPlan* p, SrsRequest* r)
 | 
				
			||||||
    req = r;
 | 
					    req = r;
 | 
				
			||||||
    plan = p;
 | 
					    plan = p;
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    int jitter = _srs_config->get_dvr_time_jitter(req->vhost);
 | 
					    jitter_algorithm = (SrsRtmpJitterAlgorithm)_srs_config->get_dvr_time_jitter(req->vhost);
 | 
				
			||||||
    jitter_algorithm = (SrsRtmpJitterAlgorithm)jitter;
 | 
					    wait_keyframe = _srs_config->get_dvr_wait_keyframe(req->vhost);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return ret;
 | 
					    return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -92,7 +92,7 @@ bool SrsDvrSegmenter::is_overflow(int64_t max_duration)
 | 
				
			||||||
    return duration >= max_duration;
 | 
					    return duration >= max_duration;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int SrsDvrSegmenter::open(bool use_tmp_file)
 | 
					int SrsDvrSegmenter::open()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    int ret = ERROR_SUCCESS;
 | 
					    int ret = ERROR_SUCCESS;
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
| 
						 | 
					@ -102,10 +102,7 @@ int SrsDvrSegmenter::open(bool use_tmp_file)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    path = generate_path();
 | 
					    path = generate_path();
 | 
				
			||||||
    bool can_append = srs_string_ends_with(path, ".flv");
 | 
					    if (srs_path_exists(path)) {
 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    bool target_exists = srs_path_exists(path);
 | 
					 | 
				
			||||||
    if (!can_append && target_exists) {
 | 
					 | 
				
			||||||
        ret = ERROR_DVR_CANNOT_APPEND;
 | 
					        ret = ERROR_DVR_CANNOT_APPEND;
 | 
				
			||||||
        srs_error("DVR can't append to exists path=%s. ret=%d", path.c_str(), ret);
 | 
					        srs_error("DVR can't append to exists path=%s. ret=%d", path.c_str(), ret);
 | 
				
			||||||
        return ret;
 | 
					        return ret;
 | 
				
			||||||
| 
						 | 
					@ -120,37 +117,23 @@ int SrsDvrSegmenter::open(bool use_tmp_file)
 | 
				
			||||||
    srs_info("create dir=%s ok", dir.c_str());
 | 
					    srs_info("create dir=%s ok", dir.c_str());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // create jitter.
 | 
					    // create jitter.
 | 
				
			||||||
    if ((ret = create_jitter(target_exists)) != ERROR_SUCCESS) {
 | 
					    if ((ret = create_jitter()) != ERROR_SUCCESS) {
 | 
				
			||||||
        srs_error("create jitter failed, path=%s, exists=%d. ret=%d", path.c_str(), target_exists, ret);
 | 
					        srs_error("create jitter failed, path=%s. ret=%d", path.c_str(), ret);
 | 
				
			||||||
        return ret;
 | 
					        return ret;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    // generate the tmp flv path.
 | 
					    // generate the tmp flv path.
 | 
				
			||||||
    if (target_exists || !use_tmp_file) {
 | 
					    tmp_dvr_file = path + ".tmp";
 | 
				
			||||||
        // when path exists, always append to it.
 | 
					 | 
				
			||||||
        // so we must use the target flv path as output flv.
 | 
					 | 
				
			||||||
        tmp_dvr_file = path;
 | 
					 | 
				
			||||||
    } else {
 | 
					 | 
				
			||||||
        // when path not exists, dvr to tmp file.
 | 
					 | 
				
			||||||
        tmp_dvr_file = path + ".tmp";
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    // open file writer, in append or create mode.
 | 
					    // open file writer, in append or create mode.
 | 
				
			||||||
    if (target_exists) {
 | 
					    if ((ret = fs->open(tmp_dvr_file)) != ERROR_SUCCESS) {
 | 
				
			||||||
        if ((ret = fs->open_append(tmp_dvr_file)) != ERROR_SUCCESS) {
 | 
					        srs_error("open file stream for file %s failed. ret=%d", path.c_str(), ret);
 | 
				
			||||||
            srs_error("append file stream for file %s failed. ret=%d", path.c_str(), ret);
 | 
					        return ret;
 | 
				
			||||||
            return ret;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        srs_trace("dvr: always append to when exists, file=%s.", path.c_str());
 | 
					 | 
				
			||||||
    } else {
 | 
					 | 
				
			||||||
        if ((ret = fs->open(tmp_dvr_file)) != ERROR_SUCCESS) {
 | 
					 | 
				
			||||||
            srs_error("open file stream for file %s failed. ret=%d", path.c_str(), ret);
 | 
					 | 
				
			||||||
            return ret;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // initialize the encoder.
 | 
					    // initialize the encoder.
 | 
				
			||||||
    if ((ret = open_encoder()) != ERROR_SUCCESS) {
 | 
					    if ((ret = open_encoder()) != ERROR_SUCCESS) {
 | 
				
			||||||
 | 
					        srs_error("initialize enc by fs for file %s failed. ret=%d", path.c_str(), ret);
 | 
				
			||||||
        return ret;
 | 
					        return ret;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
| 
						 | 
					@ -159,6 +142,62 @@ int SrsDvrSegmenter::open(bool use_tmp_file)
 | 
				
			||||||
    return ret;
 | 
					    return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int SrsDvrSegmenter::write_metadata(SrsSharedPtrMessage* metadata)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    return encode_metadata(metadata);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int SrsDvrSegmenter::write_audio(SrsSharedPtrMessage* shared_audio)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int ret = ERROR_SUCCESS;
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    SrsSharedPtrMessage* audio = shared_audio->copy();
 | 
				
			||||||
 | 
					    SrsAutoFree(SrsSharedPtrMessage, audio);
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    if ((jitter->correct(audio, jitter_algorithm)) != ERROR_SUCCESS) {
 | 
				
			||||||
 | 
					        return ret;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    int64_t timestamp = plan->filter_timestamp(audio->timestamp);
 | 
				
			||||||
 | 
					    if ((ret = encode_audio(audio, timestamp)) != ERROR_SUCCESS) {
 | 
				
			||||||
 | 
					        return ret;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int SrsDvrSegmenter::write_video(SrsSharedPtrMessage* shared_video)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int ret = ERROR_SUCCESS;
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    SrsSharedPtrMessage* video = shared_video->copy();
 | 
				
			||||||
 | 
					    SrsAutoFree(SrsSharedPtrMessage, video);
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    if ((jitter->correct(video, jitter_algorithm)) != ERROR_SUCCESS) {
 | 
				
			||||||
 | 
					        return ret;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    char* payload = video->payload;
 | 
				
			||||||
 | 
					    int size = video->size;
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    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 (is_key_frame) {
 | 
				
			||||||
 | 
					        if ((ret = plan->on_video_keyframe()) != ERROR_SUCCESS) {
 | 
				
			||||||
 | 
					            return ret;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    srs_verbose("dvr video is key: %d", is_key_frame);
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    int64_t timestamp = plan->filter_timestamp(video->timestamp);
 | 
				
			||||||
 | 
					    if ((ret = encode_video(video, timestamp, is_sequence_header, is_key_frame)) != ERROR_SUCCESS) {
 | 
				
			||||||
 | 
					        return ret;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int SrsDvrSegmenter::close()
 | 
					int SrsDvrSegmenter::close()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    int ret = ERROR_SUCCESS;
 | 
					    int ret = ERROR_SUCCESS;
 | 
				
			||||||
| 
						 | 
					@ -214,40 +253,28 @@ string SrsDvrSegmenter::generate_path()
 | 
				
			||||||
    return flv_path;
 | 
					    return flv_path;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int SrsDvrSegmenter::create_jitter(bool target_exists)
 | 
					int SrsDvrSegmenter::create_jitter()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    int ret = ERROR_SUCCESS;
 | 
					    int ret = ERROR_SUCCESS;
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    // When DVR target file not exists, create new jitter.
 | 
					    srs_freep(jitter);
 | 
				
			||||||
    if (!target_exists) {
 | 
					 | 
				
			||||||
        // jitter when publish, ensure whole stream start from 0.
 | 
					 | 
				
			||||||
        srs_freep(jitter);
 | 
					 | 
				
			||||||
        jitter = new SrsRtmpJitter();
 | 
					 | 
				
			||||||
        
 | 
					 | 
				
			||||||
        duration = 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        return ret;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // when jitter ok, do nothing.
 | 
					 | 
				
			||||||
    if (jitter) {
 | 
					 | 
				
			||||||
        return ret;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // always ensure the jitter crote.
 | 
					 | 
				
			||||||
    // for the first time, initialize jitter from exists file.
 | 
					 | 
				
			||||||
    jitter = new SrsRtmpJitter();
 | 
					    jitter = new SrsRtmpJitter();
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
    // TODO: FIXME: implements it.
 | 
					    duration = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return ret;
 | 
					    return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int SrsDvrSegmenter::on_reload_vhost_dvr(std::string /*vhost*/)
 | 
					int SrsDvrSegmenter::on_reload_vhost_dvr(std::string vhost)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    int ret = ERROR_SUCCESS;
 | 
					    int ret = ERROR_SUCCESS;
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
 | 
					    if (req->vhost != vhost) {
 | 
				
			||||||
 | 
					        return ret;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
    jitter_algorithm = (SrsRtmpJitterAlgorithm)_srs_config->get_dvr_time_jitter(req->vhost);
 | 
					    jitter_algorithm = (SrsRtmpJitterAlgorithm)_srs_config->get_dvr_time_jitter(req->vhost);
 | 
				
			||||||
 | 
					    wait_keyframe = _srs_config->get_dvr_wait_keyframe(req->vhost);
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    return ret;
 | 
					    return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -272,73 +299,92 @@ SrsDvrFlvSegmenter::~SrsDvrFlvSegmenter()
 | 
				
			||||||
    srs_freep(enc);
 | 
					    srs_freep(enc);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int SrsDvrFlvSegmenter::refresh_metadata()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int ret = ERROR_SUCCESS;
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    // no duration or filesize specified.
 | 
				
			||||||
 | 
					    if (!duration_offset || !filesize_offset) {
 | 
				
			||||||
 | 
					        return ret;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    int64_t cur = fs->tellg();
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    // buffer to write the size.
 | 
				
			||||||
 | 
					    char* buf = new char[SrsAmf0Size::number()];
 | 
				
			||||||
 | 
					    SrsAutoFreeA(char, buf);
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    SrsBuffer stream;
 | 
				
			||||||
 | 
					    if ((ret = stream.initialize(buf, SrsAmf0Size::number())) != ERROR_SUCCESS) {
 | 
				
			||||||
 | 
					        return ret;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    // filesize to buf.
 | 
				
			||||||
 | 
					    SrsAmf0Any* size = SrsAmf0Any::number((double)cur);
 | 
				
			||||||
 | 
					    SrsAutoFree(SrsAmf0Any, size);
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    stream.skip(-1 * stream.pos());
 | 
				
			||||||
 | 
					    if ((ret = size->write(&stream)) != ERROR_SUCCESS) {
 | 
				
			||||||
 | 
					        return ret;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    // update the flesize.
 | 
				
			||||||
 | 
					    fs->seek2(filesize_offset);
 | 
				
			||||||
 | 
					    if ((ret = fs->write(buf, SrsAmf0Size::number(), NULL)) != ERROR_SUCCESS) {
 | 
				
			||||||
 | 
					        return ret;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    // duration to buf
 | 
				
			||||||
 | 
					    SrsAmf0Any* dur = SrsAmf0Any::number((double)duration / 1000.0);
 | 
				
			||||||
 | 
					    SrsAutoFree(SrsAmf0Any, dur);
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    stream.skip(-1 * stream.pos());
 | 
				
			||||||
 | 
					    if ((ret = dur->write(&stream)) != ERROR_SUCCESS) {
 | 
				
			||||||
 | 
					        return ret;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    // update the duration
 | 
				
			||||||
 | 
					    fs->seek2(duration_offset);
 | 
				
			||||||
 | 
					    if ((ret = fs->write(buf, SrsAmf0Size::number(), NULL)) != ERROR_SUCCESS) {
 | 
				
			||||||
 | 
					        return ret;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    // reset the offset.
 | 
				
			||||||
 | 
					    fs->seek2(cur);
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int SrsDvrFlvSegmenter::open_encoder()
 | 
					int SrsDvrFlvSegmenter::open_encoder()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    int ret = ERROR_SUCCESS;
 | 
					    int ret = ERROR_SUCCESS;
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    if ((ret = enc->initialize(fs)) != ERROR_SUCCESS) {
 | 
					    has_keyframe = false;
 | 
				
			||||||
        srs_error("initialize enc by fs for file %s failed. ret=%d", path.c_str(), ret);
 | 
					 | 
				
			||||||
        return ret;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    bool target_exists = srs_path_exists(path);
 | 
					    // fresh stream starting.
 | 
				
			||||||
    if (target_exists){
 | 
					    starttime = -1;
 | 
				
			||||||
        has_keyframe = false;
 | 
					    stream_previous_pkt_time = -1;
 | 
				
			||||||
        
 | 
					    stream_starttime = srs_update_system_time_ms();
 | 
				
			||||||
        // fresh stream starting.
 | 
					    stream_duration = 0;
 | 
				
			||||||
        starttime = -1;
 | 
					 | 
				
			||||||
        stream_previous_pkt_time = -1;
 | 
					 | 
				
			||||||
        stream_starttime = srs_update_system_time_ms();
 | 
					 | 
				
			||||||
        stream_duration = 0;
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
        // write the flv header to writer.
 | 
					 | 
				
			||||||
        if ((ret = enc->write_header()) != ERROR_SUCCESS) {
 | 
					 | 
				
			||||||
            srs_error("write flv header failed. ret=%d", ret);
 | 
					 | 
				
			||||||
            return ret;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    // update the duration and filesize offset.
 | 
					    // update the duration and filesize offset.
 | 
				
			||||||
    duration_offset = 0;
 | 
					    duration_offset = 0;
 | 
				
			||||||
    filesize_offset = 0;
 | 
					    filesize_offset = 0;
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    return ret;
 | 
					    if ((ret = enc->initialize(fs)) != ERROR_SUCCESS) {
 | 
				
			||||||
}
 | 
					        return ret;
 | 
				
			||||||
 | 
					 | 
				
			||||||
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.
 | 
					    // write the flv header to writer.
 | 
				
			||||||
    if (stream_previous_pkt_time < 0 || stream_previous_pkt_time > msg->timestamp) {
 | 
					    if ((ret = enc->write_header()) != ERROR_SUCCESS) {
 | 
				
			||||||
        stream_previous_pkt_time = msg->timestamp;
 | 
					        srs_error("write flv header failed. ret=%d", ret);
 | 
				
			||||||
 | 
					        return ret;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    // 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;
 | 
					    return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int SrsDvrFlvSegmenter::write_metadata(SrsSharedPtrMessage* metadata)
 | 
					int SrsDvrFlvSegmenter::encode_metadata(SrsSharedPtrMessage* metadata)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    int ret = ERROR_SUCCESS;
 | 
					    int ret = ERROR_SUCCESS;
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
| 
						 | 
					@ -401,21 +447,13 @@ int SrsDvrFlvSegmenter::write_metadata(SrsSharedPtrMessage* metadata)
 | 
				
			||||||
    return ret;
 | 
					    return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int SrsDvrFlvSegmenter::write_audio(SrsSharedPtrMessage* shared_audio)
 | 
					int SrsDvrFlvSegmenter::encode_audio(SrsSharedPtrMessage* audio, int64_t dts)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    int ret = ERROR_SUCCESS;
 | 
					    int ret = ERROR_SUCCESS;
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    SrsSharedPtrMessage* audio = shared_audio->copy();
 | 
					 | 
				
			||||||
    SrsAutoFree(SrsSharedPtrMessage, audio);
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    if ((jitter->correct(audio, jitter_algorithm)) != ERROR_SUCCESS) {
 | 
					 | 
				
			||||||
        return ret;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    char* payload = audio->payload;
 | 
					    char* payload = audio->payload;
 | 
				
			||||||
    int size = audio->size;
 | 
					    int size = audio->size;
 | 
				
			||||||
    int64_t timestamp = plan->filter_timestamp(audio->timestamp);
 | 
					    if ((ret = enc->write_audio(dts, payload, size)) != ERROR_SUCCESS) {
 | 
				
			||||||
    if ((ret = enc->write_audio(timestamp, payload, size)) != ERROR_SUCCESS) {
 | 
					 | 
				
			||||||
        return ret;
 | 
					        return ret;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
| 
						 | 
					@ -426,107 +464,67 @@ int SrsDvrFlvSegmenter::write_audio(SrsSharedPtrMessage* shared_audio)
 | 
				
			||||||
    return ret;
 | 
					    return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int SrsDvrFlvSegmenter::write_video(SrsSharedPtrMessage* shared_video)
 | 
					int SrsDvrFlvSegmenter::encode_video(SrsSharedPtrMessage* video, int64_t dts, bool sh, bool keyframe)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    int ret = ERROR_SUCCESS;
 | 
					    int ret = ERROR_SUCCESS;
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    SrsSharedPtrMessage* video = shared_video->copy();
 | 
					    if (keyframe) {
 | 
				
			||||||
    SrsAutoFree(SrsSharedPtrMessage, video);
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    char* payload = video->payload;
 | 
					 | 
				
			||||||
    int size = video->size;
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    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 (is_key_frame) {
 | 
					 | 
				
			||||||
        has_keyframe = true;
 | 
					        has_keyframe = true;
 | 
				
			||||||
        if ((ret = plan->on_video_keyframe()) != ERROR_SUCCESS) {
 | 
					 | 
				
			||||||
            return ret;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    srs_verbose("dvr video is key: %d", is_key_frame);
 | 
					 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    // accept the sequence header here.
 | 
					    // accept the sequence header here.
 | 
				
			||||||
    // when got no keyframe, ignore when should wait keyframe.
 | 
					    // when got no keyframe, ignore when should wait keyframe.
 | 
				
			||||||
    if (!has_keyframe && !is_sequence_header) {
 | 
					    if (!has_keyframe && !sh) {
 | 
				
			||||||
        bool wait_keyframe = _srs_config->get_dvr_wait_keyframe(req->vhost);
 | 
					 | 
				
			||||||
        if (wait_keyframe) {
 | 
					        if (wait_keyframe) {
 | 
				
			||||||
            srs_info("dvr: ignore when wait keyframe.");
 | 
					            srs_info("dvr: ignore when wait keyframe.");
 | 
				
			||||||
            return ret;
 | 
					            return ret;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    if ((jitter->correct(video, jitter_algorithm)) != ERROR_SUCCESS) {
 | 
					 | 
				
			||||||
        return ret;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    // update segment duration, session plan just update the duration,
 | 
					    // update segment duration, session plan just update the duration,
 | 
				
			||||||
    // the segment plan will reap segment if exceed, this video will write to next segment.
 | 
					    // the segment plan will reap segment if exceed, this video will write to next segment.
 | 
				
			||||||
    if ((ret = on_update_duration(video)) != ERROR_SUCCESS) {
 | 
					    if ((ret = on_update_duration(video)) != ERROR_SUCCESS) {
 | 
				
			||||||
        return ret;
 | 
					        return ret;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    int32_t timestamp = (int32_t)plan->filter_timestamp(video->timestamp);
 | 
					    char* payload = video->payload;
 | 
				
			||||||
    if ((ret = enc->write_video(timestamp, payload, size)) != ERROR_SUCCESS) {
 | 
					    int size = video->size;
 | 
				
			||||||
 | 
					    if ((ret = enc->write_video(dts, payload, size)) != ERROR_SUCCESS) {
 | 
				
			||||||
        return ret;
 | 
					        return ret;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    return ret;
 | 
					    return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int SrsDvrFlvSegmenter::refresh_metadata()
 | 
					int SrsDvrFlvSegmenter::close_encoder()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    return refresh_metadata();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int SrsDvrFlvSegmenter::on_update_duration(SrsSharedPtrMessage* msg)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    int ret = ERROR_SUCCESS;
 | 
					    int ret = ERROR_SUCCESS;
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    // no duration or filesize specified.
 | 
					    // we must assumpt that the stream timestamp is monotonically increase,
 | 
				
			||||||
    if (!duration_offset || !filesize_offset) {
 | 
					    // that is, always use time jitter to correct the timestamp.
 | 
				
			||||||
        return ret;
 | 
					    // except the time jitter is disabled in config.
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    // set the segment starttime at first time
 | 
				
			||||||
 | 
					    if (starttime < 0) {
 | 
				
			||||||
 | 
					        starttime = msg->timestamp;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    int64_t cur = fs->tellg();
 | 
					    // no previous packet or timestamp overflow.
 | 
				
			||||||
    
 | 
					    if (stream_previous_pkt_time < 0 || stream_previous_pkt_time > msg->timestamp) {
 | 
				
			||||||
    // buffer to write the size.
 | 
					        stream_previous_pkt_time = msg->timestamp;
 | 
				
			||||||
    char* buf = new char[SrsAmf0Size::number()];
 | 
					 | 
				
			||||||
    SrsAutoFreeA(char, buf);
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    SrsBuffer stream;
 | 
					 | 
				
			||||||
    if ((ret = stream.initialize(buf, SrsAmf0Size::number())) != ERROR_SUCCESS) {
 | 
					 | 
				
			||||||
        return ret;
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    // filesize to buf.
 | 
					    // collect segment and stream duration, timestamp overflow is ok.
 | 
				
			||||||
    SrsAmf0Any* size = SrsAmf0Any::number((double)cur);
 | 
					    duration += msg->timestamp - stream_previous_pkt_time;
 | 
				
			||||||
    SrsAutoFree(SrsAmf0Any, size);
 | 
					    stream_duration += msg->timestamp - stream_previous_pkt_time;
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    stream.skip(-1 * stream.pos());
 | 
					    // update previous packet time
 | 
				
			||||||
    if ((ret = size->write(&stream)) != ERROR_SUCCESS) {
 | 
					    stream_previous_pkt_time = msg->timestamp;
 | 
				
			||||||
        return ret;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    // update the flesize.
 | 
					 | 
				
			||||||
    fs->seek2(filesize_offset);
 | 
					 | 
				
			||||||
    if ((ret = fs->write(buf, SrsAmf0Size::number(), NULL)) != ERROR_SUCCESS) {
 | 
					 | 
				
			||||||
        return ret;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    // duration to buf
 | 
					 | 
				
			||||||
    SrsAmf0Any* dur = SrsAmf0Any::number((double)duration / 1000.0);
 | 
					 | 
				
			||||||
    SrsAutoFree(SrsAmf0Any, dur);
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    stream.skip(-1 * stream.pos());
 | 
					 | 
				
			||||||
    if ((ret = dur->write(&stream)) != ERROR_SUCCESS) {
 | 
					 | 
				
			||||||
        return ret;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    // update the duration
 | 
					 | 
				
			||||||
    fs->seek2(duration_offset);
 | 
					 | 
				
			||||||
    if ((ret = fs->write(buf, SrsAmf0Size::number(), NULL)) != ERROR_SUCCESS) {
 | 
					 | 
				
			||||||
        return ret;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    // reset the offset.
 | 
					 | 
				
			||||||
    fs->seek2(cur);
 | 
					 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    return ret;
 | 
					    return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -541,42 +539,42 @@ SrsDvrMp4Segmenter::~SrsDvrMp4Segmenter()
 | 
				
			||||||
    srs_freep(enc);
 | 
					    srs_freep(enc);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int SrsDvrMp4Segmenter::refresh_metadata()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int ret = ERROR_SUCCESS;
 | 
				
			||||||
 | 
					    return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int SrsDvrMp4Segmenter::open_encoder()
 | 
					int SrsDvrMp4Segmenter::open_encoder()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    int ret = ERROR_SUCCESS;
 | 
					    int ret = ERROR_SUCCESS;
 | 
				
			||||||
    return ret;
 | 
					    return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int SrsDvrMp4Segmenter::encode_metadata(SrsSharedPtrMessage* metadata)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int ret = ERROR_SUCCESS;
 | 
				
			||||||
 | 
					    return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int SrsDvrMp4Segmenter::encode_audio(SrsSharedPtrMessage* audio, int64_t dts)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int ret = ERROR_SUCCESS;
 | 
				
			||||||
 | 
					    return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int SrsDvrMp4Segmenter::encode_video(SrsSharedPtrMessage* video, int64_t dts, bool sh, bool keyframe)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int ret = ERROR_SUCCESS;
 | 
				
			||||||
 | 
					    return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int SrsDvrMp4Segmenter::close_encoder()
 | 
					int SrsDvrMp4Segmenter::close_encoder()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    int ret = ERROR_SUCCESS;
 | 
					    int ret = ERROR_SUCCESS;
 | 
				
			||||||
    return ret;
 | 
					    return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int SrsDvrMp4Segmenter::write_metadata(SrsSharedPtrMessage* metadata)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    int ret = ERROR_SUCCESS;
 | 
					 | 
				
			||||||
    return ret;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int SrsDvrMp4Segmenter::write_audio(SrsSharedPtrMessage* shared_audio)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    int ret = ERROR_SUCCESS;
 | 
					 | 
				
			||||||
    return ret;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int SrsDvrMp4Segmenter::write_video(SrsSharedPtrMessage* shared_video)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    int ret = ERROR_SUCCESS;
 | 
					 | 
				
			||||||
    return ret;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int SrsDvrMp4Segmenter::refresh_metadata()
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    int ret = ERROR_SUCCESS;
 | 
					 | 
				
			||||||
    return ret;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
SrsDvrAsyncCallOnDvr::SrsDvrAsyncCallOnDvr(int c, SrsRequest* r, string p)
 | 
					SrsDvrAsyncCallOnDvr::SrsDvrAsyncCallOnDvr(int c, SrsRequest* r, string p)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    cid = c;
 | 
					    cid = c;
 | 
				
			||||||
| 
						 | 
					@ -732,23 +730,14 @@ int SrsDvrPlan::create_plan(string vhost, SrsDvrPlan** pplan)
 | 
				
			||||||
    int ret = ERROR_SUCCESS;
 | 
					    int ret = ERROR_SUCCESS;
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    std::string plan = _srs_config->get_dvr_plan(vhost);
 | 
					    std::string plan = _srs_config->get_dvr_plan(vhost);
 | 
				
			||||||
    std::string path = _srs_config->get_dvr_path(vhost);
 | 
					 | 
				
			||||||
    bool is_mp4 = srs_string_ends_with(path, ".mp4");
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    if (srs_config_dvr_is_plan_segment(plan)) {
 | 
					    if (srs_config_dvr_is_plan_segment(plan)) {
 | 
				
			||||||
        *pplan = new SrsDvrSegmentPlan();
 | 
					        *pplan = new SrsDvrSegmentPlan();
 | 
				
			||||||
    } else if (srs_config_dvr_is_plan_session(plan)) {
 | 
					    } else if (srs_config_dvr_is_plan_session(plan)) {
 | 
				
			||||||
        *pplan = new SrsDvrSessionPlan();
 | 
					        *pplan = new SrsDvrSessionPlan();
 | 
				
			||||||
    } else if (srs_config_dvr_is_plan_append(plan)) {
 | 
					 | 
				
			||||||
        if (is_mp4) {
 | 
					 | 
				
			||||||
            ret = ERROR_DVR_ILLEGAL_PLAN;
 | 
					 | 
				
			||||||
            srs_error("DVR plan append not support MP4. ret=%d", ret);
 | 
					 | 
				
			||||||
            return ret;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        *pplan = new SrsDvrAppendPlan();
 | 
					 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
        srs_error("invalid dvr plan=%s, vhost=%s", plan.c_str(), vhost.c_str());
 | 
					        ret = ERROR_DVR_ILLEGAL_PLAN;
 | 
				
			||||||
        srs_assert(false);
 | 
					        srs_error("DVR illegal plan=%s, vhost=%s. ret=%d", plan.c_str(), vhost.c_str(), ret);
 | 
				
			||||||
 | 
					        return ret;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    return ret;
 | 
					    return ret;
 | 
				
			||||||
| 
						 | 
					@ -779,7 +768,7 @@ int SrsDvrSessionPlan::on_publish()
 | 
				
			||||||
        return ret;
 | 
					        return ret;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if ((ret = segment->open(true)) != ERROR_SUCCESS) {
 | 
					    if ((ret = segment->open()) != ERROR_SUCCESS) {
 | 
				
			||||||
        return ret;
 | 
					        return ret;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -804,98 +793,6 @@ void SrsDvrSessionPlan::on_unpublish()
 | 
				
			||||||
    dvr_enabled = false;
 | 
					    dvr_enabled = false;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
SrsDvrAppendPlan::SrsDvrAppendPlan()
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    last_update_time = 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
SrsDvrAppendPlan::~SrsDvrAppendPlan()
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int SrsDvrAppendPlan::on_publish()
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    int ret = ERROR_SUCCESS;
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    // support multiple publish.
 | 
					 | 
				
			||||||
    if (dvr_enabled) {
 | 
					 | 
				
			||||||
        return ret;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (!_srs_config->get_dvr_enabled(req->vhost)) {
 | 
					 | 
				
			||||||
        return ret;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if ((ret = segment->open(false)) != ERROR_SUCCESS) {
 | 
					 | 
				
			||||||
        return ret;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    dvr_enabled = true;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return ret;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void SrsDvrAppendPlan::on_unpublish()
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int SrsDvrAppendPlan::on_audio(SrsSharedPtrMessage* shared_audio)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    int ret = ERROR_SUCCESS;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if ((ret = update_duration(shared_audio)) != ERROR_SUCCESS) {
 | 
					 | 
				
			||||||
        return ret;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    if ((ret = SrsDvrPlan::on_audio(shared_audio)) != ERROR_SUCCESS) {
 | 
					 | 
				
			||||||
        return ret;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return ret;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int SrsDvrAppendPlan::on_video(SrsSharedPtrMessage* shared_video)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    int ret = ERROR_SUCCESS;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if ((ret = update_duration(shared_video)) != ERROR_SUCCESS) {
 | 
					 | 
				
			||||||
        return ret;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    if ((ret = SrsDvrPlan::on_video(shared_video)) != ERROR_SUCCESS) {
 | 
					 | 
				
			||||||
        return ret;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return ret;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int SrsDvrAppendPlan::update_duration(SrsSharedPtrMessage* msg)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    int ret = ERROR_SUCCESS;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (last_update_time <= 0) {
 | 
					 | 
				
			||||||
        last_update_time = msg->timestamp;
 | 
					 | 
				
			||||||
        return ret;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (msg->timestamp < last_update_time) {
 | 
					 | 
				
			||||||
        last_update_time = msg->timestamp;
 | 
					 | 
				
			||||||
        return ret;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (SRS_DVR_UPDATE_DURATION_INTERVAL > msg->timestamp - last_update_time) {
 | 
					 | 
				
			||||||
        return ret;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    last_update_time = msg->timestamp;
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    srs_assert(segment);
 | 
					 | 
				
			||||||
    if ((ret = segment->refresh_metadata()) != ERROR_SUCCESS) {
 | 
					 | 
				
			||||||
        return ret;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return ret;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
SrsDvrSegmentPlan::SrsDvrSegmentPlan()
 | 
					SrsDvrSegmentPlan::SrsDvrSegmentPlan()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    segment_duration = -1;
 | 
					    segment_duration = -1;
 | 
				
			||||||
| 
						 | 
					@ -941,7 +838,7 @@ int SrsDvrSegmentPlan::on_publish()
 | 
				
			||||||
        return ret;
 | 
					        return ret;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if ((ret = segment->open(true)) != ERROR_SUCCESS) {
 | 
					    if ((ret = segment->open()) != ERROR_SUCCESS) {
 | 
				
			||||||
        return ret;
 | 
					        return ret;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1042,7 +939,7 @@ int SrsDvrSegmentPlan::update_duration(SrsSharedPtrMessage* msg)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    // open new flv file
 | 
					    // open new flv file
 | 
				
			||||||
    if ((ret = segment->open(true)) != ERROR_SUCCESS) {
 | 
					    if ((ret = segment->open()) != ERROR_SUCCESS) {
 | 
				
			||||||
        return ret;
 | 
					        return ret;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -59,62 +59,54 @@ class SrsMp4Encoder;
 | 
				
			||||||
class SrsDvrSegmenter : public ISrsReloadHandler
 | 
					class SrsDvrSegmenter : public ISrsReloadHandler
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
protected:
 | 
					protected:
 | 
				
			||||||
 | 
					    // The underlayer file object.
 | 
				
			||||||
    SrsFileWriter* fs;
 | 
					    SrsFileWriter* fs;
 | 
				
			||||||
    // The path of current segment flv file path.
 | 
					 | 
				
			||||||
    std::string path;
 | 
					 | 
				
			||||||
protected:
 | 
					 | 
				
			||||||
    SrsRtmpJitter* jitter;
 | 
					 | 
				
			||||||
    SrsRtmpJitterAlgorithm jitter_algorithm;
 | 
					 | 
				
			||||||
    // The duration in ms of current segment.
 | 
					    // The duration in ms of current segment.
 | 
				
			||||||
    int64_t duration;
 | 
					    int64_t duration;
 | 
				
			||||||
protected:
 | 
					    // Whether wait keyframe to reap segment.
 | 
				
			||||||
 | 
					    bool wait_keyframe;
 | 
				
			||||||
 | 
					private:
 | 
				
			||||||
 | 
					    // The path of current segment flv file path.
 | 
				
			||||||
 | 
					    std::string path;
 | 
				
			||||||
    SrsRequest* req;
 | 
					    SrsRequest* req;
 | 
				
			||||||
    SrsDvrPlan* plan;
 | 
					    SrsDvrPlan* plan;
 | 
				
			||||||
private:
 | 
					 | 
				
			||||||
    std::string tmp_dvr_file;
 | 
					    std::string tmp_dvr_file;
 | 
				
			||||||
 | 
					    SrsRtmpJitter* jitter;
 | 
				
			||||||
 | 
					    SrsRtmpJitterAlgorithm jitter_algorithm;
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
    SrsDvrSegmenter();
 | 
					    SrsDvrSegmenter();
 | 
				
			||||||
    virtual ~SrsDvrSegmenter();
 | 
					    virtual ~SrsDvrSegmenter();
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
    /**
 | 
					    // Initialize the segment.
 | 
				
			||||||
    * initialize the segment.
 | 
					 | 
				
			||||||
    */
 | 
					 | 
				
			||||||
    virtual int initialize(SrsDvrPlan* p, SrsRequest* r);
 | 
					    virtual int initialize(SrsDvrPlan* p, SrsRequest* r);
 | 
				
			||||||
    /**
 | 
					    // Get the current dvr path.
 | 
				
			||||||
     * get the current dvr path.
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    virtual std::string get_path();
 | 
					    virtual std::string get_path();
 | 
				
			||||||
    /**
 | 
					    // Whether segment is overflow.
 | 
				
			||||||
    * whether segment is overflow.
 | 
					 | 
				
			||||||
    */
 | 
					 | 
				
			||||||
    virtual bool is_overflow(int64_t max_duration);
 | 
					    virtual bool is_overflow(int64_t max_duration);
 | 
				
			||||||
    /**
 | 
					    // Open new segment file.
 | 
				
			||||||
    * open new segment file, timestamp start at 0 for fresh flv file.
 | 
					    // @param use_tmp_file Whether use tmp file for DVR, and rename when close.
 | 
				
			||||||
    * @remark ignore when already open.
 | 
					    // @remark Ignore when file is already open.
 | 
				
			||||||
    * @param use_tmp_file whether use tmp file if possible.
 | 
					    virtual int open();
 | 
				
			||||||
    */
 | 
					 | 
				
			||||||
    virtual int open(bool use_tmp_file);
 | 
					 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
    * close current segment.
 | 
					 | 
				
			||||||
    * @remark ignore when already closed.
 | 
					 | 
				
			||||||
    */
 | 
					 | 
				
			||||||
    virtual int close();
 | 
					 | 
				
			||||||
protected:
 | 
					 | 
				
			||||||
    virtual int open_encoder() = 0;
 | 
					 | 
				
			||||||
public:
 | 
					 | 
				
			||||||
    // Write the metadata.
 | 
					    // Write the metadata.
 | 
				
			||||||
    virtual int write_metadata(SrsSharedPtrMessage* metadata) = 0;
 | 
					    virtual int write_metadata(SrsSharedPtrMessage* metadata);
 | 
				
			||||||
    // Write audio packet.
 | 
					    // Write audio packet.
 | 
				
			||||||
    // @param shared_audio, directly ptr, copy it if need to save it.
 | 
					    // @param shared_audio, directly ptr, copy it if need to save it.
 | 
				
			||||||
    virtual int write_audio(SrsSharedPtrMessage* shared_audio) = 0;
 | 
					    virtual int write_audio(SrsSharedPtrMessage* shared_audio);
 | 
				
			||||||
    // Write video packet.
 | 
					    // Write video packet.
 | 
				
			||||||
    // @param shared_video, directly ptr, copy it if need to save it.
 | 
					    // @param shared_video, directly ptr, copy it if need to save it.
 | 
				
			||||||
    virtual int write_video(SrsSharedPtrMessage* shared_video) = 0;
 | 
					    virtual int write_video(SrsSharedPtrMessage* shared_video);
 | 
				
			||||||
    // Refresh the metadata. For example, there is duration in flv metadata,
 | 
					    // Refresh the metadata. For example, there is duration in flv metadata,
 | 
				
			||||||
    // when DVR in append mode, the duration must be update every some seconds.
 | 
					    // when DVR in append mode, the duration must be update every some seconds.
 | 
				
			||||||
    // @remark Maybe ignored by concreate segmenter.
 | 
					    // @remark Maybe ignored by concreate segmenter.
 | 
				
			||||||
    virtual int refresh_metadata() = 0;
 | 
					    virtual int refresh_metadata() = 0;
 | 
				
			||||||
 | 
					    // Close current segment.
 | 
				
			||||||
 | 
					    // @remark ignore when already closed.
 | 
				
			||||||
 | 
					    virtual int close();
 | 
				
			||||||
protected:
 | 
					protected:
 | 
				
			||||||
 | 
					    virtual int open_encoder() = 0;
 | 
				
			||||||
 | 
					    virtual int encode_metadata(SrsSharedPtrMessage* metadata) = 0;
 | 
				
			||||||
 | 
					    virtual int encode_audio(SrsSharedPtrMessage* audio, int64_t dts) = 0;
 | 
				
			||||||
 | 
					    virtual int encode_video(SrsSharedPtrMessage* video, int64_t dts, bool sh, bool keyframe) = 0;
 | 
				
			||||||
    virtual int close_encoder() = 0;
 | 
					    virtual int close_encoder() = 0;
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
| 
						 | 
					@ -125,7 +117,7 @@ private:
 | 
				
			||||||
    * create flv jitter. load jitter when flv exists.
 | 
					    * create flv jitter. load jitter when flv exists.
 | 
				
			||||||
    * @param target_exists whether loads the jitter from exists flv file.
 | 
					    * @param target_exists whether loads the jitter from exists flv file.
 | 
				
			||||||
    */
 | 
					    */
 | 
				
			||||||
    virtual int create_jitter(bool target_exists);
 | 
					    virtual int create_jitter();
 | 
				
			||||||
// interface ISrsReloadHandler
 | 
					// interface ISrsReloadHandler
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
    virtual int on_reload_vhost_dvr(std::string vhost);
 | 
					    virtual int on_reload_vhost_dvr(std::string vhost);
 | 
				
			||||||
| 
						 | 
					@ -164,17 +156,17 @@ private:
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
    SrsDvrFlvSegmenter();
 | 
					    SrsDvrFlvSegmenter();
 | 
				
			||||||
    virtual ~SrsDvrFlvSegmenter();
 | 
					    virtual ~SrsDvrFlvSegmenter();
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
					    virtual int refresh_metadata();
 | 
				
			||||||
protected:
 | 
					protected:
 | 
				
			||||||
    virtual int open_encoder();
 | 
					    virtual int open_encoder();
 | 
				
			||||||
 | 
					    virtual int encode_metadata(SrsSharedPtrMessage* metadata);
 | 
				
			||||||
 | 
					    virtual int encode_audio(SrsSharedPtrMessage* audio, int64_t dts);
 | 
				
			||||||
 | 
					    virtual int encode_video(SrsSharedPtrMessage* video, int64_t dts, bool sh, bool keyframe);
 | 
				
			||||||
    virtual int close_encoder();
 | 
					    virtual int close_encoder();
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
    // When update the duration of segment by rtmp msg.
 | 
					    // When update the duration of segment by rtmp msg.
 | 
				
			||||||
    virtual int on_update_duration(SrsSharedPtrMessage* msg);
 | 
					    virtual int on_update_duration(SrsSharedPtrMessage* msg);
 | 
				
			||||||
public:
 | 
					 | 
				
			||||||
    virtual int write_metadata(SrsSharedPtrMessage* metadata);
 | 
					 | 
				
			||||||
    virtual int write_audio(SrsSharedPtrMessage* shared_audio);
 | 
					 | 
				
			||||||
    virtual int write_video(SrsSharedPtrMessage* shared_video);
 | 
					 | 
				
			||||||
    virtual int refresh_metadata();
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
| 
						 | 
					@ -188,14 +180,14 @@ private:
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
    SrsDvrMp4Segmenter();
 | 
					    SrsDvrMp4Segmenter();
 | 
				
			||||||
    virtual ~SrsDvrMp4Segmenter();
 | 
					    virtual ~SrsDvrMp4Segmenter();
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
					    virtual int refresh_metadata();
 | 
				
			||||||
protected:
 | 
					protected:
 | 
				
			||||||
    virtual int open_encoder();
 | 
					    virtual int open_encoder();
 | 
				
			||||||
 | 
					    virtual int encode_metadata(SrsSharedPtrMessage* metadata);
 | 
				
			||||||
 | 
					    virtual int encode_audio(SrsSharedPtrMessage* audio, int64_t dts);
 | 
				
			||||||
 | 
					    virtual int encode_video(SrsSharedPtrMessage* video, int64_t dts, bool sh, bool keyframe);
 | 
				
			||||||
    virtual int close_encoder();
 | 
					    virtual int close_encoder();
 | 
				
			||||||
public:
 | 
					 | 
				
			||||||
    virtual int write_metadata(SrsSharedPtrMessage* metadata);
 | 
					 | 
				
			||||||
    virtual int write_audio(SrsSharedPtrMessage* shared_audio);
 | 
					 | 
				
			||||||
    virtual int write_video(SrsSharedPtrMessage* shared_video);
 | 
					 | 
				
			||||||
    virtual int refresh_metadata();
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
| 
						 | 
					@ -274,25 +266,6 @@ public:
 | 
				
			||||||
    virtual void on_unpublish();
 | 
					    virtual void on_unpublish();
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
* always append to flv file, never reap it.
 | 
					 | 
				
			||||||
*/
 | 
					 | 
				
			||||||
class SrsDvrAppendPlan : public SrsDvrPlan
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
private:
 | 
					 | 
				
			||||||
    int64_t last_update_time;
 | 
					 | 
				
			||||||
public:
 | 
					 | 
				
			||||||
    SrsDvrAppendPlan();
 | 
					 | 
				
			||||||
    virtual ~SrsDvrAppendPlan();
 | 
					 | 
				
			||||||
public:
 | 
					 | 
				
			||||||
    virtual int on_publish();
 | 
					 | 
				
			||||||
    virtual void on_unpublish();
 | 
					 | 
				
			||||||
    virtual int on_audio(SrsSharedPtrMessage* shared_audio);
 | 
					 | 
				
			||||||
    virtual int on_video(SrsSharedPtrMessage* shared_video);
 | 
					 | 
				
			||||||
private:
 | 
					 | 
				
			||||||
    virtual int update_duration(SrsSharedPtrMessage* msg);
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
* segment plan: reap flv when duration exceed.
 | 
					* segment plan: reap flv when duration exceed.
 | 
				
			||||||
*/
 | 
					*/
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue