Beispiel #1
0
    void
    AACPacketizer::pushBuffer(const uint8_t* const inBuffer, size_t inSize, IMetadata& metadata)
    {
        const auto now = std::chrono::steady_clock::now();
        const uint64_t bufferDuration(metadata.timestampDelta * 1000000.);
        const double nowmicros (std::chrono::duration_cast<std::chrono::microseconds>(now - m_epoch).count());
        
        
        const auto micros = std::floor(nowmicros / double(bufferDuration)) * bufferDuration;
        
        std::vector<uint8_t> & outBuffer = m_outbuffer;
        
        outBuffer.clear();
        
        int flags = 0;
        const int flags_size = 2;
        
        //static int prev_ts = 0;
        
        int ts = micros / 1000; // m_audioTs * 1000.;//

        
        auto output = m_output.lock();
        RTMPMetadata_t outMeta(metadata.timestampDelta);
        
        if(output) {
        
            flags = FLV_CODECID_AAC | FLV_SAMPLERATE_44100HZ | FLV_SAMPLESSIZE_16BIT | FLV_STEREO;
        
        
            outBuffer.reserve(inSize + flags_size);
        
            put_byte(outBuffer, flags);
            put_byte(outBuffer, m_sentAudioConfig);
            if(!m_sentAudioConfig) {
                
                m_sentAudioConfig = true;
                const char hdr[2] = { 0x12,0x10 };
                put_buff(outBuffer, (uint8_t*)hdr, 2);
                
            } else {
                
                put_buff(outBuffer, inBuffer, inSize);
                m_audioTs += metadata.timestampDelta;
                
            }

            outMeta.setData(ts, static_cast<int>(outBuffer.size()), FLV_TAG_TYPE_AUDIO, kAudioChannelStreamId);
            
            output->pushBuffer(&outBuffer[0], outBuffer.size(), outMeta);
        }

    }
    void
    AACPacketizer::pushBuffer(const uint8_t* const inBuffer, size_t inSize, IMetadata& metadata)
    {
        std::vector<uint8_t> & outBuffer = m_outbuffer;

        outBuffer.clear();

        int flvStereoOrMono = (m_channelCount == 2 ? FLV_STEREO : FLV_MONO);
        int flvSampleRate = FLV_SAMPLERATE_44100HZ; // default
        if (m_sampleRate == 22050.0) {
            flvSampleRate = FLV_SAMPLERATE_22050HZ;
        }

        int flags = 0;
        const int flags_size = 2;


        int ts = metadata.timestampDelta + m_ctsOffset ;
//        DLog("AAC: %06d", ts);
        
        auto output = m_output.lock();

        RTMPMetadata_t outMeta(ts);

        if(inSize == 2 && !m_asc[0] && !m_asc[1]) {
            m_asc[0] = inBuffer[0];
            m_asc[1] = inBuffer[1];
        }

        if(output) {

            flags = FLV_CODECID_AAC | flvSampleRate | FLV_SAMPLESSIZE_16BIT | flvStereoOrMono;

            outBuffer.reserve(inSize + flags_size);

            put_byte(outBuffer, flags);
            put_byte(outBuffer, m_sentAudioConfig);

            if(!m_sentAudioConfig) {
                m_sentAudioConfig = true;
                put_buff(outBuffer, (uint8_t*)m_asc, sizeof(m_asc));

            } else {
                put_buff(outBuffer, inBuffer, inSize);
            }

            outMeta.setData(ts, static_cast<int>(outBuffer.size()), RTMP_PT_AUDIO, kAudioChannelStreamId, false);

            output->pushBuffer(&outBuffer[0], outBuffer.size(), outMeta);
        }

    }
    void
    AACPacketizer::pushBuffer(const uint8_t* const inBuffer, size_t inSize, IMetadata& metadata)
    {
        std::vector<uint8_t> & outBuffer = m_outbuffer;
        
        outBuffer.clear();
        
        int flags = 0;
        const int flags_size = 2;
    
        
        int ts = metadata.timestampDelta;
        
        auto output = m_output.lock();
        
        RTMPMetadata_t outMeta(metadata.timestampDelta);
        
        if(inSize == 2 && !m_asc[0] && !m_asc[1]) {
            m_asc[0] = inBuffer[0];
            m_asc[1] = inBuffer[1];
        }
        
        if(output) {
        
            flags = FLV_CODECID_AAC | FLV_SAMPLERATE_44100HZ | FLV_SAMPLESSIZE_16BIT | FLV_STEREO;
           
            outBuffer.reserve(inSize + flags_size);
            
            put_byte(outBuffer, flags);
            put_byte(outBuffer, m_sentAudioConfig);

            if(!m_sentAudioConfig) {
                m_sentAudioConfig = true;
                put_buff(outBuffer, (uint8_t*)m_asc, sizeof(m_asc));
                
            } else {
                
                put_buff(outBuffer, inBuffer, inSize);
                m_audioTs += metadata.timestampDelta;
                
            }

            outMeta.setData(ts, static_cast<int>(outBuffer.size()), FLV_TAG_TYPE_AUDIO, kAudioChannelStreamId);
            
            output->pushBuffer(&outBuffer[0], outBuffer.size(), outMeta);
        }

    }
 void
 RTMPSession::sendSetChunkSize(int32_t chunkSize)
 {
     
     m_jobQueue.enqueue([&, chunkSize] {
         
         int streamId = 0;
         
         std::vector<uint8_t> buff;
         
         put_byte(buff, 2); // chunk stream ID 2
         put_be24(buff, 0); // ts
         put_be24(buff, 4); // size (4 bytes)
         put_byte(buff, RTMP_PT_CHUNK_SIZE); // chunk type
         
         put_buff(buff, (uint8_t*)&streamId, sizeof(int32_t)); // msg stream id is little-endian
         
         put_be32(buff, chunkSize);
         
         write(&buff[0], buff.size());
         
         m_outChunkSize = chunkSize;
     });
     
 }
 std::vector<uint8_t>
 H264Packetizer::configurationFromSpsAndPps()
 {
     std::vector<uint8_t> conf;
     
     put_byte(conf, 1); // version
     put_byte(conf, m_sps[1]); // profile
     put_byte(conf, m_sps[2]); // compat
     put_byte(conf, m_sps[3]); // level
     put_byte(conf, 0xff);   // 6 bits reserved + 2 bits nal size length - 1 (11)
     put_byte(conf, 0xe1);   // 3 bits reserved + 5 bits number of sps (00001)
     put_be16(conf, m_sps.size());
     put_buff(conf, &m_sps[0], m_sps.size());
     put_byte(conf, 1);
     put_be16(conf, m_pps.size());
     put_buff(conf, &m_pps[0], m_pps.size());
     
     return conf;
     
 }
 void
 RTMPSession::sendHeaderPacket()
 {
     std::vector<uint8_t> outBuffer;
     
     std::vector<uint8_t> enc;
     RTMPChunk_0 metadata = {{0}};
     
     put_string(enc, "@setDataFrame");
     put_string(enc, "onMetaData");
     put_byte(enc, kAMFEMCAArray);
     put_be32(enc, 5+5+2); // videoEnabled + audioEnabled + 2
     
     put_named_double(enc, "duration", 0.0);
     put_named_double(enc, "width", m_frameWidth);
     put_named_double(enc, "height", m_frameHeight);
     put_named_double(enc, "videodatarate", static_cast<double>(m_bitrate) / 1024.);
     put_named_double(enc, "framerate", m_frameDuration);
     put_named_double(enc, "videocodecid", 7.);
     
     
     put_named_double(enc, "audiodatarate", 131152. / 1024.);
     put_named_double(enc, "audiosamplerate", m_audioSampleRate);
     put_named_double(enc, "audiosamplesize", 16);
     put_named_bool(enc, "stereo", m_audioStereo);
     put_named_double(enc, "audiocodecid", 10.);
     
     
     put_named_double(enc, "filesize", 0.);
     put_be16(enc, 0);
     put_byte(enc, kAMFObjectEnd);
     size_t len = enc.size();
     
     
     put_buff(outBuffer, (uint8_t*)&enc[0], static_cast<size_t>(len));
     
     
     metadata.msg_type_id = FLV_TAG_TYPE_META;
     metadata.msg_stream_id = kAudioChannelStreamId;
     metadata.msg_length.data = static_cast<int>( outBuffer.size() );
     metadata.timestamp.data = 0;
     
     sendPacket(&outBuffer[0], outBuffer.size(), metadata);
     
 }
 void
 RTMPSession::sendSetBufferTime(int milliseconds)
 {
     m_jobQueue.enqueue([=]{
         int streamId = 0;
         std::vector<uint8_t> buff;
         put_byte(buff, 2);
         put_be24(buff, 0);
         put_be24(buff, 10);
         put_byte(buff, RTMP_PT_PING);
         put_buff(buff, (uint8_t*)&streamId, sizeof(int32_t));
         
         put_be16(buff, 3); // SetBufferTime
         put_be32(buff, m_streamId);
         put_be32(buff, milliseconds);
         
         write(&buff[0], buff.size());
         
     });
 }    bool
 void
 RTMPSession::sendPong()
 {
     m_jobQueue.enqueue([&] {
         
         int streamId = 0;
         
         std::vector<uint8_t> buff;
         
         put_byte(buff, 2); // chunk stream ID 2
         put_be24(buff, 0); // ts
         put_be24(buff, 6); // size (6 bytes)
         put_byte(buff, RTMP_PT_PING); // chunk type
         
         put_buff(buff, (uint8_t*)&streamId, sizeof(int32_t)); // msg stream id is little-endian
         put_be16(buff, 7);
         put_be16(buff, 0);
         put_be16(buff, 0);
         
         write(&buff[0], buff.size());
     });
 }
    void H264Packetizer::pushBuffer(const uint8_t* const inBuffer, size_t inSize, IMetadata& inMetadata)
    {
        
      
      
        
        std::vector<uint8_t>& outBuffer = m_outbuffer;
        
        outBuffer.clear();
        
        uint8_t nal_type = inBuffer[4] & 0x1F;
        int flags = 0;
        const int flags_size = 5;
        const int ts = inMetadata.timestampDelta;

        bool is_config = (nal_type == 7 || nal_type == 8);
        
        
        flags = FLV_CODECID_H264;
        auto output = m_output.lock();
        RTMPMetadata_t outMeta(inMetadata.timestampDelta);

        switch(nal_type) {
            case 7:
                if(m_sps.size() == 0) {
                    m_sps.resize(inSize-4);
                    memcpy(&m_sps[0], inBuffer+4, inSize-4);
                    
                }
                return;
            case 8:
                if(m_pps.size() == 0) {
                    m_pps.resize(inSize-4);
                    memcpy(&m_pps[0], inBuffer+4, inSize-4);
                }

                flags |= FLV_FRAME_KEY;
                break;
            case 5:
                flags |= FLV_FRAME_KEY;
                
                break;
            default:
                flags |= FLV_FRAME_INTER;
                
                
                break;
                
        }
        
        if(output) {
            std::vector<uint8_t> conf;
            
            if(is_config && m_sps.size() > 0 && m_pps.size() > 0 ) {
                conf = configurationFromSpsAndPps();
                inSize = conf.size();
            }
            outBuffer.reserve(inSize + flags_size);
            
            put_byte(outBuffer, flags);
            put_byte(outBuffer, !is_config);
            put_be24(outBuffer, 0);
            
            if(is_config) {
                // create modified SPS/PPS buffer
                if(m_sps.size() > 0 && m_pps.size() > 0 && !m_sentConfig) {
                    put_buff(outBuffer, &conf[0], conf.size());
                    m_sentConfig = true;
                } else {
                    return;
                }
            } else {
                put_buff(outBuffer, inBuffer, inSize);
            }
            
            static auto prev_time = std::chrono::steady_clock::now();
            auto now = std::chrono::steady_clock::now();
            
            auto m_micros = std::chrono::duration_cast<std::chrono::microseconds>(now - prev_time).count();
            static uint64_t total = 0;
            static uint64_t count = 0;
            
            total+=m_micros;
            count++;
            
            prev_time = now;
            outMeta.setData(ts, static_cast<int>(outBuffer.size()), FLV_TAG_TYPE_VIDEO, kVideoChannelStreamId);
            
            output->pushBuffer(&outBuffer[0], outBuffer.size(), outMeta);
        }
        
    }
    void H264Packetizer::pushBuffer(const uint8_t* const inBuffer, size_t inSize, IMetadata& inMetadata)
    {
        std::vector<uint8_t>& outBuffer = m_outbuffer;
        
        outBuffer.clear();
        
        uint8_t nal_type = inBuffer[4] & 0x1F;
        int flags = 0;
        const int flags_size = 5;
        int dts = inMetadata.dts ;
        int pts = inMetadata.pts + m_ctsOffset; // correct for pts < dts which some players (ffmpeg) don't like
        
        dts = dts > 0 ? dts : pts - m_ctsOffset ;
        
        bool is_config = (nal_type == 7 || nal_type == 8);
        
        flags = FLV_CODECID_H264;
        auto output = m_output.lock();

        switch(nal_type) {
            case 7:
                if(m_sps.size() == 0) {
                    m_sps.resize(inSize-4);
                    memcpy(&m_sps[0], inBuffer+4, inSize-4);
                }
                break;
            case 8:
                if(m_pps.size() == 0) {
                    m_pps.resize(inSize-4);
                    memcpy(&m_pps[0], inBuffer+4, inSize-4);
                }
                flags |= FLV_FRAME_KEY;
                break;
            case 5:
                flags |= FLV_FRAME_KEY;
                
                break;
            default:
                flags |= FLV_FRAME_INTER;
                
                
                break;
                
        }
        
        
        if(output) {
            
            RTMPMetadata_t outMeta(dts);
            std::vector<uint8_t> conf;
            
            if(is_config && m_sps.size() > 0 && m_pps.size() > 0 ) {
                conf = configurationFromSpsAndPps();
                inSize = conf.size();
            }
            outBuffer.reserve(inSize + flags_size);
            
            put_byte(outBuffer, flags);
            put_byte(outBuffer, !is_config);
            put_be24(outBuffer, pts - dts);             // Decoder delay
            
            if(is_config ) {
                // create modified SPS/PPS buffer
                if(m_sps.size() > 0 && m_pps.size() > 0 && !m_sentConfig && (flags & FLV_FRAME_KEY)) {
                    put_buff(outBuffer, &conf[0], conf.size());
                    m_sentConfig = true;
                } else {
                    return;
                }
            } else {
                put_buff(outBuffer, inBuffer, inSize);
            }
            
            outMeta.setData(dts, static_cast<int>(outBuffer.size()), RTMP_PT_VIDEO, kVideoChannelStreamId, nal_type == 5);
            
            output->pushBuffer(&outBuffer[0], outBuffer.size(), outMeta);
        }
        
    }
    void
    RTMPSession::sendHeaderPacket()
    {
        std::vector<uint8_t> outBuffer;
        
        std::vector<uint8_t> enc;
        RTMPChunk_0 metadata = {{0}};
        
        put_string(enc, "@setDataFrame");
        put_string(enc, "onMetaData");
        put_byte(enc, kAMFObject);
        //put_be32(enc, 5+5+2); // videoEnabled + audioEnabled + 2
        
        //put_named_double(enc, "duration", 0.0);
        put_named_double(enc, "width", m_frameWidth);
        put_named_double(enc, "height", m_frameHeight);
        put_named_double(enc, "displaywidth", m_frameWidth);
        put_named_double(enc, "displayheight", m_frameHeight);
        put_named_double(enc, "framewidth", m_frameWidth);
        put_named_double(enc, "frameheight", m_frameHeight);
        put_named_double(enc, "videodatarate", static_cast<double>(m_bitrate) / 1024.);
        put_named_double(enc, "videoframerate", 1. / m_frameDuration);

        put_named_string(enc, "videocodecid", "avc1");
        {
            put_name(enc, "trackinfo");
            put_byte(enc, kAMFStrictArray);
            put_be32(enc, 2);
            
            //
            // Audio stream metadata
            put_byte(enc, kAMFObject);
            put_named_string(enc, "type", "audio");
            {
                std::stringstream ss;
                ss << "{AACFrame: codec:AAC, channels: " << m_audioStereo+1 << ", frequency:" << m_audioSampleRate << ", samplesPerFrame:1024, objectType:LC}";
                put_named_string(enc, "description", ss.str());
            }
            put_named_double(enc, "timescale", 1000.);
            
            put_name(enc, "sampledescription");
            put_byte(enc, kAMFStrictArray);
            put_be32(enc, 1);
            put_byte(enc, kAMFObject);
            put_named_string(enc, "sampletype", "mpeg4-generic");
            put_byte(enc, 0);
            put_byte(enc, 0);
            put_byte(enc, kAMFObjectEnd);
            
            put_named_string(enc, "language", "eng");

            put_byte(enc, 0);
            put_byte(enc, 0);
            put_byte(enc, kAMFObjectEnd);
            
            //
            // Video stream metadata
            
            put_byte(enc, kAMFObject);
            put_named_string(enc, "type", "video");
            put_named_double(enc, "timescale", 1000.);
            put_named_string(enc, "language", "eng");
            put_name(enc, "sampledescription");
            put_byte(enc, kAMFStrictArray);
            put_be32(enc, 1);
            put_byte(enc, kAMFObject);
            put_named_string(enc, "sampletype", "H264");
            put_byte(enc, 0);
            put_byte(enc, 0);
            put_byte(enc, kAMFObjectEnd);
            put_byte(enc, 0);
            put_byte(enc, 0);
            put_byte(enc, kAMFObjectEnd);
        }
        put_be16(enc, 0);
        put_byte(enc, kAMFObjectEnd);
        put_named_double(enc, "audiodatarate", 131152. / 1024.);
        put_named_double(enc, "audiosamplerate", m_audioSampleRate);
        put_named_double(enc, "audiosamplesize", 16);
        put_named_double(enc, "audiochannels", m_audioStereo + 1);
        put_named_string(enc, "audiocodecid", "mp4a");
        
        put_be16(enc, 0);
        put_byte(enc, kAMFObjectEnd);
        size_t len = enc.size();
        
        
        put_buff(outBuffer, (uint8_t*)&enc[0], static_cast<size_t>(len));
        
        
        metadata.msg_type_id = FLV_TAG_TYPE_META;
        metadata.msg_stream_id = kAudioChannelStreamId;
        metadata.msg_length.data = static_cast<int>( outBuffer.size() );
        metadata.timestamp.data = 0;
        
        sendPacket(&outBuffer[0], outBuffer.size(), metadata);
        
    }
    void
    RTMPSession::pushBuffer(const uint8_t* const data, size_t size, IMetadata& metadata)
    {
        if(m_ending) {
            return ;
        }
        
        std::shared_ptr<Buffer> buf = std::make_shared<Buffer>(size);
        buf->put(const_cast<uint8_t*>(data), size);
        
        const RTMPMetadata_t inMetadata = static_cast<const RTMPMetadata_t&>(metadata);

        m_jobQueue.enqueue([=]() {
            
            if(!this->m_ending) {
                static int c_count = 0;
                c_count ++;
                
                auto packetTime = std::chrono::steady_clock::now();
                
                std::vector<uint8_t> chunk;
                std::shared_ptr<std::vector<uint8_t>> outb = std::make_shared<std::vector<uint8_t>>();
                outb->reserve(size + 64);
                size_t len = buf->size();
                size_t tosend = std::min(len, m_outChunkSize);
                uint8_t* p;
                buf->read(&p, buf->size());
                uint64_t ts = inMetadata.getData<kRTMPMetadataTimestamp>() ;
                const int streamId = inMetadata.getData<kRTMPMetadataMsgStreamId>();
                
#ifndef RTMP_CHUNK_TYPE_0_ONLY
                auto it = m_previousChunkData.find(streamId);
                if(it == m_previousChunkData.end()) {
#endif
                    // Type 0.
                    put_byte(chunk, ( streamId & 0x1F));
                    put_be24(chunk, static_cast<uint32_t>(ts));
                    put_be24(chunk, inMetadata.getData<kRTMPMetadataMsgLength>());
                    put_byte(chunk, inMetadata.getData<kRTMPMetadataMsgTypeId>());
                    put_buff(chunk, (uint8_t*)&m_streamId, sizeof(int32_t)); // msg stream id is little-endian
#ifndef RTMP_CHUNK_TYPE_0_ONLY
                } else {
                    // Type 1.
                    put_byte(chunk, RTMP_CHUNK_TYPE_1 | (streamId & 0x1F));
                    put_be24(chunk, static_cast<uint32_t>(ts - it->second)); // timestamp delta
                    put_be24(chunk, inMetadata.getData<kRTMPMetadataMsgLength>());
                    put_byte(chunk, inMetadata.getData<kRTMPMetadataMsgTypeId>());
                }
#endif
                m_previousChunkData[streamId] = ts;
                put_buff(chunk, p, tosend);
                
                outb->insert(outb->end(), chunk.begin(), chunk.end());
                
                len -= tosend;
                p += tosend;
                
                while(len > 0) {
                    tosend = std::min(len, m_outChunkSize);
                    p[-1] = RTMP_CHUNK_TYPE_3 | (streamId & 0x1F);
                    
                    outb->insert(outb->end(), p-1, p+tosend);
                    p+=tosend;
                    len-=tosend;
                    //  this->write(&outb[0], outb.size(), packetTime);
                    //  outb.clear();
                    
                }
                
                this->write(&(*outb)[0], outb->size(), packetTime, inMetadata.getData<kRTMPMetadataIsKeyframe>() );
            }
            
            
        });
    }