diff --git a/trunk/src/core/srs_core_client.cpp b/trunk/src/core/srs_core_client.cpp index f88a372c6..4df02c14c 100644 --- a/trunk/src/core/srs_core_client.cpp +++ b/trunk/src/core/srs_core_client.cpp @@ -332,7 +332,7 @@ int SrsClient::publish(SrsSource* source, bool is_fmle) SrsPithyPrint pithy_print(SRS_STAGE_PUBLISH_USER); // notify the hls to prepare when publish start. - if ((ret = source->on_publish(req->vhost)) != ERROR_SUCCESS) { + if ((ret = source->on_publish(req->vhost, req->stream)) != ERROR_SUCCESS) { srs_error("hls on_publish failed. ret=%d", ret); return ret; } diff --git a/trunk/src/core/srs_core_hls.cpp b/trunk/src/core/srs_core_hls.cpp index 3caaa9ec0..522226dc6 100644 --- a/trunk/src/core/srs_core_hls.cpp +++ b/trunk/src/core/srs_core_hls.cpp @@ -37,194 +37,18 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include #include -SrsHLS::SrsHLS() -{ - hls_enabled = false; - codec = new SrsCodec(); - sample = new SrsCodecSample(); - muxer = NULL; - jitter = new SrsRtmpJitter(); -} - -SrsHLS::~SrsHLS() -{ - srs_freep(codec); - srs_freep(sample); - srs_freep(muxer); - srs_freep(jitter); -} - -int SrsHLS::on_publish(std::string _vhost) -{ - int ret = ERROR_SUCCESS; - - // TODO: check config. - if (muxer) { - hls_enabled = true; - srs_trace("hls is reopen, continue streaming HLS, vhost=%s", _vhost.c_str()); - return ret; - } - - vhost = _vhost; - muxer = new SrsTSMuxer(); - - // try to open the HLS muxer - SrsConfDirective* conf = config->get_hls(vhost); - if (!conf && conf->arg0() == "off") { - return ret; - } - - // TODO: check the audio and video, ensure both exsists. - // for use fixed mpegts header specifeid the audio and video pid. - - hls_enabled = true; - - std::string path = SRS_CONF_DEFAULT_HLS_PATH; - if ((conf = config->get_hls_path(vhost)) != NULL) { - path = conf->arg0(); - } - - // TODO: generate by m3u8 muxer. - path += "/1.ts"; - - if ((ret = muxer->open(path)) != ERROR_SUCCESS) { - srs_error("open hls muxer failed. ret=%d", ret); - return ret; - } - - return ret; -} - -void SrsHLS::on_unpublish() -{ - hls_enabled = false; - //muxer->close(); - //srs_freep(muxer); -} - -int SrsHLS::on_meta_data(SrsOnMetaDataPacket* metadata) -{ - int ret = ERROR_SUCCESS; - - if (!metadata || !metadata->metadata) { - srs_trace("no metadata persent, hls ignored it."); - return ret; - } - - SrsAmf0Object* obj = metadata->metadata; - if (obj->size() <= 0) { - srs_trace("no metadata persent, hls ignored it."); - return ret; - } - - // finger out the codec info from metadata if possible. - SrsAmf0Any* prop = NULL; - - if ((prop = obj->get_property("duration")) != NULL && prop->is_number()) { - codec->duration = (int)srs_amf0_convert(prop)->value; - } - if ((prop = obj->get_property("width")) != NULL && prop->is_number()) { - codec->width = (int)srs_amf0_convert(prop)->value; - } - if ((prop = obj->get_property("height")) != NULL && prop->is_number()) { - codec->height = (int)srs_amf0_convert(prop)->value; - } - if ((prop = obj->get_property("framerate")) != NULL && prop->is_number()) { - codec->frame_rate = (int)srs_amf0_convert(prop)->value; - } - if ((prop = obj->get_property("videocodecid")) != NULL && prop->is_number()) { - codec->video_codec_id = (int)srs_amf0_convert(prop)->value; - } - if ((prop = obj->get_property("videodatarate")) != NULL && prop->is_number()) { - codec->video_data_rate = (int)(1000 * srs_amf0_convert(prop)->value); - } - - if ((prop = obj->get_property("audiocodecid")) != NULL && prop->is_number()) { - codec->audio_codec_id = (int)srs_amf0_convert(prop)->value; - } - if ((prop = obj->get_property("audiodatarate")) != NULL && prop->is_number()) { - codec->audio_data_rate = (int)(1000 * srs_amf0_convert(prop)->value); - } - - // ignore the following, for each flv/rtmp packet contains them: - // audiosamplerate, sample->sound_rate - // audiosamplesize, sample->sound_size - // stereo, sample->sound_type - - return ret; -} +// @see: NGX_RTMP_HLS_DELAY, +// 63000: 700ms, ts_tbn=90000 +#define SRS_HLS_DELAY 63000 -int SrsHLS::on_audio(SrsSharedPtrMessage* audio) -{ - int ret = ERROR_SUCCESS; - - SrsAutoFree(SrsSharedPtrMessage, audio, false); - - sample->clear(); - if ((ret = codec->audio_aac_demux(audio->payload, audio->size, sample)) != ERROR_SUCCESS) { - return ret; - } - - if (codec->audio_codec_id != SrsCodecAudioAAC) { - return ret; - } - - // TODO: maybe donot need to demux the aac? - if (!hls_enabled) { - return ret; - } - - // ignore sequence header - if (sample->aac_packet_type == SrsCodecAudioTypeSequenceHeader) { - return ret; - } - - if ((ret = jitter->correct(audio, 0, 0)) != ERROR_SUCCESS) { - return ret; - } - - if ((ret = muxer->write_audio(audio->header.timestamp, codec, sample)) != ERROR_SUCCESS) { - return ret; - } - - return ret; -} +// the mpegts header specifed the video/audio pid. +#define TS_VIDEO_PID 256 +#define TS_AUDIO_PID 257 -int SrsHLS::on_video(SrsSharedPtrMessage* video) -{ - int ret = ERROR_SUCCESS; - - SrsAutoFree(SrsSharedPtrMessage, video, false); - - sample->clear(); - if ((ret = codec->video_avc_demux(video->payload, video->size, sample)) != ERROR_SUCCESS) { - return ret; - } - - if (codec->video_codec_id != SrsCodecVideoAVC) { - return ret; - } - - // TODO: maybe donot need to demux the avc? - if (!hls_enabled) { - return ret; - } - - // ignore sequence header - if (sample->frame_type == SrsCodecVideoAVCFrameKeyFrame && sample->avc_packet_type == SrsCodecVideoAVCTypeSequenceHeader) { - return ret; - } - - if ((ret = jitter->correct(video, 0, 0)) != ERROR_SUCCESS) { - return ret; - } - - if ((ret = muxer->write_video(video->header.timestamp, codec, sample)) != ERROR_SUCCESS) { - return ret; - } - - return ret; -} +// ts aac stream id. +#define TS_AUDIO_AAC 0xc0 +// ts avc stream id. +#define TS_VIDEO_AVC 0xe0 // @see: ngx_rtmp_mpegts_header u_int8_t mpegts_header[] = { @@ -287,10 +111,6 @@ u_int8_t mpegts_header[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; -// @see: NGX_RTMP_HLS_DELAY, -// 63000: 700ms, ts_tbn=90000 -#define SRS_HLS_DELAY 63000 - // @see: ngx_rtmp_SrsMpegtsFrame_t struct SrsMpegtsFrame { @@ -527,18 +347,29 @@ private: } }; -// the mpegts header specifed the video/audio pid. -#define TS_VIDEO_PID 256 -#define TS_AUDIO_PID 257 +SrsM3u8Segment::SrsM3u8Segment() +{ + duration = 0; + sequence_no = 0; + muxer = new SrsTSMuxer(); + segment_start_dts = 0; +} -// ts aac stream id. -#define TS_AUDIO_AAC 0xc0 -// ts avc stream id. -#define TS_VIDEO_AVC 0xe0 +SrsM3u8Segment::~SrsM3u8Segment() +{ + muxer->close(); + srs_freep(muxer); +} -SrsTSMuxer::SrsTSMuxer() +SrsHLS::SrsHLS() { - fd = -1; + hls_enabled = false; + codec = new SrsCodec(); + sample = new SrsCodecSample(); + current = NULL; + jitter = new SrsRtmpJitter(); + file_index = 0; + m3u8_dts = stream_dts = 0; audio_buffer = new SrsCodecBuffer(); video_buffer = new SrsCodecBuffer(); @@ -547,9 +378,20 @@ SrsTSMuxer::SrsTSMuxer() video_frame = new SrsMpegtsFrame(); } -SrsTSMuxer::~SrsTSMuxer() +SrsHLS::~SrsHLS() { - close(); + srs_freep(codec); + srs_freep(sample); + srs_freep(jitter); + + std::vector::iterator it; + for (it = segments.begin(); it != segments.end(); ++it) { + SrsM3u8Segment* segment = *it; + srs_freep(segment); + } + segments.clear(); + + srs_freep(current); audio_buffer->free(); video_buffer->free(); @@ -561,6 +403,346 @@ SrsTSMuxer::~SrsTSMuxer() srs_freep(video_frame); } +int SrsHLS::on_publish(std::string _vhost, std::string _stream) +{ + int ret = ERROR_SUCCESS; + + vhost = _vhost; + stream = _stream; + + if ((ret = reopen()) != ERROR_SUCCESS) { + return ret; + } + + return ret; +} + +void SrsHLS::on_unpublish() +{ + hls_enabled = false; +} + +int SrsHLS::on_meta_data(SrsOnMetaDataPacket* metadata) +{ + int ret = ERROR_SUCCESS; + + if (!metadata || !metadata->metadata) { + srs_trace("no metadata persent, hls ignored it."); + return ret; + } + + SrsAmf0Object* obj = metadata->metadata; + if (obj->size() <= 0) { + srs_trace("no metadata persent, hls ignored it."); + return ret; + } + + // finger out the codec info from metadata if possible. + SrsAmf0Any* prop = NULL; + + if ((prop = obj->get_property("duration")) != NULL && prop->is_number()) { + codec->duration = (int)srs_amf0_convert(prop)->value; + } + if ((prop = obj->get_property("width")) != NULL && prop->is_number()) { + codec->width = (int)srs_amf0_convert(prop)->value; + } + if ((prop = obj->get_property("height")) != NULL && prop->is_number()) { + codec->height = (int)srs_amf0_convert(prop)->value; + } + if ((prop = obj->get_property("framerate")) != NULL && prop->is_number()) { + codec->frame_rate = (int)srs_amf0_convert(prop)->value; + } + if ((prop = obj->get_property("videocodecid")) != NULL && prop->is_number()) { + codec->video_codec_id = (int)srs_amf0_convert(prop)->value; + } + if ((prop = obj->get_property("videodatarate")) != NULL && prop->is_number()) { + codec->video_data_rate = (int)(1000 * srs_amf0_convert(prop)->value); + } + + if ((prop = obj->get_property("audiocodecid")) != NULL && prop->is_number()) { + codec->audio_codec_id = (int)srs_amf0_convert(prop)->value; + } + if ((prop = obj->get_property("audiodatarate")) != NULL && prop->is_number()) { + codec->audio_data_rate = (int)(1000 * srs_amf0_convert(prop)->value); + } + + // ignore the following, for each flv/rtmp packet contains them: + // audiosamplerate, sample->sound_rate + // audiosamplesize, sample->sound_size + // stereo, sample->sound_type + + return ret; +} + +int SrsHLS::on_audio(SrsSharedPtrMessage* audio) +{ + int ret = ERROR_SUCCESS; + + SrsAutoFree(SrsSharedPtrMessage, audio, false); + + // TODO: maybe donot need to demux the aac? + if (!hls_enabled) { + return ret; + } + + sample->clear(); + if ((ret = codec->audio_aac_demux(audio->payload, audio->size, sample)) != ERROR_SUCCESS) { + return ret; + } + + if (codec->audio_codec_id != SrsCodecAudioAAC) { + return ret; + } + + // ignore sequence header + if (sample->aac_packet_type == SrsCodecAudioTypeSequenceHeader) { + return ret; + } + + if ((ret = jitter->correct(audio, 0, 0)) != ERROR_SUCCESS) { + return ret; + } + + srs_assert(current); + + stream_dts = audio_frame->dts = audio_frame->pts = audio->header.timestamp * 90; + audio_frame->pid = TS_AUDIO_PID; + audio_frame->sid = TS_AUDIO_AAC; + + if ((ret = current->muxer->write_audio(audio_frame, audio_buffer, codec, sample)) != ERROR_SUCCESS) { + return ret; + } + + return ret; +} + +int SrsHLS::on_video(SrsSharedPtrMessage* video) +{ + int ret = ERROR_SUCCESS; + + SrsAutoFree(SrsSharedPtrMessage, video, false); + + // TODO: maybe donot need to demux the avc? + if (!hls_enabled) { + return ret; + } + + sample->clear(); + if ((ret = codec->video_avc_demux(video->payload, video->size, sample)) != ERROR_SUCCESS) { + return ret; + } + + if (codec->video_codec_id != SrsCodecVideoAVC) { + return ret; + } + + // ignore sequence header + if (sample->frame_type == SrsCodecVideoAVCFrameKeyFrame && sample->avc_packet_type == SrsCodecVideoAVCTypeSequenceHeader) { + return ret; + } + + if ((ret = jitter->correct(video, 0, 0)) != ERROR_SUCCESS) { + return ret; + } + + stream_dts = video_frame->dts = video->header.timestamp * 90; + video_frame->pts = video_frame->dts + sample->cts * 90; + video_frame->pid = TS_VIDEO_PID; + video_frame->sid = TS_VIDEO_AVC; + video_frame->key = sample->frame_type == SrsCodecVideoAVCFrameKeyFrame; + + // reopen the muxer for a gop + if (sample->frame_type == SrsCodecVideoAVCFrameKeyFrame) { + int64_t diff = stream_dts - m3u8_dts; + // 10s. + if (diff / 90000 >= 10) { + if ((ret = reopen()) != ERROR_SUCCESS) { + return ret; + } + } + } + + srs_assert(current); + if ((ret = current->muxer->write_video(video_frame, video_buffer, codec, sample)) != ERROR_SUCCESS) { + return ret; + } + + return ret; +} + +int SrsHLS::reopen() +{ + int ret = ERROR_SUCCESS; + + // try to open the HLS muxer + SrsConfDirective* conf = config->get_hls(vhost); + if (!conf && conf->arg0() == "off") { + return ret; + } + + // TODO: check the audio and video, ensure both exsists. + // for use fixed mpegts header specifeid the audio and video pid. + + hls_enabled = true; + + hls_path = SRS_CONF_DEFAULT_HLS_PATH; + if ((conf = config->get_hls_path(vhost)) != NULL) { + hls_path = conf->arg0(); + } + + // start new segment. + if (current) { + current->duration = (stream_dts - current->segment_start_dts) / 90000.0; + segments.push_back(current); + current = NULL; + + if ((ret = refresh_m3u8()) != ERROR_SUCCESS) { + return ret; + } + } + // new segment. + current = new SrsM3u8Segment(); + m3u8_dts = current->segment_start_dts = stream_dts; + + // generate filename. + char filename[128]; + snprintf(filename, sizeof(filename), "%s-%d.ts", stream.c_str(), file_index++); + + current->full_path = hls_path; + current->full_path += "/"; + current->full_path += filename; + + // TODO: support base url, and so on. + current->uri = filename; + + if ((ret = current->muxer->open(current->full_path)) != ERROR_SUCCESS) { + srs_error("open hls muxer failed. ret=%d", ret); + return ret; + } + srs_trace("open HLS muxer success. vhost=%s, path=%s", vhost.c_str(), current->full_path.c_str()); + + return ret; +} + +int SrsHLS::refresh_m3u8() +{ + int ret = ERROR_SUCCESS; + + int fd = -1; + ret = _refresh_m3u8(fd); + if (fd >= 0) { + close(fd); + } + + return ret; +} + +int SrsHLS::_refresh_m3u8(int& fd) +{ + int ret = ERROR_SUCCESS; + + // no segments, return. + if (segments.size() == 0) { + return ret; + } + + m3u8 = hls_path; + m3u8 += "/"; + m3u8 += stream; + m3u8 += ".m3u8"; + + int flags = O_CREAT|O_WRONLY|O_TRUNC; + mode_t mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH; + if ((fd = ::open(m3u8.c_str(), flags, mode)) < 0) { + ret = ERROR_HLS_OPEN_FAILED; + srs_error("open m3u8 file %s failed. ret=%d", m3u8.c_str(), ret); + return ret; + } + srs_info("open m3u8 file %s success.", m3u8.c_str()); + + // #EXTM3U\n#EXT-X-VERSION:3\n + char header[] = { + // #EXTM3U\n + 0x23, 0x45, 0x58, 0x54, 0x4d, 0x33, 0x55, 0xa, + // #EXT-X-VERSION:3\n + 0x23, 0x45, 0x58, 0x54, 0x2d, 0x58, 0x2d, 0x56, 0x45, 0x52, + 0x53, 0x49, 0x4f, 0x4e, 0x3a, 0x33, 0xa + }; + if (::write(fd, header, sizeof(header)) != sizeof(header)) { + ret = ERROR_HLS_WRITE_FAILED; + srs_error("write m3u8 header failed. ret=%d", ret); + return ret; + } + srs_verbose("write m3u8 header success."); + + // #EXT-X-MEDIA-SEQUENCE:4294967295\n + SrsM3u8Segment* first = *segments.begin(); + char sequence[34] = {}; + int len = snprintf(sequence, sizeof(sequence), "#EXT-X-MEDIA-SEQUENCE:%d\n", first->sequence_no); + if (::write(fd, sequence, len) != len) { + ret = ERROR_HLS_WRITE_FAILED; + srs_error("write m3u8 sequence failed. ret=%d", ret); + return ret; + } + srs_verbose("write m3u8 sequence success."); + + // #EXT-X-TARGETDURATION:4294967295\n + int target_duration = 0; + std::vector::iterator it; + for (it = segments.begin(); it != segments.end(); ++it) { + SrsM3u8Segment* segment = *it; + target_duration = srs_max(target_duration, (int)segment->duration); + } + // TODO: maybe need to take an around value + target_duration += 1; + char duration[34]; + len = snprintf(duration, sizeof(duration), "#EXT-X-TARGETDURATION:%d\n", target_duration); + if (::write(fd, duration, len) != len) { + ret = ERROR_HLS_WRITE_FAILED; + srs_error("write m3u8 duration failed. ret=%d", ret); + return ret; + } + srs_verbose("write m3u8 duration success."); + + // write all segments + for (it = segments.begin(); it != segments.end(); ++it) { + SrsM3u8Segment* segment = *it; + + // "#EXTINF:4294967295.208,\n" + char ext_info[25]; + len = snprintf(ext_info, sizeof(ext_info), "#EXTINF:%.3f\n", segment->duration); + if (::write(fd, ext_info, len) != len) { + ret = ERROR_HLS_WRITE_FAILED; + srs_error("write m3u8 segment failed. ret=%d", ret); + return ret; + } + srs_verbose("write m3u8 segment success."); + + // file name + std::string filename = segment->uri; + filename += "\n"; + if (::write(fd, filename.c_str(), filename.length()) != (int)filename.length()) { + ret = ERROR_HLS_WRITE_FAILED; + srs_error("write m3u8 segment uri failed. ret=%d", ret); + return ret; + } + srs_verbose("write m3u8 segment uri success."); + } + srs_info("write m3u8 %s success.", m3u8.c_str()); + + return ret; +} + +SrsTSMuxer::SrsTSMuxer() +{ + fd = -1; +} + +SrsTSMuxer::~SrsTSMuxer() +{ + close(); +} + int SrsTSMuxer::open(std::string _path) { int ret = ERROR_SUCCESS; @@ -585,14 +767,10 @@ int SrsTSMuxer::open(std::string _path) return ret; } -int SrsTSMuxer::write_audio(u_int32_t time, SrsCodec* codec, SrsCodecSample* sample) +int SrsTSMuxer::write_audio(SrsMpegtsFrame* audio_frame, SrsCodecBuffer* audio_buffer, SrsCodec* codec, SrsCodecSample* sample) { int ret = ERROR_SUCCESS; - audio_frame->dts = audio_frame->pts = time * 90; - audio_frame->pid = TS_AUDIO_PID; - audio_frame->sid = TS_AUDIO_AAC; - for (int i = 0; i < sample->nb_buffers; i++) { SrsCodecBuffer* buf = &sample->buffers[i]; int32_t size = buf->size; @@ -660,16 +838,10 @@ int SrsTSMuxer::write_audio(u_int32_t time, SrsCodec* codec, SrsCodecSample* sam return ret; } -int SrsTSMuxer::write_video(u_int32_t time, SrsCodec* codec, SrsCodecSample* sample) +int SrsTSMuxer::write_video(SrsMpegtsFrame* video_frame, SrsCodecBuffer* video_buffer, SrsCodec* codec, SrsCodecSample* sample) { int ret = ERROR_SUCCESS; - video_frame->dts = time * 90; - video_frame->pts = video_frame->dts + sample->cts * 90; - video_frame->pid = TS_VIDEO_PID; - video_frame->sid = TS_VIDEO_AVC; - video_frame->key = sample->frame_type == SrsCodecVideoAVCFrameKeyFrame; - static u_int8_t aud_nal[] = { 0x00, 0x00, 0x00, 0x01, 0x09, 0xf0 }; video_buffer->append(aud_nal, sizeof(aud_nal)); diff --git a/trunk/src/core/srs_core_hls.hpp b/trunk/src/core/srs_core_hls.hpp index b3d82f251..6ff684e1d 100644 --- a/trunk/src/core/srs_core_hls.hpp +++ b/trunk/src/core/srs_core_hls.hpp @@ -30,34 +30,88 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include #include +#include class SrsOnMetaDataPacket; class SrsSharedPtrMessage; class SrsCodecSample; class SrsCodecBuffer; class SrsMpegtsFrame; +class SrsRtmpJitter; class SrsTSMuxer; class SrsCodec; -class SrsRtmpJitter; +/** +* 3.3.2. EXTINF +* The EXTINF tag specifies the duration of a media segment. +*/ +struct SrsM3u8Segment +{ + // duration in seconds in m3u8. + double duration; + // sequence number in m3u8. + int sequence_no; + // ts uri in m3u8. + std::string uri; + // ts full file to write. + std::string full_path; + // the muxer to write ts. + SrsTSMuxer* muxer; + // current segment start dts for m3u8 + int64_t segment_start_dts; + + SrsM3u8Segment(); + virtual ~SrsM3u8Segment(); +}; + +/** +* write m3u8 hls. +*/ class SrsHLS { private: std::string vhost; + std::string stream; + std::string hls_path; +private: + int file_index; + std::string m3u8; +private: + /** + * m3u8 segments. + */ + std::vector segments; + /** + * current writing segment. + */ + SrsM3u8Segment* current; + // current frame and buffer + SrsMpegtsFrame* audio_frame; + SrsCodecBuffer* audio_buffer; + SrsMpegtsFrame* video_frame; + SrsCodecBuffer* video_buffer; + // last known dts + int64_t stream_dts; + // last segment dts in m3u8 + int64_t m3u8_dts; +private: bool hls_enabled; SrsCodec* codec; SrsCodecSample* sample; - SrsTSMuxer* muxer; SrsRtmpJitter* jitter; public: SrsHLS(); virtual ~SrsHLS(); public: - virtual int on_publish(std::string _vhost); + virtual int on_publish(std::string _vhost, std::string _stream); virtual void on_unpublish(); virtual int on_meta_data(SrsOnMetaDataPacket* metadata); virtual int on_audio(SrsSharedPtrMessage* audio); virtual int on_video(SrsSharedPtrMessage* video); +private: + virtual int reopen(); + virtual int refresh_m3u8(); + virtual int _refresh_m3u8(int& fd); }; class SrsTSMuxer @@ -65,18 +119,13 @@ class SrsTSMuxer private: int fd; std::string path; -private: - SrsMpegtsFrame* audio_frame; - SrsCodecBuffer* audio_buffer; - SrsMpegtsFrame* video_frame; - SrsCodecBuffer* video_buffer; public: SrsTSMuxer(); virtual ~SrsTSMuxer(); public: virtual int open(std::string _path); - virtual int write_audio(u_int32_t time, SrsCodec* codec, SrsCodecSample* sample); - virtual int write_video(u_int32_t time, SrsCodec* codec, SrsCodecSample* sample); + virtual int write_audio(SrsMpegtsFrame* audio_frame, SrsCodecBuffer* audio_buffer, SrsCodec* codec, SrsCodecSample* sample); + virtual int write_video(SrsMpegtsFrame* video_frame, SrsCodecBuffer* video_buffer, SrsCodec* codec, SrsCodecSample* sample); virtual void close(); }; diff --git a/trunk/src/core/srs_core_source.cpp b/trunk/src/core/srs_core_source.cpp index 8b1344e77..16dc10263 100644 --- a/trunk/src/core/srs_core_source.cpp +++ b/trunk/src/core/srs_core_source.cpp @@ -413,6 +413,7 @@ int SrsSource::on_video(SrsCommonMessage* video) } srs_verbose("initialize shared ptr video success."); + // TODO: when return error, crash. if ((ret = hls->on_video(msg->copy())) != ERROR_SUCCESS) { srs_error("hls process video message failed. ret=%d", ret); return ret; @@ -451,9 +452,9 @@ int SrsSource::on_video(SrsCommonMessage* video) return ret; } -int SrsSource::on_publish(std::string vhost) +int SrsSource::on_publish(std::string vhost, std::string stream) { - return hls->on_publish(vhost); + return hls->on_publish(vhost, stream); } void SrsSource::on_unpublish() diff --git a/trunk/src/core/srs_core_source.hpp b/trunk/src/core/srs_core_source.hpp index 2a5c6c4dc..62f0bdc1f 100644 --- a/trunk/src/core/srs_core_source.hpp +++ b/trunk/src/core/srs_core_source.hpp @@ -166,7 +166,7 @@ public: virtual int on_meta_data(SrsCommonMessage* msg, SrsOnMetaDataPacket* metadata); virtual int on_audio(SrsCommonMessage* audio); virtual int on_video(SrsCommonMessage* video); - virtual int on_publish(std::string vhost); + virtual int on_publish(std::string vhost, std::string stream); virtual void on_unpublish(); public: virtual int create_consumer(SrsConsumer*& consumer);