diff --git a/trunk/src/app/srs_app_hls.cpp b/trunk/src/app/srs_app_hls.cpp index b751e26ef..c6b1f5d72 100644 --- a/trunk/src/app/srs_app_hls.cpp +++ b/trunk/src/app/srs_app_hls.cpp @@ -309,6 +309,12 @@ int SrsHlsMuxer::flush_audio(SrsMpegtsFrame* af, SrsSimpleBuffer* ab) { int ret = ERROR_SUCCESS; + // if flushed yet, ignore. + if (ab->length() == 0) { + srs_info("ignore hls segment audio flushed yet."); + return ret; + } + // if current is NULL, segment is not open, ignore the flush event. if (!current) { srs_warn("flush audio ignored, for segment is not open."); @@ -336,6 +342,12 @@ int SrsHlsMuxer::flush_video(SrsMpegtsFrame* /*af*/, SrsSimpleBuffer* /*ab*/, Sr { int ret = ERROR_SUCCESS; + // if flushed yet, ignore. + if (vb->length() == 0) { + srs_info("ignore hls segment video flushed yet."); + return ret; + } + // if current is NULL, segment is not open, ignore the flush event. if (!current) { srs_warn("flush video ignored, for segment is not open."); @@ -776,6 +788,13 @@ int SrsHlsCache::reap_segment(string log_desc, SrsHlsMuxer* muxer, int64_t segme } // TODO: flush audio before or after segment? + + // segment open, flush video first. + if ((ret = muxer->flush_video(cache->af, cache->ab, cache->vf, cache->vb)) != ERROR_SUCCESS) { + srs_error("m3u8 muxer flush video failed. ret=%d", ret); + return ret; + } + // segment open, flush the audio. // @see: ngx_rtmp_hls_open_fragment /* start fragment with audio to make iPhone happy */ diff --git a/trunk/src/core/srs_core.hpp b/trunk/src/core/srs_core.hpp index 7c341e8e9..7ff4aa757 100644 --- a/trunk/src/core/srs_core.hpp +++ b/trunk/src/core/srs_core.hpp @@ -31,7 +31,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // current release version #define VERSION_MAJOR 2 #define VERSION_MINOR 0 -#define VERSION_REVISION 112 +#define VERSION_REVISION 113 // server info. #define RTMP_SIG_SRS_KEY "SRS" diff --git a/trunk/src/kernel/srs_kernel_codec.cpp b/trunk/src/kernel/srs_kernel_codec.cpp index 4f4ada27b..5d1cc519e 100644 --- a/trunk/src/kernel/srs_kernel_codec.cpp +++ b/trunk/src/kernel/srs_kernel_codec.cpp @@ -281,25 +281,41 @@ int SrsAvcAacCodec::audio_aac_demux(char* data, int size, SrsCodecSample* sample } // only need to decode the first 2bytes: - // audioObjectType, aac_profile, 5bits. - // samplingFrequencyIndex, aac_sample_rate, 4bits. - // channelConfiguration, aac_channels, 4bits + // audioObjectType, aac_profile, 5bits. + // samplingFrequencyIndex, aac_sample_rate, 4bits. + // channelConfiguration, aac_channels, 4bits if (!stream->require(2)) { ret = ERROR_HLS_DECODE_ERROR; srs_error("audio codec decode aac sequence header failed. ret=%d", ret); return ret; } - aac_profile = stream->read_1bytes(); - aac_sample_rate = stream->read_1bytes(); + u_int8_t profile_ObjectType = stream->read_1bytes(); + u_int8_t samplingFrequencyIndex = stream->read_1bytes(); - aac_channels = (aac_sample_rate >> 3) & 0x0f; - aac_sample_rate = ((aac_profile << 1) & 0x0e) | ((aac_sample_rate >> 7) & 0x01); - aac_profile = (aac_profile >> 3) & 0x1f; + aac_channels = (samplingFrequencyIndex >> 3) & 0x0f; + samplingFrequencyIndex = ((profile_ObjectType << 1) & 0x0e) | ((samplingFrequencyIndex >> 7) & 0x01); + profile_ObjectType = (profile_ObjectType >> 3) & 0x1f; + + // set the aac sample rate. + aac_sample_rate = samplingFrequencyIndex; + + // the profile = object_id + 1 + // @see aac-mp4a-format-ISO_IEC_14496-3+2001.pdf, page 78, + // Table 1. A.9 每 MPEG-2 Audio profiles and MPEG-4 Audio object types + aac_profile = profile_ObjectType + 1; - if (aac_profile == 0 || aac_profile == 0x1f) { + // the valid aac profile: + // MPEG-2 profile + // Main profile (ID == 1) + // Low Complexity profile (LC) (ID == 2) + // Scalable Sampling Rate profile (SSR) (ID == 3) + // (reserved) (ID == 4) + // @see aac-mp4a-format-ISO_IEC_14496-3+2001.pdf, page 78, + // Table 1. A.9 每 MPEG-2 Audio profiles and MPEG-4 Audio object types + if (aac_profile > 4) { ret = ERROR_HLS_DECODE_ERROR; srs_error("audio codec decode aac sequence header failed, " - "adts object=%d invalid. ret=%d", aac_profile, ret); + "adts object=%d invalid. ret=%d", profile_ObjectType, ret); return ret; } diff --git a/trunk/src/kernel/srs_kernel_ts.cpp b/trunk/src/kernel/srs_kernel_ts.cpp index 439261172..3ba7f16fa 100644 --- a/trunk/src/kernel/srs_kernel_ts.cpp +++ b/trunk/src/kernel/srs_kernel_ts.cpp @@ -1989,6 +1989,20 @@ int SrsTsCache::do_cache_audio(SrsAvcAacCodec* codec, SrsCodecSample* sample) srs_error("invalid aac frame length=%d, ret=%d", size, ret); return ret; } + + // the profile = object_id + 1 + // @see aac-mp4a-format-ISO_IEC_14496-3+2001.pdf, page 78, + // Table 1. A.9 每 MPEG-2 Audio profiles and MPEG-4 Audio object types + // the valid object type: + // AAC Main(ID == 0) + // AAC LC(ID == 1) + // AAC SSR(ID == 2) + // AAC LTP(ID == 3) + u_int8_t profile_ObjectType = codec->aac_profile - 1; + + // TODO: FIXME: only support Main or LC. + // @see https://github.com/winlinvip/simple-rtmp-server/issues/310 + profile_ObjectType = srs_min(1, profile_ObjectType); // the frame length is the AAC raw data plus the adts header size. int32_t frame_length = size + 7; @@ -2022,7 +2036,7 @@ int SrsTsCache::do_cache_audio(SrsAvcAacCodec* codec, SrsCodecSample* sample) int8_t number_of_raw_data_blocks_in_frame; //2bits, 0 indicating 1 raw_data_block() */ // profile, 2bits - adts_header[2] = (codec->aac_profile << 6) & 0xc0; + adts_header[2] = (profile_ObjectType << 6) & 0xc0; // sampling_frequency_index 4bits adts_header[2] |= (codec->aac_sample_rate << 2) & 0x3c; // channel_configuration 3bits diff --git a/trunk/src/protocol/srs_raw_avc.cpp b/trunk/src/protocol/srs_raw_avc.cpp index 1b7c1fe01..143ea6fa3 100644 --- a/trunk/src/protocol/srs_raw_avc.cpp +++ b/trunk/src/protocol/srs_raw_avc.cpp @@ -375,10 +375,10 @@ int SrsRawAacStream::adts_demux(SrsStream* stream, char** pframe, int* pnb_frame // channel_configuration 3 uimsbf // original/copy 1 bslbf // home 1 bslbf - int8_t fh_Profile_ObjectType = (fh1 >> 14) & 0x03; - int8_t fh_sampling_frequency_index = (fh1 >> 10) & 0x0f; + int8_t audioObjectType = (fh1 >> 14) & 0x03; + int8_t samplingFrequencyIndex = (fh1 >> 10) & 0x0f; /*int8_t fh_private_bit = (fh1 >> 9) & 0x01;*/ - int8_t fh_channel_configuration = (fh1 >> 6) & 0x07; + int8_t channelConfiguration = (fh1 >> 6) & 0x07; /*int8_t fh_original = (fh1 >> 5) & 0x01;*/ /*int8_t fh_home = (fh1 >> 4) & 0x01;*/ // @remark, Emphasis is removed, @@ -412,8 +412,8 @@ int SrsRawAacStream::adts_demux(SrsStream* stream, char** pframe, int* pnb_frame /*int16_t crc_check = */stream->read_2bytes(); } - // TODO: check the fh_sampling_frequency_index - // TODO: check the fh_channel_configuration + // TODO: check the samplingFrequencyIndex + // TODO: check the channelConfiguration // raw_data_blocks int adts_header_size = stream->pos() - adts_header_start; @@ -425,34 +425,34 @@ int SrsRawAacStream::adts_demux(SrsStream* stream, char** pframe, int* pnb_frame // the profile = object_id + 1 // @see aac-mp4a-format-ISO_IEC_14496-3+2001.pdf, page 78, // Table 1. A.9 每 MPEG-2 Audio profiles and MPEG-4 Audio object types - char aac_profile = fh_Profile_ObjectType + 1; + char aac_profile = audioObjectType + 1; // the codec info. codec.protection_absent = fh_protection_absent; - codec.Profile_ObjectType = fh_Profile_ObjectType; - codec.sampling_frequency_index = fh_sampling_frequency_index; - codec.channel_configuration = fh_channel_configuration; + codec.Profile_ObjectType = audioObjectType; + codec.sampling_frequency_index = samplingFrequencyIndex; + codec.channel_configuration = channelConfiguration; codec.aac_frame_length = fh_aac_frame_length; codec.aac_profile = aac_profile; - codec.aac_samplerate = fh_sampling_frequency_index; - codec.aac_channel = fh_channel_configuration; + codec.aac_samplerate = samplingFrequencyIndex; + codec.aac_channel = channelConfiguration; // @see srs_audio_write_raw_frame(). codec.sound_format = 10; // AAC - if (fh_sampling_frequency_index <= 0x0c && fh_sampling_frequency_index > 0x0a) { + if (samplingFrequencyIndex <= 0x0c && samplingFrequencyIndex > 0x0a) { codec.sound_rate = SrsCodecAudioSampleRate5512; - } else if (fh_sampling_frequency_index <= 0x0a && fh_sampling_frequency_index > 0x07) { + } else if (samplingFrequencyIndex <= 0x0a && samplingFrequencyIndex > 0x07) { codec.sound_rate = SrsCodecAudioSampleRate11025; - } else if (fh_sampling_frequency_index <= 0x07 && fh_sampling_frequency_index > 0x04) { + } else if (samplingFrequencyIndex <= 0x07 && samplingFrequencyIndex > 0x04) { codec.sound_rate = SrsCodecAudioSampleRate22050; - } else if (fh_sampling_frequency_index <= 0x04) { + } else if (samplingFrequencyIndex <= 0x04) { codec.sound_rate = SrsCodecAudioSampleRate44100; } else { codec.sound_rate = SrsCodecAudioSampleRate44100; - srs_warn("adts invalid sample rate for flv, rate=%#x", fh_sampling_frequency_index); + srs_warn("adts invalid sample rate for flv, rate=%#x", samplingFrequencyIndex); } - codec.sound_size = srs_max(0, srs_min(1, fh_channel_configuration - 1)); + codec.sound_size = srs_max(0, srs_min(1, channelConfiguration - 1)); // TODO: FIXME: finger it out the sound size by adts. codec.sound_size = 1; // 0(8bits) or 1(16bits). @@ -470,20 +470,28 @@ int SrsRawAacStream::adts_demux(SrsStream* stream, char** pframe, int* pnb_frame int SrsRawAacStream::mux_sequence_header(SrsRawAacStreamCodec* codec, string& sh) { int ret = ERROR_SUCCESS; + + // only support aac profile 1-4. + if (codec->aac_profile < 1 || codec->aac_profile > 4) { + return ERROR_AAC_DATA_INVALID; + } - char aac_channel = codec->aac_channel; - char aac_profile = codec->aac_profile; - char aac_samplerate = codec->aac_samplerate; + // the profile = object_id + 1 + // @see aac-mp4a-format-ISO_IEC_14496-3+2001.pdf, page 78, + // Table 1. A.9 每 MPEG-2 Audio profiles and MPEG-4 Audio object types + char profile_ObjectType = codec->aac_profile - 1; + char channelConfiguration = codec->aac_channel; + char samplingFrequencyIndex = codec->aac_samplerate; // override the aac samplerate by user specified. // @see https://github.com/winlinvip/simple-rtmp-server/issues/212#issuecomment-64146899 switch (codec->sound_rate) { case SrsCodecAudioSampleRate11025: - aac_samplerate = 0x0a; break; + samplingFrequencyIndex = 0x0a; break; case SrsCodecAudioSampleRate22050: - aac_samplerate = 0x07; break; + samplingFrequencyIndex = 0x07; break; case SrsCodecAudioSampleRate44100: - aac_samplerate = 0x04; break; + samplingFrequencyIndex = 0x04; break; default: break; } @@ -495,26 +503,22 @@ int SrsRawAacStream::mux_sequence_header(SrsRawAacStreamCodec* codec, string& sh // AudioSpecificConfig (), page 33 // 1.6.2.1 AudioSpecificConfig // audioObjectType; 5 bslbf - ch = (aac_profile << 3) & 0xf8; + ch = (profile_ObjectType << 3) & 0xf8; // 3bits left. // samplingFrequencyIndex; 4 bslbf - ch |= (aac_samplerate >> 1) & 0x07; + ch |= (samplingFrequencyIndex >> 1) & 0x07; sh += ch; - ch = (aac_samplerate << 7) & 0x80; - if (aac_samplerate == 0x0f) { + ch = (samplingFrequencyIndex << 7) & 0x80; + if (samplingFrequencyIndex == 0x0f) { return ERROR_AAC_DATA_INVALID; } // 7bits left. // channelConfiguration; 4 bslbf - ch |= (aac_channel << 3) & 0x78; + ch |= (channelConfiguration << 3) & 0x78; // 3bits left. - // only support aac profile 1-4. - if (aac_profile < 1 || aac_profile > 4) { - return ERROR_AAC_DATA_INVALID; - } // GASpecificConfig(), page 451 // 4.4.1 Decoder configuration (GASpecificConfig) // frameLengthFlag; 1 bslbf