Skip to content

Commit f0fc2c5

Browse files
committed
hls fmp4: support audio only and video only;
1 parent 96cd36a commit f0fc2c5

File tree

4 files changed

+110
-23
lines changed

4 files changed

+110
-23
lines changed

trunk/src/app/srs_app_hls.cpp

+90-14
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,53 @@ srs_error_t SrsInitMp4Segment::write(SrsFormat* format, int v_tid, int a_tid)
9393
{
9494
srs_error_t err = srs_success;
9595

96+
if ((err = init_encoder()) != srs_success) {
97+
return srs_error_wrap(err, "init encoder");
98+
}
99+
100+
if ((err = init_->write(format, v_tid, a_tid)) != srs_success) {
101+
return srs_error_wrap(err, "write init");
102+
}
103+
104+
return err;
105+
}
106+
107+
srs_error_t SrsInitMp4Segment::write_video_only(SrsFormat* format, int v_tid)
108+
{
109+
srs_error_t err = srs_success;
110+
111+
if ((err = init_encoder()) != srs_success) {
112+
return srs_error_wrap(err, "init encoder");
113+
}
114+
115+
if ((err = init_->write(format, true, v_tid)) != srs_success) {
116+
return srs_error_wrap(err, "write init");
117+
}
118+
119+
return err;
120+
}
121+
122+
srs_error_t SrsInitMp4Segment::write_audio_only(SrsFormat* format, int a_tid)
123+
{
124+
srs_error_t err = srs_success;
125+
126+
if ((err = init_encoder()) != srs_success) {
127+
return srs_error_wrap(err, "init encoder");
128+
}
129+
130+
if ((err = init_->write(format, false, a_tid)) != srs_success) {
131+
return srs_error_wrap(err, "write init");
132+
}
133+
134+
return err;
135+
}
136+
137+
srs_error_t SrsInitMp4Segment::init_encoder()
138+
{
139+
srs_error_t err = srs_success;
140+
141+
srs_assert(!fullpath().empty());
142+
96143
string path_tmp = tmppath();
97144
if ((err = fw_->open(path_tmp)) != srs_success) {
98145
return srs_error_wrap(err, "Open init mp4 failed, path=%s", path_tmp.c_str());
@@ -101,14 +148,11 @@ srs_error_t SrsInitMp4Segment::write(SrsFormat* format, int v_tid, int a_tid)
101148
if ((err = init_->initialize(fw_)) != srs_success) {
102149
return srs_error_wrap(err, "init");
103150
}
104-
105-
if ((err = init_->write(format, v_tid, a_tid)) != srs_success) {
106-
return srs_error_wrap(err, "write init");
107-
}
108-
151+
109152
return err;
110153
}
111154

155+
112156
SrsHlsM4sSegment::SrsHlsM4sSegment()
113157
{
114158
fw_ = new SrsFileWriter();
@@ -428,7 +472,7 @@ srs_error_t SrsHlsFmp4Muxer::on_publish(SrsRequest* req)
428472
return err;
429473
}
430474

431-
srs_error_t SrsHlsFmp4Muxer::write_init_mp4(SrsFormat* format)
475+
srs_error_t SrsHlsFmp4Muxer::write_init_mp4(SrsFormat* format, bool has_video, bool has_audio)
432476
{
433477
srs_error_t err = srs_success;
434478

@@ -448,8 +492,20 @@ srs_error_t SrsHlsFmp4Muxer::write_init_mp4(SrsFormat* format)
448492

449493
init_mp4->set_path(path);
450494

451-
if ((err = init_mp4->write(format, video_track_id_, audio_track_id_)) != srs_success) {
452-
return srs_error_wrap(err, "write hls init.mp4 with audio and video");
495+
if (has_video && has_audio) {
496+
if ((err = init_mp4->write(format, video_track_id_, audio_track_id_)) != srs_success) {
497+
return srs_error_wrap(err, "write hls init.mp4 with audio and video");
498+
}
499+
} else if (has_video) {
500+
if ((err = init_mp4->write_video_only(format, video_track_id_)) != srs_success) {
501+
return srs_error_wrap(err, "write hls init.mp4 with video only");
502+
}
503+
} else if (has_audio) {
504+
if ((err = init_mp4->write_audio_only(format, audio_track_id_)) != srs_success) {
505+
return srs_error_wrap(err, "write hls init.mp4 with audio only");
506+
}
507+
} else {
508+
return srs_error_new(ERROR_HLS_WRITE_FAILED, "no video and no audio sequence header");
453509
}
454510

455511
if ((err = init_mp4->rename()) != srs_success) {
@@ -471,6 +527,16 @@ srs_error_t SrsHlsFmp4Muxer::write_audio(SrsSharedPtrMessage* shared_audio, SrsF
471527
return srs_error_wrap(err, "open segment");
472528
}
473529
}
530+
531+
if (current_->duration() >= hls_fragment_) {
532+
if ((err = segment_close()) != srs_success) {
533+
return srs_error_wrap(err, "segment close");
534+
}
535+
536+
if ((err = segment_open(shared_audio->timestamp * SRS_UTIME_MILLISECONDS)) != srs_success) {
537+
return srs_error_wrap(err, "open segment");
538+
}
539+
}
474540

475541
current_->write(shared_audio, format);
476542
return err;
@@ -488,7 +554,8 @@ srs_error_t SrsHlsFmp4Muxer::write_video(SrsSharedPtrMessage* shared_video, SrsF
488554
}
489555
}
490556

491-
bool reopen = format->video->frame_type == SrsVideoAvcFrameTypeKeyFrame && current_->duration() >= hls_fragment_;
557+
// TODO: reap segment only when get key frame?
558+
bool reopen = current_->duration() >= hls_fragment_;
492559
if (reopen) {
493560
if ((err = segment_close()) != srs_success) {
494561
return srs_error_wrap(err, "segment close");
@@ -499,7 +566,6 @@ srs_error_t SrsHlsFmp4Muxer::write_video(SrsSharedPtrMessage* shared_video, SrsF
499566
}
500567
}
501568

502-
// TODO: do reap segment here.
503569
current_->write(shared_video, format);
504570

505571
return err;
@@ -2046,7 +2112,7 @@ srs_error_t SrsHlsMp4Controller::on_sequence_header(SrsSharedPtrMessage* msg, Sr
20462112
has_audio_sh_ = true;
20472113
}
20482114

2049-
muxer_->write_init_mp4(format);
2115+
muxer_->write_init_mp4(format, has_video_sh_, has_audio_sh_);
20502116

20512117
return err;
20522118
}
@@ -2291,8 +2357,14 @@ void SrsHls::on_unpublish()
22912357

22922358
srs_error_t SrsHls::on_audio(SrsSharedPtrMessage* shared_audio, SrsFormat* format)
22932359
{
2360+
// srs_warn("hls: on_audio, is_aac_sh=%s, aac_extra_data.size=%d", format->is_aac_sequence_header() ? "true" : "false", format->acodec->aac_extra_data.size());
2361+
22942362
srs_error_t err = srs_success;
22952363

2364+
if (format->acodec->aac_extra_data.size() == 0) {
2365+
srs_trace("the audio codec's aac extra data is empty");
2366+
return err;
2367+
}
22962368
// If not able to transmux to HLS, ignore.
22972369
if (!enabled || unpublishing_) return err;
22982370
if (async_reload_) return reload();
@@ -2317,7 +2389,8 @@ srs_error_t SrsHls::on_audio(SrsSharedPtrMessage* shared_audio, SrsFormat* forma
23172389

23182390
// ignore sequence header
23192391
srs_assert(format->audio);
2320-
if (acodec == SrsAudioCodecIdAAC && format->audio->aac_packet_type == SrsAudioAacFrameTraitSequenceHeader) {
2392+
// TODO: verify mp3 play by HLS.
2393+
if (format->is_aac_sequence_header() || format->is_mp3_sequence_header()) {
23212394
return controller->on_sequence_header(audio.get(), format);
23222395
}
23232396

@@ -2335,6 +2408,7 @@ srs_error_t SrsHls::on_audio(SrsSharedPtrMessage* shared_audio, SrsFormat* forma
23352408

23362409
srs_error_t SrsHls::on_video(SrsSharedPtrMessage* shared_video, SrsFormat* format)
23372410
{
2411+
// srs_warn("hls: on_video, is_avc_sh=%s", format->is_avc_sequence_header() ? "true" : "false");
23382412
srs_error_t err = srs_success;
23392413

23402414
// If not able to transmux to HLS, ignore.
@@ -2364,8 +2438,10 @@ srs_error_t SrsHls::on_video(SrsSharedPtrMessage* shared_video, SrsFormat* forma
23642438
return err;
23652439
}
23662440

2367-
// ignore sequence header
2368-
if (format->video->avc_packet_type == SrsVideoAvcFrameTraitSequenceHeader) {
2441+
// ignore sequence header avc and hevc
2442+
// is avc|hevc|av1 sequence header check, but av1 packet already ignored above. so it's ok to use
2443+
// below method.
2444+
if (format->is_avc_sequence_header()) {
23692445
return controller->on_sequence_header(video.get(), format);
23702446
}
23712447

trunk/src/app/srs_app_hls.hpp

+7-1
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,12 @@ class SrsInitMp4Segment : public SrsFragment
7878

7979
// Write the init mp4 file, with the v_tid(video track id) and a_tid (audio track id).
8080
virtual srs_error_t write(SrsFormat* format, int v_tid, int a_tid);
81+
82+
virtual srs_error_t write_video_only(SrsFormat* format, int v_tid);
83+
virtual srs_error_t write_audio_only(SrsFormat* format, int a_tid);
84+
private:
85+
virtual srs_error_t init_encoder();
86+
8187
};
8288

8389
// TODO: merge this code with SrsFragmentedMp4 in dash
@@ -342,7 +348,7 @@ class SrsHlsFmp4Muxer
342348
// When publish or unpublish stream.
343349
virtual srs_error_t on_publish(SrsRequest* req);
344350

345-
virtual srs_error_t write_init_mp4(SrsFormat* format);
351+
virtual srs_error_t write_init_mp4(SrsFormat* format, bool has_video, bool has_audio);
346352
virtual srs_error_t write_audio(SrsSharedPtrMessage* shared_audio, SrsFormat* format);
347353
virtual srs_error_t write_video(SrsSharedPtrMessage* shared_video, SrsFormat* format);
348354

trunk/src/kernel/srs_kernel_codec.hpp

+1
Original file line numberDiff line numberDiff line change
@@ -1298,6 +1298,7 @@ class SrsVideoFrame : public SrsFrame
12981298
{
12991299
public:
13001300
// video specified
1301+
// TODO: H.264 and H.265 reused AvcFrameType and AvcFrameTrait?
13011302
SrsVideoAvcFrameType frame_type;
13021303
SrsVideoAvcFrameTrait avc_packet_type;
13031304
// whether sample_units contains IDR frame.

trunk/src/kernel/srs_kernel_mp4.cpp

+12-8
Original file line numberDiff line numberDiff line change
@@ -6646,18 +6646,22 @@ srs_error_t SrsMp4M2tsInitEncoder::write(SrsFormat* format, int v_tid, int a_tid
66466646
moov->set_mvex(mvex);
66476647

66486648
// video trex
6649-
SrsMp4TrackExtendsBox* v_trex = new SrsMp4TrackExtendsBox();
6650-
mvex->add_trex(v_trex);
6649+
if (format->vcodec) {
6650+
SrsMp4TrackExtendsBox* v_trex = new SrsMp4TrackExtendsBox();
6651+
mvex->add_trex(v_trex);
66516652

6652-
v_trex->track_ID = v_tid;
6653-
v_trex->default_sample_description_index = 1;
6653+
v_trex->track_ID = v_tid;
6654+
v_trex->default_sample_description_index = 1;
6655+
}
66546656

66556657
// audio trex
6656-
SrsMp4TrackExtendsBox* a_trex = new SrsMp4TrackExtendsBox();
6657-
mvex->add_trex(a_trex);
6658+
if (format->acodec) {
6659+
SrsMp4TrackExtendsBox* a_trex = new SrsMp4TrackExtendsBox();
6660+
mvex->add_trex(a_trex);
66586661

6659-
a_trex->track_ID = a_tid;
6660-
a_trex->default_sample_description_index = 1;
6662+
a_trex->track_ID = a_tid;
6663+
a_trex->default_sample_description_index = 1;
6664+
}
66616665
}
66626666

66636667
if ((err = srs_mp4_write_box(writer, moov.get())) != srs_success) {

0 commit comments

Comments
 (0)