harlanc / xiu

A simple,high performance and secure live media server in pure Rust (RTMP[cluster]/RTSP/WebRTC[whip/whep]/HTTP-FLV/HLS).🦀
https://www.rustxiu.com
MIT License
1.6k stars 168 forks source link

fix RTMP publish single AAC from ffmpeg client. #110

Closed suzp1984 closed 2 months ago

suzp1984 commented 3 months ago

step to reproduce

ffmpeg -stream_loop -1 -re -i music.aac -c copy -f flv -y rtmp://localhost/live/test

error logs

[2024-03-28T07:04:23Z INFO  rtmp::rtmp] session run error: session_type: server, app_name: live, stream_name: livestream, err: cache error name: mpeg aac error

cause

the first two chunk stream's body length is 2 and 4. xiu can't handle them. the first packet: 0xAF, 0x00 the second packet: 0xAF, 0x00, 0x11, 0x90

Solution

  1. ignore the chunk payload with small size.
  2. AAC profile workaround, there is a overflow error.
suzp1984 commented 3 months ago

@harlanc told me the first two audio frame are AAC sequence header, the first frame is just the Audio Tag header, 0xAF, 0x00, without any data, while the second frame, 0xAF, 0x00, 0x11, 0x90, the data is 0x11, 0x90, which is the Audio Specific Config.

I copy the SRS's solution to process the AAC sequence Header.

srs_error_t SrsFormat::audio_aac_demux(SrsBuffer* stream, int64_t timestamp)
{
    srs_error_t err = srs_success;

    audio->cts = 0;
    audio->dts = timestamp;

    // @see: E.4.2 Audio Tags, video_file_format_spec_v10_1.pdf, page 76
    int8_t sound_format = stream->read_1bytes();

    int8_t sound_type = sound_format & 0x01;
    int8_t sound_size = (sound_format >> 1) & 0x01;
    int8_t sound_rate = (sound_format >> 2) & 0x03;
    sound_format = (sound_format >> 4) & 0x0f;

    SrsAudioCodecId codec_id = (SrsAudioCodecId)sound_format;
    acodec->id = codec_id;

    acodec->sound_type = (SrsAudioChannels)sound_type;
    acodec->sound_rate = (SrsAudioSampleRate)sound_rate;
    acodec->sound_size = (SrsAudioSampleBits)sound_size;

    // we support h.264+mp3 for hls.
    if (codec_id == SrsAudioCodecIdMP3) {
        return srs_error_new(ERROR_HLS_TRY_MP3, "try mp3");
    }

    // only support aac
    if (codec_id != SrsAudioCodecIdAAC) {
        return srs_error_new(ERROR_HLS_DECODE_ERROR, "not supported codec %d", codec_id);
    }

    if (!stream->require(1)) {
        return srs_error_new(ERROR_HLS_DECODE_ERROR, "aac decode aac_packet_type");
    }

    SrsAudioAacFrameTrait aac_packet_type = (SrsAudioAacFrameTrait)stream->read_1bytes();
    audio->aac_packet_type = (SrsAudioAacFrameTrait)aac_packet_type;

    // Update the RAW AAC data.
    raw = stream->data() + stream->pos();
    nb_raw = stream->size() - stream->pos();

    if (aac_packet_type == SrsAudioAacFrameTraitSequenceHeader) {
        // AudioSpecificConfig
        // 1.6.2.1 AudioSpecificConfig, in ISO_IEC_14496-3-AAC-2001.pdf, page 33.
        int aac_extra_size = stream->size() - stream->pos();
        if (aac_extra_size > 0) {
            char *copy_stream_from = stream->data() + stream->pos();
            acodec->aac_extra_data = std::vector<char>(copy_stream_from, copy_stream_from + aac_extra_size);

            if ((err = audio_aac_sequence_header_demux(&acodec->aac_extra_data[0], aac_extra_size)) != srs_success) {
                return srs_error_wrap(err, "demux aac sh");
            }
        }
    } else if (aac_packet_type == SrsAudioAacFrameTraitRawData) {

https://github.com/ossrs/srs/blob/427104f1dab86f5afc7d7b49b02ed27d03ef9346/trunk/src/kernel/srs_kernel_codec.cpp#L2654-L2709

For the AAC sequence header, ignore the 0xAF, 0x00, just handle the AudioSpecificConfig, 0x11, 0x90.

suzp1984 commented 2 months ago

The single AAC can be played now, by RTMP, RTSP, FLV, HLS now.

harlanc commented 2 months ago

Thanks.