庖丁解牛-----Live555源码彻底解密(根据OpenRTSP讲解)

本文介绍使用OpenRTSP录制H264视频文件的关键步骤,包括文件初始化、帧数据处理及文件输出等。特别关注了SPS/PPS NAL单元的处理及帧率设置。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

OpenRtsp中写H264文件注意的地方:

 

OpenRtsp客户端包括OpenRtsp.cpp和playCommon.cpp 两个文件

 

1)接受buffer保存到文件

void H264VideoFileSink::afterGettingFrame(unsignedframeSize,unsignednumTruncatedBytes,structtimeval presentationTime) {

  unsigned char const start_code[4] = {0x00, 0x00, 0x00, 0x01};

 

  if (!fHaveWrittenFirstFrame) {

    // If we have PPS/SPS NAL units encoded in a "sprop parameter string", prepend these to the file:

    unsigned numSPropRecords;

    SPropRecord* sPropRecords = parseSPropParameterSets(fSPropParameterSetsStr,numSPropRecords);

    for (unsignedi = 0;i < numSPropRecords; ++i) {

      addData(start_code, 4,presentationTime);

      addData(sPropRecords[i].sPropBytes,sPropRecords[i].sPropLength,presentationTime);

    }

    delete[] sPropRecords;

    fHaveWrittenFirstFrame = True; // for next time

  }

 

  // Write the input data to the file, with the start code in front:

  addData(start_code, 4,presentationTime);

 

  // Call the parent class to complete the normal file write with the input data:

  FileSink::afterGettingFrame(frameSize,numTruncatedBytes,presentationTime);

}

 

2)获取到路径名

              // Create an output file for each desired stream:

                   char outFileName[1000];

                   if (singleMedium ==NULL) {

                       // Output file name is

                       //     "<filename-prefix><medium_name>-<codec_name>-<counter>"

                       static unsigned streamCounter = 0;

                       //outFileName为文件名

                       snprintf(outFileName,sizeofoutFileName,"%s%s-%s-%d",

                            fileNamePrefix,subsession->mediumName(),

                            subsession->codecName(), ++streamCounter);

                   } else {

                       sprintf(outFileName,"stdout");

                   }

 

3)保存文件

void FileSink::afterGettingFrame(unsignedframeSize,

                    unsigned numTruncatedBytes,

                    struct timeval presentationTime) {

  if (numTruncatedBytes > 0) {

    envir() << "FileSink::afterGettingFrame(): The input frame data was too large for our buffer size ("

         << fBufferSize << ").  "

            << numTruncatedBytes <<" bytes of trailing data was dropped! Correct this by increasing the \"bufferSize\" parameter in the \"createNew()\" call to at least "

            << fBufferSize + numTruncatedBytes << "\n";

  }

  addData(fBuffer,frameSize,presentationTime);

 

  if (fOutFid ==NULL ||fflush(fOutFid) ==EOF) {

    // The output file has closed.  Handle this the same way as if the input source had closed:

    if (fSource !=NULL)fSource->stopGettingFrames();

    onSourceClosure(this);

    return;

  }

 

  if (fPerFrameFileNameBuffer !=NULL) {

    if (fOutFid !=NULL) {fclose(fOutFid);fOutFid =NULL; }

  }

 

  // Then try getting the next frame:

  continuePlaying();

}

 

 

1)   写文件

void FileSink::addData(unsignedcharconst* data, unsigned dataSize,

                struct timeval presentationTime) {

  if (fPerFrameFileNameBuffer !=NULL) {

    // Special case: Open a new file on-the-fly for this frame

    sprintf(fPerFrameFileNameBuffer,"%s-%lu.%06lu",fPerFrameFileNamePrefix,

         presentationTime.tv_sec,presentationTime.tv_usec);

    fOutFid = OpenOutputFile(envir(), fPerFrameFileNameBuffer);

  }

 

  // Write to our file:

#ifdef TEST_LOSS

  static unsigned const framesPerPacket = 10;

  static unsigned const frameCount = 0;

  static Boolean const packetIsLost;

  if ((frameCount++)%framesPerPacket == 0) {

    packetIsLost = (our_random()%10 == 0); // simulate 10% packet loss #####

  }

 

  if (!packetIsLost)

#endif

  if (fOutFid !=NULL &&data !=NULL) {

    fwrite(data, 1,dataSize,fOutFid);

  }

}

 

其中  unsigned char* fBuffer; 用来保存文件的Buff;

  fBuffer = new unsigned char[bufferSize]; 缓冲区的size,默认多少?

 

 

#ifndef _H264_VIDEO_FILE_SINK_HH

#define _H264_VIDEO_FILE_SINK_HH

 

#ifndef _FILE_SINK_HH

#include "FileSink.hh"

#endif

 

class H264VideoFileSink: public FileSink {

public:

  static H264VideoFileSink* createNew(UsageEnvironment&env,char const* fileName,

                         char const* sPropParameterSetsStr = NULL,

  // An optional 'SDP format' string (comma-separated Base64-encoded) representing SPS and/or PPS NAL-units to prepend to the output

                         unsigned bufferSize = 100000,

                         BooleanoneFilePerFrame =False);

  // See "FileSink.hh" for a description of these parameters.

 

protected:

  H264VideoFileSink(UsageEnvironment&env,FILE* fid,

             char const* sPropParameterSetsStr,

             unsigned bufferSize, char const* perFrameFileNamePrefix);

      // called only by createNew()

  virtual ~H264VideoFileSink();

 

protected: // redefined virtual functions:

  virtual void afterGettingFrame(unsignedframeSize,unsignednumTruncatedBytes,structtimeval presentationTime);

 

private:

  char const*fSPropParameterSetsStr;

  Boolean fHaveWrittenFirstFrame;

};

 

#endif

 

默认的是100k 可以修改,在OpenRtsp中修改unsignedfileSinkBufferSize = 1000000;           //modify by zh 100000 to 1000000

 

OpenRtsp还需要获取帧率的信息,进行录像,帧率的参数可以从OpenRtsp中进行修改;

unsigned movieFPS = 30; // default                 //帧率信息modify by zhongh 15 to 30

 

相机1080p的 30帧,每秒1.18M

 

 

OpenRtsp将文件写成AVI的代码如下:

else if (outputAVIFile) {

              // Create an "AVIFileSink", to write to 'stdout':

 

              //如何将stdout修改成写avi 文件

              aviOut = AVIFileSink::createNew(*env, *session,"d:\\test1.avi",

                   fileSinkBufferSize,

                   movieWidth,movieHeight,

                   movieFPS,              //帧率

                   packetLossCompensate);//包丢失补偿;

              if (aviOut ==NULL) {

                   *env << "Failed to create AVI file sink for stdout: " << env->getResultMsg();

                   shutdown();

              }

 

aviOut->startPlaying(sessionAfterPlaying,NULL);

 

<think>我们正在讨论如何使用live555发送AAC流媒体数据。根据引用内容,live555支持多种音频格式,其中包括AAC(ADTS格式)音频文件(文件名后缀为“.aac”)。因此,我们可以利用live555提供的功能来实现AAC流媒体的传输。步骤概述:1.准备AAC源:确保AAC文件是ADTS格式(通常以.aac为后缀)。2.使用live555提供的MediaServer:live555包含一个RTSP服务器实现,可以将文件作为流媒体源。3.配置服务器:将AAC文件作为媒体源,启动RTSP服务器。具体步骤:一、编译live555首先需要编译live555源码。在Windows上可以使用MSVC,Linux上使用g++。这里以Linux为例:```bash./genMakefileslinuxmake```二、准备AAC文件确保你的AAC文件是ADTS格式(可以使用工具转换,如ffmpeg)。三、运行RTSP服务器live555提供了一个示例程序`live555MediaServer`,它位于`mediaServer`目录下。运行该程序,并将AAC文件放在服务器可访问的目录中(默认是当前目录)。启动服务器:```bash./live555MediaServer```四、客户端访问客户端可以使用RTSPURL来访问AAC流。例如,如果服务器IP是192.168.1.100,AAC文件名为`test.aac`,则RTSPURL为:```rtsp://192.168.1.100:8554/test.aac```注意:live555MediaServer默认使用8554端口。五、自定义配置如果需要更灵活的控制(例如从其他来源获取AAC数据而不是文件),则需要编写自己的应用程序。可以参考live555提供的示例,如`testOnDemandRTSPServer`,并修改以支持AAC流。创建自定义服务器的大致步骤:1.创建一个继承自`OnDemandServerMediaSubsession`的类,用于处理AAC流。2.实现虚函数,创建`FramedSource`和`RTPSink`。3.在`FramedSource`中,你需要提供AAC数据(可以从文件、麦克风、网络等读取)。4.在`RTPSink`中,使用live555提供的`ADTSAudioFileSource`(如果是文件)或自定义源。示例代码片段(基于文件):```cpp#include<liveMedia.hh>#include<BasicUsageEnvironment.hh>//创建RTSP服务器RTSPServer*createRTSPServer(Portport){RTSPServer*rtspServer=RTSPServer::createNew(env,port);if(rtspServer==NULL){*env<<"FailedtocreateRTSPserver:"<<env->getResultMsg()<<"\n";exit(1);}returnrtspServer;}//添加AAC流会话voidaddAACStream(RTSPServer*rtspServer,charconst*streamName,charconst*inputFileName){ServerMediaSession*sms=ServerMediaSession::createNew(*env,streamName);//使用ADTS音频文件源sms->addSubsession(ADTSAudioFileServerMediaSubsession::createNew(*env,inputFileName));rtspServer->addServerMediaSession(sms);}intmain(){//初始化环境TaskScheduler*scheduler=BasicTaskScheduler::createNew();UsageEnvironment*env=BasicUsageEnvironment::createNew(*scheduler);//创建RTSP服务器,端口8554RTSPServer*rtspServer=createRTSPServer(8554);//添加AAC流,假设文件名为"test.aac"addAACStream(rtspServer,"aacTest","test.aac");//进入事件循环env->taskScheduler().doEventLoop();return0;}```注意:以上代码仅为示例,实际使用时需要处理错误和资源释放。六、传输中的配置AAC流通常使用RTP传输,live555会自动将AAC数据封装成RTP包。在SDP描述中,会包含AAC的配置信息(如采样率、声道数等),客户端根据这些信息进行解码。七、测试使用支持RTSP的播放器(如VLC)打开上述URL进行测试。相关问题:1.如何将其他格式的音频文件转换为ADTSAAC格式?2.live555如何处理实时采集的AAC数据(如来自麦克风)?3.live555在传输AAC流时,如何实现多客户端同时访问?4.live555的RTSP服务器支持哪些认证机制?5.如何优化live555以降低AAC流传输的延迟?</think>### 如何使用 Live555 发送 AAC 流媒体数据 以下是配置 Live555 传输 AAC 流媒体数据的完整步骤: #### 一、准备工作 1. **编译 Live555** 确保已正确编译 Live555(参考[编译指南](^3)): ```bash ./genMakefiles <平台> # 如 linux 或 win32 make ``` 2. **准备 AAC 源文件** 文件必须是 **ADTS 格式的 AAC 文件**(后缀 `.aac`)[^2]。若需转换其他格式: ```bash ffmpeg -i input.mp3 -c:a aac -b:a 128k -f adts output.aac ``` --- #### 二、配置 RTSP 服务器 1. **启动媒体服务器** 将 AAC 文件放入服务器工作目录,执行: ```bash ./live555MediaServer ``` 默认端口 `8554`,文件路径即流名称(如 `test.aac` 对应流地址 `rtsp://server:8554/test.aac`) 2. **自定义流名称(可选)** 创建符号链接指向 AAC 文件: ```bash ln -s test.aac my_stream.aac ``` 客户端访问:`rtsp://server:8554/my_stream.aac` --- #### 三、关键代码实现(自定义场景) 若需动态生成 AAC 流(非静态文件),需实现 **`FramedSource`** 子类: ```cpp #include <liveMedia.hh> class AACFrameSource : public FramedSource { public: static AACFrameSource* createNew(UsageEnvironment& env) { return new AACFrameSource(env); } protected: AACFrameSource(UsageEnvironment& env) : FramedSource(env) {} virtual void doGetNextFrame() override { // 在此填充 AAC 数据到 fTo getAACData(fTo, fMaxSize); // 自定义数据获取函数 // 设置帧属性(示例值) fFrameSize = 1024; // 实际数据大小 fNumTruncatedBytes = 0; // 无截断 fPresentationTime = ...; // 设置时间戳 // 通知数据就绪 FramedSource::afterGetting(this); } }; ``` 在媒体会话中注册: ```cpp ServerMediaSession* sms = ServerMediaSession::createNew(env, "liveAAC"); sms->addSubsession(PassiveServerMediaSubsession::createNew( ADTSAudioStreamDiscreteFramer::createNew(env, AACFrameSource::createNew(env)), NULL )); rtspServer->addServerMediaSession(sms); ``` --- #### 四、客户端拉流 使用 `openRTSP` 工具测试: ```bash ./openRTSP -v rtsp://192.168.1.100:8554/test.aac > output.aac ``` 或通过 VLC 播放: `媒体 → 打开网络串流 → 输入 rtsp://server:8554/test.aac` --- #### 五、调试与验证 1. **日志监控** 启动时添加 `-v` 参数查看详细日志: ```bash ./live555MediaServer -v ``` 2. **Wireshark 抓包** 过滤 `rtsp` 和 `rtp` 协议,确认: - RTSP 交互过程(OPTIONS/DESCRIBE/SETUP/PLAY) - RTP 负载类型是否为 `96`(动态 AAC) - 时间戳连续性 --- ### 常见问题解决 | 问题现象 | 解决方案 | |---------------------------|------------------------------------------| | 客户端报错 "415 Unsupported Media" | 检查 AAC 文件是否为 ADTS 格式[^2] | | 无音频输出 | 确认客户端支持 AAC-LC 解码 | | 高延迟 | 调整 `BUFFER_SIZE`(默认 200KB) |
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值