自学内容网 自学内容网

srs rtmp转flv

SrsLiveStream 转换启动类

srs是通过SrsLiveStream来转换rtmp到flv,该类会判断http请求参数,根据后缀".flv"来开启

flv转换相关逻辑。

SrsLiveStream的实现如下:

// HTTP Live Streaming, to transmux RTMP to HTTP FLV or other format.
// TODO: FIXME: Rename to SrsHttpLive
class SrsLiveStream : public ISrsHttpHandler
{
private:
    SrsRequest* req;
    SrsLiveSource* source;
    SrsBufferCache* cache;
public:
    SrsLiveStream(SrsLiveSource* s, SrsRequest* r, SrsBufferCache* c);
    virtual ~SrsLiveStream();
    virtual srs_error_t update_auth(SrsLiveSource* s, SrsRequest* r);
public:
    virtual srs_error_t serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r);
private:
    virtual srs_error_t do_serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r);
    virtual srs_error_t http_hooks_on_play(ISrsHttpMessage* r);
    virtual void http_hooks_on_stop(ISrsHttpMessage* r);
    virtual srs_error_t streaming_send_messages(ISrsBufferEncoder* enc, SrsSharedPtrMessage** msgs, int nb_msgs);
};

调用堆栈

srs!SrsFlvTransmuxer::write_tags(SrsSharedPtrMessage**, int) (/Users/changan1/working/program/srs/trunk/src/kernel/srs_kernel_flv.cpp:568)
srs!SrsFlvStreamEncoder::write_tags(SrsSharedPtrMessage**, int) (/Users/changan1/working/program/srs/trunk/src/app/srs_app_http_stream.cpp:380)
srs!SrsLiveStream::do_serve_http(ISrsHttpResponseWriter*, ISrsHttpMessage*) (/Users/changan1/working/program/srs/trunk/src/app/srs_app_http_stream.cpp:750)
srs!SrsLiveStream::serve_http(ISrsHttpResponseWriter*, ISrsHttpMessage*) (/Users/changan1/working/program/srs/trunk/src/app/srs_app_http_stream.cpp:602)
srs!SrsHttpServeMux::serve_http(ISrsHttpResponseWriter*, ISrsHttpMessage*) (/Users/changan1/working/program/srs/trunk/src/protocol/srs_protocol_http_stack.cpp:788)
srs!SrsHttpServer::serve_http(ISrsHttpResponseWriter*, ISrsHttpMessage*) (/Users/changan1/working/program/srs/trunk/src/app/srs_app_http_conn.cpp:571)
srs!SrsHttpAuthMux::serve_http(ISrsHttpResponseWriter*, ISrsHttpMessage*) (/Users/changan1/working/program/srs/trunk/src/protocol/srs_protocol_http_stack.cpp:977)
srs!SrsHttpCorsMux::serve_http(ISrsHttpResponseWriter*, ISrsHttpMessage*) (/Users/changan1/working/program/srs/trunk/src/protocol/srs_protocol_http_stack.cpp:944)
srs!SrsHttpConn::process_request(ISrsHttpResponseWriter*, ISrsHttpMessage*, int) (/Users/changan1/working/program/srs/trunk/src/app/srs_app_http_conn.cpp:258)
srs!SrsHttpConn::process_requests(SrsRequest**) (/Users/changan1/working/program/srs/trunk/src/app/srs_app_http_conn.cpp:211)
srs!SrsHttpConn::do_cycle() (/Users/changan1/working/program/srs/trunk/src/app/srs_app_http_conn.cpp:162)
srs!SrsHttpConn::cycle() (/Users/changan1/working/program/srs/trunk/src/app/srs_app_http_conn.cpp:107)
srs!SrsFastCoroutine::cycle() (/Users/changan1/working/program/srs/trunk/src/app/srs_app_st.cpp:285)
srs!SrsFastCoroutine::pfn(void*) (/Users/changan1/working/program/srs/trunk/src/app/srs_app_st.cpp:300)
srs!_st_thread_main (/Users/changan1/working/program/srs/trunk/objs/Platform-SRS5-Darwin-22.6.0-Clang15.0.0-x86_64/st-srs/sched.c:380)
srs!st_thread_create (/Users/changan1/working/program/srs/trunk/objs/Platform-SRS5-Darwin-22.6.0-Clang15.0.0-x86_64/st-srs/sched.c:666)

主要函数

srs_error_t SrsLiveStream::do_serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r)
{

  //根据请求参数,开启flv功能
    srs_assert(entry);
    bool drop_if_not_match = _srs_config->get_vhost_http_remux_drop_if_not_match(req->vhost);
    bool has_audio = _srs_config->get_vhost_http_remux_has_audio(req->vhost);
    bool has_video = _srs_config->get_vhost_http_remux_has_video(req->vhost);
    bool guess_has_av = _srs_config->get_vhost_http_remux_guess_has_av(req->vhost);

    if (srs_string_ends_with(entry->pattern, ".flv")) {
        w->header()->set_content_type("video/x-flv");
        enc_desc = "FLV";
        enc = new SrsFlvStreamEncoder();
        ((SrsFlvStreamEncoder*)enc)->set_drop_if_not_match(drop_if_not_match);
        ((SrsFlvStreamEncoder*)enc)->set_has_audio(has_audio);
        ((SrsFlvStreamEncoder*)enc)->set_has_video(has_video);
        ((SrsFlvStreamEncoder*)enc)->set_guess_has_av(guess_has_av);
    } else if (srs_string_ends_with(entry->pattern, ".aac")) {
        w->header()->set_content_type("audio/x-aac");
        enc_desc = "AAC";
        enc = new SrsAacStreamEncoder();

   //创建该 flv转换对应的consumer
   
SrsAutoFree(SrsLiveConsumer, consumer);
    if ((err = source->create_consumer(hc, consumer)) != srs_success) {
        return srs_error_wrap(err, "create consumer");
    }
    if ((err = source->consumer_dumps(consumer, true, true, !enc->has_cache())) != srs_success) {
        return srs_error_wrap(err, "dumps consumer");
    }

       // the memory writer.
    SrsBufferWriter writer(w);
    if ((err = enc->initialize(&writer, cache)) != srs_success) {
        return srs_error_wrap(err, "init encoder");
    }
    //把gop缓存发给新创建的consumer
    // if gop cache enabled for encoder, dump to consumer.
    if (enc->has_cache()) {
        if ((err = enc->dump_cache(consumer, source->jitter())) != srs_success) {
            return srs_error_wrap(err, "encoder dump cache");
        }
    }

    //开启一个while 循环,一直轮训读取rtmp数据,进行转换
    while (/*entry->enabled*/ true) {
        // Whether client closed the FD.
        if ((err = trd->pull()) != srs_success) {
            return srs_error_wrap(err, "recv thread");
        }
 // get messages from consumer.
        // each msg in msgs.msgs must be free, for the SrsMessageArray never free them.
        int count = 0;
        if ((err = consumer->dump_packets(&msgs, count)) != srs_success) {
            return srs_error_wrap(err, "consumer dump packets");
        }
        //写入flv 对应的tag
         // sendout all messages.
        if (ffe) {
            err = ffe->write_tags(msgs.msgs, count);

}

SrsFlvStreamEncoder

最终会调用到:SrsFlvStreamEncoder

srs_error_t SrsFlvStreamEncoder::write_tags(SrsSharedPtrMessage** msgs, int count)
{

    // For https://github.com/ossrs/srs/issues/939
    //首先写入 flv header
    if (!header_written) {
        bool has_video = has_video_; bool has_audio = has_audio_;
    
     if ((err = write_header(has_video, has_audio))  != srs_success) {
            return srs_error_wrap(err, "write header");
     }
  
    //再写入对应的 tag
  
    // Write tags after header is done.
    return enc->write_tags(msgs, count);
}

SrsFlvTransmuxer

写tag,协议层面见类SrsFlvTransmuxer

srs_error_t SrsFlvTransmuxer::write_tags(SrsSharedPtrMessage** msgs, int count)
{
    srs_error_t err = srs_success;
    
    // Do realloc the iovss if required.
    iovec* iovss = iovss_cache;
    do {
        int nn_might_iovss = 3 * count;
        if (nb_iovss_cache < nn_might_iovss) {
            srs_freepa(iovss_cache);

            nb_iovss_cache = nn_might_iovss;
            iovss = iovss_cache = new iovec[nn_might_iovss];
        }
    } while (false);
    
    // Do realloc the tag headers if required.
    char* cache = tag_headers;
    if (nb_tag_headers < count) {
        srs_freepa(tag_headers);
        
        nb_tag_headers = count;
        cache = tag_headers = new char[SRS_FLV_TAG_HEADER_SIZE * count];
    }
    
    // Do realloc the pts if required.
    char* pts = ppts;
    if (nb_ppts < count) {
        srs_freepa(ppts);
        
        nb_ppts = count;
        pts = ppts = new char[SRS_FLV_PREVIOUS_TAG_SIZE * count];
    }
    
    // Now all caches are ok, start to write all messages.
    iovec* iovs = iovss; int nn_real_iovss = 0;
    for (int i = 0; i < count; i++) {
        SrsSharedPtrMessage* msg = msgs[i];
        
        // Cache FLV packet header.
        if (msg->is_audio()) {
            if (drop_if_not_match_ && !has_audio_) continue; // Ignore audio packets if no audio stream.
            cache_audio(msg->timestamp, msg->payload, msg->size, cache);
        } else if (msg->is_video()) {
            if (drop_if_not_match_ && !has_video_) continue; // Ignore video packets if no video stream.
            cache_video(msg->timestamp, msg->payload, msg->size, cache);
        } else {
            cache_metadata(SrsFrameTypeScript, msg->payload, msg->size, cache);
        }
        
        // Cache FLV pts.
        cache_pts(SRS_FLV_TAG_HEADER_SIZE + msg->size, pts);
        
        // Set cache to iovec.
        iovs[0].iov_base = cache;
        iovs[0].iov_len = SRS_FLV_TAG_HEADER_SIZE;
        iovs[1].iov_base = msg->payload;
        iovs[1].iov_len = msg->size;
        iovs[2].iov_base = pts;
        iovs[2].iov_len = SRS_FLV_PREVIOUS_TAG_SIZE;
        
        // Move to next cache.
        cache += SRS_FLV_TAG_HEADER_SIZE;
        pts += SRS_FLV_PREVIOUS_TAG_SIZE;
        iovs += 3; nn_real_iovss += 3;
    }

    // Send out all data carried by iovec.
    if ((err = writer->writev(iovss, nn_real_iovss, NULL)) != srs_success) {
        return srs_error_wrap(err, "write flv tags failed");
    }
    
    return err;
}


原文地址:https://blog.csdn.net/lcalqf/article/details/136043572

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!