void SrsEncoder::encoder_cycle()
{
	int ret = ERROR_SUCCESS;
	
	log_context->generate_id();
	srs_trace("encoder cycle start");
	
	while (loop) {
		if ((ret = cycle()) != ERROR_SUCCESS) {
			srs_warn("encoder cycle failed, ignored and retry, ret=%d", ret);
		} else {
			srs_info("encoder cycle success, retry");
		}
		
		if (!loop) {
			break;
		}
		
		st_usleep(SRS_ENCODER_SLEEP_MS * 1000);
	}
	
	// kill ffmpeg when finished and it alive
	std::vector<SrsFFMPEG*>::iterator it;
	for (it = ffmpegs.begin(); it != ffmpegs.end(); ++it) {
		SrsFFMPEG* ffmpeg = *it;
		ffmpeg->stop();
	}
	
	srs_trace("encoder cycle finished");
}
int SrsEncoder::parse_transcode(SrsConfDirective* conf)
{
	int ret = ERROR_SUCCESS;
	
	srs_assert(conf);
	
	// enabled
	if (!config->get_transcode_enabled(conf)) {
		srs_trace("ignore the disabled transcode: %s", 
			conf->arg0().c_str());
		return ret;
	}
	
	// ffmpeg
	std::string ffmpeg_bin = config->get_transcode_ffmpeg(conf);
	if (ffmpeg_bin.empty()) {
		srs_trace("ignore the empty ffmpeg transcode: %s", 
			conf->arg0().c_str());
		return ret;
	}
	
	// get all engines.
	std::vector<SrsConfDirective*> engines;
	config->get_transcode_engines(conf, engines);
	if (engines.empty()) {
		srs_trace("ignore the empty transcode engine: %s", 
			conf->arg0().c_str());
		return ret;
	}
	
	// create engine
	for (int i = 0; i < (int)engines.size(); i++) {
		SrsConfDirective* engine = engines[i];
		if (!config->get_engine_enabled(engine)) {
			srs_trace("ignore the diabled transcode engine: %s %s", 
				conf->arg0().c_str(), engine->arg0().c_str());
			continue;
		}
		
		SrsFFMPEG* ffmpeg = new SrsFFMPEG(ffmpeg_bin);
		
		if ((ret = ffmpeg->initialize(vhost, port, app, stream, engine)) != ERROR_SUCCESS) {
			srs_freep(ffmpeg);
			
			// if got a loop, donot transcode the whole stream.
			if (ret == ERROR_ENCODER_LOOP) {
				clear_engines();
				break;
			}
			
			srs_error("invalid transcode engine: %s %s", 
				conf->arg0().c_str(), engine->arg0().c_str());
			return ret;
		}

		ffmpegs.push_back(ffmpeg);
	}
	
	return ret;
}
int SrsEncoder::cycle()
{
    int ret = ERROR_SUCCESS;
    
    std::vector<SrsFFMPEG*>::iterator it;
    for (it = ffmpegs.begin(); it != ffmpegs.end(); ++it) {
        SrsFFMPEG* ffmpeg = *it;
        
        // start all ffmpegs.
        if ((ret = ffmpeg->start()) != ERROR_SUCCESS) {
            srs_error("transcode ffmpeg start failed. ret=%d", ret);
            return ret;
        }

        // check ffmpeg status.
        if ((ret = ffmpeg->cycle()) != ERROR_SUCCESS) {
            srs_error("transcode ffmpeg cycle failed. ret=%d", ret);
            return ret;
        }
    }

    // pithy print
    encoder();
    pithy_print->elapse();
    
    return ret;
}
void SrsEncoder::on_thread_stop()
{
    // kill ffmpeg when finished and it alive
    std::vector<SrsFFMPEG*>::iterator it;

    for (it = ffmpegs.begin(); it != ffmpegs.end(); ++it) {
        SrsFFMPEG* ffmpeg = *it;
        ffmpeg->stop();
    }
}
int SrsEncoder::cycle()
{
	int ret = ERROR_SUCCESS;
	
	// start all ffmpegs.
	std::vector<SrsFFMPEG*>::iterator it;
	for (it = ffmpegs.begin(); it != ffmpegs.end(); ++it) {
		SrsFFMPEG* ffmpeg = *it;
		if ((ret = ffmpeg->start()) != ERROR_SUCCESS) {
			srs_error("ffmpeg start failed. ret=%d", ret);
			return ret;
		}
	}
	
	return ret;
}
void SrsEncoder::clear_engines()
{
    std::vector<SrsFFMPEG*>::iterator it;
    
    for (it = ffmpegs.begin(); it != ffmpegs.end(); ++it) {
        SrsFFMPEG* ffmpeg = *it;
    
        std::string output = ffmpeg->output();
        
        std::vector<std::string>::iterator it;
        it = std::find(_transcoded_url.begin(), _transcoded_url.end(), output);
        if (it != _transcoded_url.end()) {
            _transcoded_url.erase(it);
        }
        
        srs_freep(ffmpeg);
    }

    ffmpegs.clear();
}