winlin

support HLS(m3u8)

@@ -332,7 +332,7 @@ int SrsClient::publish(SrsSource* source, bool is_fmle) @@ -332,7 +332,7 @@ int SrsClient::publish(SrsSource* source, bool is_fmle)
332 SrsPithyPrint pithy_print(SRS_STAGE_PUBLISH_USER); 332 SrsPithyPrint pithy_print(SRS_STAGE_PUBLISH_USER);
333 333
334 // notify the hls to prepare when publish start. 334 // notify the hls to prepare when publish start.
335 - if ((ret = source->on_publish(req->vhost)) != ERROR_SUCCESS) { 335 + if ((ret = source->on_publish(req->vhost, req->stream)) != ERROR_SUCCESS) {
336 srs_error("hls on_publish failed. ret=%d", ret); 336 srs_error("hls on_publish failed. ret=%d", ret);
337 return ret; 337 return ret;
338 } 338 }
@@ -37,194 +37,18 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -37,194 +37,18 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
37 #include <srs_core_source.hpp> 37 #include <srs_core_source.hpp>
38 #include <srs_core_autofree.hpp> 38 #include <srs_core_autofree.hpp>
39 39
40 -SrsHLS::SrsHLS()  
41 -{  
42 - hls_enabled = false;  
43 - codec = new SrsCodec();  
44 - sample = new SrsCodecSample();  
45 - muxer = NULL;  
46 - jitter = new SrsRtmpJitter();  
47 -}  
48 -  
49 -SrsHLS::~SrsHLS()  
50 -{  
51 - srs_freep(codec);  
52 - srs_freep(sample);  
53 - srs_freep(muxer);  
54 - srs_freep(jitter);  
55 -}  
56 -  
57 -int SrsHLS::on_publish(std::string _vhost)  
58 -{  
59 - int ret = ERROR_SUCCESS;  
60 -  
61 - // TODO: check config.  
62 - if (muxer) {  
63 - hls_enabled = true;  
64 - srs_trace("hls is reopen, continue streaming HLS, vhost=%s", _vhost.c_str());  
65 - return ret;  
66 - }  
67 -  
68 - vhost = _vhost;  
69 - muxer = new SrsTSMuxer();  
70 -  
71 - // try to open the HLS muxer  
72 - SrsConfDirective* conf = config->get_hls(vhost);  
73 - if (!conf && conf->arg0() == "off") {  
74 - return ret;  
75 - }  
76 -  
77 - // TODO: check the audio and video, ensure both exsists.  
78 - // for use fixed mpegts header specifeid the audio and video pid.  
79 -  
80 - hls_enabled = true;  
81 -  
82 - std::string path = SRS_CONF_DEFAULT_HLS_PATH;  
83 - if ((conf = config->get_hls_path(vhost)) != NULL) {  
84 - path = conf->arg0();  
85 - }  
86 -  
87 - // TODO: generate by m3u8 muxer.  
88 - path += "/1.ts";  
89 -  
90 - if ((ret = muxer->open(path)) != ERROR_SUCCESS) {  
91 - srs_error("open hls muxer failed. ret=%d", ret);  
92 - return ret;  
93 - }  
94 -  
95 - return ret;  
96 -}  
97 -  
98 -void SrsHLS::on_unpublish()  
99 -{  
100 - hls_enabled = false;  
101 - //muxer->close();  
102 - //srs_freep(muxer);  
103 -}  
104 -  
105 -int SrsHLS::on_meta_data(SrsOnMetaDataPacket* metadata)  
106 -{  
107 - int ret = ERROR_SUCCESS;  
108 -  
109 - if (!metadata || !metadata->metadata) {  
110 - srs_trace("no metadata persent, hls ignored it.");  
111 - return ret;  
112 - }  
113 -  
114 - SrsAmf0Object* obj = metadata->metadata;  
115 - if (obj->size() <= 0) {  
116 - srs_trace("no metadata persent, hls ignored it.");  
117 - return ret;  
118 - }  
119 -  
120 - // finger out the codec info from metadata if possible.  
121 - SrsAmf0Any* prop = NULL;  
122 -  
123 - if ((prop = obj->get_property("duration")) != NULL && prop->is_number()) {  
124 - codec->duration = (int)srs_amf0_convert<SrsAmf0Number>(prop)->value;  
125 - }  
126 - if ((prop = obj->get_property("width")) != NULL && prop->is_number()) {  
127 - codec->width = (int)srs_amf0_convert<SrsAmf0Number>(prop)->value;  
128 - }  
129 - if ((prop = obj->get_property("height")) != NULL && prop->is_number()) {  
130 - codec->height = (int)srs_amf0_convert<SrsAmf0Number>(prop)->value;  
131 - }  
132 - if ((prop = obj->get_property("framerate")) != NULL && prop->is_number()) {  
133 - codec->frame_rate = (int)srs_amf0_convert<SrsAmf0Number>(prop)->value;  
134 - }  
135 - if ((prop = obj->get_property("videocodecid")) != NULL && prop->is_number()) {  
136 - codec->video_codec_id = (int)srs_amf0_convert<SrsAmf0Number>(prop)->value;  
137 - }  
138 - if ((prop = obj->get_property("videodatarate")) != NULL && prop->is_number()) {  
139 - codec->video_data_rate = (int)(1000 * srs_amf0_convert<SrsAmf0Number>(prop)->value);  
140 - }  
141 -  
142 - if ((prop = obj->get_property("audiocodecid")) != NULL && prop->is_number()) {  
143 - codec->audio_codec_id = (int)srs_amf0_convert<SrsAmf0Number>(prop)->value;  
144 - }  
145 - if ((prop = obj->get_property("audiodatarate")) != NULL && prop->is_number()) {  
146 - codec->audio_data_rate = (int)(1000 * srs_amf0_convert<SrsAmf0Number>(prop)->value);  
147 - }  
148 -  
149 - // ignore the following, for each flv/rtmp packet contains them:  
150 - // audiosamplerate, sample->sound_rate  
151 - // audiosamplesize, sample->sound_size  
152 - // stereo, sample->sound_type  
153 -  
154 - return ret;  
155 -} 40 +// @see: NGX_RTMP_HLS_DELAY,
  41 +// 63000: 700ms, ts_tbn=90000
  42 +#define SRS_HLS_DELAY 63000
156 43
157 -int SrsHLS::on_audio(SrsSharedPtrMessage* audio)  
158 -{  
159 - int ret = ERROR_SUCCESS;  
160 -  
161 - SrsAutoFree(SrsSharedPtrMessage, audio, false);  
162 -  
163 - sample->clear();  
164 - if ((ret = codec->audio_aac_demux(audio->payload, audio->size, sample)) != ERROR_SUCCESS) {  
165 - return ret;  
166 - }  
167 -  
168 - if (codec->audio_codec_id != SrsCodecAudioAAC) {  
169 - return ret;  
170 - }  
171 -  
172 - // TODO: maybe donot need to demux the aac?  
173 - if (!hls_enabled) {  
174 - return ret;  
175 - }  
176 -  
177 - // ignore sequence header  
178 - if (sample->aac_packet_type == SrsCodecAudioTypeSequenceHeader) {  
179 - return ret;  
180 - }  
181 -  
182 - if ((ret = jitter->correct(audio, 0, 0)) != ERROR_SUCCESS) {  
183 - return ret;  
184 - }  
185 -  
186 - if ((ret = muxer->write_audio(audio->header.timestamp, codec, sample)) != ERROR_SUCCESS) {  
187 - return ret;  
188 - }  
189 -  
190 - return ret;  
191 -} 44 +// the mpegts header specifed the video/audio pid.
  45 +#define TS_VIDEO_PID 256
  46 +#define TS_AUDIO_PID 257
192 47
193 -int SrsHLS::on_video(SrsSharedPtrMessage* video)  
194 -{  
195 - int ret = ERROR_SUCCESS;  
196 -  
197 - SrsAutoFree(SrsSharedPtrMessage, video, false);  
198 -  
199 - sample->clear();  
200 - if ((ret = codec->video_avc_demux(video->payload, video->size, sample)) != ERROR_SUCCESS) {  
201 - return ret;  
202 - }  
203 -  
204 - if (codec->video_codec_id != SrsCodecVideoAVC) {  
205 - return ret;  
206 - }  
207 -  
208 - // TODO: maybe donot need to demux the avc?  
209 - if (!hls_enabled) {  
210 - return ret;  
211 - }  
212 -  
213 - // ignore sequence header  
214 - if (sample->frame_type == SrsCodecVideoAVCFrameKeyFrame && sample->avc_packet_type == SrsCodecVideoAVCTypeSequenceHeader) {  
215 - return ret;  
216 - }  
217 -  
218 - if ((ret = jitter->correct(video, 0, 0)) != ERROR_SUCCESS) {  
219 - return ret;  
220 - }  
221 -  
222 - if ((ret = muxer->write_video(video->header.timestamp, codec, sample)) != ERROR_SUCCESS) {  
223 - return ret;  
224 - }  
225 -  
226 - return ret;  
227 -} 48 +// ts aac stream id.
  49 +#define TS_AUDIO_AAC 0xc0
  50 +// ts avc stream id.
  51 +#define TS_VIDEO_AVC 0xe0
228 52
229 // @see: ngx_rtmp_mpegts_header 53 // @see: ngx_rtmp_mpegts_header
230 u_int8_t mpegts_header[] = { 54 u_int8_t mpegts_header[] = {
@@ -287,10 +111,6 @@ u_int8_t mpegts_header[] = { @@ -287,10 +111,6 @@ u_int8_t mpegts_header[] = {
287 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff 111 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
288 }; 112 };
289 113
290 -// @see: NGX_RTMP_HLS_DELAY,  
291 -// 63000: 700ms, ts_tbn=90000  
292 -#define SRS_HLS_DELAY 63000  
293 -  
294 // @see: ngx_rtmp_SrsMpegtsFrame_t 114 // @see: ngx_rtmp_SrsMpegtsFrame_t
295 struct SrsMpegtsFrame 115 struct SrsMpegtsFrame
296 { 116 {
@@ -527,18 +347,29 @@ private: @@ -527,18 +347,29 @@ private:
527 } 347 }
528 }; 348 };
529 349
530 -// the mpegts header specifed the video/audio pid.  
531 -#define TS_VIDEO_PID 256  
532 -#define TS_AUDIO_PID 257 350 +SrsM3u8Segment::SrsM3u8Segment()
  351 +{
  352 + duration = 0;
  353 + sequence_no = 0;
  354 + muxer = new SrsTSMuxer();
  355 + segment_start_dts = 0;
  356 +}
533 357
534 -// ts aac stream id.  
535 -#define TS_AUDIO_AAC 0xc0  
536 -// ts avc stream id.  
537 -#define TS_VIDEO_AVC 0xe0 358 +SrsM3u8Segment::~SrsM3u8Segment()
  359 +{
  360 + muxer->close();
  361 + srs_freep(muxer);
  362 +}
538 363
539 -SrsTSMuxer::SrsTSMuxer() 364 +SrsHLS::SrsHLS()
540 { 365 {
541 - fd = -1; 366 + hls_enabled = false;
  367 + codec = new SrsCodec();
  368 + sample = new SrsCodecSample();
  369 + current = NULL;
  370 + jitter = new SrsRtmpJitter();
  371 + file_index = 0;
  372 + m3u8_dts = stream_dts = 0;
542 373
543 audio_buffer = new SrsCodecBuffer(); 374 audio_buffer = new SrsCodecBuffer();
544 video_buffer = new SrsCodecBuffer(); 375 video_buffer = new SrsCodecBuffer();
@@ -547,9 +378,20 @@ SrsTSMuxer::SrsTSMuxer() @@ -547,9 +378,20 @@ SrsTSMuxer::SrsTSMuxer()
547 video_frame = new SrsMpegtsFrame(); 378 video_frame = new SrsMpegtsFrame();
548 } 379 }
549 380
550 -SrsTSMuxer::~SrsTSMuxer() 381 +SrsHLS::~SrsHLS()
551 { 382 {
552 - close(); 383 + srs_freep(codec);
  384 + srs_freep(sample);
  385 + srs_freep(jitter);
  386 +
  387 + std::vector<SrsM3u8Segment*>::iterator it;
  388 + for (it = segments.begin(); it != segments.end(); ++it) {
  389 + SrsM3u8Segment* segment = *it;
  390 + srs_freep(segment);
  391 + }
  392 + segments.clear();
  393 +
  394 + srs_freep(current);
553 395
554 audio_buffer->free(); 396 audio_buffer->free();
555 video_buffer->free(); 397 video_buffer->free();
@@ -561,6 +403,346 @@ SrsTSMuxer::~SrsTSMuxer() @@ -561,6 +403,346 @@ SrsTSMuxer::~SrsTSMuxer()
561 srs_freep(video_frame); 403 srs_freep(video_frame);
562 } 404 }
563 405
  406 +int SrsHLS::on_publish(std::string _vhost, std::string _stream)
  407 +{
  408 + int ret = ERROR_SUCCESS;
  409 +
  410 + vhost = _vhost;
  411 + stream = _stream;
  412 +
  413 + if ((ret = reopen()) != ERROR_SUCCESS) {
  414 + return ret;
  415 + }
  416 +
  417 + return ret;
  418 +}
  419 +
  420 +void SrsHLS::on_unpublish()
  421 +{
  422 + hls_enabled = false;
  423 +}
  424 +
  425 +int SrsHLS::on_meta_data(SrsOnMetaDataPacket* metadata)
  426 +{
  427 + int ret = ERROR_SUCCESS;
  428 +
  429 + if (!metadata || !metadata->metadata) {
  430 + srs_trace("no metadata persent, hls ignored it.");
  431 + return ret;
  432 + }
  433 +
  434 + SrsAmf0Object* obj = metadata->metadata;
  435 + if (obj->size() <= 0) {
  436 + srs_trace("no metadata persent, hls ignored it.");
  437 + return ret;
  438 + }
  439 +
  440 + // finger out the codec info from metadata if possible.
  441 + SrsAmf0Any* prop = NULL;
  442 +
  443 + if ((prop = obj->get_property("duration")) != NULL && prop->is_number()) {
  444 + codec->duration = (int)srs_amf0_convert<SrsAmf0Number>(prop)->value;
  445 + }
  446 + if ((prop = obj->get_property("width")) != NULL && prop->is_number()) {
  447 + codec->width = (int)srs_amf0_convert<SrsAmf0Number>(prop)->value;
  448 + }
  449 + if ((prop = obj->get_property("height")) != NULL && prop->is_number()) {
  450 + codec->height = (int)srs_amf0_convert<SrsAmf0Number>(prop)->value;
  451 + }
  452 + if ((prop = obj->get_property("framerate")) != NULL && prop->is_number()) {
  453 + codec->frame_rate = (int)srs_amf0_convert<SrsAmf0Number>(prop)->value;
  454 + }
  455 + if ((prop = obj->get_property("videocodecid")) != NULL && prop->is_number()) {
  456 + codec->video_codec_id = (int)srs_amf0_convert<SrsAmf0Number>(prop)->value;
  457 + }
  458 + if ((prop = obj->get_property("videodatarate")) != NULL && prop->is_number()) {
  459 + codec->video_data_rate = (int)(1000 * srs_amf0_convert<SrsAmf0Number>(prop)->value);
  460 + }
  461 +
  462 + if ((prop = obj->get_property("audiocodecid")) != NULL && prop->is_number()) {
  463 + codec->audio_codec_id = (int)srs_amf0_convert<SrsAmf0Number>(prop)->value;
  464 + }
  465 + if ((prop = obj->get_property("audiodatarate")) != NULL && prop->is_number()) {
  466 + codec->audio_data_rate = (int)(1000 * srs_amf0_convert<SrsAmf0Number>(prop)->value);
  467 + }
  468 +
  469 + // ignore the following, for each flv/rtmp packet contains them:
  470 + // audiosamplerate, sample->sound_rate
  471 + // audiosamplesize, sample->sound_size
  472 + // stereo, sample->sound_type
  473 +
  474 + return ret;
  475 +}
  476 +
  477 +int SrsHLS::on_audio(SrsSharedPtrMessage* audio)
  478 +{
  479 + int ret = ERROR_SUCCESS;
  480 +
  481 + SrsAutoFree(SrsSharedPtrMessage, audio, false);
  482 +
  483 + // TODO: maybe donot need to demux the aac?
  484 + if (!hls_enabled) {
  485 + return ret;
  486 + }
  487 +
  488 + sample->clear();
  489 + if ((ret = codec->audio_aac_demux(audio->payload, audio->size, sample)) != ERROR_SUCCESS) {
  490 + return ret;
  491 + }
  492 +
  493 + if (codec->audio_codec_id != SrsCodecAudioAAC) {
  494 + return ret;
  495 + }
  496 +
  497 + // ignore sequence header
  498 + if (sample->aac_packet_type == SrsCodecAudioTypeSequenceHeader) {
  499 + return ret;
  500 + }
  501 +
  502 + if ((ret = jitter->correct(audio, 0, 0)) != ERROR_SUCCESS) {
  503 + return ret;
  504 + }
  505 +
  506 + srs_assert(current);
  507 +
  508 + stream_dts = audio_frame->dts = audio_frame->pts = audio->header.timestamp * 90;
  509 + audio_frame->pid = TS_AUDIO_PID;
  510 + audio_frame->sid = TS_AUDIO_AAC;
  511 +
  512 + if ((ret = current->muxer->write_audio(audio_frame, audio_buffer, codec, sample)) != ERROR_SUCCESS) {
  513 + return ret;
  514 + }
  515 +
  516 + return ret;
  517 +}
  518 +
  519 +int SrsHLS::on_video(SrsSharedPtrMessage* video)
  520 +{
  521 + int ret = ERROR_SUCCESS;
  522 +
  523 + SrsAutoFree(SrsSharedPtrMessage, video, false);
  524 +
  525 + // TODO: maybe donot need to demux the avc?
  526 + if (!hls_enabled) {
  527 + return ret;
  528 + }
  529 +
  530 + sample->clear();
  531 + if ((ret = codec->video_avc_demux(video->payload, video->size, sample)) != ERROR_SUCCESS) {
  532 + return ret;
  533 + }
  534 +
  535 + if (codec->video_codec_id != SrsCodecVideoAVC) {
  536 + return ret;
  537 + }
  538 +
  539 + // ignore sequence header
  540 + if (sample->frame_type == SrsCodecVideoAVCFrameKeyFrame && sample->avc_packet_type == SrsCodecVideoAVCTypeSequenceHeader) {
  541 + return ret;
  542 + }
  543 +
  544 + if ((ret = jitter->correct(video, 0, 0)) != ERROR_SUCCESS) {
  545 + return ret;
  546 + }
  547 +
  548 + stream_dts = video_frame->dts = video->header.timestamp * 90;
  549 + video_frame->pts = video_frame->dts + sample->cts * 90;
  550 + video_frame->pid = TS_VIDEO_PID;
  551 + video_frame->sid = TS_VIDEO_AVC;
  552 + video_frame->key = sample->frame_type == SrsCodecVideoAVCFrameKeyFrame;
  553 +
  554 + // reopen the muxer for a gop
  555 + if (sample->frame_type == SrsCodecVideoAVCFrameKeyFrame) {
  556 + int64_t diff = stream_dts - m3u8_dts;
  557 + // 10s.
  558 + if (diff / 90000 >= 10) {
  559 + if ((ret = reopen()) != ERROR_SUCCESS) {
  560 + return ret;
  561 + }
  562 + }
  563 + }
  564 +
  565 + srs_assert(current);
  566 + if ((ret = current->muxer->write_video(video_frame, video_buffer, codec, sample)) != ERROR_SUCCESS) {
  567 + return ret;
  568 + }
  569 +
  570 + return ret;
  571 +}
  572 +
  573 +int SrsHLS::reopen()
  574 +{
  575 + int ret = ERROR_SUCCESS;
  576 +
  577 + // try to open the HLS muxer
  578 + SrsConfDirective* conf = config->get_hls(vhost);
  579 + if (!conf && conf->arg0() == "off") {
  580 + return ret;
  581 + }
  582 +
  583 + // TODO: check the audio and video, ensure both exsists.
  584 + // for use fixed mpegts header specifeid the audio and video pid.
  585 +
  586 + hls_enabled = true;
  587 +
  588 + hls_path = SRS_CONF_DEFAULT_HLS_PATH;
  589 + if ((conf = config->get_hls_path(vhost)) != NULL) {
  590 + hls_path = conf->arg0();
  591 + }
  592 +
  593 + // start new segment.
  594 + if (current) {
  595 + current->duration = (stream_dts - current->segment_start_dts) / 90000.0;
  596 + segments.push_back(current);
  597 + current = NULL;
  598 +
  599 + if ((ret = refresh_m3u8()) != ERROR_SUCCESS) {
  600 + return ret;
  601 + }
  602 + }
  603 + // new segment.
  604 + current = new SrsM3u8Segment();
  605 + m3u8_dts = current->segment_start_dts = stream_dts;
  606 +
  607 + // generate filename.
  608 + char filename[128];
  609 + snprintf(filename, sizeof(filename), "%s-%d.ts", stream.c_str(), file_index++);
  610 +
  611 + current->full_path = hls_path;
  612 + current->full_path += "/";
  613 + current->full_path += filename;
  614 +
  615 + // TODO: support base url, and so on.
  616 + current->uri = filename;
  617 +
  618 + if ((ret = current->muxer->open(current->full_path)) != ERROR_SUCCESS) {
  619 + srs_error("open hls muxer failed. ret=%d", ret);
  620 + return ret;
  621 + }
  622 + srs_trace("open HLS muxer success. vhost=%s, path=%s", vhost.c_str(), current->full_path.c_str());
  623 +
  624 + return ret;
  625 +}
  626 +
  627 +int SrsHLS::refresh_m3u8()
  628 +{
  629 + int ret = ERROR_SUCCESS;
  630 +
  631 + int fd = -1;
  632 + ret = _refresh_m3u8(fd);
  633 + if (fd >= 0) {
  634 + close(fd);
  635 + }
  636 +
  637 + return ret;
  638 +}
  639 +
  640 +int SrsHLS::_refresh_m3u8(int& fd)
  641 +{
  642 + int ret = ERROR_SUCCESS;
  643 +
  644 + // no segments, return.
  645 + if (segments.size() == 0) {
  646 + return ret;
  647 + }
  648 +
  649 + m3u8 = hls_path;
  650 + m3u8 += "/";
  651 + m3u8 += stream;
  652 + m3u8 += ".m3u8";
  653 +
  654 + int flags = O_CREAT|O_WRONLY|O_TRUNC;
  655 + mode_t mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH;
  656 + if ((fd = ::open(m3u8.c_str(), flags, mode)) < 0) {
  657 + ret = ERROR_HLS_OPEN_FAILED;
  658 + srs_error("open m3u8 file %s failed. ret=%d", m3u8.c_str(), ret);
  659 + return ret;
  660 + }
  661 + srs_info("open m3u8 file %s success.", m3u8.c_str());
  662 +
  663 + // #EXTM3U\n#EXT-X-VERSION:3\n
  664 + char header[] = {
  665 + // #EXTM3U\n
  666 + 0x23, 0x45, 0x58, 0x54, 0x4d, 0x33, 0x55, 0xa,
  667 + // #EXT-X-VERSION:3\n
  668 + 0x23, 0x45, 0x58, 0x54, 0x2d, 0x58, 0x2d, 0x56, 0x45, 0x52,
  669 + 0x53, 0x49, 0x4f, 0x4e, 0x3a, 0x33, 0xa
  670 + };
  671 + if (::write(fd, header, sizeof(header)) != sizeof(header)) {
  672 + ret = ERROR_HLS_WRITE_FAILED;
  673 + srs_error("write m3u8 header failed. ret=%d", ret);
  674 + return ret;
  675 + }
  676 + srs_verbose("write m3u8 header success.");
  677 +
  678 + // #EXT-X-MEDIA-SEQUENCE:4294967295\n
  679 + SrsM3u8Segment* first = *segments.begin();
  680 + char sequence[34] = {};
  681 + int len = snprintf(sequence, sizeof(sequence), "#EXT-X-MEDIA-SEQUENCE:%d\n", first->sequence_no);
  682 + if (::write(fd, sequence, len) != len) {
  683 + ret = ERROR_HLS_WRITE_FAILED;
  684 + srs_error("write m3u8 sequence failed. ret=%d", ret);
  685 + return ret;
  686 + }
  687 + srs_verbose("write m3u8 sequence success.");
  688 +
  689 + // #EXT-X-TARGETDURATION:4294967295\n
  690 + int target_duration = 0;
  691 + std::vector<SrsM3u8Segment*>::iterator it;
  692 + for (it = segments.begin(); it != segments.end(); ++it) {
  693 + SrsM3u8Segment* segment = *it;
  694 + target_duration = srs_max(target_duration, (int)segment->duration);
  695 + }
  696 + // TODO: maybe need to take an around value
  697 + target_duration += 1;
  698 + char duration[34];
  699 + len = snprintf(duration, sizeof(duration), "#EXT-X-TARGETDURATION:%d\n", target_duration);
  700 + if (::write(fd, duration, len) != len) {
  701 + ret = ERROR_HLS_WRITE_FAILED;
  702 + srs_error("write m3u8 duration failed. ret=%d", ret);
  703 + return ret;
  704 + }
  705 + srs_verbose("write m3u8 duration success.");
  706 +
  707 + // write all segments
  708 + for (it = segments.begin(); it != segments.end(); ++it) {
  709 + SrsM3u8Segment* segment = *it;
  710 +
  711 + // "#EXTINF:4294967295.208,\n"
  712 + char ext_info[25];
  713 + len = snprintf(ext_info, sizeof(ext_info), "#EXTINF:%.3f\n", segment->duration);
  714 + if (::write(fd, ext_info, len) != len) {
  715 + ret = ERROR_HLS_WRITE_FAILED;
  716 + srs_error("write m3u8 segment failed. ret=%d", ret);
  717 + return ret;
  718 + }
  719 + srs_verbose("write m3u8 segment success.");
  720 +
  721 + // file name
  722 + std::string filename = segment->uri;
  723 + filename += "\n";
  724 + if (::write(fd, filename.c_str(), filename.length()) != (int)filename.length()) {
  725 + ret = ERROR_HLS_WRITE_FAILED;
  726 + srs_error("write m3u8 segment uri failed. ret=%d", ret);
  727 + return ret;
  728 + }
  729 + srs_verbose("write m3u8 segment uri success.");
  730 + }
  731 + srs_info("write m3u8 %s success.", m3u8.c_str());
  732 +
  733 + return ret;
  734 +}
  735 +
  736 +SrsTSMuxer::SrsTSMuxer()
  737 +{
  738 + fd = -1;
  739 +}
  740 +
  741 +SrsTSMuxer::~SrsTSMuxer()
  742 +{
  743 + close();
  744 +}
  745 +
564 int SrsTSMuxer::open(std::string _path) 746 int SrsTSMuxer::open(std::string _path)
565 { 747 {
566 int ret = ERROR_SUCCESS; 748 int ret = ERROR_SUCCESS;
@@ -585,14 +767,10 @@ int SrsTSMuxer::open(std::string _path) @@ -585,14 +767,10 @@ int SrsTSMuxer::open(std::string _path)
585 return ret; 767 return ret;
586 } 768 }
587 769
588 -int SrsTSMuxer::write_audio(u_int32_t time, SrsCodec* codec, SrsCodecSample* sample) 770 +int SrsTSMuxer::write_audio(SrsMpegtsFrame* audio_frame, SrsCodecBuffer* audio_buffer, SrsCodec* codec, SrsCodecSample* sample)
589 { 771 {
590 int ret = ERROR_SUCCESS; 772 int ret = ERROR_SUCCESS;
591 773
592 - audio_frame->dts = audio_frame->pts = time * 90;  
593 - audio_frame->pid = TS_AUDIO_PID;  
594 - audio_frame->sid = TS_AUDIO_AAC;  
595 -  
596 for (int i = 0; i < sample->nb_buffers; i++) { 774 for (int i = 0; i < sample->nb_buffers; i++) {
597 SrsCodecBuffer* buf = &sample->buffers[i]; 775 SrsCodecBuffer* buf = &sample->buffers[i];
598 int32_t size = buf->size; 776 int32_t size = buf->size;
@@ -660,16 +838,10 @@ int SrsTSMuxer::write_audio(u_int32_t time, SrsCodec* codec, SrsCodecSample* sam @@ -660,16 +838,10 @@ int SrsTSMuxer::write_audio(u_int32_t time, SrsCodec* codec, SrsCodecSample* sam
660 return ret; 838 return ret;
661 } 839 }
662 840
663 -int SrsTSMuxer::write_video(u_int32_t time, SrsCodec* codec, SrsCodecSample* sample) 841 +int SrsTSMuxer::write_video(SrsMpegtsFrame* video_frame, SrsCodecBuffer* video_buffer, SrsCodec* codec, SrsCodecSample* sample)
664 { 842 {
665 int ret = ERROR_SUCCESS; 843 int ret = ERROR_SUCCESS;
666 844
667 - video_frame->dts = time * 90;  
668 - video_frame->pts = video_frame->dts + sample->cts * 90;  
669 - video_frame->pid = TS_VIDEO_PID;  
670 - video_frame->sid = TS_VIDEO_AVC;  
671 - video_frame->key = sample->frame_type == SrsCodecVideoAVCFrameKeyFrame;  
672 -  
673 static u_int8_t aud_nal[] = { 0x00, 0x00, 0x00, 0x01, 0x09, 0xf0 }; 845 static u_int8_t aud_nal[] = { 0x00, 0x00, 0x00, 0x01, 0x09, 0xf0 };
674 video_buffer->append(aud_nal, sizeof(aud_nal)); 846 video_buffer->append(aud_nal, sizeof(aud_nal));
675 847
@@ -30,34 +30,88 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -30,34 +30,88 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 #include <srs_core.hpp> 30 #include <srs_core.hpp>
31 31
32 #include <string> 32 #include <string>
  33 +#include <vector>
33 34
34 class SrsOnMetaDataPacket; 35 class SrsOnMetaDataPacket;
35 class SrsSharedPtrMessage; 36 class SrsSharedPtrMessage;
36 class SrsCodecSample; 37 class SrsCodecSample;
37 class SrsCodecBuffer; 38 class SrsCodecBuffer;
38 class SrsMpegtsFrame; 39 class SrsMpegtsFrame;
  40 +class SrsRtmpJitter;
39 class SrsTSMuxer; 41 class SrsTSMuxer;
40 class SrsCodec; 42 class SrsCodec;
41 -class SrsRtmpJitter;  
42 43
  44 +/**
  45 +* 3.3.2. EXTINF
  46 +* The EXTINF tag specifies the duration of a media segment.
  47 +*/
  48 +struct SrsM3u8Segment
  49 +{
  50 + // duration in seconds in m3u8.
  51 + double duration;
  52 + // sequence number in m3u8.
  53 + int sequence_no;
  54 + // ts uri in m3u8.
  55 + std::string uri;
  56 + // ts full file to write.
  57 + std::string full_path;
  58 + // the muxer to write ts.
  59 + SrsTSMuxer* muxer;
  60 + // current segment start dts for m3u8
  61 + int64_t segment_start_dts;
  62 +
  63 + SrsM3u8Segment();
  64 + virtual ~SrsM3u8Segment();
  65 +};
  66 +
  67 +/**
  68 +* write m3u8 hls.
  69 +*/
43 class SrsHLS 70 class SrsHLS
44 { 71 {
45 private: 72 private:
46 std::string vhost; 73 std::string vhost;
  74 + std::string stream;
  75 + std::string hls_path;
  76 +private:
  77 + int file_index;
  78 + std::string m3u8;
  79 +private:
  80 + /**
  81 + * m3u8 segments.
  82 + */
  83 + std::vector<SrsM3u8Segment*> segments;
  84 + /**
  85 + * current writing segment.
  86 + */
  87 + SrsM3u8Segment* current;
  88 + // current frame and buffer
  89 + SrsMpegtsFrame* audio_frame;
  90 + SrsCodecBuffer* audio_buffer;
  91 + SrsMpegtsFrame* video_frame;
  92 + SrsCodecBuffer* video_buffer;
  93 + // last known dts
  94 + int64_t stream_dts;
  95 + // last segment dts in m3u8
  96 + int64_t m3u8_dts;
  97 +private:
47 bool hls_enabled; 98 bool hls_enabled;
48 SrsCodec* codec; 99 SrsCodec* codec;
49 SrsCodecSample* sample; 100 SrsCodecSample* sample;
50 - SrsTSMuxer* muxer;  
51 SrsRtmpJitter* jitter; 101 SrsRtmpJitter* jitter;
52 public: 102 public:
53 SrsHLS(); 103 SrsHLS();
54 virtual ~SrsHLS(); 104 virtual ~SrsHLS();
55 public: 105 public:
56 - virtual int on_publish(std::string _vhost); 106 + virtual int on_publish(std::string _vhost, std::string _stream);
57 virtual void on_unpublish(); 107 virtual void on_unpublish();
58 virtual int on_meta_data(SrsOnMetaDataPacket* metadata); 108 virtual int on_meta_data(SrsOnMetaDataPacket* metadata);
59 virtual int on_audio(SrsSharedPtrMessage* audio); 109 virtual int on_audio(SrsSharedPtrMessage* audio);
60 virtual int on_video(SrsSharedPtrMessage* video); 110 virtual int on_video(SrsSharedPtrMessage* video);
  111 +private:
  112 + virtual int reopen();
  113 + virtual int refresh_m3u8();
  114 + virtual int _refresh_m3u8(int& fd);
61 }; 115 };
62 116
63 class SrsTSMuxer 117 class SrsTSMuxer
@@ -65,18 +119,13 @@ class SrsTSMuxer @@ -65,18 +119,13 @@ class SrsTSMuxer
65 private: 119 private:
66 int fd; 120 int fd;
67 std::string path; 121 std::string path;
68 -private:  
69 - SrsMpegtsFrame* audio_frame;  
70 - SrsCodecBuffer* audio_buffer;  
71 - SrsMpegtsFrame* video_frame;  
72 - SrsCodecBuffer* video_buffer;  
73 public: 122 public:
74 SrsTSMuxer(); 123 SrsTSMuxer();
75 virtual ~SrsTSMuxer(); 124 virtual ~SrsTSMuxer();
76 public: 125 public:
77 virtual int open(std::string _path); 126 virtual int open(std::string _path);
78 - virtual int write_audio(u_int32_t time, SrsCodec* codec, SrsCodecSample* sample);  
79 - virtual int write_video(u_int32_t time, SrsCodec* codec, SrsCodecSample* sample); 127 + virtual int write_audio(SrsMpegtsFrame* audio_frame, SrsCodecBuffer* audio_buffer, SrsCodec* codec, SrsCodecSample* sample);
  128 + virtual int write_video(SrsMpegtsFrame* video_frame, SrsCodecBuffer* video_buffer, SrsCodec* codec, SrsCodecSample* sample);
80 virtual void close(); 129 virtual void close();
81 }; 130 };
82 131
@@ -413,6 +413,7 @@ int SrsSource::on_video(SrsCommonMessage* video) @@ -413,6 +413,7 @@ int SrsSource::on_video(SrsCommonMessage* video)
413 } 413 }
414 srs_verbose("initialize shared ptr video success."); 414 srs_verbose("initialize shared ptr video success.");
415 415
  416 + // TODO: when return error, crash.
416 if ((ret = hls->on_video(msg->copy())) != ERROR_SUCCESS) { 417 if ((ret = hls->on_video(msg->copy())) != ERROR_SUCCESS) {
417 srs_error("hls process video message failed. ret=%d", ret); 418 srs_error("hls process video message failed. ret=%d", ret);
418 return ret; 419 return ret;
@@ -451,9 +452,9 @@ int SrsSource::on_video(SrsCommonMessage* video) @@ -451,9 +452,9 @@ int SrsSource::on_video(SrsCommonMessage* video)
451 return ret; 452 return ret;
452 } 453 }
453 454
454 -int SrsSource::on_publish(std::string vhost) 455 +int SrsSource::on_publish(std::string vhost, std::string stream)
455 { 456 {
456 - return hls->on_publish(vhost); 457 + return hls->on_publish(vhost, stream);
457 } 458 }
458 459
459 void SrsSource::on_unpublish() 460 void SrsSource::on_unpublish()
@@ -166,7 +166,7 @@ public: @@ -166,7 +166,7 @@ public:
166 virtual int on_meta_data(SrsCommonMessage* msg, SrsOnMetaDataPacket* metadata); 166 virtual int on_meta_data(SrsCommonMessage* msg, SrsOnMetaDataPacket* metadata);
167 virtual int on_audio(SrsCommonMessage* audio); 167 virtual int on_audio(SrsCommonMessage* audio);
168 virtual int on_video(SrsCommonMessage* video); 168 virtual int on_video(SrsCommonMessage* video);
169 - virtual int on_publish(std::string vhost); 169 + virtual int on_publish(std::string vhost, std::string stream);
170 virtual void on_unpublish(); 170 virtual void on_unpublish();
171 public: 171 public:
172 virtual int create_consumer(SrsConsumer*& consumer); 172 virtual int create_consumer(SrsConsumer*& consumer);