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

2024-01-13 01:18

本文主要是介绍庖丁解牛-----Live555源码彻底解密(根据OpenRTSP讲解),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

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);

 

这篇关于庖丁解牛-----Live555源码彻底解密(根据OpenRTSP讲解)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/599771

相关文章

Unity新手入门学习殿堂级知识详细讲解(图文)

《Unity新手入门学习殿堂级知识详细讲解(图文)》Unity是一款跨平台游戏引擎,支持2D/3D及VR/AR开发,核心功能模块包括图形、音频、物理等,通过可视化编辑器与脚本扩展实现开发,项目结构含A... 目录入门概述什么是 UnityUnity引擎基础认知编辑器核心操作Unity 编辑器项目模式分类工程

MySQL连表查询之笛卡尔积查询的详细过程讲解

《MySQL连表查询之笛卡尔积查询的详细过程讲解》在使用MySQL或任何关系型数据库进行多表查询时,如果连接条件设置不当,就可能发生所谓的笛卡尔积现象,:本文主要介绍MySQL连表查询之笛卡尔积查... 目录一、笛卡尔积的数学本质二、mysql中的实现机制1. 显式语法2. 隐式语法3. 执行原理(以Nes

SpringBoot实现RSA+AES自动接口解密的实战指南

《SpringBoot实现RSA+AES自动接口解密的实战指南》在当今数据泄露频发的网络环境中,接口安全已成为开发者不可忽视的核心议题,RSA+AES混合加密方案因其安全性高、性能优越而被广泛采用,本... 目录一、项目依赖与环境准备1.1 Maven依赖配置1.2 密钥生成与配置二、加密工具类实现2.1

解密SQL查询语句执行的过程

《解密SQL查询语句执行的过程》文章讲解了SQL语句的执行流程,涵盖解析、优化、执行三个核心阶段,并介绍执行计划查看方法EXPLAIN,同时提出性能优化技巧如合理使用索引、避免SELECT*、JOIN... 目录1. SQL语句的基本结构2. SQL语句的执行过程3. SQL语句的执行计划4. 常见的性能优

RabbitMQ消费端单线程与多线程案例讲解

《RabbitMQ消费端单线程与多线程案例讲解》文章解析RabbitMQ消费端单线程与多线程处理机制,说明concurrency控制消费者数量,max-concurrency控制最大线程数,prefe... 目录 一、基础概念详细解释:举个例子:✅ 单消费者 + 单线程消费❌ 单消费者 + 多线程消费❌ 多

一文解密Python进行监控进程的黑科技

《一文解密Python进行监控进程的黑科技》在计算机系统管理和应用性能优化中,监控进程的CPU、内存和IO使用率是非常重要的任务,下面我们就来讲讲如何Python写一个简单使用的监控进程的工具吧... 目录准备工作监控CPU使用率监控内存使用率监控IO使用率小工具代码整合在计算机系统管理和应用性能优化中,监

从入门到进阶讲解Python自动化Playwright实战指南

《从入门到进阶讲解Python自动化Playwright实战指南》Playwright是针对Python语言的纯自动化工具,它可以通过单个API自动执行Chromium,Firefox和WebKit... 目录Playwright 简介核心优势安装步骤观点与案例结合Playwright 核心功能从零开始学习

SpringBoot中SM2公钥加密、私钥解密的实现示例详解

《SpringBoot中SM2公钥加密、私钥解密的实现示例详解》本文介绍了如何在SpringBoot项目中实现SM2公钥加密和私钥解密的功能,通过使用Hutool库和BouncyCastle依赖,简化... 目录一、前言1、加密信息(示例)2、加密结果(示例)二、实现代码1、yml文件配置2、创建SM2工具

python实现对数据公钥加密与私钥解密

《python实现对数据公钥加密与私钥解密》这篇文章主要为大家详细介绍了如何使用python实现对数据公钥加密与私钥解密,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录公钥私钥的生成使用公钥加密使用私钥解密公钥私钥的生成这一部分,使用python生成公钥与私钥,然后保存在两个文

嵌入式数据库SQLite 3配置使用讲解

《嵌入式数据库SQLite3配置使用讲解》本文强调嵌入式项目中SQLite3数据库的重要性,因其零配置、轻量级、跨平台及事务处理特性,可保障数据溯源与责任明确,详细讲解安装配置、基础语法及SQLit... 目录0、惨痛教训1、SQLite3环境配置(1)、下载安装SQLite库(2)、解压下载的文件(3)、