庖丁解牛-----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

相关文章

解密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)、

如何在Mac上彻底删除Edge账户? 手动卸载Edge浏览器并清理残留文件技巧

《如何在Mac上彻底删除Edge账户?手动卸载Edge浏览器并清理残留文件技巧》Mac上的Edge账户里存了不少网站密码和个人信息,结果同事一不小心打开了,简直尴尬到爆炸,想要卸载edge浏览器并清... 如果你遇到 Microsoft Edge 浏览器运行迟缓、频繁崩溃或网页加载异常等问题,可以尝试多种方

Java进程CPU使用率过高排查步骤详细讲解

《Java进程CPU使用率过高排查步骤详细讲解》:本文主要介绍Java进程CPU使用率过高排查的相关资料,针对Java进程CPU使用率高的问题,我们可以遵循以下步骤进行排查和优化,文中通过代码介绍... 目录前言一、初步定位问题1.1 确认进程状态1.2 确定Java进程ID1.3 快速生成线程堆栈二、分析

一文彻底搞懂Java 中的 SPI 是什么

《一文彻底搞懂Java中的SPI是什么》:本文主要介绍Java中的SPI是什么,本篇文章将通过经典题目、实战解析和面试官视角,帮助你从容应对“SPI”相关问题,赢得技术面试的加分项,需要的朋... 目录一、面试主题概述二、高频面试题汇总三、重点题目详解✅ 面试题1:Java 的 SPI 是什么?如何实现一个