zhuizhu 7 ماه پیش
والد
کامیت
c6cfc4c6f5
2فایلهای تغییر یافته به همراه95 افزوده شده و 21 حذف شده
  1. 2 2
      config/networkconfig.cpp
  2. 93 19
      libs/Recorder/muxer_ffmpeg.cpp

+ 2 - 2
config/networkconfig.cpp

@@ -93,9 +93,9 @@ void NetworkConfig::initDefaults()
     m_serverConfig.apiPath = "/api";
     
     // 流媒体配置 (默认使用RTMP协议)
-    m_streamConfig.protocol = StreamProtocol::RTSP;
+    m_streamConfig.protocol = StreamProtocol::RTMP;
     m_streamConfig.host = "127.0.0.1"; // 使用项目中的生产服务器
-    m_streamConfig.port = 554;
+    m_streamConfig.port = 1935;
     m_streamConfig.app = "stream";
     m_streamConfig.streamKey = "V1";
     

+ 93 - 19
libs/Recorder/muxer_ffmpeg.cpp

@@ -22,6 +22,7 @@ namespace am {
 muxer_ffmpeg::muxer_ffmpeg()
 {
     ffmpeg_register_all();
+    ffmpeg_register_devices(); // 添加设备注册,支持RTSP等网络协议
 
     _v_stream = NULL;
     _a_stream = NULL;
@@ -454,15 +455,21 @@ int muxer_ffmpeg::alloc_oc(const char *output_file, const MUX_SETTING_T &setting
     int ret = 0;
 
     do {
-        // 检查是否为RTMP流,如果是则指定flv格式
+        // 检查协议类型并指定相应的输出格式
         const char* format_name = NULL;
         std::string url_str(output_file);
         if (url_str.find("rtmp://") == 0 || url_str.find("rtmps://") == 0) {
             format_name = "flv";
+        } else if (url_str.find("rtsp://") == 0) {
+            // RTSP推流使用RTSP muxer,由FFmpeg管理RTP会话
+            format_name = "rtsp";
+            al_debug("RTSP URL detected, using RTSP format");
         }
         
         ret = avformat_alloc_output_context2(&_fmt_ctx, NULL, format_name, output_file);
         if (ret < 0 || !_fmt_ctx) {
+            al_debug("avformat_alloc_output_context2 failed with ret=%d, format=%s, url=%s", 
+                     ret, format_name ? format_name : "auto", output_file);
             error = AE_FFMPEG_ALLOC_CONTEXT_FAILED;
             break;
         }
@@ -542,24 +549,27 @@ int muxer_ffmpeg::add_video_stream(const MUX_SETTING_T &setting, record_desktop
         ffmpeg_set_stream_codec_id(st, _v_stream->v_enc->get_codec_id());
         ffmpeg_set_stream_bit_rate(st, setting.v_bit_rate);
         ffmpeg_set_stream_codec_type(st, AVMEDIA_TYPE_VIDEO);
-        st->time_base.den = setting.v_frame_rate;
-        st->time_base.num = 1;
+
+        // 使用编码器/设置的帧率作为时间基(1/fps),避免异常的帧率显示
+        st->time_base = {1, setting.v_frame_rate};
         ffmpeg_set_stream_pix_fmt(st, AV_PIX_FMT_YUV420P);
 
         ffmpeg_set_stream_dimensions(st, setting.v_out_width, setting.v_out_height);
-        st->time_base = {1, 90000};  //fixed?
-        st->avg_frame_rate = av_inv_q(st->time_base);
 
-        if (_fmt_ctx->oformat->flags & AVFMT_GLOBALHEADER) {
-            uint8_t* extradata = (uint8_t*)av_memdup(_v_stream->v_enc->get_extradata(),
-                                                     _v_stream->v_enc->get_extradata_size());
+        // 正确设置平均帧率为 fps/1
+        st->avg_frame_rate = {setting.v_frame_rate, 1};
+
+        // 始终为视频流设置extradata(SPS/PPS等),RTSP/SDP需要该信息
+        {
+            uint8_t *extradata = (uint8_t *) av_memdup(_v_stream->v_enc->get_extradata(),
+                                                       _v_stream->v_enc->get_extradata_size());
             ffmpeg_set_stream_extradata(st, extradata, _v_stream->v_enc->get_extradata_size());
         }
 
-        _v_stream->st = st;
+         _v_stream->st = st;
 
-        _v_stream->setting = setting;
-        //_v_stream->filter = av_bitstream_filter_init("h264_mp4toannexb");
+         _v_stream->setting = setting;
+         //_v_stream->filter = av_bitstream_filter_init("h264_mp4toannexb");
     } while (0);
 
     return error;
@@ -766,6 +776,16 @@ int muxer_ffmpeg::add_audio_stream(const MUX_SETTING_T &setting,
             }
         }
 
+        // 始终为音频流设置extradata(AudioSpecificConfig),RTSP/SDP/MP4/FLV等容器需要该信息
+        if (_a_stream->a_enc->get_extradata_size() > 0) {
+            uint8_t *asc = (uint8_t *)av_memdup(_a_stream->a_enc->get_extradata(),
+                                                _a_stream->a_enc->get_extradata_size());
+            ffmpeg_set_stream_extradata(st, asc, _a_stream->a_enc->get_extradata_size());
+            al_debug("Set AAC extradata on stream: size=%d", _a_stream->a_enc->get_extradata_size());
+        } else {
+            al_warn("AAC extradata size is 0; some outputs (e.g., RTSP/MP4) may fail in avformat_write_header");
+        }
+
         _a_stream->st = st;
 
         _a_stream->setting = setting;
@@ -776,10 +796,23 @@ int muxer_ffmpeg::add_audio_stream(const MUX_SETTING_T &setting,
             _a_stream->filter = nullptr;
             al_debug("RTMP output detected, skipping aac_adtstoasc filter");
         } else {
-            // 其他格式(如MP4),使用aac_adtstoasc过滤器
+            // 其他格式(如MP4/RTSP),使用aac_adtstoasc过滤器以去除可能存在的ADTS头
             _a_stream->filter = ffmpeg_bitstream_filter_init("aac_adtstoasc");
             al_debug("Non-RTMP output, using aac_adtstoasc filter");
         }
+        if (_fmt_ctx->oformat) {
+            const char *ofmt = _fmt_ctx->oformat->name;
+            // FLV/RTMP、RTSP、MP4等容器需要原始AAC(无ADTS),因此启用 aac_adtstoasc 过滤器
+            if (strcmp(ofmt, "flv") == 0 || strcmp(ofmt, "rtsp") == 0 || strcmp(ofmt, "mp4") == 0
+                || strcmp(ofmt, "mov") == 0 || strcmp(ofmt, "matroska") == 0) {
+                _a_stream->filter = ffmpeg_bitstream_filter_init("aac_adtstoasc");
+                al_debug("Container '%s' requires raw AAC, enabling aac_adtstoasc filter", ofmt);
+            } else {
+                // 对于期望ADTS的容器(如 mpegts/adts),不使用过滤器
+                _a_stream->filter = nullptr;
+                al_debug("Container '%s' supports ADTS, skipping aac_adtstoasc filter", ofmt);
+            }
+        }
 
     } while (0);
 
@@ -801,14 +834,26 @@ int muxer_ffmpeg::open_output(const char *output_file, const MUX_SETTING_T &sett
         }
 
         AVDictionary *opt = NULL;
-        av_dict_set_int(&opt, "video_track_timescale", _v_stream->setting.v_frame_rate, 0);
+        
+        // 检查是否为RTSP推流,添加特定参数
+        std::string url_str(output_file);
+        if (url_str.find("rtsp://") == 0) {
+            // RTSP推流特定参数设置
+            av_dict_set(&opt, "rtsp_transport", "tcp", 0);  // 使用TCP传输,更稳定
+            av_dict_set(&opt, "muxdelay", "0.1", 0);        // 设置复用延迟
+            av_dict_set(&opt, "fflags", "+genpts", 0);      // 生成PTS
+            al_debug("RTSP output detected, setting specific parameters");
+        } else {
+            // 非RTSP推流的原有参数
+            av_dict_set_int(&opt, "video_track_timescale", _v_stream->setting.v_frame_rate, 0);
+        }
 
-        //ret = avformat_write_header(_fmt_ctx, &opt);//no need to set this
-        ret = avformat_write_header(_fmt_ctx, NULL);
+        ret = avformat_write_header(_fmt_ctx, &opt);
 
         av_dict_free(&opt);
 
         if (ret < 0) {
+            al_debug("avformat_write_header failed with ret=%d, error=%s", ret, av_err2str(ret));
             error = AE_FFMPEG_WRITE_HEADER_FAILED;
             break;
         }
@@ -1021,7 +1066,34 @@ int muxer_ffmpeg::write_audio(AVPacket *packet)
         al_debug("RTMP AAC packet: size=%d, header=0x%02X%02X", 
                 packet->size, packet->data[0], packet->data[1]);
     }
-    
+    // 根据容器判断是否期望ADTS头部
+    bool expectsAdts = false;
+    if (_fmt_ctx->oformat && _fmt_ctx->oformat->name) {
+        const char *ofmt = _fmt_ctx->oformat->name;
+        if (strcmp(ofmt, "mpegts") == 0 || strcmp(ofmt, "adts") == 0) {
+            expectsAdts = true;
+        }
+    }
+
+    if (expectsAdts) {
+        // 期望ADTS:做最基本校验
+        if (packet->size < 7) {
+            al_warn("AAC packet too small for ADTS: %d bytes (min 7)", packet->size);
+            return -1;
+        }
+        if (packet->size >= 2 && (packet->data[0] != 0xFF || (packet->data[1] & 0xF0) != 0xF0)) {
+            al_warn("Missing ADTS syncword in ADTS-expected container, header=0x%02X%02X",
+                    packet->data[0],
+                    packet->data[1]);
+        }
+    } else {
+        // 不期望ADTS(如 RTSP/FLV/MP4 等):如果存在ADTS,仅打印调试信息
+        if (packet->size >= 2 && packet->data[0] == 0xFF && (packet->data[1] & 0xF0) == 0xF0) {
+            al_debug(
+                "ADTS header present but container doesn't require it; filter may strip it later");
+        }
+    }
+
     // 应用bitstream过滤器(如果存在)
     AVPacket *filtered_packet = packet;
     if (_a_stream->filter) {
@@ -1032,12 +1104,14 @@ int muxer_ffmpeg::write_audio(AVPacket *packet)
             if (filter_ret >= 0) {
                 // 验证过滤后的包大小
                 if (temp_packet->size < 2) {
-                    al_warn("Filtered AAC packet too small: %d bytes, using original packet", temp_packet->size);
+                    al_warn("Filtered AAC packet too small: %d bytes, using original packet",
+                            temp_packet->size);
                     av_packet_free(&temp_packet);
                 } else {
                     filtered_packet = temp_packet;
-                    al_debug("Applied aac_adtstoasc filter, original size: %d, filtered size: %d", 
-                            packet->size, temp_packet->size);
+                    al_debug("Applied aac_adtstoasc filter, original size: %d, filtered size: %d",
+                             packet->size,
+                             temp_packet->size);
                 }
             } else {
                 al_warn("Failed to apply bitstream filter: %d, using original packet", filter_ret);