├── .gitignore ├── CMakeLists.txt ├── LICENSE ├── README.md └── src ├── AVPacket ├── AVReadPacket.cpp ├── AVReadPacket.h ├── AVWritePacket.cpp ├── AVWritePacket.h └── CMakeLists.txt ├── CMakeLists.txt ├── adts ├── CMakeLists.txt ├── adtsHeader.cpp ├── adtsHeader.h ├── adtsReader.cpp └── adtsReader.h ├── bitStream ├── CMakeLists.txt ├── readStream.cpp ├── readStream.h ├── writeStream.cpp └── writeStream.h ├── flashVideo ├── CMakeLists.txt ├── FLVAudioTag.cpp ├── FLVAudioTag.h ├── FLVHeader.cpp ├── FLVHeader.h ├── FLVScriptTag.cpp ├── FLVScriptTag.h ├── FLVTagHeader.cpp ├── FLVTagHeader.h ├── FLVVideoTag.cpp └── FLVVideoTag.h ├── log ├── CMakeLists.txt ├── logger.cpp └── logger.h ├── main.cpp ├── nalu ├── CMakeLists.txt ├── NALDecodedPictureBuffer.cpp ├── NALDecodedPictureBuffer.h ├── NALHeader.cpp ├── NALHeader.h ├── NALPicture.cpp ├── NALPicture.h ├── NALPictureParameterSet.cpp ├── NALPictureParameterSet.h ├── NALReader.cpp ├── NALReader.h ├── NALSeqParameterSet.cpp ├── NALSeqParameterSet.h ├── NALSliceHeader.cpp └── NALSliceHeader.h ├── protocol ├── CMakeLists.txt ├── http.cpp ├── http.h ├── httpFlv.cpp ├── httpFlv.h ├── httpHls.cpp ├── httpHls.h ├── rtsp.cpp ├── rtsp.h ├── rtspReceiveData.cpp ├── rtspReceiveData.h ├── rtspSendData.cpp └── rtspSendData.h ├── server ├── CMakeLists.txt ├── server.cpp └── server.h ├── socket ├── CMakeLists.txt ├── Socket.h ├── TcpSocket.cpp ├── TcpSocket.h ├── UdpSocket.cpp └── UdpSocket.h ├── threadPool ├── CMakeLists.txt ├── httpTask.cpp ├── httpTask.h ├── rtspTask.cpp ├── rtspTask.h ├── task.cpp ├── task.h ├── threadPool.cpp └── threadPool.h ├── transportStream ├── CMakeLists.txt ├── PES.cpp ├── PES.h ├── SI.cpp ├── SI.h ├── demuxPacket.cpp ├── demuxPacket.h ├── transportPacket.cpp └── transportPacket.h └── utils ├── CMakeLists.txt ├── parseUrl.cpp ├── parseUrl.h ├── util.cpp └── util.h /.gitignore: -------------------------------------------------------------------------------- 1 | /.idea 2 | /cmake-build-* 3 | /.vs 4 | /.vscode 5 | /out 6 | /build 7 | /resource 8 | 9 | CMakeSettings.json 10 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.16.3) 2 | project(mediaServer) 3 | 4 | 5 | set(CMAKE_INSTALL_PREFIX "${PROJECT_SOURCE_DIR}/${CMAKE_BUILD_TYPE}") 6 | if (MSVC) 7 | add_compile_definitions("_CRT_SECURE_NO_WARNINGS") 8 | add_compile_options("/utf-8") 9 | endif () 10 | 11 | 12 | 13 | set(CMAKE_CXX_STANDARD 17) 14 | ##cpp11标准 15 | #set(CMAKE_CXX_STANDARD 11) 16 | #关闭编译器扩展 17 | set(CMAKE_CXX_EXTENSIONS OFF) 18 | #指定必须要11标准,不然cmake会自己找 19 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 20 | 21 | add_subdirectory(src) -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 肖锋 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 一个从零开始没有使用任何第三方库的流媒体服务器 2 | 3 | ### 项目特点 4 | 5 | - 支持rtsp推流,http-flv,hls,rtsp拉流 6 | - 支持linux、macos、windows平台 7 | - 代码清晰,无任何依赖 8 | 9 | 10 | ### 编译代码 11 | ```console 12 | $ git clone https://github.com/xfxhn/mediaServer 13 | $ cd mediaServer 14 | $ cmake -D CMAKE_BUILD_TYPE="Debug" -S . -B build 15 | $ cmake --build build --target install 16 | ``` 17 | 18 | 19 | ### 使用 FFmpeg 推流 20 | 现在暂时只支持rtsp over tcp的推流 21 | ```bash 22 | ffmpeg -re -i "test.mp4" -vcodec h264 -acodec aac -f rtsp -rtsp_transport tcp rtsp://127.0.0.1/live/test 23 | ``` 24 | 25 | 26 | ### 播放直播流 27 | #### flv 流格式 28 | ```bash 29 | ffplay http://localhost/live/test.flv 30 | ``` 31 | 32 | #### hls 流格式 33 | ```bash 34 | ffplay http://localhost/live/test/test.m3u8 35 | ``` 36 | 37 | #### rtsp 流格式 38 | ```bash 39 | ffplay rtsp://127.0.0.1/live/test -rtsp_transport tcp 40 | ``` 41 | 42 | 43 | 44 | **** 45 | 46 | **这个项目是我个人为了学习流媒体协议,和音视频知识所创建的项目,所以里面所有用到的封装和解封装都是自己编写, 现在还有很多协议和特性没支持,比如rtmp,比如接入https,rtsps,以后会慢慢添加。** 47 | 48 | **并且由于我不是专门做后端的, 性能方面还有很多可以优化,比如我只是简单写了个线程池,来处理每个socket链接, 没有使用epoll,select等网络模型,这对于高并发肯定是不行的,并且代码还有很多可以优化的地方,如果有大佬,觉得 49 | 我某段代码实现不够效率,不够优雅,也欢迎加入来一起开发这个项目** 50 | 51 | **不过这个项目作为学习流媒体服务器,确实是一个不错的项目,没有什么奇技淫巧的优化,也完全没有使用任何第三方库, 代码够简单清晰。 如果你有什么疑问,可以加qq群814462428,我的qq号是2456346488** 52 | 53 | 54 | **我也会不断完善这个项目,并能够让其真正商用。** -------------------------------------------------------------------------------- /src/AVPacket/AVReadPacket.cpp: -------------------------------------------------------------------------------- 1 |  2 | 3 | #include "AVReadPacket.h" 4 | #include 5 | #include 6 | 7 | #include "bitStream/readStream.h" 8 | #include "log/logger.h" 9 | 10 | /*存储一个启动时间,然后在每个要发送的函数里获取当前时间,用当前的这个时间减去启动时间 11 | * 然后用这个时间和dts作比较,如果dts大于这个时间,就不发送 12 | * */ 13 | 14 | int AVReadPacket::init(const std::string &dir, uint32_t transportStreamPacketNumber) { 15 | path = dir; 16 | currentPacket = transportStreamPacketNumber; 17 | 18 | std::string name = "/test" + std::to_string(currentPacket) + ".ts"; 19 | log_info("读取%s文件", name.c_str()); 20 | 21 | fs.open(path + name, std::ios::out | std::ios::binary); 22 | if (!fs.is_open()) { 23 | log_error("open %s failed", (path + name).c_str()); 24 | return -1; 25 | } 26 | 27 | 28 | videoReader.init(); 29 | audioReader.init(); 30 | 31 | 32 | picture = videoReader.allocPicture(); 33 | start = std::chrono::high_resolution_clock::now(); 34 | return 0; 35 | } 36 | 37 | 38 | int AVReadPacket::readTransportStream(bool videoFlag, bool audioFlag) { 39 | 40 | int ret = 0; 41 | 42 | elapsed = std::chrono::duration_cast(std::chrono::high_resolution_clock::now() - start); 43 | /*需要视频的dts和音频的dts都小于这个时间才会去读取*/ 44 | if (header.pts > elapsed.count() || picture->dts > elapsed.count()) { 45 | return 1; 46 | } 47 | 48 | std::string name; 49 | uint32_t size = 0; 50 | while (true) { 51 | 52 | fs.read(reinterpret_cast(transportStreamBuffer + size), TRANSPORT_STREAM_PACKETS_SIZE - size); 53 | size += fs.gcount(); 54 | if (size == 0) { 55 | name = "/test" + std::to_string(++currentPacket) + ".ts"; 56 | if (!std::filesystem::exists(path + name)) { 57 | // /*没有这个文件,说明这个文件还没读完,要继续读这个文件*/ 58 | // --currentPacket; 59 | // fs.clear(); 60 | // fprintf(stderr, "没有下个文件,等待一会儿\n"); 61 | // std::this_thread::sleep_for(std::chrono::milliseconds(100)); 62 | // continue; 63 | log_info("没有文件可以读了,退出"); 64 | return AVERROR_EOF; 65 | } 66 | 67 | /*表示这个文件读完了,读下一个*/ 68 | fs.close(); 69 | fs.open(path + name, std::ios::out | std::ios::binary); 70 | if (!fs.is_open()) { 71 | fprintf(stderr, "读取%s失败 video\n", name.c_str()); 72 | return -1; 73 | } 74 | 75 | fs.read(reinterpret_cast(transportStreamBuffer), TRANSPORT_STREAM_PACKETS_SIZE); 76 | size = fs.gcount(); 77 | if (size != TRANSPORT_STREAM_PACKETS_SIZE) { 78 | fprintf(stderr, "没读到一个ts包的大小,read size = %d\n", size); 79 | return -1; 80 | } 81 | } else if (size < TRANSPORT_STREAM_PACKETS_SIZE) { 82 | fs.clear(); 83 | fprintf(stderr, "size < TRANSPORT_STREAM_PACKETS_SIZE %d, video\n", size); 84 | std::this_thread::sleep_for(std::chrono::milliseconds(100)); 85 | continue; 86 | } 87 | /*走到这里肯定有188个字节*/ 88 | ReadStream rs(transportStreamBuffer, size); 89 | ret = demux.readFrame(rs); 90 | if (ret < 0) { 91 | fprintf(stderr, "demux.readVideoFrame失败\n"); 92 | return ret; 93 | } 94 | if (ret == VIDEO_PID && videoFlag) { 95 | size = rs.size - rs.position; 96 | videoReader.putData(rs.currentPtr, size); 97 | break; 98 | } else if (ret == AUDIO_PID && audioFlag) { 99 | size = rs.size - rs.position; 100 | audioReader.putData(rs.currentPtr, size); 101 | break; 102 | } 103 | size = 0; 104 | } 105 | 106 | 107 | return ret; 108 | } 109 | 110 | 111 | int AVReadPacket::getParameter() { 112 | int ret; 113 | 114 | bool videoFlag = true; 115 | bool audioFlag = true; 116 | while (videoFlag || audioFlag) { 117 | videoReader.resetBuffer(); 118 | audioReader.resetBuffer(); 119 | 120 | ret = readTransportStream(videoFlag, audioFlag); 121 | if (ret < 0) { 122 | fprintf(stderr, "getTransportStreamData 失败\n"); 123 | return ret; 124 | } 125 | if (ret == VIDEO_PID && videoFlag) { 126 | ret = videoReader.getParameter(); 127 | if (ret < 0) { 128 | fprintf(stderr, "videoReader.getParameter 失败\n"); 129 | return -1; 130 | } 131 | 132 | if (ret == 3) { 133 | // sps 134 | sps = videoReader.sps; 135 | spsData = videoReader.spsData; 136 | spsSize = videoReader.spsSize; 137 | } else if (ret == 4) { 138 | // pps 139 | pps = videoReader.pps; 140 | ppsData = videoReader.ppsData; 141 | ppsSize = videoReader.ppsSize; 142 | videoFlag = false; 143 | } 144 | } else if (ret == AUDIO_PID && audioFlag) { 145 | ret = audioReader.getParameter(); 146 | if (ret < 0) { 147 | fprintf(stderr, "audioReader.getParameter 失败\n"); 148 | return -1; 149 | } 150 | if (ret == 1) { 151 | aacHeader = audioReader.parameter; 152 | audioFlag = false; 153 | } 154 | } 155 | } 156 | return 0; 157 | } 158 | 159 | 160 | int AVReadPacket::readFrame(AVPackage *package) { 161 | int ret; 162 | header.finishFlag = false; 163 | picture->finishFlag = false; 164 | 165 | 166 | videoReader.resetBuffer(); 167 | audioReader.resetBuffer(); 168 | 169 | while (true) { 170 | /*有可能这个时候读ts tag包的是video,但是这个ts tag包凑不够一帧,下个ts tag包是audio*/ 171 | ret = readTransportStream(); 172 | if (ret < 0) { 173 | if (ret == AVERROR_EOF) { 174 | return AVERROR_EOF; 175 | } 176 | log_error("getTransportStreamData 失败"); 177 | return ret; 178 | } 179 | 180 | if (ret == 1) { 181 | std::this_thread::sleep_for(std::chrono::milliseconds(10)); 182 | continue; 183 | } 184 | 185 | 186 | if (ret == VIDEO_PID) { 187 | ret = videoReader.getVideoFrame3(picture); 188 | if (ret < 0) { 189 | fprintf(stderr, "videoReader.getVideoFrame3 失败\n"); 190 | return -1; 191 | } 192 | /* 193 | * 每次进来获取一帧数据的时候把finishFlag设置为false,然后循环去读取数据, 194 | * 只有读够了完整的一帧,finishFlag才会被设置为true 195 | * */ 196 | if (picture->finishFlag) { 197 | package->idrFlag = picture->sliceHeader.nalu.IdrPicFlag; 198 | package->fps = picture->sliceHeader.sps.fps; 199 | package->pts = picture->pts; 200 | package->dts = picture->dts; 201 | package->decodeFrameNumber = picture->decodeFrameNumber; 202 | package->data1 = picture->data; 203 | package->size = picture->size; 204 | package->type = "video"; 205 | break; 206 | } 207 | 208 | } else if (ret == AUDIO_PID) { 209 | ret = audioReader.getAudioFrame2(header); 210 | if (ret < 0) { 211 | fprintf(stderr, "audioReader.getAudioFrame2 失败\n"); 212 | return -1; 213 | } 214 | 215 | if (header.finishFlag) { 216 | package->idrFlag = true; 217 | package->fps = header.sample_rate; 218 | package->dts = header.dts; 219 | package->pts = header.pts; 220 | package->data2 = header.data; 221 | package->size = header.size; 222 | package->type = "audio"; 223 | break; 224 | } 225 | } 226 | 227 | } 228 | return 0; 229 | } 230 | 231 | AVPackage *AVReadPacket::allocPacket() { 232 | return new AVPackage; 233 | } 234 | 235 | void AVReadPacket::freePacket(AVPackage *package) { 236 | delete package; 237 | } 238 | 239 | AVReadPacket::~AVReadPacket() { 240 | fs.close(); 241 | } 242 | 243 | 244 | 245 | 246 | -------------------------------------------------------------------------------- /src/AVPacket/AVReadPacket.h: -------------------------------------------------------------------------------- 1 |  2 | #ifndef RTSP_PACKET_H 3 | #define RTSP_PACKET_H 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include "transportStream/demuxPacket.h" 10 | #include "nalu/NALReader.h" 11 | #include "nalu/NALPicture.h" 12 | #include "adts/adtsReader.h" 13 | #include "adts/adtsHeader.h" 14 | 15 | #define TRANSPORT_STREAM_PACKETS_SIZE 188 16 | 17 | #define AVERROR_EOF (-10) 18 | 19 | struct AVPackage { 20 | bool idrFlag{false}; 21 | std::string type; 22 | double fps{0}; 23 | uint64_t dts{0}; 24 | uint64_t pts{0}; 25 | uint32_t size{0}; 26 | uint32_t decodeFrameNumber{0}; 27 | std::vector data1; 28 | uint8_t *data2{nullptr}; 29 | }; 30 | 31 | class AVReadPacket { 32 | private: 33 | std::chrono::time_point start; 34 | std::chrono::duration elapsed; 35 | std::ifstream fs; 36 | std::string path; 37 | uint32_t currentPacket; 38 | 39 | uint8_t transportStreamBuffer[TRANSPORT_STREAM_PACKETS_SIZE]; 40 | DemuxPacket demux; 41 | 42 | 43 | NALReader videoReader; 44 | NALPicture *picture; 45 | AdtsReader audioReader; 46 | AdtsHeader header; 47 | public: 48 | NALSeqParameterSet sps; 49 | NALPictureParameterSet pps; 50 | uint8_t *spsData{nullptr}; 51 | uint8_t *ppsData{nullptr}; 52 | uint8_t spsSize{0}; 53 | uint8_t ppsSize{0}; 54 | AdtsHeader aacHeader; 55 | 56 | public: 57 | 58 | int init(const std::string &dir, uint32_t transportStreamPacketNumber); 59 | 60 | static AVPackage *allocPacket(); 61 | 62 | static void freePacket(AVPackage *package); 63 | 64 | int readFrame(AVPackage *package); 65 | 66 | int getParameter(); 67 | 68 | ~AVReadPacket(); 69 | 70 | private: 71 | int readTransportStream(bool videoFlag = true, bool audioFlag = true); 72 | }; 73 | 74 | 75 | #endif //RTSP_PACKET_H 76 | -------------------------------------------------------------------------------- /src/AVPacket/AVWritePacket.cpp: -------------------------------------------------------------------------------- 1 |  2 | #include "AVWritePacket.h" 3 | 4 | #include 5 | #include "log/logger.h" 6 | 7 | int AVWritePacket::init(const std::string &dir, uint32_t transportStreamPacketNumber) { 8 | ts.init(); 9 | 10 | path = dir; 11 | /*创建目录*/ 12 | /*返回true表示创建成功,返回false表示已经存在*/ 13 | std::filesystem::create_directories(path); 14 | 15 | currentPacket = transportStreamPacketNumber; 16 | m3u8FileSystem.open(dir + "/test.m3u8", std::ios::binary | std::ios::out | std::ios::trunc); 17 | if (!m3u8FileSystem.is_open()) { 18 | fprintf(stderr, "cloud not open %s\n", (dir + "/test.m3u8").c_str()); 19 | return -1; 20 | } 21 | 22 | videoReader.init(); 23 | audioReader.init(); 24 | picture = videoReader.allocPicture(); 25 | return 0; 26 | } 27 | 28 | int AVWritePacket::writeFrame(uint8_t *data, uint32_t size, const std::string &type, bool flag) { 29 | int ret; 30 | if (type == "video") { 31 | memcpy(videoReader.bufferStart + videoReader.blockBufferSize, data, size); 32 | videoReader.blockBufferSize += size; 33 | if (flag) { 34 | ret = videoReader.getVideoFrame2(picture, videoReader.bufferStart, videoReader.blockBufferSize, 4); 35 | if (ret < 0) { 36 | log_error("videoReader.getVideoFrame2 错误"); 37 | return ret; 38 | } 39 | 40 | if (picture->pictureFinishFlag) { 41 | ret = writeTransportStream(); 42 | if (ret < 0) { 43 | log_error("writeTransportStream 错误"); 44 | return ret; 45 | } 46 | } 47 | videoReader.blockBufferSize = 0; 48 | } 49 | 50 | } else if (type == "audio") { 51 | AdtsHeader::setFrameLength((int) size); 52 | memcpy(data, AdtsHeader::header, 7); 53 | audioReader.disposeAudio(header, data, size); 54 | ret = ts.writeAudioFrame(header, transportStreamFileSystem); 55 | if (ret < 0) { 56 | log_error("写入音频失败"); 57 | return -1; 58 | } 59 | } 60 | 61 | 62 | return 0; 63 | } 64 | 65 | int AVWritePacket::writeTransportStream() { 66 | int ret; 67 | if (picture->sliceHeader.nalu.IdrPicFlag) { 68 | /*set ts packet = 0*/ 69 | ts.resetPacketSize(); 70 | 71 | transportStreamFileSystem.close(); 72 | std::string name = "test" + std::to_string(currentPacket++) + ".ts"; 73 | log_info("写入%s文件", name.c_str()); 74 | double duration = picture->duration - lastDuration; 75 | list.push_back({name, duration}); 76 | transportStreamFileSystem.open(path + "/" + name, std::ios::binary | std::ios::out | std::ios::trunc); 77 | if (!transportStreamFileSystem.is_open()) { 78 | log_error("打开%s文件失败", name.c_str()); 79 | return -1; 80 | } 81 | ts.writeTable(transportStreamFileSystem); 82 | 83 | if (list.size() > 3) { 84 | char m3u8Buffer[512]{0}; 85 | TransportStreamInfo info1 = list[list.size() - 1]; 86 | TransportStreamInfo info2 = list[list.size() - 2]; 87 | TransportStreamInfo info3 = list[list.size() - 3]; 88 | double maxDuration = std::max(info3.duration, std::max(info1.duration, info2.duration)); 89 | 90 | m3u8FileSystem.seekp(0, std::ios::beg); 91 | m3u8FileSystem.write("", 0); 92 | 93 | sprintf(m3u8Buffer, 94 | "#EXTM3U\r\n" 95 | "#EXT-X-VERSION:3\r\n" 96 | "#EXT-X-TARGETDURATION:%f\r\n" 97 | "#EXT-X-MEDIA-SEQUENCE:%d\r\n" 98 | "#EXTINF:%f,\r\n" 99 | "%s\r\n" 100 | "#EXTINF:%f,\r\n" 101 | "%s\r\n" 102 | "#EXTINF:%f,\r\n" 103 | "%s\r\n", 104 | maxDuration, 105 | seq++, 106 | info3.duration, 107 | info3.name.c_str(), 108 | info2.duration, 109 | info2.name.c_str(), 110 | info1.duration, 111 | info1.name.c_str() 112 | ); 113 | m3u8FileSystem.write(m3u8Buffer, (int) strlen(m3u8Buffer)); 114 | } 115 | if (list.size() > 10) { 116 | std::string &oldName = list[0].name; 117 | ret = std::filesystem::remove(path + "/" + oldName); 118 | if (!ret) { 119 | log_error("删除%s失败", oldName.c_str()); 120 | return ret; 121 | } 122 | list.erase(list.begin()); 123 | } 124 | lastDuration = picture->duration; 125 | } 126 | 127 | ret = ts.writeVideoFrame(picture, transportStreamFileSystem); 128 | if (ret < 0) { 129 | log_error("写入视频帧失败"); 130 | return ret; 131 | } 132 | return 0; 133 | } 134 | 135 | int AVWritePacket::setVideoParameter(uint8_t *data, uint32_t size) { 136 | return videoReader.getVideoFrame2(picture, data, size, 4); 137 | } 138 | 139 | int AVWritePacket::setAudioParameter(uint8_t audioObjectType, uint8_t samplingFrequencyIndex, 140 | uint8_t channelConfiguration) { 141 | WriteStream ws(AdtsHeader::header, 7); 142 | header.setConfig(audioObjectType, samplingFrequencyIndex, channelConfiguration, 0); 143 | header.writeAdtsHeader(ws); 144 | return 0; 145 | } -------------------------------------------------------------------------------- /src/AVPacket/AVWritePacket.h: -------------------------------------------------------------------------------- 1 |  2 | #ifndef MEDIASERVER_AVWRITEPACKET_H 3 | #define MEDIASERVER_AVWRITEPACKET_H 4 | 5 | #include 6 | #include 7 | #include 8 | #include "nalu/NALReader.h" 9 | #include "adts/adtsReader.h" 10 | #include "transportStream/transportPacket.h" 11 | 12 | struct TransportStreamInfo { 13 | std::string name; 14 | double duration; 15 | }; 16 | 17 | class AVWritePacket { 18 | private: 19 | std::string path; 20 | uint32_t currentPacket; 21 | TransportPacket ts; 22 | std::ofstream transportStreamFileSystem; 23 | std::ofstream m3u8FileSystem; 24 | 25 | 26 | NALReader videoReader; 27 | NALPicture *picture; 28 | AdtsReader audioReader; 29 | AdtsHeader header; 30 | 31 | 32 | uint32_t seq{0}; 33 | double lastDuration{0}; 34 | 35 | 36 | std::vector list; 37 | public: 38 | int init(const std::string &dir, uint32_t transportStreamPacketNumber); 39 | 40 | int setVideoParameter(uint8_t *data, uint32_t size); 41 | 42 | int setAudioParameter(uint8_t audioObjectType, uint8_t samplingFrequencyIndex, uint8_t channelConfiguration); 43 | 44 | int writeFrame(uint8_t *data, uint32_t size, const std::string &type, bool flag); 45 | 46 | private: 47 | int writeTransportStream(); 48 | }; 49 | 50 | 51 | #endif //MEDIASERVER_AVWRITEPACKET_H 52 | -------------------------------------------------------------------------------- /src/AVPacket/CMakeLists.txt: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | add_library(AVPacket AVReadPacket.cpp AVWritePacket.cpp) 6 | 7 | 8 | target_include_directories(AVPacket 9 | PRIVATE ${PROJECT_SOURCE_DIR}/src 10 | ) 11 | 12 | target_link_libraries(AVPacket 13 | PRIVATE bitStream log nalu adts transportStream 14 | ) 15 | -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | add_subdirectory(log) 7 | add_subdirectory(bitStream) 8 | add_subdirectory(nalu) 9 | add_subdirectory(adts) 10 | add_subdirectory(AVPacket) 11 | add_subdirectory(server) 12 | add_subdirectory(socket) 13 | add_subdirectory(threadPool) 14 | add_subdirectory(protocol) 15 | add_subdirectory(utils) 16 | add_subdirectory(transportStream) 17 | add_subdirectory(flashVideo) 18 | 19 | 20 | add_executable(mediaServer main.cpp) 21 | target_include_directories(mediaServer 22 | PRIVATE ${PROJECT_SOURCE_DIR}/src 23 | ) 24 | 25 | target_link_libraries(mediaServer PRIVATE server) 26 | 27 | 28 | install(TARGETS mediaServer DESTINATION bin) 29 | -------------------------------------------------------------------------------- /src/adts/CMakeLists.txt: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | add_library(adts adtsReader.cpp adtsHeader.cpp) 5 | 6 | 7 | target_include_directories(adts 8 | PRIVATE ${PROJECT_SOURCE_DIR}/src 9 | ) 10 | target_link_libraries(adts PRIVATE bitStream utils) -------------------------------------------------------------------------------- /src/adts/adtsHeader.cpp: -------------------------------------------------------------------------------- 1 |  2 | #include "adtsHeader.h" 3 | 4 | #include 5 | #include "bitStream/readStream.h" 6 | #include "bitStream/writeStream.h" 7 | 8 | enum AudioObjectType { 9 | Main = 0, 10 | LC = 1, 11 | SSR = 2, 12 | LTP = 3, 13 | LD = 23 14 | }; 15 | uint8_t AdtsHeader::header[7]{0}; 16 | 17 | constexpr static uint32_t adts_sample_rates[] = { 18 | 96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000, 7350, 0, 0, 0 19 | }; 20 | 21 | int AdtsHeader::adts_fixed_header(ReadStream &rs) { 22 | syncword = rs.readMultiBit(12); 23 | ID = rs.readBit(); 24 | layer = rs.readMultiBit(2); 25 | protection_absent = rs.readMultiBit(1); 26 | if (protection_absent == 0) { 27 | fprintf(stderr, "不支持CRC校验\n"); 28 | return -1; 29 | } 30 | profile = rs.readMultiBit(2); 31 | sampling_frequency_index = rs.readMultiBit(4); 32 | sample_rate = adts_sample_rates[sampling_frequency_index]; 33 | private_bit = rs.readBit(); 34 | channel_configuration = rs.readMultiBit(3); 35 | original_copy = rs.readBit(); 36 | home = rs.readBit(); 37 | 38 | return 0; 39 | } 40 | 41 | int AdtsHeader::adts_variable_header(ReadStream &rs) { 42 | copyright_identification_bit = rs.readBit(); 43 | copyright_identification_start = rs.readBit(); 44 | frame_length = rs.readMultiBit(13); 45 | adts_buffer_fullness = rs.readMultiBit(11); 46 | number_of_raw_data_blocks_in_frame = rs.readMultiBit(2); 47 | return 0; 48 | } 49 | 50 | 51 | void AdtsHeader::setConfig(uint8_t audioObjectType, uint8_t samplingFrequencyIndex, uint8_t channelConfiguration, 52 | uint16_t length) { 53 | profile = audioObjectType; 54 | sampling_frequency_index = samplingFrequencyIndex; 55 | channel_configuration = channelConfiguration; 56 | frame_length = length; 57 | sample_rate = adts_sample_rates[sampling_frequency_index]; 58 | } 59 | 60 | int AdtsHeader::writeAdtsHeader(WriteStream &ws) const { 61 | /*adts_fixed_header*/ 62 | ws.writeMultiBit(12, syncword); 63 | ws.writeMultiBit(1, ID); 64 | ws.writeMultiBit(2, layer); 65 | ws.writeMultiBit(1, protection_absent); 66 | ws.writeMultiBit(2, profile); 67 | ws.writeMultiBit(4, sampling_frequency_index); 68 | ws.writeMultiBit(1, private_bit); 69 | ws.writeMultiBit(3, channel_configuration); 70 | ws.writeMultiBit(1, original_copy); 71 | ws.writeMultiBit(1, home); 72 | 73 | /*adts_variable_header*/ 74 | ws.writeMultiBit(1, copyright_identification_bit); 75 | ws.writeMultiBit(1, copyright_identification_start); 76 | ws.writeMultiBit(13, frame_length); 77 | ws.writeMultiBit(11, adts_buffer_fullness); 78 | ws.writeMultiBit(2, number_of_raw_data_blocks_in_frame); 79 | return 0; 80 | } 81 | 82 | int AdtsHeader::setFrameLength(int frameLength) { 83 | // 检查参数是否有效 84 | if (frameLength <= 0) { 85 | return -1; 86 | } 87 | // 取出frameLength最前面的两位放在header[3]最后面两位 88 | header[3] = (header[3] & 0xFC) | ((frameLength & 0x1800) >> 11); 89 | // 取出frameLength中间的8位 90 | header[4] = ((frameLength & 0x7F8) >> 3); 91 | /*取出最后3位,放在header[5]前三位上*/ 92 | header[5] = (header[5] & 0x1F) | ((frameLength & 0x7) << 5); 93 | return 0; 94 | } 95 | 96 | 97 | -------------------------------------------------------------------------------- /src/adts/adtsHeader.h: -------------------------------------------------------------------------------- 1 |  2 | #ifndef MUX_ADTSHEADER_H 3 | #define MUX_ADTSHEADER_H 4 | 5 | #include 6 | 7 | class ReadStream; 8 | 9 | class WriteStream; 10 | 11 | /* 12 | * profile 13 | * 该数据元素的解释取决于ID位的值。 14 | * 如果ID等于“1”,该字段包含与ISO/IEC 13818-7中定义的ADTS流中的profile字段相同的信息。 15 | * 如果ID等于“0”,这个元素表示MPEG-4音频对象类型(profile_ObjectType+1),根据subsub1.5.2.1中定义的表。 16 | * */ 17 | class AdtsHeader { 18 | public: 19 | 20 | 21 | static uint8_t header[7]; 22 | bool finishFlag{false}; 23 | uint8_t *data{nullptr}; 24 | uint32_t size{0}; 25 | uint64_t pts{0}; 26 | uint64_t dts{0}; 27 | int interval{0}; 28 | double duration{0}; 29 | /*fixed_header*/ 30 | /*帧同步标识一个帧的开始,固定为0xFFF*/ 31 | uint16_t syncword{0xFFF}; 32 | /*MPEG标识符,如果ADTS流中的音频数据为MPEG-2 AAC,则设置为' 1 ' 33 | (参见ISO/IEC 13818-7),如果音频数据是MPEG-4,则设置为' 0 '。另请参阅 34 | ISO/IEC 11172-3,第2.4.2.3款。*/ 35 | uint8_t ID{0}; 36 | /*表示使用哪一层 11=Layer1 10=Layer2 01=Layer3 00=保留。参考mpeg-1 part3 2.4.2.3小节,这里是AAC,不兼容mpeg1音频,固定为00*/ 37 | uint8_t layer{0}; 38 | /* 是否在音频位流中添加了冗余以方便错误检测和隐藏(参见mpeg-1 part3 protection_bit)。标识是否进行误码校验。0表示有CRC校验,1表示没有CRC校验*/ 39 | uint8_t protection_absent{1}; 40 | /*标识使用哪个级别的AAC id=0,这个值要减1*/ 41 | uint8_t profile{0}; 42 | /*标识使用的采样率的下标*/ 43 | uint8_t sampling_frequency_index{0}; 44 | /*对应的采样率*/ 45 | uint32_t sample_rate{0}; 46 | /*私有位,编码时设置为0,解码时忽略 47 | 指示是否在音频位流中添加了冗余以方便 48 | 错误检测和隐藏。 如果没有添加冗余,则等于'1',如果添加了冗余,则等于'0' 49 | */ 50 | uint8_t private_bit{0}; 51 | 52 | /*标识声道数 通道配置 53 | * 如果如果channel_configuration大于0,则通道配置由表42中的' Default bitstream index number '给出,参见表8.5 54 | * 如果channel_configuration = 0,则通道配置未在标头中指定, 55 | * 并且必须由作为标头之后第一个 raw_data_block() 中的第一个句法元素的program_config_element() 或由隐式配置给出, 56 | * */ 57 | uint8_t channel_configuration{0}; 58 | /*编码时设置为0,解码时忽略*/ 59 | uint8_t original_copy{0}; 60 | /*编码时设置为0,解码时忽略*/ 61 | uint8_t home{0}; 62 | 63 | 64 | /*variable_header*/ 65 | /*编码时设置为0,解码时忽略*/ 66 | uint8_t copyright_identification_bit{0}; 67 | /*编码时设置为0,解码时忽略*/ 68 | uint8_t copyright_identification_start{0}; 69 | /*ADTS帧长度包括ADTS长度和AAC声音数据长度的和。即 aac_frame_length = (protection_absent == 0 ? 9 : 7) + audio_data_length*/ 70 | uint16_t frame_length{0}; 71 | /*固定为0x7FF。表示是码率可变的码流*/ 72 | uint16_t adts_buffer_fullness{0x7FF}; 73 | /*表示当前帧有number_of_raw_data_blocks_in_frame + 1 个原始帧(一个AAC原始帧包含一段时间内1024个采样及相关数据)。*/ 74 | uint8_t number_of_raw_data_blocks_in_frame{0}; 75 | 76 | 77 | public: 78 | /*ADTS 的固定标头。此标头中的信息不会因帧而异。它 在每一帧重复以允许随机访问比特流比特流*/ 79 | int adts_fixed_header(ReadStream &rs); 80 | 81 | /*ADTS 的可变标头。该报头与固定报头一样每帧传输, 但包含随帧变化的数据*/ 82 | int adts_variable_header(ReadStream &rs); 83 | 84 | void 85 | setConfig(uint8_t audioObjectType, uint8_t samplingFrequencyIndex, uint8_t channelConfiguration, uint16_t length); 86 | 87 | int writeAdtsHeader(WriteStream &ws) const; 88 | 89 | static int setFrameLength(int frameLength); 90 | }; 91 | 92 | 93 | #endif //MUX_ADTSHEADER_H 94 | -------------------------------------------------------------------------------- /src/adts/adtsReader.cpp: -------------------------------------------------------------------------------- 1 | #include "adtsReader.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include "utils/util.h" 7 | #include "bitStream/readStream.h" 8 | 9 | 10 | 11 | 12 | int AdtsReader::init() { 13 | buffer = new uint8_t[MAX_BUFFER_SIZE]; 14 | blockBufferSize = 0; 15 | return 0; 16 | } 17 | 18 | 19 | 20 | 21 | 22 | 23 | void AdtsReader::putData(uint8_t *data, uint32_t size) { 24 | memcpy(buffer + blockBufferSize, data, size); 25 | blockBufferSize += size; 26 | bufferEnd = buffer + blockBufferSize; 27 | } 28 | 29 | void AdtsReader::resetBuffer() { 30 | if (resetFlag) { 31 | uint32_t remainingByte = bufferEnd - bufferPosition; 32 | blockBufferSize = remainingByte; 33 | memcpy(buffer, bufferPosition, remainingByte); 34 | resetFlag = false; 35 | } 36 | 37 | } 38 | 39 | int AdtsReader::getParameter() { 40 | int ret; 41 | 42 | if (buffer == nullptr) { 43 | fprintf(stderr, "请初始化\n"); 44 | return -1; 45 | } 46 | if (blockBufferSize < MAX_HEADER_SIZE) { 47 | return 0; 48 | } 49 | 50 | 51 | ReadStream rs(buffer, blockBufferSize); 52 | if (rs.getMultiBit(12) != 0xFFF) { 53 | fprintf(stderr, "格式不对,不等于0xFFF\n"); 54 | return -1; 55 | } 56 | 57 | ret = parameter.adts_fixed_header(rs); 58 | if (ret < 0) { 59 | fprintf(stderr, "解析adts fixed header失败\n"); 60 | return -1; 61 | } 62 | parameter.adts_variable_header(rs); 63 | 64 | uint16_t frameLength = parameter.frame_length; 65 | 66 | if (blockBufferSize >= frameLength) { 67 | parameter.data = &buffer[MAX_HEADER_SIZE]; 68 | parameter.size = frameLength - MAX_HEADER_SIZE; 69 | bufferPosition = buffer + frameLength; 70 | 71 | disposeAudio(parameter, parameter.data, parameter.size); 72 | resetFlag = true; 73 | return 1; 74 | } 75 | return 0; 76 | } 77 | 78 | int AdtsReader::getAudioFrame2(AdtsHeader &header) { 79 | int ret; 80 | 81 | if (buffer == nullptr) { 82 | fprintf(stderr, "请初始化\n"); 83 | return -1; 84 | } 85 | if (blockBufferSize < MAX_HEADER_SIZE) { 86 | return 0; 87 | } 88 | 89 | ReadStream rs(buffer, blockBufferSize); 90 | if (rs.getMultiBit(12) != 0xFFF) { 91 | fprintf(stderr, "格式不对,不等于0xFFF\n"); 92 | return -1; 93 | } 94 | 95 | ret = header.adts_fixed_header(rs); 96 | if (ret < 0) { 97 | fprintf(stderr, "解析adts fixed header失败\n"); 98 | return -1; 99 | } 100 | header.adts_variable_header(rs); 101 | 102 | uint16_t frameLength = header.frame_length; 103 | 104 | if (blockBufferSize >= frameLength) { 105 | header.data = &buffer[MAX_HEADER_SIZE]; 106 | header.size = frameLength - MAX_HEADER_SIZE; 107 | bufferPosition = buffer + frameLength; 108 | 109 | disposeAudio(header, header.data, header.size); 110 | resetFlag = true; 111 | } 112 | 113 | 114 | return 0; 115 | } 116 | 117 | 118 | void AdtsReader::disposeAudio(AdtsHeader &header, uint8_t *data, uint32_t size) { 119 | header.data = data; 120 | header.size = size; 121 | header.duration = (double) audioDecodeFrameNumber / header.sample_rate; 122 | header.dts = audioDecodeFrameNumber; 123 | header.pts = av_rescale_q(audioDecodeFrameNumber, {1, static_cast(header.sample_rate)}, {1, 1000}); 124 | /*转换成微秒*/ 125 | header.interval = (int) (1024.0 / (double) header.sample_rate * 1000.0); 126 | audioDecodeFrameNumber += 1024; 127 | header.finishFlag = true; 128 | } 129 | 130 | 131 | AdtsReader::~AdtsReader() { 132 | if (buffer) { 133 | delete[] buffer; 134 | buffer = nullptr; 135 | } 136 | } 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | -------------------------------------------------------------------------------- /src/adts/adtsReader.h: -------------------------------------------------------------------------------- 1 |  2 | #ifndef MUX_ADTSREADER_H 3 | #define MUX_ADTSREADER_H 4 | 5 | #include 6 | #include "adtsHeader.h" 7 | 8 | 9 | class AdtsReader { 10 | public: 11 | static constexpr uint32_t MAX_BUFFER_SIZE{8191}; 12 | static constexpr uint32_t MAX_HEADER_SIZE{7}; 13 | 14 | /*给外部提供参数信息用的*/ 15 | AdtsHeader parameter; 16 | private: 17 | bool resetFlag{true}; 18 | 19 | uint8_t *buffer{nullptr}; 20 | uint8_t *bufferEnd{nullptr}; 21 | uint8_t *bufferPosition{nullptr}; 22 | 23 | uint32_t blockBufferSize{0}; 24 | 25 | uint64_t audioDecodeFrameNumber{0}; 26 | public: 27 | 28 | int init(); 29 | 30 | int getParameter(); 31 | 32 | int getAudioFrame2(AdtsHeader &header); 33 | 34 | void resetBuffer(); 35 | 36 | void disposeAudio(AdtsHeader &header, uint8_t *data, uint32_t size); 37 | 38 | void putData(uint8_t *data, uint32_t size); 39 | 40 | ~AdtsReader(); 41 | 42 | 43 | }; 44 | 45 | 46 | #endif //MUX_ADTSREADER_H 47 | -------------------------------------------------------------------------------- /src/bitStream/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library(bitStream writeStream.cpp readStream.cpp) -------------------------------------------------------------------------------- /src/bitStream/readStream.cpp: -------------------------------------------------------------------------------- 1 | #include "readStream.h" 2 | 3 | #include 4 | 5 | ReadStream::ReadStream(uint8_t *buf, uint32_t _size) { 6 | startPtr = buf; 7 | currentPtr = buf; 8 | endPtr = buf + _size - 1; 9 | size = _size; 10 | } 11 | 12 | uint8_t ReadStream::readBit() { 13 | --bitsLeft; 14 | 15 | uint8_t result = ((unsigned) (*currentPtr) >> bitsLeft) & 1u; 16 | 17 | if (bitsLeft == 0) { 18 | currentPtr++; 19 | position++; 20 | bitsLeft = 8; 21 | } 22 | return result; 23 | } 24 | 25 | uint64_t ReadStream::readMultiBit(uint32_t n) { 26 | uint64_t result = 0; 27 | for (uint32_t i = 0; i < n; ++i) { 28 | //把前n位移到后面n位来 29 | //readBit()在算数表达式小于int类型,会被扩展为整型 30 | result = result | ((unsigned) readBit() << (n - i - 1u)); 31 | } 32 | return result; 33 | } 34 | 35 | uint64_t ReadStream::getMultiBit(uint32_t n) { 36 | uint64_t ret; 37 | 38 | uint8_t *tempPtr = currentPtr; 39 | uint8_t tempBitsLeft = bitsLeft; 40 | uint32_t tempPosition = position; 41 | 42 | ret = readMultiBit(n); 43 | 44 | currentPtr = tempPtr; 45 | bitsLeft = tempBitsLeft; 46 | position = tempPosition; 47 | return ret; 48 | } 49 | 50 | int ReadStream::getString(char str[], uint32_t n) { 51 | for (int i = 0; i < n; ++i) { 52 | char c = (char) readMultiBit(8); 53 | str[i] = c; 54 | } 55 | return 0; 56 | } 57 | 58 | int ReadStream::setBytePtr(uint32_t n) { 59 | currentPtr += n; 60 | position += n; 61 | bitsLeft = 8; 62 | return 0; 63 | } 64 | 65 | int ReadStream::byteAlignment() { 66 | while (bitsLeft != 8) { 67 | readBit(); 68 | } 69 | return 0; 70 | } 71 | 72 | uint32_t ReadStream::bitsToDecode() const { 73 | return (size - position - 1u) * 8 + bitsLeft; 74 | } 75 | 76 | uint32_t ReadStream::readUE() { 77 | uint32_t result = 0; 78 | size_t i = 0; 79 | while ((readBit() == 0) && (i < 32)) { 80 | i++; 81 | } 82 | result = readMultiBit(i); 83 | //因为上面readBit多读了一位,把分割的1放在原来的位置上 84 | result += (1 << i) - 1; 85 | return result; 86 | } 87 | 88 | int32_t ReadStream::readSE() { 89 | int r = (int) readUE(); 90 | if (r & 0x01) { 91 | r = (r + 1) / 2; 92 | } else { 93 | r = -(r / 2); 94 | } 95 | return r; 96 | } 97 | 98 | int ReadStream::more_rbsp_data() { 99 | if (position > size || (position == size && bitsLeft != 8)) { 100 | fprintf(stderr, "超出可读内存长度\n"); 101 | return -1; 102 | } 103 | 104 | if (position == size) { //表示读完 105 | return 0; 106 | } 107 | uint8_t *end = endPtr; 108 | //从后往前找,直到找到第一个非0值字节位置为止 109 | while (end > currentPtr && *end == 0) --end; 110 | 111 | if (end > currentPtr) { 112 | return true; //说明当前位置bs.currentPtr后面还有码流数据 113 | } else { //走到这里end==currentPtr了 114 | bool flag = false; 115 | int i; 116 | for (i = 0; i < 8; i++) { //在单个字节的8个比特位中,从后往前找,找到rbsp_stop_one_bit位置 117 | int v = ((*currentPtr) >> i) & 0x01; 118 | if (v == 1) { 119 | ++i;//加的一个rbsp_stop_one_bit 120 | flag = true; 121 | break; 122 | } 123 | } 124 | 125 | if (flag) { 126 | return i < bitsLeft; 127 | } else { 128 | fprintf(stderr, "找不到rbsp_stop_one_bit\n"); 129 | return -1; 130 | } 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /src/bitStream/readStream.h: -------------------------------------------------------------------------------- 1 |  2 | #ifndef DEMUX_READSTREAM_H 3 | #define DEMUX_READSTREAM_H 4 | 5 | #include "cstdint" 6 | 7 | class ReadStream { 8 | private: 9 | 10 | //指向开始的位置 11 | uint8_t *startPtr = nullptr; 12 | //指向结束的位置 13 | uint8_t *endPtr = nullptr; 14 | // 当前读取到了字节中的第几位 15 | uint8_t bitsLeft{8}; 16 | 17 | public: 18 | 19 | // buffer 的长度(单位 Byte) 20 | uint32_t size{0}; 21 | // 读取到第几字节 22 | uint32_t position{0}; 23 | 24 | 25 | // 当前读取到了哪个字节的指针 26 | uint8_t *currentPtr = nullptr; 27 | 28 | ReadStream(uint8_t *buf, uint32_t _size); 29 | 30 | //读取1bit 31 | uint8_t readBit(); 32 | 33 | //读取n个bit 34 | uint64_t readMultiBit(uint32_t n); 35 | 36 | /*无符号指数哥伦布*/ 37 | uint32_t readUE(); 38 | 39 | /*有符号指数哥伦布*/ 40 | int32_t readSE(); 41 | 42 | int getString(char str[], uint32_t n); 43 | 44 | //获取n个bit 45 | uint64_t getMultiBit(uint32_t n); 46 | 47 | /*字节对齐*/ 48 | int byteAlignment(); 49 | 50 | /*在当前位置往后跳几个字节*/ 51 | int setBytePtr(uint32_t n); 52 | 53 | /*返回还剩多少个bit未解码*/ 54 | uint32_t bitsToDecode() const; 55 | 56 | 57 | int more_rbsp_data(); 58 | }; 59 | 60 | #endif //DEMUX_READSTREAM_H 61 | -------------------------------------------------------------------------------- /src/bitStream/writeStream.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "writeStream.h" 3 | 4 | WriteStream::WriteStream(uint8_t *buf, uint32_t size) { 5 | 6 | memset(buf, 0, size); 7 | bufferStart = buf; 8 | currentPtr = buf; 9 | endPtr = buf + size - 1; 10 | bufferSize = size; 11 | position = 0; 12 | 13 | } 14 | 15 | uint8_t WriteStream::writeBit(uint8_t bit) { 16 | --bitsLeft; 17 | uint8_t val = *currentPtr >> (bitsLeft); 18 | *currentPtr = (unsigned) (val | bit) << (bitsLeft); 19 | 20 | if (bitsLeft == 0) { 21 | currentPtr++; 22 | position++; 23 | bitsLeft = 8; 24 | } 25 | return 0; 26 | } 27 | 28 | int WriteStream::writeMultiBit(uint32_t n, uint64_t val) { 29 | uint8_t bitPos = n; 30 | for (int i = 0; i < n; ++i) { 31 | --bitPos; 32 | uint8_t bit = (val >> bitPos) & 1u; 33 | writeBit(bit); 34 | } 35 | return 0; 36 | } 37 | 38 | int WriteStream::setString(const char *str, uint32_t n) { 39 | for (int i = 0; i < n; ++i) { 40 | writeMultiBit(8, str[i]); 41 | } 42 | return 0; 43 | } 44 | 45 | void WriteStream::setBytePtr(uint32_t n) { 46 | currentPtr += n; 47 | position += n; 48 | bitsLeft = 8; 49 | } 50 | 51 | void WriteStream::paddingByte(uint32_t n, uint8_t val) { 52 | for (int i = 0; i < n; ++i) { 53 | *currentPtr++ = val; 54 | ++position; 55 | } 56 | bitsLeft = 8; 57 | } 58 | 59 | void WriteStream::fillByte(uint8_t val) const { 60 | memset(currentPtr, val, bufferSize - position); 61 | } 62 | 63 | /*初始化为最先的样子*/ 64 | void WriteStream::reset() { 65 | memset(bufferStart, 0, bufferSize); 66 | currentPtr = bufferStart; 67 | position = 0; 68 | bitsLeft = 8; 69 | } 70 | 71 | 72 | -------------------------------------------------------------------------------- /src/bitStream/writeStream.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef DEMUX_WRITESTREAM_H 3 | #define DEMUX_WRITESTREAM_H 4 | 5 | #include 6 | 7 | class WriteStream { 8 | private: 9 | uint8_t *endPtr = nullptr; 10 | // 当前读取到了字节中的第几位 11 | uint8_t bitsLeft = 8; 12 | 13 | 14 | public: 15 | //指向开始的位置 16 | uint8_t *bufferStart = nullptr; 17 | // 写到第几字节 18 | uint32_t position; 19 | // 当前读取到了哪个字节的指针 20 | uint8_t *currentPtr = nullptr; 21 | // buffer 的长度(单位 Byte) 22 | uint32_t bufferSize = 0; 23 | public: 24 | WriteStream(uint8_t *buf, uint32_t _size); 25 | 26 | //写入1bit 27 | uint8_t writeBit(uint8_t bit); 28 | 29 | //写入n个bit 30 | int writeMultiBit(uint32_t n, uint64_t val); 31 | 32 | void fillByte(uint8_t val) const; 33 | 34 | void paddingByte(uint32_t n, uint8_t val); 35 | 36 | int setString(const char str[], uint32_t n); 37 | 38 | void setBytePtr(uint32_t n); 39 | 40 | void reset(); 41 | }; 42 | 43 | #endif //DEMUX_WRITESTREAM_H 44 | -------------------------------------------------------------------------------- /src/flashVideo/CMakeLists.txt: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | add_library(flashVideo FLVHeader.cpp FLVTagHeader.cpp FLVScriptTag.cpp FLVVideoTag.cpp FLVAudioTag.cpp) 5 | 6 | 7 | target_include_directories(flashVideo 8 | PRIVATE ${PROJECT_SOURCE_DIR}/src 9 | ) 10 | 11 | target_link_libraries(flashVideo PRIVATE bitStream) -------------------------------------------------------------------------------- /src/flashVideo/FLVAudioTag.cpp: -------------------------------------------------------------------------------- 1 |  2 | 3 | #include "FLVAudioTag.h" 4 | 5 | void FLVAudioTag::setConfig(uint8_t packetType) { 6 | AACPacketType = packetType; 7 | } 8 | 9 | int FLVAudioTag::writeData(WriteStream &ws) const { 10 | ws.writeMultiBit(4, SoundFormat); 11 | ws.writeMultiBit(2, SoundRate); 12 | ws.writeMultiBit(1, SoundSize); 13 | ws.writeMultiBit(1, SoundType); 14 | ws.writeMultiBit(8, AACPacketType); 15 | 16 | return 0; 17 | } 18 | 19 | int FLVAudioTag::writeConfig(WriteStream &ws) const { 20 | ws.writeMultiBit(4, SoundFormat); 21 | ws.writeMultiBit(2, SoundRate); 22 | ws.writeMultiBit(1, SoundSize); 23 | ws.writeMultiBit(1, SoundType); 24 | ws.writeMultiBit(8, AACPacketType); 25 | 26 | /*--- aac config ---*/ 27 | ws.writeMultiBit(5, audioObjectType); 28 | ws.writeMultiBit(4, samplingFrequencyIndex); 29 | ws.writeMultiBit(4, channelConfiguration); 30 | 31 | 32 | ws.writeMultiBit(1, frameLengthFlag); 33 | ws.writeMultiBit(1, dependsOnCoreCoder); 34 | ws.writeMultiBit(1, extensionFlag); 35 | return 0; 36 | } 37 | 38 | void FLVAudioTag::setConfigurationRecord(uint8_t profile, uint8_t index, uint8_t channel) { 39 | audioObjectType = profile; 40 | samplingFrequencyIndex = index; 41 | channelConfiguration = channel; 42 | } 43 | 44 | 45 | -------------------------------------------------------------------------------- /src/flashVideo/FLVAudioTag.h: -------------------------------------------------------------------------------- 1 |  2 | 3 | #ifndef MEDIASERVER_FLVAUDIOTAG_H 4 | #define MEDIASERVER_FLVAUDIOTAG_H 5 | 6 | #include 7 | #include "bitStream/writeStream.h" 8 | 9 | class FLVAudioTag { 10 | private: 11 | /* 12 | * SoundData格式。定义了以下值: 13 | * 0 = Linear PCM, platform endian 14 | * 1 = ADPCM 15 | * 2 = MP3 16 | * 3 = Linear PCM, little endian 17 | * 10 = AAC 18 | * */ 19 | uint8_t SoundFormat{10}; 20 | /* 21 | 采样率 对于AAC来说,该值总是3 22 | 0 = 5.5 kHz 23 | 1 = 11 kHz 24 | 2 = 22 kHz 25 | 3 = 44 kHz 26 | */ 27 | uint8_t SoundRate{3}; 28 | /* 29 | 每个采样点数据的大小, 这个字段只左右于未压缩格式 ,PCM 就是未压缩格式。而AAC这类就是已经压缩过的格式了。这个字段总是1 30 | 0 = 8-bit samples 31 | 1 = 16-bit samples*/ 32 | uint8_t SoundSize{1}; 33 | /* 34 | 单声道或立体声 对于AAC的话总是1 35 | 0 = Mono sound 36 | 1 = Stereo sound 37 | */ 38 | uint8_t SoundType{1}; 39 | /* 40 | 是AAC编码的才有这个值 41 | 0 = AAC sequence header 42 | 1 = AAC raw 43 | */ 44 | uint8_t AACPacketType{0}; 45 | private: 46 | uint8_t audioObjectType; 47 | uint8_t channelConfiguration; 48 | uint8_t samplingFrequencyIndex; 49 | 50 | bool frameLengthFlag{false}; 51 | bool dependsOnCoreCoder{false}; 52 | bool extensionFlag{false}; 53 | 54 | 55 | uint16_t syncExtensionType; 56 | public: 57 | void setConfig(uint8_t packetType); 58 | 59 | void setConfigurationRecord(uint8_t profile, uint8_t index, uint8_t channel); 60 | 61 | int writeConfig(WriteStream &ws) const; 62 | 63 | int writeData(WriteStream &ws) const; 64 | }; 65 | 66 | 67 | #endif //MEDIASERVER_FLVAUDIOTAG_H 68 | -------------------------------------------------------------------------------- /src/flashVideo/FLVHeader.cpp: -------------------------------------------------------------------------------- 1 |  2 | 3 | #include "FLVHeader.h" 4 | #include "bitStream/writeStream.h" 5 | 6 | int FLVHeader::write(WriteStream &ws) { 7 | 8 | ws.setString(Signature, 3); 9 | 10 | ws.writeMultiBit(8, Version); 11 | //Reserved 12 | ws.writeMultiBit(5, 0); 13 | ws.writeMultiBit(1, TypeFlagsAudio); 14 | //Reserved 15 | ws.writeMultiBit(1, 0); 16 | ws.writeMultiBit(1, TypeFlagsVideo); 17 | ws.writeMultiBit(32, DataOffset); 18 | return 0; 19 | } 20 | -------------------------------------------------------------------------------- /src/flashVideo/FLVHeader.h: -------------------------------------------------------------------------------- 1 |  2 | 3 | #ifndef MUX_FLVHEADER_H 4 | #define MUX_FLVHEADER_H 5 | 6 | #include 7 | 8 | class WriteStream; 9 | 10 | class FLVHeader { 11 | public: 12 | constexpr static int size{9}; 13 | 14 | int write(WriteStream &ws); 15 | 16 | private: 17 | char Signature[3]{'F', 'L', 'V'}; 18 | uint8_t Version{1}; 19 | //uint8_t TypeFlagsReserved{0}; 20 | uint8_t TypeFlagsAudio{1}; 21 | //uint8_t TypeFlagsReserved{0}; 22 | uint8_t TypeFlagsVideo{1}; 23 | /*这个header的长度*/ 24 | uint32_t DataOffset{9}; 25 | }; 26 | 27 | 28 | #endif //MUX_FLVHEADER_H 29 | -------------------------------------------------------------------------------- /src/flashVideo/FLVScriptTag.cpp: -------------------------------------------------------------------------------- 1 |  2 | #include "FLVScriptTag.h" 3 | #include 4 | 5 | static Item list[7] = { 6 | {"width", number_marker}, 7 | {"height", number_marker}, 8 | {"framerate", number_marker}, 9 | {"videocodecid", number_marker}, 10 | {"audiosamplerate", number_marker}, 11 | {"stereo", boolean_marker}, 12 | {"audiocodecid", number_marker} 13 | }; 14 | 15 | int FLVScriptTag::write(WriteStream &ws) { 16 | 17 | /*第⼀个AMF包*/ 18 | ws.writeMultiBit(8, string_marker); 19 | const char *msg = "onMetaData"; 20 | ws.writeMultiBit(16, strlen(msg)); 21 | ws.setString(msg, strlen(msg)); 22 | 23 | /*第⼆个AMF包*/ 24 | ws.writeMultiBit(8, ecma_array_marker); 25 | /*数组的长度*/ 26 | ws.writeMultiBit(32, 7); 27 | 28 | 29 | for (auto &i: list) { 30 | /*写入字符串大小*/ 31 | ws.writeMultiBit(16, i.name.length()); 32 | /*写入字符串*/ 33 | ws.setString(i.name.c_str(), i.name.length()); 34 | ws.writeMultiBit(8, i.type); 35 | 36 | if (i.type == number_marker) { 37 | if (i.name == "width") { 38 | ws.writeMultiBit(64, *(uint64_t *) (&width)); 39 | } else if (i.name == "height") { 40 | ws.writeMultiBit(64, *(uint64_t *) (&height)); 41 | } else if (i.name == "framerate") { 42 | ws.writeMultiBit(64, *(uint64_t *) (&framerate)); 43 | } else if (i.name == "videocodecid") { 44 | ws.writeMultiBit(64, *(uint64_t *) (&videocodecid)); 45 | } else if (i.name == "audiosamplerate") { 46 | ws.writeMultiBit(64, *(uint64_t *) (&audiosamplerate)); 47 | } else if (i.name == "audiocodecid") { 48 | ws.writeMultiBit(64, *(uint64_t *) (&audiocodecid)); 49 | } 50 | 51 | } else if (i.type == boolean_marker) { 52 | ws.writeMultiBit(8, stereo); 53 | } else { 54 | fprintf(stderr, "AMF 数组写入不对\n"); 55 | return -1; 56 | } 57 | } 58 | 59 | 60 | /*输入结束符*/ 61 | ws.writeMultiBit(24, object_end_marker); 62 | return 0; 63 | } 64 | 65 | void FLVScriptTag::setConfig(double _width, double _height, double _fps, double _sampleRate, uint8_t channel) { 66 | width = _width; 67 | height = _height; 68 | framerate = _fps; 69 | audiosamplerate = _sampleRate; 70 | stereo = channel == 2; 71 | } 72 | -------------------------------------------------------------------------------- /src/flashVideo/FLVScriptTag.h: -------------------------------------------------------------------------------- 1 |  2 | #ifndef MEDIASERVER_SCRIPTTAG_H 3 | #define MEDIASERVER_SCRIPTTAG_H 4 | 5 | #include 6 | #include "bitStream/writeStream.h" 7 | 8 | 9 | enum marker { 10 | number_marker, 11 | boolean_marker, 12 | string_marker = 2, 13 | object_marker, 14 | movieclip_marker, 15 | null_marker, 16 | undefined_marker, 17 | reference_marker, 18 | ecma_array_marker, 19 | object_end_marker 20 | }; 21 | struct Item { 22 | std::string name; 23 | marker type; 24 | }; 25 | 26 | class FLVScriptTag { 27 | private: 28 | double videocodecid{7.0}; 29 | double audiocodecid{10.0}; 30 | 31 | 32 | double width{0}; 33 | double height{0}; 34 | double framerate{0}; 35 | double audiosamplerate{0}; 36 | bool stereo{false}; 37 | public: 38 | void setConfig(double _width, double _height, double _fps, double _sampleRate, uint8_t channel); 39 | 40 | int write(WriteStream &ws); 41 | }; 42 | 43 | 44 | #endif //MEDIASERVER_SCRIPTTAG_H 45 | -------------------------------------------------------------------------------- /src/flashVideo/FLVTagHeader.cpp: -------------------------------------------------------------------------------- 1 |  2 | #include "FLVTagHeader.h" 3 | 4 | int FLVTagHeader::write(WriteStream &ws) const { 5 | ws.writeMultiBit(2, 0); 6 | ws.writeMultiBit(1, Filter); 7 | ws.writeMultiBit(5, TagType); 8 | /*除了这个header,实际存储多少数据的大小*/ 9 | ws.writeMultiBit(24, DataSize); 10 | ws.writeMultiBit(24, Timestamp); 11 | ws.writeMultiBit(8, TimestampExtended); 12 | ws.writeMultiBit(24, StreamID); 13 | 14 | return 0; 15 | } 16 | 17 | void FLVTagHeader::setConfig(uint8_t type, uint32_t size, uint64_t dts) { 18 | TagType = type; 19 | DataSize = size; 20 | Timestamp = dts & 0xFFFFFF; 21 | TimestampExtended = dts >> 24 & 0xFF; 22 | } 23 | -------------------------------------------------------------------------------- /src/flashVideo/FLVTagHeader.h: -------------------------------------------------------------------------------- 1 |  2 | 3 | #ifndef MEDIASERVER_FLVTAGHEADER_H 4 | #define MEDIASERVER_FLVTAGHEADER_H 5 | 6 | #include "bitStream/writeStream.h" 7 | 8 | 9 | enum { 10 | AUDIO = 8, 11 | VIDEO = 9, 12 | SCRIPT = 18 13 | }; 14 | 15 | class FLVTagHeader { 16 | public: 17 | void setConfig(uint8_t type, uint32_t size, uint64_t dts); 18 | 19 | int write(WriteStream &ws) const; 20 | 21 | private: 22 | /*是否加密*/ 23 | uint8_t Filter{0}; 24 | /*此tag中的内容类型*/ 25 | uint8_t TagType{0}; 26 | /*表明当前tag中存储的音频或视频文件的大小,包括文件的头*/ 27 | /*消息的长度。从StreamID到标签结尾的字节数(等于标签的长度- 11)*/ 28 | uint32_t DataSize{0}; 29 | 30 | uint32_t Timestamp{0}; 31 | uint8_t TimestampExtended{0}; 32 | 33 | uint32_t StreamID{0}; 34 | }; 35 | 36 | 37 | #endif //MEDIASERVER_FLVTAGHEADER_H 38 | -------------------------------------------------------------------------------- /src/flashVideo/FLVVideoTag.cpp: -------------------------------------------------------------------------------- 1 |  2 | #include "FLVVideoTag.h" 3 | #include 4 | #include 5 | 6 | int FLVVideoTag::writeData(WriteStream &ws) { 7 | ws.writeMultiBit(4, frameType); 8 | ws.writeMultiBit(4, codecID); 9 | ws.writeMultiBit(8, AVCPacketType); 10 | ws.writeMultiBit(24, compositionTime); 11 | return 0; 12 | } 13 | 14 | int FLVVideoTag::writeConfig(WriteStream &ws, uint8_t *sps, uint8_t spsSize, uint8_t *pps, uint8_t ppsSize) { 15 | ws.writeMultiBit(4, frameType); 16 | ws.writeMultiBit(4, codecID); 17 | ws.writeMultiBit(8, AVCPacketType); 18 | ws.writeMultiBit(24, compositionTime); 19 | 20 | /*-----AVC config------*/ 21 | ws.writeMultiBit(8, configurationVersion); 22 | ws.writeMultiBit(8, AVCProfileIndication); 23 | 24 | ws.writeMultiBit(8, profile_compatibility); 25 | 26 | ws.writeMultiBit(8, AVCLevelIndication); 27 | ws.writeMultiBit(6, 0); 28 | ws.writeMultiBit(2, lengthSizeMinusOne); 29 | 30 | ws.writeMultiBit(3, 0); 31 | /*--- write sps ---*/ 32 | ws.writeMultiBit(5, numOfSequenceParameterSets); 33 | ws.writeMultiBit(16, spsSize); 34 | memcpy(ws.currentPtr, sps, spsSize); 35 | ws.setBytePtr(spsSize); 36 | /*--- write pps ---*/ 37 | ws.writeMultiBit(8, numOfPictureParameterSets); 38 | ws.writeMultiBit(16, ppsSize); 39 | memcpy(ws.currentPtr, pps, ppsSize); 40 | ws.setBytePtr(ppsSize); 41 | return 0; 42 | } 43 | 44 | void FLVVideoTag::setConfig(uint8_t type, FRAME_TYPE packetType, uint32_t timestamp) { 45 | frameType = type; 46 | AVCPacketType = packetType; 47 | compositionTime = timestamp; 48 | } 49 | 50 | void FLVVideoTag::setConfigurationRecord(uint8_t profile, uint8_t level, uint8_t compatibility) { 51 | AVCProfileIndication = profile; 52 | AVCLevelIndication = level; 53 | profile_compatibility = compatibility; 54 | } 55 | 56 | 57 | -------------------------------------------------------------------------------- /src/flashVideo/FLVVideoTag.h: -------------------------------------------------------------------------------- 1 |  2 | 3 | #ifndef MEDIASERVER_FLVVIDEOTAG_H 4 | #define MEDIASERVER_FLVVIDEOTAG_H 5 | 6 | #include 7 | #include 8 | #include "bitStream/writeStream.h" 9 | 10 | enum FRAME_TYPE { 11 | AVC_sequence_header = 0, 12 | AVC_NALU = 1, 13 | AVC_end_of_sequence = 2 14 | }; 15 | 16 | /*enum CODEC_ID { 17 | AVC_standard = 7 18 | };*/ 19 | 20 | class FLVVideoTag { 21 | private: 22 | uint8_t frameType{0}; 23 | /*编码标准*/ 24 | uint8_t codecID{7}; 25 | FRAME_TYPE AVCPacketType{AVC_end_of_sequence}; 26 | uint32_t compositionTime{0}; 27 | private: 28 | uint8_t configurationVersion{1}; 29 | uint8_t AVCProfileIndication{0}; 30 | uint8_t profile_compatibility{0}; 31 | uint8_t AVCLevelIndication{0}; 32 | /*这个字段表示用几字节存储nalu的长度,这里设置为3的话,表示使用4字节存储 3+1*/ 33 | uint8_t lengthSizeMinusOne{3}; 34 | uint8_t numOfSequenceParameterSets{1}; 35 | uint8_t numOfPictureParameterSets{1}; 36 | public: 37 | void setConfig(uint8_t type, FRAME_TYPE packetType, uint32_t timestamp); 38 | 39 | void setConfigurationRecord(uint8_t profile_idc, uint8_t level_idc, uint8_t compatibility); 40 | 41 | int writeConfig(WriteStream &ws, uint8_t *sps, uint8_t spsSize, uint8_t *pps, uint8_t ppsSize); 42 | 43 | int writeData(WriteStream &ws); 44 | }; 45 | 46 | 47 | #endif //MEDIASERVER_FLVVIDEOTAG_H 48 | -------------------------------------------------------------------------------- /src/log/CMakeLists.txt: -------------------------------------------------------------------------------- 1 |  2 | add_library(log logger.cpp) 3 | 4 | if (UNIX) 5 | target_compile_definitions(log PRIVATE LOG_USE_COLOR) 6 | endif () -------------------------------------------------------------------------------- /src/log/logger.cpp: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | #include "logger.h" 5 | #include 6 | #include 7 | 8 | Logger *Logger::instance = nullptr; 9 | const char *Logger::level_strings[6] = {"TRACE", "DEBUG", "INFO", "WARN", "ERROR", "FATAL"}; 10 | #ifdef LOG_USE_COLOR 11 | const char *Logger::level_colors[6] = {"\x1b[94m", "\x1b[36m", "\x1b[32m", "\x1b[33m", "\x1b[31m", "\x1b[35m"}; 12 | #endif 13 | 14 | Logger *Logger::getInstance() { 15 | if (instance == nullptr) { 16 | instance = new Logger(); 17 | } 18 | return instance; 19 | } 20 | 21 | void Logger::log(Level level, const char *file, int line, const char *format, ...) { 22 | mux.lock(); 23 | /*如果当前日志级别小于level*/ 24 | if (level < levels) { 25 | mux.unlock(); 26 | return; 27 | } 28 | 29 | //获取当前时间戳 30 | time_t timeTicks = time(nullptr); 31 | //将当前时间戳转化为时间结构体 32 | tm *time = localtime(&timeTicks); 33 | 34 | // char buf[16]; 35 | 36 | buf[strftime(buf, sizeof(buf), "%H:%M:%S", time)] = '\0'; 37 | 38 | va_start(ap, format);//初始化ap指向参数arg的下一个参数 39 | #ifdef LOG_USE_COLOR 40 | fprintf(stderr, "%s %s%-5s\x1b[0m \x1b[90m%s:%d:\x1b[0m ", 41 | buf, level_colors[level], level_strings[level], file, line); 42 | #else 43 | fprintf(stderr, "%s %-5s %s:%d: ", buf, level_strings[level], file, line); 44 | #endif 45 | vfprintf(stderr, format, ap); 46 | fprintf(stderr, "\n"); 47 | fflush(stderr); 48 | va_end(ap); 49 | mux.unlock(); 50 | } 51 | 52 | void Logger::setLevel(Level level) { 53 | levels = level; 54 | } 55 | -------------------------------------------------------------------------------- /src/log/logger.h: -------------------------------------------------------------------------------- 1 |  2 | #ifndef PROJECTNAME_LOGGER_H 3 | #define PROJECTNAME_LOGGER_H 4 | 5 | #include 6 | #include 7 | 8 | #define log_trace(...) Logger::getInstance()->log(LOG_TRACE, __FILE__, __LINE__, __VA_ARGS__) 9 | #define log_debug(...) Logger::getInstance()->log(LOG_DEBUG, __FILE__, __LINE__, __VA_ARGS__) 10 | #define log_info(...) Logger::getInstance()->log(LOG_INFO, __FILE__, __LINE__, __VA_ARGS__) 11 | #define log_warn(...) Logger::getInstance()->log(LOG_WARN, __FILE__, __LINE__, __VA_ARGS__) 12 | #define log_error(...) Logger::getInstance()->log(LOG_ERROR, __FILE__, __LINE__, __VA_ARGS__) 13 | #define log_fatal(...) Logger::getInstance()->log(LOG_FATAL, __FILE__, __LINE__, __VA_ARGS__) 14 | enum Level { 15 | LOG_TRACE = 0, LOG_DEBUG = 1, LOG_INFO = 2, LOG_WARN = 3, LOG_ERROR = 4, LOG_FATAL = 5 16 | }; 17 | 18 | class Logger { 19 | private: 20 | //单例对象 21 | static Logger *instance; 22 | static const char *level_strings[6]; 23 | 24 | #ifdef LOG_USE_COLOR 25 | static const char *level_colors[6]; 26 | #endif 27 | std::mutex mux; 28 | 29 | //当前日志级别(用于过滤低级别日志内容) 30 | Level levels; 31 | char buf[16]; 32 | va_list ap; //定义一个可变参数列表ap 33 | public: 34 | static Logger *getInstance(); 35 | 36 | public: 37 | 38 | void setLevel(Level level); 39 | 40 | void log(Level level, const char *fileName, int line, const char *format, ...); 41 | }; 42 | 43 | 44 | #endif //PROJECTNAME_LOGGER_H 45 | -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 |  2 | 3 | #include "server/server.h" 4 | 5 | 6 | int main() { 7 | 8 | int ret; 9 | constexpr unsigned short SERVER_RTSP_PORT = 554; 10 | constexpr unsigned short SERVER_HTTP_PORT = 80; 11 | 12 | Server server; 13 | ret = server.init(SERVER_RTSP_PORT, SERVER_HTTP_PORT); 14 | if (ret < 0) { 15 | return ret; 16 | } 17 | 18 | server.start(); 19 | 20 | return 0; 21 | } -------------------------------------------------------------------------------- /src/nalu/CMakeLists.txt: -------------------------------------------------------------------------------- 1 |  2 | 3 | add_library( 4 | nalu NALReader.cpp NALHeader.cpp NALSeqParameterSet.cpp 5 | NALPictureParameterSet.cpp NALSliceHeader.cpp NALDecodedPictureBuffer.cpp 6 | NALPicture.cpp 7 | ) 8 | 9 | target_include_directories(nalu 10 | PRIVATE ${PROJECT_SOURCE_DIR}/src 11 | ) 12 | target_link_libraries(nalu PRIVATE bitStream log) 13 | -------------------------------------------------------------------------------- /src/nalu/NALDecodedPictureBuffer.cpp: -------------------------------------------------------------------------------- 1 |  2 | #include "NALDecodedPictureBuffer.h" 3 | 4 | #include 5 | 6 | #include "NALHeader.h" 7 | #include "NALSliceHeader.h" 8 | 9 | NALDecodedPictureBuffer::NALDecodedPictureBuffer() { 10 | for (NALPicture *&pic: dpb) { 11 | pic = new NALPicture; 12 | } 13 | } 14 | 15 | void NALDecodedPictureBuffer::reset() { 16 | for (NALPicture *&pic: dpb) { 17 | if (pic) pic->reset(); 18 | } 19 | } 20 | 21 | int NALDecodedPictureBuffer::decoding_finish(NALPicture *picture, NALPicture *&unoccupiedPicture) { 22 | int ret; 23 | /*This process is invoked for decoded pictures when nal_ref_idc is not equal to 0.*/ 24 | if (picture->sliceHeader.nalu.nal_ref_idc != 0) { 25 | //标记当前解码完成的帧是什么类型 26 | /*nal_ref_idc不等于0的解码图片称为参考图片,被标记为“用于短期参考”或“用于长期参考”。*/ 27 | ret = decoded_reference_picture_marking_process(picture); 28 | if (ret < 0) { 29 | fprintf(stderr, "图像标记失败\n"); 30 | return ret; 31 | } 32 | } 33 | 34 | 35 | /*找到一个空闲的picture*/ 36 | unoccupiedPicture = getUnoccupiedPicture(picture); 37 | if (unoccupiedPicture == nullptr) { 38 | fprintf(stderr, "没有在dpb找到空闲的picture\n"); 39 | return -1; 40 | } 41 | /*重置*/ 42 | unoccupiedPicture->reset(); 43 | 44 | unoccupiedPicture->previousPicture = picture; 45 | if (picture->reference_marked_type != UNUSED_FOR_REFERENCE) { 46 | unoccupiedPicture->referencePicture = picture; 47 | } else { 48 | unoccupiedPicture->referencePicture = picture->referencePicture; 49 | } 50 | return 0; 51 | } 52 | 53 | int NALDecodedPictureBuffer::decoded_reference_picture_marking_process(NALPicture *picture) { 54 | 55 | const NALSliceHeader &sliceHeader = picture->sliceHeader; 56 | 57 | 58 | if (sliceHeader.nalu.IdrPicFlag) { 59 | /*All reference pictures are marked as "unused for reference"*/ 60 | for (NALPicture *pic: dpb) { 61 | pic->reference_marked_type = UNUSED_FOR_REFERENCE; 62 | } 63 | 64 | if (sliceHeader.long_term_reference_flag) { 65 | picture->reference_marked_type = LONG_TERM_REFERENCE; 66 | picture->MaxLongTermFrameIdx = 0; 67 | picture->LongTermFrameIdx = 0; 68 | } else { 69 | picture->reference_marked_type = SHORT_TERM_REFERENCE; 70 | picture->MaxLongTermFrameIdx = -1; 71 | } 72 | } else { 73 | if (sliceHeader.adaptive_ref_pic_marking_mode_flag) { 74 | adaptive_memory_control_decoded_reference_picture_marking_process(picture); 75 | } else { 76 | //8.2.5.3 Sliding window decoded reference picture marking process 滑动窗口解码参考图像的标识过程 77 | sliding_window_decoded_reference_picture_marking_process(picture); 78 | } 79 | } 80 | 81 | /*当前图片不是IDR图片,且memory_management_control_operation未将其标记为“用于长期参考”时,则将其标记为“用于短期参考”。*/ 82 | if (!sliceHeader.nalu.IdrPicFlag && !picture->memory_management_control_operation_6_flag) { 83 | picture->reference_marked_type = SHORT_TERM_REFERENCE; 84 | //设置为没有长期索引 85 | picture->MaxLongTermFrameIdx = -1; 86 | picture->LongTermFrameIdx = -1; 87 | } 88 | return 0; 89 | } 90 | 91 | int NALDecodedPictureBuffer::sliding_window_decoded_reference_picture_marking_process(const NALPicture *picture) { 92 | 93 | int numShortTerm = 0; 94 | int numLongTerm = 0; 95 | 96 | for (NALPicture *pic: dpb) { 97 | if (pic->reference_marked_type == SHORT_TERM_REFERENCE) { 98 | ++numShortTerm; 99 | } 100 | if (pic->reference_marked_type == LONG_TERM_REFERENCE) { 101 | ++numLongTerm; 102 | } 103 | } 104 | if (numShortTerm + numLongTerm == std::max(picture->sliceHeader.sps.max_num_ref_frames, 1u) && 105 | numShortTerm > 0 106 | ) { 107 | /*有着最小 FrameNumWrap 值的短期参考帧标记为“不用于参考”*/ 108 | 109 | int idx = -1; 110 | int FrameNumWrap = -1; 111 | 112 | for (int i = 0; i < 16; ++i) { 113 | if (dpb[i]->reference_marked_type == SHORT_TERM_REFERENCE) { 114 | 115 | if (idx == -1) { 116 | idx = i; 117 | FrameNumWrap = dpb[i]->FrameNumWrap; 118 | continue; 119 | } 120 | 121 | if (dpb[i]->FrameNumWrap < FrameNumWrap) { 122 | FrameNumWrap = dpb[i]->FrameNumWrap; 123 | idx = i; 124 | } 125 | } 126 | } 127 | if (idx != -1) { 128 | dpb[idx]->reference_marked_type = UNUSED_FOR_REFERENCE; 129 | } 130 | } 131 | 132 | return 0; 133 | } 134 | 135 | int NALDecodedPictureBuffer::adaptive_memory_control_decoded_reference_picture_marking_process(NALPicture *picture) { 136 | const NALSliceHeader &sliceHeader = picture->sliceHeader; 137 | for (size_t i = 0; i < sliceHeader.dec_ref_pic_markings_size; i++) { 138 | 139 | if (sliceHeader.dec_ref_pic_markings[i].memory_management_control_operation == 1) { 140 | /*将短期参考图片标记为“不用于参考”的过程*/ 141 | /*picNumX 用来指定一个标记为“用于短期参考”且未被标记为“不存在”的帧*/ 142 | int picNumX = 143 | sliceHeader.CurrPicNum - (sliceHeader.dec_ref_pic_markings[i].difference_of_pic_nums_minus1 + 1); 144 | for (NALPicture *pic: dpb) { 145 | /*picNumX指定的短期参考系或短期互补参考字段对,其字段都标记为“未使用参考”*/ 146 | if (pic->reference_marked_type == SHORT_TERM_REFERENCE && pic->PicNum == picNumX) { 147 | pic->reference_marked_type = UNUSED_FOR_REFERENCE; 148 | } 149 | } 150 | 151 | } else if (sliceHeader.dec_ref_pic_markings[i].memory_management_control_operation == 2) { 152 | /*将长期参考图片标记为“不用于参考”的过程*/ 153 | for (NALPicture *pic: dpb) { 154 | if (pic->reference_marked_type == LONG_TERM_REFERENCE && 155 | pic->LongTermPicNum == sliceHeader.dec_ref_pic_markings[i].long_term_pic_num) { 156 | pic->reference_marked_type = UNUSED_FOR_REFERENCE; 157 | } 158 | } 159 | } else if (sliceHeader.dec_ref_pic_markings[i].memory_management_control_operation == 3) { 160 | /*分配LongTermFrameIdx到短期参考图片的过程*/ 161 | int picNumX = 162 | sliceHeader.CurrPicNum - (sliceHeader.dec_ref_pic_markings[i].difference_of_pic_nums_minus1 + 1); 163 | 164 | /*当LongTermFrameIdx等于long_term_frame_idx已经被分配给一个长期参考帧,该帧被标记为“未使用的参考”*/ 165 | for (NALPicture *pic: dpb) { 166 | if (pic->reference_marked_type == LONG_TERM_REFERENCE 167 | && pic->LongTermFrameIdx == sliceHeader.dec_ref_pic_markings[i].long_term_frame_idx) { 168 | pic->reference_marked_type = UNUSED_FOR_REFERENCE; 169 | } 170 | } 171 | for (NALPicture *pic: dpb) { 172 | if (pic->reference_marked_type == SHORT_TERM_REFERENCE && pic->PicNum == picNumX) { 173 | pic->reference_marked_type = LONG_TERM_REFERENCE; 174 | picture->LongTermFrameIdx = sliceHeader.dec_ref_pic_markings[i].long_term_frame_idx; 175 | } 176 | } 177 | 178 | } else if (sliceHeader.dec_ref_pic_markings[i].memory_management_control_operation == 4) { 179 | /*基于MaxLongTermFrameIdx的标记过程*/ 180 | 181 | 182 | for (NALPicture *pic: dpb) { 183 | if ((pic->LongTermFrameIdx > sliceHeader.dec_ref_pic_markings[i].max_long_term_frame_idx_plus1 - 1) && 184 | pic->reference_marked_type == LONG_TERM_REFERENCE) { 185 | pic->reference_marked_type = UNUSED_FOR_REFERENCE; 186 | } 187 | } 188 | 189 | if (sliceHeader.dec_ref_pic_markings[i].max_long_term_frame_idx_plus1 == 0) { 190 | picture->MaxLongTermFrameIdx = -1;//非长期帧索引 191 | } else { 192 | picture->MaxLongTermFrameIdx = sliceHeader.dec_ref_pic_markings[i].max_long_term_frame_idx_plus1 - 1; 193 | } 194 | } else if (sliceHeader.dec_ref_pic_markings[i].memory_management_control_operation == 5) { 195 | /*所有参考图像标记为“不用于参考”*/ 196 | for (NALPicture *pic: dpb) { 197 | pic->reference_marked_type = UNUSED_FOR_REFERENCE; 198 | } 199 | 200 | picture->MaxLongTermFrameIdx = -1; 201 | picture->memory_management_control_operation_5_flag = true; 202 | 203 | } else if (sliceHeader.dec_ref_pic_markings[i].memory_management_control_operation == 6) { 204 | /*为当前图片分配长期帧索引的过程*/ 205 | for (NALPicture *pic: dpb) { 206 | if (pic->LongTermFrameIdx == sliceHeader.dec_ref_pic_markings[i].long_term_frame_idx && 207 | pic->reference_marked_type == LONG_TERM_REFERENCE) { 208 | pic->reference_marked_type = UNUSED_FOR_REFERENCE; 209 | } 210 | } 211 | picture->reference_marked_type = LONG_TERM_REFERENCE; 212 | picture->LongTermFrameIdx = sliceHeader.dec_ref_pic_markings[i].long_term_frame_idx; 213 | picture->memory_management_control_operation_6_flag = true; 214 | } 215 | 216 | } 217 | return 0; 218 | } 219 | 220 | int NALDecodedPictureBuffer::decoding_process_for_reference_picture_lists_construction(NALPicture *picture) { 221 | /*图像序号的计算*/ 222 | decoding_process_for_picture_numbers(picture); 223 | 224 | 225 | /*参考帧列表初始化*/ 226 | /*这里不解码,就不用去初始化了*/ 227 | /*Initialisation_process_for_reference_picture_lists*/ 228 | 229 | /*参考帧列表重排序*/ 230 | /*这里不解码,就不用去排序了*/ 231 | /*Modification_process_for_reference_picture_lists*/ 232 | return 0; 233 | } 234 | 235 | int NALDecodedPictureBuffer::decoding_process_for_picture_numbers(NALPicture *picture) { 236 | const NALSliceHeader &sliceHeader = picture->sliceHeader; 237 | /* 238 | * 对于每个短期参考图片,变量FrameNum和FrameNumWrap被分配如下。 239 | * 首先,FrameNum被设置为等于语法元素frame_num, 240 | * 该语法元素已在相应的短期参考图片的片标头中解码。 241 | * 然后,变量FrameNumWrap被派生为: 242 | * */ 243 | picture->FrameNum = sliceHeader.frame_num; 244 | /*其中使用的frame_num的值是当前图片切片头中的frame_num*/ 245 | for (NALPicture *pic: dpb) { 246 | //对每一个短期参考图像 247 | if (pic->reference_marked_type == SHORT_TERM_REFERENCE) { 248 | if (pic->FrameNum > sliceHeader.frame_num) { 249 | pic->FrameNumWrap = pic->FrameNum - pic->sliceHeader.sps.MaxFrameNum; 250 | } else { 251 | pic->FrameNumWrap = pic->FrameNum; 252 | } 253 | pic->PicNum = pic->FrameNumWrap; 254 | } 255 | 256 | if (pic->reference_marked_type == LONG_TERM_REFERENCE) { 257 | pic->LongTermPicNum = pic->LongTermFrameIdx; 258 | } 259 | } 260 | 261 | 262 | return 0; 263 | } 264 | 265 | NALPicture *NALDecodedPictureBuffer::getUnoccupiedPicture(const NALPicture *picture) { 266 | NALPicture *ret = nullptr; 267 | for (NALPicture *pic: dpb) { 268 | if (pic != picture && 269 | !pic->useFlag && 270 | pic->reference_marked_type == UNUSED_FOR_REFERENCE 271 | ) { 272 | 273 | ret = pic; 274 | break; 275 | } 276 | } 277 | return ret; 278 | } 279 | 280 | NALDecodedPictureBuffer::~NALDecodedPictureBuffer() { 281 | for (NALPicture *&pic: dpb) { 282 | delete pic; 283 | pic = nullptr; 284 | } 285 | } 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | -------------------------------------------------------------------------------- /src/nalu/NALDecodedPictureBuffer.h: -------------------------------------------------------------------------------- 1 |  2 | 3 | #ifndef MUX_NALDECODEDPICTUREBUFFER_H 4 | #define MUX_NALDECODEDPICTUREBUFFER_H 5 | 6 | #include 7 | #include 8 | 9 | 10 | #include "NALPicture.h" 11 | 12 | class NALSliceHeader; 13 | 14 | class NALSeqParameterSet; 15 | 16 | 17 | class NALDecodedPictureBuffer { 18 | public: 19 | NALPicture *dpb[16]{nullptr}; 20 | public: 21 | NALDecodedPictureBuffer(); 22 | 23 | void reset(); 24 | 25 | int decoding_finish(NALPicture *picture, NALPicture *&unoccupiedPicture); 26 | 27 | int decoding_process_for_reference_picture_lists_construction(NALPicture *picture); 28 | 29 | ~NALDecodedPictureBuffer(); 30 | 31 | private: 32 | int decoded_reference_picture_marking_process(NALPicture *picture); 33 | 34 | int sliding_window_decoded_reference_picture_marking_process(const NALPicture *picture); 35 | 36 | int adaptive_memory_control_decoded_reference_picture_marking_process(NALPicture *picture); 37 | 38 | 39 | int decoding_process_for_picture_numbers(NALPicture *picture); 40 | 41 | NALPicture *getUnoccupiedPicture(const NALPicture *picture); 42 | }; 43 | 44 | 45 | #endif //MUX_NALDECODEDPICTUREBUFFER_H 46 | -------------------------------------------------------------------------------- /src/nalu/NALHeader.cpp: -------------------------------------------------------------------------------- 1 | #include "NALHeader.h" 2 | 3 | /*header*/ 4 | void NALHeader::nal_unit(uint8_t header) { 5 | forbidden_zero_bit = header >> 7 & 1; 6 | nal_ref_idc = header >> 5 & 3; 7 | nal_unit_type = header & 31; 8 | IdrPicFlag = nal_unit_type == 5; 9 | 10 | /* 11 | 不解析 12 | nalUnitHeaderBytes = 1 13 | if(nal_unit_type = = 14 || nal_unit_type = = 20 || nal_unit_type = = 21) { 14 | if( nal_unit_type ! = 21 ) 15 | 分别对应同一码流内可以包含具有不同帧率、不同分辨率、不同码率的分层编码方式 16 | svc_extension_flag All u(1) 17 | else 18 | 表示3D编码 19 | avc_3d_extension_flag All u(1) 20 | 21 | if( svc_extension_flag ) { 22 | nal_unit_header_svc_extension() *//* specified in Annex G *//* All 23 | nalUnitHeaderBytes += 3 24 | } else if( avc_3d_extension_flag ) { 25 | nal_unit_header_3davc_extension() *//* specified in Annex J *//* 26 | nalUnitHeaderBytes += 2 27 | } else { 28 | nal_unit_header_mvc_extension() *//* specified in Annex H *//* All 29 | nalUnitHeaderBytes += 3 30 | } 31 | }*/ 32 | } 33 | 34 | 35 | void NALHeader::ebsp_to_rbsp(uint8_t *data, uint32_t &size) { 36 | uint32_t NumBytesInRBSP = 0; 37 | for (uint32_t i = 1; i < size; i++) { 38 | if ((i + 2 < size) && data[i] == 0 && data[i + 1] == 0 && data[i + 2] == 3) { 39 | data[NumBytesInRBSP++] = data[i]; 40 | data[NumBytesInRBSP++] = data[i + 1]; 41 | i += 2; 42 | } else { 43 | data[NumBytesInRBSP++] = data[i]; 44 | } 45 | } 46 | size = NumBytesInRBSP; 47 | } 48 | -------------------------------------------------------------------------------- /src/nalu/NALHeader.h: -------------------------------------------------------------------------------- 1 |  2 | #ifndef MUX_NALHEADER_H 3 | #define MUX_NALHEADER_H 4 | 5 | #include 6 | 7 | 8 | class NALHeader { 9 | public: 10 | bool forbidden_zero_bit{false}; 11 | /*用来指示当前NAL单元的优先级。0的优先级最低, 12 | * 如果当前NAL单元内是非参考图像的slice或者slice data partition等不是那么重要的数据,那么这个值为0; 13 | * 如果当前NAL单元内是sps、pps、参考图像的slice或者slice data partition等重要数据,那么这个值不为0*/ 14 | uint8_t nal_ref_idc{0}; 15 | uint8_t nal_unit_type{5}; 16 | bool IdrPicFlag{false}; 17 | public: 18 | void nal_unit(uint8_t header); 19 | 20 | static void ebsp_to_rbsp(uint8_t *data, uint32_t &size); 21 | 22 | }; 23 | 24 | 25 | #endif //MUX_NALHEADER_H 26 | -------------------------------------------------------------------------------- /src/nalu/NALPicture.cpp: -------------------------------------------------------------------------------- 1 |  2 | 3 | #include "NALPicture.h" 4 | 5 | #include 6 | 7 | 8 | /* 9 | * 解码POC需要用到上一个参考帧,和上一个顺序解码的帧,那就肯定要缓存帧,以做解码, 10 | * 所以需要标记参考帧,放进参考帧列表里面,并且也要有参考帧标记过程,把一些不用于参考的给剔除, 11 | * 你也得要有参考标记过程,标记哪个是参考帧,所以之前那个是必须的, 12 | * 所以解码POC需要有参考帧标记流程,因为用到了上一个参考帧 13 | * */ 14 | 15 | int NALPicture::decoding_process_for_picture_order_count() { 16 | int ret = 0; 17 | if (sliceHeader.sps.pic_order_cnt_type == 0) { 18 | ret = decoding_process_for_picture_order_count_type_0(); 19 | if (ret < 0) { 20 | fprintf(stderr, "解码POC失败,pic_order_cnt_type = 0\n"); 21 | return ret; 22 | } 23 | } else if (sliceHeader.sps.pic_order_cnt_type == 1) { 24 | ret = decoding_process_for_picture_order_count_type_1(); 25 | if (ret < 0) { 26 | fprintf(stderr, "解码POC失败,pic_order_cnt_type = 1\n"); 27 | return ret; 28 | } 29 | } else if (sliceHeader.sps.pic_order_cnt_type == 2) { 30 | ret = decoding_process_for_picture_order_count_type_2(); 31 | if (ret < 0) { 32 | fprintf(stderr, "解码POC失败,pic_order_cnt_type = 2\n"); 33 | return ret; 34 | } 35 | } else { 36 | fprintf(stderr, "解码POC失败,pic_order_cnt_type = %d\n", sliceHeader.sps.pic_order_cnt_type); 37 | return -1; 38 | } 39 | pictureOrderCount = std::min(TopFieldOrderCnt, BottomFieldOrderCnt); 40 | //printf("POC = %d\n", pictureOrderCount); 41 | /*计算出POC*/ 42 | return ret; 43 | } 44 | 45 | int NALPicture::decoding_process_for_picture_order_count_type_0() { 46 | //前一个参考图像的 PicOrderCntMsb 47 | uint32_t prevPicOrderCntMsb; 48 | uint32_t prevPicOrderCntLsb; 49 | if (sliceHeader.nalu.IdrPicFlag) { 50 | prevPicOrderCntMsb = 0; 51 | prevPicOrderCntLsb = 0; 52 | } else { 53 | if (referencePicture == nullptr) { 54 | fprintf(stderr, "上一个参考帧为null\n"); 55 | return -1; 56 | } 57 | //如果前面的参考图片在解码顺序中包含一个memory_management_control_operation等于5 58 | if (referencePicture->memory_management_control_operation_5_flag) { 59 | //如果在解码顺序上前一个参考图像不是底场,则prevPicOrderCntMsb设置为0,prevPicOrderCntLsb设置为解码顺序上前一个参考图像的TopFieldOrderCnt值。 60 | prevPicOrderCntMsb = 0; 61 | prevPicOrderCntLsb = referencePicture->TopFieldOrderCnt; 62 | } else { 63 | prevPicOrderCntMsb = referencePicture->PicOrderCntMsb; 64 | prevPicOrderCntLsb = referencePicture->sliceHeader.pic_order_cnt_lsb; 65 | } 66 | } 67 | 68 | if ((sliceHeader.pic_order_cnt_lsb < prevPicOrderCntLsb) 69 | && ((prevPicOrderCntLsb - sliceHeader.pic_order_cnt_lsb) >= (sliceHeader.sps.MaxPicOrderCntLsb / 2)) 70 | ) { 71 | /*当前图像的pic_order_cnt_lsb比上一针小,且未发生乱序*/ 72 | PicOrderCntMsb = prevPicOrderCntMsb + sliceHeader.sps.MaxPicOrderCntLsb; 73 | } else if ((sliceHeader.pic_order_cnt_lsb > prevPicOrderCntLsb) 74 | && ((sliceHeader.pic_order_cnt_lsb - prevPicOrderCntLsb) > (sliceHeader.sps.MaxPicOrderCntLsb / 2))) { 75 | /*当前图像的pic_order_cnt_lsb比上一针大,且发生乱序*/ 76 | PicOrderCntMsb = prevPicOrderCntMsb - sliceHeader.sps.MaxPicOrderCntLsb; 77 | } else { 78 | PicOrderCntMsb = prevPicOrderCntMsb; 79 | } 80 | 81 | // 当前图像为非底场时 82 | TopFieldOrderCnt = PicOrderCntMsb + sliceHeader.pic_order_cnt_lsb; 83 | // 当前图像为非顶场时 84 | BottomFieldOrderCnt = TopFieldOrderCnt + sliceHeader.delta_pic_order_cnt_bottom; 85 | 86 | return 0; 87 | } 88 | 89 | int NALPicture::decoding_process_for_picture_order_count_type_1() { 90 | 91 | if (previousPicture == nullptr) { 92 | fprintf(stderr, "上一顺序解码的图像不存在\n"); 93 | return -1; 94 | } 95 | const uint16_t prevFrameNum = previousPicture->sliceHeader.frame_num; 96 | int prevFrameNumOffset = 0; 97 | 98 | if (!sliceHeader.nalu.IdrPicFlag) { 99 | if (previousPicture->memory_management_control_operation_5_flag) { 100 | //If the previous picture in decoding order included a memory_management_control_operation equal to 5 101 | prevFrameNumOffset = 0; 102 | } else { 103 | prevFrameNumOffset = previousPicture->FrameNumOffset; 104 | } 105 | } 106 | 107 | 108 | if (sliceHeader.nalu.IdrPicFlag) { 109 | FrameNumOffset = 0; 110 | } else if (prevFrameNum > sliceHeader.frame_num) { 111 | FrameNumOffset = prevFrameNumOffset + sliceHeader.sps.MaxFrameNum; 112 | } else { 113 | FrameNumOffset = prevFrameNumOffset; 114 | } 115 | 116 | int absFrameNum = 0; 117 | if (sliceHeader.sps.num_ref_frames_in_pic_order_cnt_cycle != 0) { 118 | absFrameNum = FrameNumOffset + sliceHeader.frame_num; 119 | } 120 | 121 | if (sliceHeader.nalu.nal_ref_idc == 0 && absFrameNum > 0) { 122 | absFrameNum = absFrameNum - 1; 123 | } 124 | 125 | int picOrderCntCycleCnt; 126 | int frameNumInPicOrderCntCycle; 127 | if (absFrameNum > 0) { 128 | picOrderCntCycleCnt = (absFrameNum - 1) / sliceHeader.sps.num_ref_frames_in_pic_order_cnt_cycle; 129 | frameNumInPicOrderCntCycle = (absFrameNum - 1) % sliceHeader.sps.num_ref_frames_in_pic_order_cnt_cycle; 130 | } 131 | 132 | int expectedPicOrderCnt = 0; 133 | if (absFrameNum > 0) { 134 | expectedPicOrderCnt = picOrderCntCycleCnt * sliceHeader.sps.ExpectedDeltaPerPicOrderCntCycle; 135 | for (int i = 0; i <= frameNumInPicOrderCntCycle; i++) 136 | expectedPicOrderCnt = expectedPicOrderCnt + sliceHeader.sps.offset_for_ref_frame[i]; 137 | } 138 | 139 | if (sliceHeader.nalu.nal_ref_idc == 0) { 140 | expectedPicOrderCnt = expectedPicOrderCnt + sliceHeader.sps.offset_for_non_ref_pic; 141 | } 142 | TopFieldOrderCnt = expectedPicOrderCnt + sliceHeader.delta_pic_order_cnt[0]; 143 | BottomFieldOrderCnt = 144 | TopFieldOrderCnt + sliceHeader.sps.offset_for_top_to_bottom_field + sliceHeader.delta_pic_order_cnt[1]; 145 | return 0; 146 | } 147 | 148 | int NALPicture::decoding_process_for_picture_order_count_type_2() { 149 | 150 | if (previousPicture == nullptr) { 151 | fprintf(stderr, "上一顺序解码的图像不存在\n"); 152 | return -1; 153 | } 154 | 155 | const uint16_t prevFrameNum = previousPicture->sliceHeader.frame_num; 156 | 157 | int prevFrameNumOffset; 158 | 159 | if (!sliceHeader.nalu.IdrPicFlag) { 160 | if (previousPicture->memory_management_control_operation_5_flag) { 161 | prevFrameNumOffset = 0; 162 | } else { 163 | prevFrameNumOffset = previousPicture->FrameNumOffset; 164 | } 165 | } 166 | 167 | if (sliceHeader.nalu.IdrPicFlag) 168 | FrameNumOffset = 0; 169 | else if (prevFrameNum > sliceHeader.frame_num) 170 | FrameNumOffset = prevFrameNumOffset + sliceHeader.sps.MaxFrameNum; 171 | else 172 | FrameNumOffset = prevFrameNumOffset; 173 | 174 | 175 | int tempPicOrderCnt; 176 | if (sliceHeader.nalu.IdrPicFlag) { 177 | tempPicOrderCnt = 0; 178 | } else if (sliceHeader.nalu.nal_ref_idc == 0) { 179 | //当前图像为非参考图像 180 | tempPicOrderCnt = 2 * (FrameNumOffset + sliceHeader.frame_num) - 1; 181 | } else { 182 | tempPicOrderCnt = 2 * (FrameNumOffset + sliceHeader.frame_num); 183 | } 184 | 185 | 186 | TopFieldOrderCnt = tempPicOrderCnt; 187 | BottomFieldOrderCnt = tempPicOrderCnt; 188 | 189 | 190 | return 0; 191 | } 192 | 193 | void NALPicture::reset() { 194 | decodeFrameNumber = 0; 195 | pictureFinishFlag = false; 196 | finishFlag = false; 197 | useFlag = false; 198 | size = 0; 199 | dts = 0; 200 | pts = 0; 201 | pcr = 0; 202 | duration = 0; 203 | pictureOrderCount = 0; 204 | previousPicture = nullptr; 205 | referencePicture = nullptr; 206 | reference_marked_type = UNUSED_FOR_REFERENCE; 207 | MaxLongTermFrameIdx = -1; 208 | LongTermFrameIdx = -1; 209 | FrameNum = 0; 210 | FrameNumWrap = -1; 211 | PicNum = -1; 212 | LongTermPicNum = -1; 213 | 214 | memory_management_control_operation_5_flag = false; 215 | memory_management_control_operation_6_flag = false; 216 | 217 | 218 | FrameNumOffset = 0; 219 | PicOrderCntMsb = 0; 220 | /*while (!data.empty()) { 221 | uint8_t *buf = data.back().data; 222 | delete[] buf; 223 | data.pop_back(); 224 | }*/ 225 | data.clear(); 226 | } 227 | 228 | NALPicture::~NALPicture() { 229 | data.clear(); 230 | /*while (!data.empty()) { 231 | uint8_t *buf = data.back().data; 232 | delete[] buf; 233 | data.pop_back(); 234 | }*/ 235 | } 236 | -------------------------------------------------------------------------------- /src/nalu/NALPicture.h: -------------------------------------------------------------------------------- 1 | #ifndef MUX_NALPICTURE_H 2 | #define MUX_NALPICTURE_H 3 | 4 | #include 5 | #include 6 | 7 | #include "NALSliceHeader.h" 8 | 9 | struct Frame { 10 | uint32_t nalUintSize; 11 | uint8_t *data; 12 | int type; 13 | }; 14 | enum PICTURE_MARKING { 15 | SHORT_TERM_REFERENCE, //短期参考帧 16 | LONG_TERM_REFERENCE, //长期参考帧 17 | UNUSED_FOR_REFERENCE, //不用于参考 18 | }; 19 | 20 | class NALPicture { 21 | 22 | private: 23 | /*POC相关*/ 24 | uint32_t PicOrderCntMsb{0}; 25 | uint32_t TopFieldOrderCnt{0}; 26 | uint32_t BottomFieldOrderCnt{0}; 27 | int FrameNumOffset{0}; 28 | 29 | public: 30 | bool finishFlag{false}; 31 | bool pictureFinishFlag{false}; 32 | /*记录这帧大小*/ 33 | uint32_t size{0}; 34 | 35 | uint64_t dts{0}; 36 | uint64_t pts{0}; 37 | uint64_t pcr{0}; 38 | uint32_t decodeFrameNumber{0}; 39 | /*帧间隔,持续时间,毫秒*/ 40 | int interval{0}; 41 | double duration{0}; 42 | 43 | uint32_t pictureOrderCount{0}; 44 | /*前一图像(按照解码顺序)*/ 45 | NALPicture *previousPicture{nullptr}; 46 | /*前一个参考图像(按照解码顺序)*/ 47 | NALPicture *referencePicture{nullptr}; 48 | 49 | /*表示当前这帧是否正在使用*/ 50 | bool useFlag{false}; 51 | 52 | PICTURE_MARKING reference_marked_type{UNUSED_FOR_REFERENCE}; 53 | int MaxLongTermFrameIdx{-1}; //长期参考帧的最大数目 54 | int LongTermFrameIdx{-1}; //长期参考帧索引 55 | 56 | 57 | /*等于frame_num*/ 58 | uint16_t FrameNum{0}; 59 | int FrameNumWrap{-1}; 60 | /*标记一个短期参考图像*/ 61 | int PicNum{-1}; 62 | /*标记一个长期参考图像*/ 63 | int LongTermPicNum{-1}; 64 | 65 | 66 | NALSliceHeader sliceHeader; 67 | std::vector data; 68 | 69 | 70 | bool memory_management_control_operation_5_flag{false}; 71 | bool memory_management_control_operation_6_flag{false}; 72 | public: 73 | void reset(); 74 | 75 | int decoding_process_for_picture_order_count(); 76 | 77 | int decoding_process_for_picture_order_count_type_0(); 78 | 79 | int decoding_process_for_picture_order_count_type_1(); 80 | 81 | int decoding_process_for_picture_order_count_type_2(); 82 | 83 | ~NALPicture(); 84 | }; 85 | 86 | 87 | #endif //MUX_NALPICTURE_H 88 | -------------------------------------------------------------------------------- /src/nalu/NALPictureParameterSet.cpp: -------------------------------------------------------------------------------- 1 |  2 | #include "NALPictureParameterSet.h" 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | 9 | 10 | #include "NALSeqParameterSet.h" 11 | 12 | int NALPictureParameterSet::pic_parameter_set_rbsp(ReadStream &rs, const NALSeqParameterSet (&spsList)[32]) { 13 | int ret; 14 | 15 | pic_parameter_set_id = rs.readUE(); 16 | //sps id通过这个id可以找到所引用的sps 17 | seq_parameter_set_id = rs.readUE(); 18 | 19 | 20 | const NALSeqParameterSet &sps = spsList[seq_parameter_set_id]; 21 | 22 | /*熵编码使用的方法,不同的语法元素在不同模式选择的方式不同的 23 | 等于0,那么采用语法表中左边的描述符所指定的方法 24 | 等于1,就采用语法表中右边的描述符所指定的方法*/ 25 | entropy_coding_mode_flag = rs.readBit(); 26 | /*标识位,用于表示slice header中的两个语法元素delta_pic_order_cnt_bottom和delta_pic_order_cn是否存在的标识。 27 | 这两个语法元素表示了某一帧的底场的POC的计算方法*/ 28 | bottom_field_pic_order_in_frame_present_flag = rs.readBit(); 29 | 30 | /* 31 | slice groups数量减去1,为0的是时候这个slice属于所有slice group,大于0被分割成多个slice group 32 | num_slice_groups_minus1等于0,图像只有一个片组时,则不启用FMO;其他情况下,一个图像中有多个片组,这时都使用FMO。 33 | slice group表示一帧中红快的组成方式 34 | 片组的数量,为0时表示没有使用片组模式。H264规定每张影像最多分成8个片组。 35 | 注意,这里并不是说slice片的数量,而是片组。一帧中可能会有多个片,但是他们属于同一个片组 36 | 加1表示一个图像中的条带组数。当 num_slice_groups_minus1 等于 0 时,图像中 所有的条带属于同一个条带组。*/ 37 | num_slice_groups_minus1 = rs.readUE(); 38 | 39 | 40 | if (num_slice_groups_minus1 > 0) { 41 | //MFO前面的slice内部宏块总是连续的。FMO技术通过映射表(macroblock to slice group map)决定具体每个宏块属于哪个slice groups,突破了宏块连续的限制。 42 | 43 | /*slice groups又可以按扫描顺序分成多个slice,当不使用FMO时,就相当于整个图像是一个slice groups的情形。由于各slice groups的解码也是独立的。 44 | 当码流传输错误的时候,解码端可以根据邻近正确解码的其他slice groups宏块,进行错误隐藏。*/ 45 | 46 | /*slice_group_map_type 等于 0 表示隔行扫描的条带组。 47 | slice_group_map_type 等于 1 表示一种分散的条带组映射。 48 | slice_group_map_type 等于 2 表示一个或多个前景条带组和一个残余条带组。 49 | slice_group_map_type 的值等于 3、4 和 5 表示变换的条带组。当 num_slice_groups_minus1 不等于 1 时, slice_group_map_type 不应等于3、4 或 5。 50 | slice_group_map_type 等于 6 表示对每个条带组映射单元清楚地分配一个条带组。*/ 51 | 52 | //slice_group_map_type可以指定使用哪个规则为当前图像划分片组 53 | //如果这六种默认的规则都不能满足要求,还可以定制自己的映射规则。 54 | slice_group_map_type = rs.readUE(); 55 | 56 | int iGroup; 57 | if (slice_group_map_type == 0) { 58 | for (iGroup = 0; iGroup <= num_slice_groups_minus1; iGroup++) { 59 | //用来指定条带组映射单元的光栅扫描顺序中分配给第 i 个条带组的连续条带组映射单 元的数目。 60 | //run_length_minus1[ i ] 的取值范围应该在0 到 PicSizeInMapUnits – 1 内(包括边界值)。 61 | run_length_minus1[iGroup] = rs.readUE(); 62 | } 63 | } else if (slice_group_map_type == 2) { 64 | for (iGroup = 0; iGroup < num_slice_groups_minus1; iGroup++) { 65 | top_left[iGroup] = rs.readUE(); 66 | bottom_right[iGroup] = rs.readUE(); 67 | } 68 | } else if (slice_group_map_type == 3 || slice_group_map_type == 4 || slice_group_map_type == 5) { 69 | slice_group_change_direction_flag = rs.readBit(); 70 | /*取值范围是0 ~ PicSizeInMapUnits−1*/ 71 | slice_group_change_rate_minus1 = rs.readUE(); 72 | } else if (slice_group_map_type == 6) { 73 | 74 | /*取值范围是0 ~ PicSizeInMapUnits−1*/ 75 | pic_size_in_map_units_minus1 = rs.readUE(); 76 | slice_group_id = new uint8_t[pic_size_in_map_units_minus1 + 1]; 77 | 78 | /*slice_group_id[i] 表示光栅扫描顺序中的第 i 个条带组映射单元的一个条带组。 79 | slice_group_id[i] 语法元素的大小是 Ceil(Log2(num_slice_groups_minus1 + 1)) 比特。 80 | slice_group_id[i] 的 值 应 该 在 0 到 num_slice_groups_minus1 范围内(包括边界值)。*/ 81 | 82 | int v = std::ceil(std::log2(num_slice_groups_minus1 + 1)); 83 | //Ceil( Log2( num_slice_groups_minus1 + 1 ) ); 84 | for (size_t i = 0; i <= pic_size_in_map_units_minus1; i++) { 85 | /*取值范围为0 ~ num_slice_groups_minus1*/ 86 | slice_group_id[i] = rs.readMultiBit(v); 87 | } 88 | } 89 | 90 | } 91 | 92 | //表示当Slice Header中的num_ref_idx_active_override_flag标识位为0时, 93 | //P/SP/B slice的语法元素num_ref_idx_l0_active_minus1和num_ref_idx_l1_active_minus1的默认值。 94 | num_ref_idx_l0_default_active_minus1 = rs.readUE(); 95 | num_ref_idx_l1_default_active_minus1 = rs.readUE(); 96 | 97 | //是否开启加权预测 98 | weighted_pred_flag = rs.readBit(); 99 | 100 | 101 | //weighted_bipred_idc 等于 0 表示 B 条带应该采用默认的加权预测。 102 | //weighted_bipred_idc 等于 1 表示 B 条带应该采用具体指明的加权预测。 103 | //weighted_bipred_idc 等于 2 表示 B 条带应该采用隐含的加权预测。 104 | //weighted_bipred_idc 的值应该在0 到 2 之间(包括0 和2) 105 | weighted_bipred_idc = rs.readMultiBit(2); 106 | 107 | /* 表示每个条带的SliceQPY 初始值减 26。 108 | 当解码非0 值的slice_qp_delta 时,该初始值在 条带层被修正, 109 | 并且在宏块层解码非 0 值的 mb_qp_delta 时进一步被修正。pic_init_qp_minus26 的值应该在- (26 + QpBdOffsetY ) 到 +25 之间(包括边界值)。*/ 110 | pic_init_qp_minus26 = static_cast (rs.readSE()); 111 | 112 | //表示在 SP 或 SI 条带中的所有宏块的 SliceQSY初始值减26 113 | pic_init_qs_minus26 = static_cast (rs.readSE()); 114 | 115 | //计算色度量化参数的偏移量值范围:-22-- - 22 116 | chroma_qp_index_offset = static_cast (rs.readSE()); 117 | 118 | //slice header中是否存在去块滤波器控制相关信息 =1存在响应去块滤波器 =0没有相应信息 119 | deblocking_filter_control_present_flag = rs.readBit(); 120 | 121 | /* 122 | 在 P 和 B 片中,帧内编码的宏块的邻近宏块可能是采用的帧间编码。 123 | 当本句法元素等于 1 时,表示帧内编码的宏块不能用帧间编码的宏块的像素作为自己的预测, 124 | 即帧内编码的宏块只能用邻近帧内编码的宏块的像素作为自己的预测;而本句法元素等于 0 时,表示不存在这种限制。*/ 125 | constrained_intra_pred_flag = rs.readBit(); 126 | 127 | //等于0表示redundant_pic_cnt语法元素不会在条带头、图像参数集中指明(直接或与相应的数据分割块A关联)的数据分割块 B 和数据分割块 C 中出现。 128 | //redundant_pic_cnt_present_flag 等 于 1 表示 redundant_pic_cnt语法元素将出现在条带头、 129 | //图像参数集中指明(直接或与相应的数据分割块 A 关联的数据分割块 B 和数据分割块 C 中。 130 | redundant_pic_cnt_present_flag = rs.readBit(); 131 | 132 | ret = rs.more_rbsp_data(); 133 | if (ret < 0) { 134 | fprintf(stderr, "pps解析失败\n"); 135 | return ret; 136 | } 137 | if (ret == 1) { 138 | //等于1表示8x8变换解码过程可能正在使用(参见 8.5 节)。transform_8x8_mode_flag 等于 0 表示未使用 8x8 变换解码过程。 139 | //当 transform_8x8_mode_flag 不存在时,默认其值 为0。 140 | bool transform_8x8_mode_flag = rs.readBit(); 141 | 142 | 143 | //等于 1 表示存在用来修改在序列参数集中指定的缩放比例列表的参数。 144 | //pic_scaling_matrix_present_flag 等于 0 表示用于该图像中的缩放比例列表应等于那些由序列参数集规定的。 145 | //当 pic_scaling_matrix_present_flag 不存在时,默认其值为0。 146 | //基准档次不应该出现这个元素 147 | bool pic_scaling_matrix_present_flag = rs.readBit(); 148 | if (pic_scaling_matrix_present_flag) { 149 | fprintf(stderr, "缩放比例列表的参数解析失败\n"); 150 | return -1; 151 | } 152 | //表示为在 QPC 值的表格中寻找 Cr 色度分量而应加到参数 QPY 和 QSY 上的偏移。second_chroma_qp_index_offset 的值应在-12 到 +12 范围内(包括边界值) 153 | second_chroma_qp_index_offset = static_cast (rs.readSE()); 154 | } 155 | 156 | return 0; 157 | } 158 | 159 | NALPictureParameterSet &NALPictureParameterSet::operator=(const NALPictureParameterSet &pps) { 160 | if (this == &pps) { 161 | return *this; 162 | } 163 | 164 | memcpy(this, &pps, sizeof(NALPictureParameterSet)); 165 | 166 | if (pps.num_slice_groups_minus1 > 0 && pps.slice_group_map_type == 6) { 167 | slice_group_id = new uint8_t[pps.pic_size_in_map_units_minus1 + 1]; 168 | memcpy(slice_group_id, pps.slice_group_id, sizeof(uint8_t) * pps.pic_size_in_map_units_minus1 + 1); 169 | } 170 | 171 | return *this; 172 | } 173 | 174 | NALPictureParameterSet::~NALPictureParameterSet() { 175 | if (slice_group_id) { 176 | delete[]slice_group_id; 177 | slice_group_id = nullptr; 178 | } 179 | } 180 | -------------------------------------------------------------------------------- /src/nalu/NALPictureParameterSet.h: -------------------------------------------------------------------------------- 1 | #ifndef MUX_NALPICTUREPARAMETERSET_H 2 | #define MUX_NALPICTUREPARAMETERSET_H 3 | 4 | 5 | #include 6 | #include "bitStream/readStream.h" 7 | 8 | 9 | class NALSeqParameterSet; 10 | 11 | class NALPictureParameterSet { 12 | public: 13 | uint8_t pic_parameter_set_id{0}; 14 | uint8_t seq_parameter_set_id{0}; 15 | uint8_t entropy_coding_mode_flag{0}; 16 | bool bottom_field_pic_order_in_frame_present_flag{false}; 17 | 18 | /*片组相关的参数*/ 19 | uint8_t num_slice_groups_minus1{0}; 20 | uint8_t slice_group_map_type{0}; 21 | uint32_t run_length_minus1[8]{0}; 22 | uint32_t top_left[8]{0}; 23 | uint32_t bottom_right[8]{0}; 24 | uint8_t slice_group_change_direction_flag{0}; 25 | uint32_t slice_group_change_rate_minus1{0}; 26 | uint32_t pic_size_in_map_units_minus1{0}; 27 | uint8_t *slice_group_id{nullptr}; 28 | 29 | 30 | /*值应该在0到31的范围内(含31)*/ 31 | uint8_t num_ref_idx_l0_default_active_minus1{0}; 32 | uint8_t num_ref_idx_l1_default_active_minus1{0}; 33 | 34 | uint8_t weighted_pred_flag{0}; 35 | uint8_t weighted_bipred_idc{0}; 36 | /*值范围为−(26 + QpBdOffsetY) ~ +25(含)*/ 37 | int8_t pic_init_qp_minus26{0}; 38 | /*值范围为−26 ~ +25(含)*/ 39 | int8_t pic_init_qs_minus26{0}; 40 | int8_t chroma_qp_index_offset{0}; 41 | uint8_t deblocking_filter_control_present_flag{0}; 42 | uint8_t constrained_intra_pred_flag{0}; 43 | uint8_t redundant_pic_cnt_present_flag{0}; 44 | int8_t second_chroma_qp_index_offset{0}; 45 | 46 | public: 47 | int pic_parameter_set_rbsp(ReadStream &rs, const NALSeqParameterSet (&spsList)[32]); 48 | 49 | NALPictureParameterSet &operator=(const NALPictureParameterSet &pps); 50 | 51 | ~NALPictureParameterSet(); 52 | }; 53 | 54 | 55 | #endif //MUX_NALPICTUREPARAMETERSET_H 56 | -------------------------------------------------------------------------------- /src/nalu/NALReader.cpp: -------------------------------------------------------------------------------- 1 | #include "NALReader.h" 2 | #include "bitStream/readStream.h" 3 | #include "log/logger.h" 4 | 5 | 6 | int NALReader::init() { 7 | 8 | bufferStart = new uint8_t[MAX_BUFFER_SIZE]; 9 | blockBufferSize = 0; 10 | return 0; 11 | } 12 | 13 | 14 | int NALReader::findNALU(uint8_t *&pos1, uint8_t *&pos2, int &startCodeLen1, int &startCodeLen2) const { 15 | 16 | if (!bufferStart) { 17 | log_error("请初始化"); 18 | return -1; 19 | } 20 | 21 | if (blockBufferSize == 0) { 22 | return 1; 23 | } 24 | startCodeLen1 = 0; 25 | startCodeLen2 = 0; 26 | uint32_t pos = 0; 27 | while (pos + 3 < blockBufferSize) { 28 | if (bufferStart[pos] == 0 && bufferStart[pos + 1] == 0 && bufferStart[pos + 2] == 1) { 29 | startCodeLen1 = 3; 30 | break; 31 | } else if (bufferStart[pos] == 0 && bufferStart[pos + 1] == 0 && bufferStart[pos + 2] == 0 && 32 | bufferStart[pos + 3] == 1) { 33 | startCodeLen1 = 4; 34 | break; 35 | } 36 | pos++; 37 | } 38 | pos1 = &bufferStart[pos]; 39 | if (startCodeLen1 == 0) { 40 | fprintf(stderr, "没找到start code\n"); 41 | return -1; 42 | } 43 | 44 | pos = pos + startCodeLen1; 45 | while (pos + 3 < blockBufferSize) { 46 | if (bufferStart[pos] == 0 && bufferStart[pos + 1] == 0 && bufferStart[pos + 2] == 1) { 47 | startCodeLen2 = 3; 48 | break; 49 | } else if (bufferStart[pos] == 0 && bufferStart[pos + 1] == 0 && bufferStart[pos + 2] == 0 && 50 | bufferStart[pos + 3] == 1) { 51 | startCodeLen2 = 4; 52 | break; 53 | } 54 | pos++; 55 | } 56 | pos2 = &bufferStart[pos]; 57 | 58 | return startCodeLen2 == 0 ? 1 : 2; 59 | } 60 | 61 | 62 | int NALReader::getParameter() { 63 | int ret; 64 | 65 | uint8_t *pos1 = nullptr; 66 | uint8_t *pos2 = nullptr; 67 | int startCodeLen1 = 0; 68 | int startCodeLen2 = 0; 69 | 70 | 71 | ret = findNALU(pos1, pos2, startCodeLen1, startCodeLen2); 72 | if (ret == 2) { 73 | /*表示找到一个nalu*/ 74 | uint8_t *data = pos1 + startCodeLen1; 75 | uint32_t size = pos2 - data; 76 | 77 | nalUnitHeader.nal_unit(data[0]); 78 | if (nalUnitHeader.nal_unit_type == H264_NAL_SPS) { 79 | memcpy(spsData, data, size); 80 | spsSize = size; 81 | 82 | NALHeader::ebsp_to_rbsp(data, size); 83 | ReadStream rs(data, size); 84 | sps.seq_parameter_set_data(rs); 85 | spsList[sps.seq_parameter_set_id] = sps; 86 | ret = 3; 87 | } else if (nalUnitHeader.nal_unit_type == H264_NAL_PPS) { 88 | memcpy(ppsData, data, size); 89 | ppsSize = size; 90 | 91 | NALHeader::ebsp_to_rbsp(data, size); 92 | ReadStream rs(data, size); 93 | pps.pic_parameter_set_rbsp(rs, spsList); 94 | ret = 4; 95 | } 96 | resetFlag = true; 97 | bufferPosition = pos2; 98 | 99 | } 100 | 101 | return ret; 102 | } 103 | 104 | void NALReader::putData(uint8_t *data, uint32_t size) { 105 | memcpy(bufferStart + blockBufferSize, data, size); 106 | blockBufferSize += size; 107 | bufferEnd = bufferStart + blockBufferSize; 108 | } 109 | 110 | void NALReader::resetBuffer() { 111 | /*有可能找到了,但是bufferEnd - bufferPosition刚好=0*/ 112 | if (resetFlag) { 113 | uint32_t remainingByte = bufferEnd - bufferPosition; 114 | blockBufferSize = remainingByte; 115 | 116 | memcpy(bufferStart, bufferPosition, remainingByte); 117 | resetFlag = false; 118 | } 119 | 120 | } 121 | 122 | 123 | int NALReader::getVideoFrame3(NALPicture *&picture) { 124 | int ret; 125 | 126 | uint8_t *pos1 = nullptr; 127 | uint8_t *pos2 = nullptr; 128 | int startCodeLen1 = 0; 129 | int startCodeLen2 = 0; 130 | 131 | /*找到了nalu,判断是否是完整的一帧*/ 132 | // if (picture->pictureFinishFlag) { 133 | // picture = unoccupiedPicture; 134 | // } 135 | ret = findNALU(pos1, pos2, startCodeLen1, startCodeLen2); 136 | if (ret == 2) { 137 | 138 | 139 | uint8_t *data = pos1 + startCodeLen1; 140 | uint32_t size = pos2 - data; 141 | 142 | ret = getVideoFrame2(picture, data, size, 0); 143 | if (ret < 0) { 144 | return ret; 145 | } 146 | 147 | /*找到一个nalu,才可以去重置这个内存*/ 148 | resetFlag = true; 149 | bufferPosition = pos2; 150 | if (picture->finishFlag == false) { 151 | resetBuffer(); 152 | } 153 | } 154 | return ret; 155 | } 156 | 157 | int NALReader::getVideoFrame2(NALPicture *&picture, uint8_t *data, uint32_t size, uint8_t startCodeLength) { 158 | 159 | /*能够进入到这个函数,肯定是一个完整的nalu了 */ 160 | if (picture->pictureFinishFlag) { 161 | /*进入到这里才是完整的一帧*/ 162 | picture = unoccupiedPicture; 163 | } 164 | 165 | int ret = disposePicture(picture, data, size, startCodeLength); 166 | if (ret < 0) { 167 | log_error("disposePicture 错误"); 168 | return ret; 169 | } 170 | return 0; 171 | } 172 | 173 | int NALReader::disposePicture(NALPicture *picture, uint8_t *data, uint32_t size, uint8_t startCodeLength) { 174 | int ret; 175 | 176 | nalUnitHeader.nal_unit(data[startCodeLength]); 177 | if (nalUnitHeader.nal_unit_type == H264_NAL_SPS) { 178 | /*有起始码的*/ 179 | memcpy(spsData, data, size); 180 | spsSize = size; 181 | 182 | size -= startCodeLength; 183 | /*去除防竞争字节*/ 184 | uint8_t *ebsp = data + startCodeLength; 185 | NALHeader::ebsp_to_rbsp(ebsp, size); 186 | ReadStream rs(ebsp, size); 187 | 188 | 189 | sps.seq_parameter_set_data(rs); 190 | spsList[sps.seq_parameter_set_id] = sps; 191 | picture->pictureFinishFlag = false; 192 | picture->finishFlag = false; 193 | } else if (nalUnitHeader.nal_unit_type == H264_NAL_PPS) { 194 | 195 | /*有起始码的*/ 196 | memcpy(ppsData, data, size); 197 | ppsSize = size; 198 | 199 | size -= startCodeLength; 200 | uint8_t *ebsp = data + startCodeLength; 201 | NALHeader::ebsp_to_rbsp(ebsp, size); 202 | ReadStream rs(ebsp, size); 203 | 204 | pps.pic_parameter_set_rbsp(rs, spsList); 205 | ppsList[pps.pic_parameter_set_id] = pps; 206 | picture->pictureFinishFlag = false; 207 | picture->finishFlag = false; 208 | } else if (nalUnitHeader.nal_unit_type == H264_NAL_SLICE || nalUnitHeader.nal_unit_type == H264_NAL_IDR_SLICE) { 209 | 210 | /* 211 | * 这里只对一帧的前30个字节进行去除防竞争字节,然后去解码slice header 212 | * 但是这里有可能slice header 30个字节不够,导致解析错误,概率很小很小,一般slice header不足30个字节 213 | * 或者一帧数据还不够30个字节,也不太可能 214 | * */ 215 | uint32_t headerSize = 30; 216 | /*todo 这里可以优化,放到类里面,避免多次分配释放*/ 217 | uint8_t header[30]; 218 | memcpy(header, data + startCodeLength, headerSize); 219 | NALHeader::ebsp_to_rbsp(header, headerSize); 220 | ReadStream rs(header, headerSize); 221 | 222 | 223 | picture->sliceHeader.slice_header(rs, nalUnitHeader, spsList, ppsList); 224 | if (picture->sliceHeader.first_mb_in_slice != 0) { 225 | log_error("不支持一帧分成多个slice"); 226 | return -1; 227 | } 228 | /*解码POC,查看h264文档 8 Decoding process (only needed to be invoked for one slice of a picture)只需要为一帧的切片调用即可*/ 229 | ret = picture->decoding_process_for_picture_order_count(); 230 | if (ret < 0) { 231 | log_error("解析picture order count 失败"); 232 | return ret; 233 | } 234 | /*参考帧重排序在每个P、SP或B片的解码过程开始时调用。*/ 235 | if (picture->sliceHeader.slice_type == H264_SLIECE_TYPE_P || 236 | picture->sliceHeader.slice_type == H264_SLIECE_TYPE_SP || 237 | picture->sliceHeader.slice_type == H264_SLIECE_TYPE_B) { 238 | gop.decoding_process_for_reference_picture_lists_construction(picture); 239 | } 240 | /* 241 | * 参考图片标记过程 242 | * 当前图片的所有SLICE都被解码。 243 | * 参考8.2.5.1第一条规则 244 | * */ 245 | /*这里标记了这个使用的帧是长期参考还是短期参考,并且给出一个空闲的帧*/ 246 | ret = gop.decoding_finish(picture, unoccupiedPicture); 247 | if (ret < 0) { 248 | log_error("图像解析失败"); 249 | return ret; 250 | } 251 | /*计算pts和dts*/ 252 | computedTimestamp(picture); 253 | 254 | if (nalUnitHeader.nal_unit_type == H264_NAL_IDR_SLICE) { 255 | /*为每个IDR帧前面添加sps和pps*/ 256 | picture->size += spsSize; 257 | picture->data.push_back({spsSize, spsData, 1}); 258 | 259 | picture->size += ppsSize; 260 | picture->data.push_back({ppsSize, ppsData, 2}); 261 | } 262 | picture->size += size; 263 | picture->data.push_back({size, data, 0}); 264 | 265 | picture->pictureFinishFlag = true; 266 | picture->finishFlag = true; 267 | } else { 268 | log_warn("其他type"); 269 | picture->pictureFinishFlag = false; 270 | picture->finishFlag = false; 271 | } 272 | return 0; 273 | } 274 | 275 | 276 | void NALReader::computedTimestamp(NALPicture *picture) { 277 | if (picture->pictureOrderCount == 0) { 278 | videoDecodeIdrFrameNumber = videoDecodeFrameNumber * 2; 279 | } 280 | picture->decodeFrameNumber = videoDecodeFrameNumber; 281 | picture->pts = av_rescale_q((videoDecodeIdrFrameNumber + picture->pictureOrderCount) / 2, 282 | picture->sliceHeader.sps.timeBase, 283 | {1, 1000}); 284 | picture->dts = av_rescale_q(videoDecodeFrameNumber, picture->sliceHeader.sps.timeBase, {1, 1000}); 285 | picture->pcr = av_rescale_q(videoDecodeFrameNumber, picture->sliceHeader.sps.timeBase, {1, 1000}); 286 | 287 | /*转换成微秒*/ 288 | picture->interval = 1000 / (int) picture->sliceHeader.sps.fps; 289 | picture->duration = (double) videoDecodeFrameNumber / picture->sliceHeader.sps.fps; 290 | ++videoDecodeFrameNumber; 291 | } 292 | 293 | NALPicture *NALReader::allocPicture() { 294 | 295 | for (NALPicture *pic: gop.dpb) { 296 | if (!pic->useFlag && pic->reference_marked_type == UNUSED_FOR_REFERENCE) { 297 | return pic; 298 | } 299 | } 300 | return nullptr; 301 | } 302 | 303 | 304 | NALReader::~NALReader() { 305 | delete[] bufferStart; 306 | } 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | -------------------------------------------------------------------------------- /src/nalu/NALReader.h: -------------------------------------------------------------------------------- 1 |  2 | #ifndef MUX_NALREADER_H 3 | #define MUX_NALREADER_H 4 | 5 | #include 6 | #include 7 | #include 8 | #include "NALHeader.h" 9 | #include "NALPicture.h" 10 | #include "NALDecodedPictureBuffer.h" 11 | 12 | 13 | enum NalUintType { 14 | H264_NAL_UNSPECIFIED = 0, 15 | H264_NAL_SLICE = 1, 16 | H264_NAL_IDR_SLICE = 5, 17 | H264_NAL_SEI = 6, 18 | H264_NAL_SPS = 7, 19 | H264_NAL_PPS = 8 20 | }; 21 | 22 | class NALReader { 23 | public: 24 | 25 | static constexpr uint32_t MAX_BUFFER_SIZE{1024 * 1024}; 26 | NALSeqParameterSet sps; 27 | NALPictureParameterSet pps; 28 | uint8_t spsData[50]; 29 | uint8_t ppsData[50]; 30 | uint8_t spsSize{0}; 31 | uint8_t ppsSize{0}; 32 | 33 | 34 | uint8_t *bufferStart{nullptr}; 35 | uint8_t *bufferPosition{nullptr}; 36 | uint8_t *bufferEnd{nullptr}; 37 | uint32_t blockBufferSize{0}; 38 | 39 | private: 40 | bool resetFlag{true}; 41 | NALPicture *unoccupiedPicture{nullptr}; 42 | NALHeader nalUnitHeader; 43 | NALDecodedPictureBuffer gop; 44 | 45 | /*计算pts和dts用的*/ 46 | uint32_t videoDecodeFrameNumber{0}; 47 | uint32_t videoDecodeIdrFrameNumber{0}; 48 | 49 | NALSeqParameterSet spsList[32]; 50 | NALPictureParameterSet ppsList[256]; 51 | 52 | public: 53 | int init(); 54 | 55 | void putData(uint8_t *data, uint32_t size); 56 | 57 | int getParameter(); 58 | 59 | int getVideoFrame2(NALPicture *&picture, uint8_t *data, uint32_t size, uint8_t startCodeLength); 60 | 61 | int getVideoFrame3(NALPicture *&picture); 62 | 63 | 64 | NALPicture *allocPicture(); 65 | 66 | void resetBuffer(); 67 | 68 | ~NALReader(); 69 | 70 | private: 71 | 72 | int disposePicture(NALPicture *picture, uint8_t *data, uint32_t size, uint8_t startCodeLength); 73 | 74 | int findNALU(uint8_t *&pos1, uint8_t *&pos2, int &startCodeLen1, int &startCodeLen2) const; 75 | 76 | void computedTimestamp(NALPicture *picture); 77 | }; 78 | 79 | 80 | #endif //MUX_NALREADER_H 81 | -------------------------------------------------------------------------------- /src/nalu/NALSeqParameterSet.h: -------------------------------------------------------------------------------- 1 |  2 | #ifndef MUX_NALSEQPARAMETERSET_H 3 | #define MUX_NALSEQPARAMETERSET_H 4 | 5 | // 7.4.2.1.1: num_ref_frames_in_pic_order_cnt_cycle的范围是0到255(包括0和255)。 6 | #define H264_MAX_OFFSET_REF_FRAME_COUNT 256 7 | 8 | #include 9 | 10 | #include "bitStream/readStream.h" 11 | #include "utils/util.h" 12 | 13 | 14 | 15 | class NALSeqParameterSet { 16 | 17 | public: 18 | uint8_t profile_idc{}; 19 | uint8_t compatibility{0}; 20 | bool constraint_set0_flag{}; 21 | bool constraint_set1_flag{}; 22 | bool constraint_set2_flag{}; 23 | bool constraint_set3_flag{}; 24 | bool constraint_set4_flag{}; 25 | bool constraint_set5_flag{}; 26 | 27 | uint8_t level_idc{}; 28 | uint8_t seq_parameter_set_id{}; 29 | uint8_t chroma_format_idc{}; 30 | bool separate_colour_plane_flag{}; 31 | uint8_t bit_depth_luma_minus8{}; //当bit_depth_luma_minus8不存在时,它将被推断为等于0。bit_depth_luma_minus8的取值范围为0到6(包括6)。 32 | uint8_t bit_depth_chroma_minus8{}; 33 | bool qpprime_y_zero_transform_bypass_flag{false}; //没有特别指定时,应推定其值为0 34 | bool seq_scaling_matrix_present_flag{}; 35 | /*bool seq_scaling_list_present_flag[12];*/ 36 | uint8_t log2_max_frame_num_minus4{}; // 0-12 37 | uint16_t MaxFrameNum{0}; 38 | uint8_t pic_order_cnt_type{}; 39 | uint8_t log2_max_pic_order_cnt_lsb_minus4{}; 40 | uint32_t MaxPicOrderCntLsb{0}; 41 | bool delta_pic_order_always_zero_flag{true}; 42 | int offset_for_non_ref_pic{0}; //-2^31-1 - 2^31-1,有符号4字节整数 43 | int offset_for_top_to_bottom_field{0}; 44 | uint8_t num_ref_frames_in_pic_order_cnt_cycle{0}; // 0-255 45 | int offset_for_ref_frame[H264_MAX_OFFSET_REF_FRAME_COUNT]{}; //-2^31-1 - 2^31-1,有符号4字节整数 46 | int ExpectedDeltaPerPicOrderCntCycle{0}; 47 | 48 | uint8_t max_num_ref_frames{}; 49 | bool gaps_in_frame_num_value_allowed_flag{}; 50 | uint32_t pic_width_in_mbs_minus1{}; 51 | uint32_t pic_height_in_map_units_minus1{}; 52 | bool frame_mbs_only_flag{}; 53 | //bool mb_adaptive_frame_field_flag{}; 54 | bool direct_8x8_inference_flag{}; 55 | bool frame_cropping_flag{}; 56 | uint32_t frame_crop_left_offset{}; 57 | uint32_t frame_crop_right_offset{}; 58 | uint32_t frame_crop_top_offset{}; 59 | uint32_t frame_crop_bottom_offset{}; 60 | 61 | 62 | uint32_t PicWidthInMbs{0}; 63 | uint32_t PicHeightInMapUnits{0}; //PicHeightInMapUnits = pic_height_in_map_units_minus1 + 1; 64 | uint32_t PicSizeInMapUnits{0}; 65 | uint8_t ChromaArrayType{0}; 66 | uint32_t PicWidthInSamplesL{0}; 67 | uint32_t PicHeightInSamplesL{0}; 68 | 69 | bool vui_parameters_present_flag{false}; 70 | 71 | 72 | //辅助信息 73 | 74 | double fps{25.0}; 75 | AVRational timeBase{1, 25}; 76 | 77 | uint8_t aspect_ratio_idc{0}; 78 | //长宽比 79 | uint16_t sar_width{0}; 80 | uint16_t sar_height{0}; 81 | bool overscan_appropriate_flag{false}; 82 | 83 | uint8_t video_format{5}; 84 | bool video_full_range_flag{false}; 85 | uint8_t colour_primaries{}; 86 | uint8_t transfer_characteristics{}; 87 | uint8_t matrix_coefficients{}; 88 | 89 | //取值范围为0 ~ 5,包括0 ~ 5 90 | uint8_t chroma_sample_loc_type_top_field{}; 91 | uint8_t chroma_sample_loc_type_bottom_field{}; 92 | 93 | bool timing_info_present_flag{false}; 94 | uint32_t num_units_in_tick{0}; 95 | uint32_t time_scale{0}; 96 | bool fixed_frame_rate_flag{false}; 97 | 98 | 99 | bool low_delay_hrd_flag{false}; 100 | 101 | 102 | int max_num_reorder_frames{-1}; 103 | int max_dec_frame_buffering{-1}; 104 | public: 105 | int seq_parameter_set_data(ReadStream &rs); 106 | 107 | int vui_parameters(ReadStream &rs); 108 | }; 109 | 110 | 111 | #endif //MUX_NALSEQPARAMETERSET_H 112 | -------------------------------------------------------------------------------- /src/nalu/NALSliceHeader.cpp: -------------------------------------------------------------------------------- 1 |  2 | #include "NALSliceHeader.h" 3 | 4 | #include 5 | 6 | 7 | #include "NALHeader.h" 8 | 9 | 10 | int NALSliceHeader::slice_header(ReadStream &rs, NALHeader &nalUnit, const NALSeqParameterSet spsList[], 11 | const NALPictureParameterSet ppsList[]) { 12 | 13 | int ret; 14 | 15 | first_mb_in_slice = rs.readUE(); 16 | slice_type = rs.readUE() % 5; 17 | pic_parameter_set_id = rs.readUE(); 18 | 19 | nalu = nalUnit; 20 | pps = ppsList[pic_parameter_set_id]; 21 | sps = spsList[pps.seq_parameter_set_id]; 22 | 23 | 24 | if (sps.separate_colour_plane_flag) { 25 | //指定与当前切片RBSP关联的颜色平面。colour_plane_id的值应该在0到2的范围内 26 | //colour_plane_id等于0、1和2分别对应于Y、Cb和Cr平面。 27 | colour_plane_id = rs.readMultiBit(2); //2 u(2) 28 | } 29 | 30 | frame_num = rs.readMultiBit(sps.log2_max_frame_num_minus4 + 4); 31 | 32 | if (nalu.IdrPicFlag) { 33 | idr_pic_id = rs.readUE(); 34 | } 35 | 36 | if (sps.pic_order_cnt_type == 0) { 37 | pic_order_cnt_lsb = rs.readMultiBit(sps.log2_max_pic_order_cnt_lsb_minus4 + 4); 38 | 39 | //当field_pic_flag 不存在时,应推定其值为0 40 | if (pps.bottom_field_pic_order_in_frame_present_flag) { 41 | //表示一个编码帧的底场和顶场的图像顺序数之间的差 不存在时推断为0 42 | delta_pic_order_cnt_bottom = rs.readSE(); 43 | } 44 | } 45 | 46 | if (sps.pic_order_cnt_type == 1 && !sps.delta_pic_order_always_zero_flag) { 47 | /* 48 | * POC 的第二和第三种算法是从 frame_num 映射得来,这两个句法元素用于映射算法。 49 | * delta_pic_order_cnt[0]用于帧编码方式下的底场和场编码方式的场, 50 | * delta_pic_order_cnt[1]用于帧编码方式下的顶场 51 | * */ 52 | delta_pic_order_cnt[0] = rs.readSE(); 53 | if (pps.bottom_field_pic_order_in_frame_present_flag) { 54 | delta_pic_order_cnt[1] = rs.readSE(); 55 | } 56 | } 57 | 58 | /*对于那些属于基本编码图像的条带和条带数据分割块应等于0。在冗余编码图像中的编码 59 | 条带和编码条带数据分割块的 redundant_pic_cnt 的值应大于 0。当redundant_pic_cnt不存在时,默认其值为 0。 60 | redundant_pic_cnt的值应该在 0 到 127 范围内(包括 0 和 127)*/ 61 | if (pps.redundant_pic_cnt_present_flag) { 62 | redundant_pic_cnt = rs.readUE(); 63 | } 64 | 65 | if (slice_type == H264_SLIECE_TYPE_B) { 66 | //指出在B图像的直接预测的模式下,用时间预测还是用空间预测。1: 空间预测;0:时间预测。 67 | direct_spatial_mv_pred_flag = rs.readBit(); 68 | } 69 | 70 | if (slice_type == H264_SLIECE_TYPE_P || slice_type == H264_SLIECE_TYPE_SP || slice_type == H264_SLIECE_TYPE_B) { 71 | /* 72 | num_ref_idx_l0_active_minus1 和 num_ref_idx_l1_active_minus1 指定当前参考帧队列中实际可用的参考帧的数目。 73 | 在片头可以重载这对句法元素,以给某特定图像更大的灵活度。 74 | 这个句法元素就是指明片头是否会重载,如果该句法元素等于 1, 75 | 下面会出现新的num_ref_idx_l0_active_minus1和num_ref_idx_l1_active_minus1值*/ 76 | bool num_ref_idx_active_override_flag = rs.readBit(); 77 | 78 | num_ref_idx_l0_active_minus1 = pps.num_ref_idx_l0_default_active_minus1; 79 | num_ref_idx_l1_active_minus1 = pps.num_ref_idx_l1_default_active_minus1; 80 | if (num_ref_idx_active_override_flag) { 81 | num_ref_idx_l0_active_minus1 = rs.readUE(); 82 | if (slice_type == H264_SLIECE_TYPE_B) { 83 | num_ref_idx_l1_active_minus1 = rs.readUE(); 84 | } 85 | } 86 | } 87 | 88 | if (nalu.nal_unit_type == 20 || nalu.nal_unit_type == 21) { 89 | fprintf(stderr, "参见附录H,不支持解析\n"); 90 | return -1; 91 | } else { 92 | /* 参考图像序列重排序相关 */ 93 | ret = ref_pic_list_modification(rs); 94 | if (ret < 0) { 95 | fprintf(stderr, "slice header 解析参考帧列表排序字段失败\n"); 96 | return ret; 97 | } 98 | } 99 | 100 | 101 | if ((pps.weighted_pred_flag && (slice_type == H264_SLIECE_TYPE_P || slice_type == H264_SLIECE_TYPE_SP)) || 102 | (pps.weighted_bipred_idc == 1 && slice_type == H264_SLIECE_TYPE_B) 103 | ) { 104 | /*加权预测相关*/ 105 | pred_weight_table(rs); 106 | } 107 | 108 | if (nalu.nal_ref_idc != 0) { 109 | /*参考图像序列标记相关*/ 110 | dec_ref_pic_marking(rs); 111 | } 112 | // todo... 113 | 114 | 115 | 116 | /*MaxPicNum = (field_pic_flag == 0) ? sps.MaxFrameNum : (2 * sps.MaxFrameNum); 117 | CurrPicNum = (field_pic_flag == 0) ? frame_num : (2 * frame_num + 1);*/ 118 | /*表征 PicNum 的最大值,PicNum 和 frame_num 一样,也是嵌在循环中,当达到这个最大值时,PicNum 将从 0 开始重新计数*/ 119 | MaxPicNum = sps.MaxFrameNum; 120 | /*当前图像的 PicNum 值,在计算 PicNum 的过程中,当前图像的 PicNum 值是由 frame_num 直接算出*/ 121 | CurrPicNum = frame_num; 122 | return 0; 123 | } 124 | 125 | int NALSliceHeader::ref_pic_list_modification(ReadStream &rs) { 126 | //H264_SLIECE_TYPE_I = 2; H264_SLIECE_TYPE_SI = 4; 127 | if (slice_type != 2 && slice_type != 4) { 128 | bool ref_pic_list_modification_flag_l0 = rs.readBit(); 129 | /*指明了是否有重排序的操作*/ 130 | if (ref_pic_list_modification_flag_l0) { 131 | /*指定参考图片列表0*/ 132 | int i = 0; 133 | do { 134 | if (i >= 32) { 135 | fprintf(stderr, "参考列表0,i必须在0-31\n"); 136 | return -1; 137 | } 138 | 139 | modification_of_pic_nums_idc[0][i] = rs.readUE(); 140 | if (modification_of_pic_nums_idc[0][i] == 0 || modification_of_pic_nums_idc[0][i] == 1) { 141 | /*在对短期参考帧重排序时指明重排序图像与当前的差*/ 142 | abs_diff_pic_num_minus1[0][i] = rs.readUE(); 143 | } else if (modification_of_pic_nums_idc[0][i] == 2) { 144 | /*在对长期参考帧重排序时指明重排序图像*/ 145 | long_term_pic_num[0][i] = rs.readUE(); 146 | } 147 | i++; 148 | } while (modification_of_pic_nums_idc[0][i - 1] != 3); 149 | // ref_pic_list_modification_count_l0 = i; 150 | } 151 | } 152 | 153 | //H264_SLIECE_TYPE_B = 1; 154 | if (slice_type % 5 == 1) { 155 | bool ref_pic_list_modification_flag_l1 = rs.readBit(); 156 | /*指明了是否有重排序的操作*/ 157 | if (ref_pic_list_modification_flag_l1) { 158 | int i = 0; 159 | do { 160 | if (i >= 32) { 161 | fprintf(stderr, "参考列表1,i必须在0-31\n"); 162 | return -1; 163 | } 164 | 165 | modification_of_pic_nums_idc[1][i] = rs.readUE(); 166 | if (modification_of_pic_nums_idc[1][i] == 0 || modification_of_pic_nums_idc[1][i] == 1) { 167 | abs_diff_pic_num_minus1[1][i] = rs.readUE(); 168 | } else if (modification_of_pic_nums_idc[1][i] == 2) { 169 | long_term_pic_num[1][i] = rs.readUE(); 170 | } 171 | i++; 172 | } while (modification_of_pic_nums_idc[1][i - 1] != 3); 173 | //ref_pic_list_modification_count_l1 = i; 174 | } 175 | } 176 | return 0; 177 | } 178 | 179 | int NALSliceHeader::pred_weight_table(ReadStream &rs) { 180 | 181 | int i = 0; 182 | int j = 0; 183 | 184 | luma_log2_weight_denom = rs.readUE(); 185 | if (sps.ChromaArrayType != 0) { 186 | chroma_log2_weight_denom = rs.readUE(); 187 | } 188 | 189 | for (i = 0; i <= num_ref_idx_l0_active_minus1; i++) { 190 | /*luma_log2_weight_denom是所有luma权重因子的分母以2为底的对数*/ 191 | luma_weight_l0[i] = static_cast(1 << luma_log2_weight_denom); //When luma_weight_l0_flag=0 192 | luma_offset_l0[i] = 0; //When luma_weight_l0_flag is equal to 0 193 | /*等于1时,指的是在参考序列0中的亮度的加权系数存在;等于0时,在参考序列0中的亮度的加权系数不存在*/ 194 | bool luma_weight_l0_flag = rs.readBit(); 195 | if (luma_weight_l0_flag) { 196 | luma_weight_l0[i] = static_cast(rs.readSE()); 197 | luma_offset_l0[i] = static_cast(rs.readSE()); 198 | } 199 | 200 | if (sps.ChromaArrayType != 0) { 201 | /*chroma_log2_weight_denom是所有chroma权重因子的分母以2为底的对数*/ 202 | chroma_weight_l0[i][0] = static_cast(1 << chroma_log2_weight_denom); //When chroma_weight_l0_flag=0 203 | chroma_weight_l0[i][1] = static_cast(1 << chroma_log2_weight_denom); //When chroma_weight_l0_flag=0 204 | chroma_offset_l0[i][0] = 0; 205 | chroma_offset_l0[i][1] = 0; 206 | 207 | /*chroma_weight_l0_flag=0,色度权重因子不存在*/ 208 | bool chroma_weight_l0_flag = rs.readBit(); 209 | 210 | /*chroma_weight_l0[i][j]是应用于使用RefPicList0[i]进行列表0预测的色度预测值的权重因子,取值范围为−128 ~ 127*/ 211 | /*chroma_offset_l0[i][j]是使用refpiclist0[i]对列表0预测的色度预测值应用的加性偏移量,取值范围为−128 ~ 127*/ 212 | /*对于Cb j等于0,对于Cr j等于1*/ 213 | if (chroma_weight_l0_flag) { 214 | for (j = 0; j < 2; j++) { 215 | chroma_weight_l0[i][j] = static_cast(rs.readSE()); 216 | chroma_offset_l0[i][j] = static_cast(rs.readSE()); 217 | } 218 | } 219 | } 220 | } 221 | 222 | if (slice_type % 5 == 1) { 223 | for (i = 0; i <= num_ref_idx_l1_active_minus1; i++) { 224 | luma_weight_l1[i] = static_cast(1 << luma_log2_weight_denom); //When luma_weight_l1_flag=0 225 | luma_offset_l1[i] = 0; //When luma_weight_l1_flag=0 226 | 227 | bool luma_weight_l1_flag = rs.readBit(); 228 | if (luma_weight_l1_flag) { 229 | luma_weight_l1[i] = static_cast(rs.readSE()); 230 | luma_offset_l1[i] = static_cast(rs.readSE()); 231 | } 232 | 233 | if (sps.ChromaArrayType != 0) { 234 | chroma_weight_l1[i][0] = static_cast(1 << chroma_log2_weight_denom); //chroma_weight_l1_flag=0 235 | chroma_weight_l1[i][1] = static_cast(1 << chroma_log2_weight_denom); //chroma_weight_l1_flag=0 236 | chroma_offset_l1[i][0] = 0; 237 | chroma_offset_l1[i][1] = 0; 238 | 239 | bool chroma_weight_l1_flag = rs.readBit(); 240 | if (chroma_weight_l1_flag) { 241 | for (j = 0; j < 2; j++) { 242 | chroma_weight_l1[i][j] = static_cast(rs.readSE()); 243 | chroma_offset_l1[i][j] = static_cast(rs.readSE()); 244 | } 245 | } 246 | } 247 | } 248 | } 249 | return 0; 250 | } 251 | 252 | int NALSliceHeader::dec_ref_pic_marking(ReadStream &rs) { 253 | if (nalu.IdrPicFlag) { 254 | no_output_of_prior_pics_flag = rs.readBit(); 255 | long_term_reference_flag = rs.readBit(); 256 | } else { 257 | /*=0,先入先出(FIFO):使用滑动窗的机制,先入先出,在这种模式下没有办法对长期参考帧进行操作*/ 258 | /*=1,自适应标记(marking):后续码流中会有一系列句法元素显式指明操作的步骤。自适应是指编码器可根据情况随机灵活地作出决策。*/ 259 | adaptive_ref_pic_marking_mode_flag = rs.readBit(); 260 | if (adaptive_ref_pic_marking_mode_flag) { 261 | int i = 0; 262 | do { 263 | dec_ref_pic_markings[i].memory_management_control_operation = rs.readUE(); 264 | 265 | if (dec_ref_pic_markings[i].memory_management_control_operation == 1 || 266 | dec_ref_pic_markings[i].memory_management_control_operation == 3) { 267 | // 这个句法元素可以计算得到需要操作的图像在短期参考队列中的序号 268 | dec_ref_pic_markings[i].difference_of_pic_nums_minus1 = rs.readUE(); 269 | } 270 | 271 | if (dec_ref_pic_markings[i].memory_management_control_operation == 2) { 272 | // 此句法元素得到所要操作的长期参考图像的序号 273 | dec_ref_pic_markings[i].long_term_pic_num = rs.readUE(); 274 | } 275 | 276 | if (dec_ref_pic_markings[i].memory_management_control_operation == 3 || 277 | dec_ref_pic_markings[i].memory_management_control_operation == 6) { 278 | // 分配一个长期参考帧的序号给一个图像 279 | dec_ref_pic_markings[i].long_term_frame_idx = rs.readUE(); 280 | } 281 | 282 | if (dec_ref_pic_markings[i].memory_management_control_operation == 4) { 283 | //此句法元素减1 ,指明长期参考队列的最大数目。 284 | dec_ref_pic_markings[i].max_long_term_frame_idx_plus1 = rs.readUE(); 285 | } 286 | ++i; 287 | 288 | } while (dec_ref_pic_markings[i - 1].memory_management_control_operation != 0); 289 | dec_ref_pic_markings_size = i; 290 | } 291 | } 292 | 293 | return 0; 294 | } 295 | 296 | -------------------------------------------------------------------------------- /src/nalu/NALSliceHeader.h: -------------------------------------------------------------------------------- 1 |  2 | #ifndef MUX_NALSLICEHEADER_H 3 | #define MUX_NALSLICEHEADER_H 4 | 5 | #include 6 | #include "bitStream/readStream.h" 7 | #include "NALHeader.h" 8 | #include "NALSeqParameterSet.h" 9 | #include "NALPictureParameterSet.h" 10 | 11 | 12 | class NALSeqParameterSet; 13 | 14 | class NALPictureParameterSet; 15 | 16 | enum SLIECETYPE { 17 | H264_SLIECE_TYPE_P = 0, 18 | H264_SLIECE_TYPE_B = 1, 19 | H264_SLIECE_TYPE_I = 2, 20 | H264_SLIECE_TYPE_SP = 3, 21 | H264_SLIECE_TYPE_SI = 4, 22 | H264_SLIECE_TYPE_P2 = 5, 23 | H264_SLIECE_TYPE_B2 = 6, 24 | H264_SLIECE_TYPE_I2 = 7, 25 | H264_SLIECE_TYPE_SP2 = 8, 26 | H264_SLIECE_TYPE_SI2 = 9, 27 | }; 28 | struct DEC_REF_PIC_MARKING { 29 | uint8_t memory_management_control_operation; //在自适应标记(marking)模式中指明本次操作的具体内容 表7-24 30 | uint8_t difference_of_pic_nums_minus1; 31 | uint8_t long_term_pic_num; 32 | uint8_t long_term_frame_idx; 33 | uint8_t max_long_term_frame_idx_plus1; 34 | }; 35 | 36 | class NALSliceHeader { 37 | public: 38 | NALHeader nalu; 39 | NALSeqParameterSet sps; 40 | NALPictureParameterSet pps; 41 | 42 | uint32_t first_mb_in_slice{0}; 43 | uint8_t slice_type{0}; 44 | uint8_t pic_parameter_set_id{0}; 45 | uint8_t colour_plane_id{0}; 46 | uint16_t frame_num{0}; 47 | uint16_t idr_pic_id{0}; 48 | uint16_t pic_order_cnt_lsb{0}; 49 | int delta_pic_order_cnt_bottom{0}; 50 | /*默认值为0*/ 51 | int delta_pic_order_cnt[2]{0}; 52 | 53 | 54 | uint8_t redundant_pic_cnt{0}; 55 | bool direct_spatial_mv_pred_flag{false}; 56 | uint8_t num_ref_idx_l0_active_minus1{0}; 57 | uint8_t num_ref_idx_l1_active_minus1{0}; 58 | 59 | uint8_t modification_of_pic_nums_idc[2][32]{0}; 60 | uint16_t abs_diff_pic_num_minus1[2][32]{0}; // 0 到 MaxPicNum – 1 61 | uint32_t long_term_pic_num[2][32]; 62 | 63 | /*加权预测*/ 64 | /*给出参考帧列表中参考图像所有亮度的加权系数,是个初始值uma_log2_weight_denom 值的范围是 0 to 7*/ 65 | uint8_t luma_log2_weight_denom{0}; 66 | /*给出参考帧列表中参考图像所有色度的加权系数,是个初始值chroma_log2_weight_denom 值的范围是 0 to 7*/ 67 | uint8_t chroma_log2_weight_denom{0}; 68 | /*用参考序列 0 预测亮度值时,所用的加权系数*/ 69 | int8_t luma_weight_l0[32]{0}; 70 | /*用参考序列 0 预测亮度值时,所用的加权系数的额外的偏移 。luma_offset_l0[ i ] 值的范围–128 to 127*/ 71 | int8_t luma_offset_l0[32]{0}; 72 | int8_t chroma_weight_l0[32][2]{0}; 73 | int8_t chroma_offset_l0[32][2]{0}; 74 | 75 | /*参考列表1的权重因子*/ 76 | int8_t luma_weight_l1[32]{0}; 77 | int8_t luma_offset_l1[32]{0}; 78 | int8_t chroma_weight_l1[32][2]{0}; 79 | int8_t chroma_offset_l1[32][2]{0}; 80 | 81 | /*参考图像序列标记相关*/ 82 | /*指明是否要将前面已解码的图像全部输出*/ 83 | bool no_output_of_prior_pics_flag{false}; 84 | /* 85 | * 这个句法元素指明是否使用长期参考这个机制。 86 | * 如果取值为 1,表明使用长期参考,并且每个 IDR 图像被解码后自动成为长期参考帧, 87 | * 否则(取值为 0),IDR 图像被解码后自动成为短期参考帧 88 | * */ 89 | bool long_term_reference_flag{false}; 90 | /*指明标记(marking)操作的模式*/ 91 | bool adaptive_ref_pic_marking_mode_flag{false}; 92 | /*在自适应标记(marking)模式中,指明本次操作的具体内容 见毕厚杰表 7.24*/ 93 | uint8_t memory_management_control_operation{0}; 94 | DEC_REF_PIC_MARKING dec_ref_pic_markings[32]; 95 | /*dec_ref_pic_markings实际大小*/ 96 | uint8_t dec_ref_pic_markings_size{0}; 97 | 98 | uint16_t MaxPicNum{0}; 99 | uint16_t CurrPicNum{0}; 100 | public: 101 | int slice_header(ReadStream &rs, NALHeader &nalUnit, const NALSeqParameterSet spsList[], 102 | const NALPictureParameterSet ppsList[]); 103 | 104 | private: 105 | int ref_pic_list_modification(ReadStream &rs); 106 | 107 | int pred_weight_table(ReadStream &rs); 108 | 109 | int dec_ref_pic_marking(ReadStream &rs); 110 | }; 111 | 112 | 113 | #endif //MUX_NALSLICEHEADER_H 114 | -------------------------------------------------------------------------------- /src/protocol/CMakeLists.txt: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | add_library(protocol rtsp.cpp rtspSendData.cpp rtspReceiveData.cpp http.cpp httpHls.cpp httpFlv.cpp) 5 | 6 | 7 | target_include_directories(protocol 8 | PRIVATE ${PROJECT_SOURCE_DIR}/src 9 | ) 10 | #[[todo 更改每个lib的依赖]] 11 | target_link_libraries(protocol 12 | PRIVATE bitStream log utils socket flashVideo AVPacket 13 | ) -------------------------------------------------------------------------------- /src/protocol/http.cpp: -------------------------------------------------------------------------------- 1 |  2 | #include "http.h" 3 | #include "utils/util.h" 4 | #include "log/logger.h" 5 | 6 | #define TAG_SIZE 4 7 | #define TAG_HEADER_SIZE 11 8 | 9 | 10 | uint8_t Http::response[1024]{0}; 11 | 12 | int Http::init(SOCKET socket) { 13 | clientSocket = socket; 14 | return 0; 15 | } 16 | 17 | 18 | int Http::parse(std::string &packet, const std::string &data) { 19 | int ret; 20 | 21 | 22 | std::string method, path, version; 23 | 24 | std::vector list = split(data, "\r\n"); 25 | 26 | std::istringstream iss(list.front()); 27 | iss >> method >> path >> version; 28 | 29 | list.erase(list.begin()); 30 | request = getObj(list, ":"); 31 | 32 | if (method != "GET") { 33 | fprintf(stderr, "method = %s\n", method.c_str()); 34 | responseData(405, "Method Not Allowed"); 35 | return -1; 36 | } 37 | 38 | 39 | std::filesystem::path source("." + path); 40 | 41 | if (source.extension() == ".m3u8" || source.extension() == ".ts") { 42 | ret = hls.init(source, clientSocket); 43 | if (ret < 0) { 44 | responseData(500, "错误"); 45 | return -1; 46 | } 47 | ret = hls.disposeHls(); 48 | if (ret < 0) { 49 | responseData(500, "错误"); 50 | return -1; 51 | } 52 | } else if (source.extension() == ".flv") { 53 | /*这里应该单独开个线程去发送数据*/ 54 | sendFlVThread = new std::thread(&Http::sendFLV, this, source); 55 | } else { 56 | fprintf(stderr, "不支持这种类型\n"); 57 | ret = responseData(415, "Unsupported Media Type"); 58 | return -1; 59 | } 60 | 61 | return 0; 62 | } 63 | 64 | int Http::sendFLV(std::filesystem::path path) { 65 | int ret; 66 | ret = flv.init(path, clientSocket); 67 | if (ret < 0) { 68 | stopFlag = false; 69 | responseData(500, "错误"); 70 | return -1; 71 | } 72 | ret = flv.disposeFlv(); 73 | if (ret < 0) { 74 | stopFlag = false; 75 | responseData(500, "错误"); 76 | return -1; 77 | } 78 | return 0; 79 | } 80 | 81 | int Http::responseData(int status, const std::string &msg) const { 82 | memset(response, 0, 1024); 83 | std::string body = "

" + msg + "

"; 84 | sprintf(reinterpret_cast(response), 85 | "HTTP/1.1 %d %s\r\n" 86 | "Content-Type: text/html\r\n" 87 | "Content-Length: %zu\r\n" 88 | "\r\n" 89 | "%s", 90 | status, msg.c_str(), 91 | body.size(), 92 | body.c_str() 93 | ); 94 | 95 | int ret = TcpSocket::sendData(clientSocket, response, (int) strlen(reinterpret_cast(response))); 96 | if (ret < 0) { 97 | fprintf(stderr, "发送数据失败\n"); 98 | return ret; 99 | } 100 | return 0; 101 | } 102 | 103 | Http::~Http() { 104 | log_info("http 析构"); 105 | stopFlag = false; 106 | flv.setStopFlag(stopFlag); 107 | if (sendFlVThread && sendFlVThread->joinable()) { 108 | sendFlVThread->join(); 109 | } 110 | 111 | log_info("sendFlVThread 执行完成"); 112 | } 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | -------------------------------------------------------------------------------- /src/protocol/http.h: -------------------------------------------------------------------------------- 1 |  2 | 3 | #ifndef RTSP_HTTP_H 4 | #define RTSP_HTTP_H 5 | 6 | #include 7 | #include 8 | #include 9 | #include "httpHls.h" 10 | #include "httpFlv.h" 11 | #include "socket/TcpSocket.h" 12 | 13 | class Http { 14 | private: 15 | HttpHls hls; 16 | HttpFlv flv; 17 | 18 | SOCKET clientSocket{0}; 19 | std::map request; 20 | static uint8_t response[1024]; 21 | std::thread *sendFlVThread{nullptr}; 22 | 23 | public: 24 | bool stopFlag{true}; 25 | 26 | int init(SOCKET socket); 27 | 28 | int parse(std::string &packet, const std::string &data); 29 | 30 | ~Http(); 31 | 32 | private: 33 | 34 | int sendFLV(std::filesystem::path path); 35 | 36 | int responseData(int status, const std::string &msg) const; 37 | }; 38 | 39 | 40 | #endif //RTSP_HTTP_H 41 | -------------------------------------------------------------------------------- /src/protocol/httpFlv.cpp: -------------------------------------------------------------------------------- 1 |  2 | #include "httpFlv.h" 3 | #include 4 | 5 | #include "bitStream/writeStream.h" 6 | #include "flashVideo/FLVHeader.h" 7 | #include "flashVideo/FLVScriptTag.h" 8 | 9 | 10 | #include "log/logger.h" 11 | 12 | 13 | #define TAG_SIZE 4 14 | #define TAG_HEADER_SIZE 11 15 | 16 | static inline uint32_t bswap_32(uint32_t x) { 17 | x = ((x << 8) & 0xFF00FF00) | ((x >> 8) & 0x00FF00FF); 18 | return (x >> 16) | (x << 16); 19 | } 20 | 21 | 22 | int HttpFlv::init(std::filesystem::path &path, SOCKET socket) { 23 | 24 | path.replace_extension(""); 25 | if (!std::filesystem::exists(path)) { 26 | fprintf(stderr, "目录不存在\n"); 27 | return -1; 28 | } 29 | 30 | dir = path.string(); 31 | for (const std::filesystem::directory_entry &entry: std::filesystem::directory_iterator(path)) { 32 | std::string extension = entry.path().extension().string(); 33 | if (extension == ".ts") { 34 | std::string filename = entry.path().filename().string(); 35 | std::size_t start = filename.find("test") + 4; 36 | std::size_t end = filename.find(".ts"); 37 | int number = std::stoi(filename.substr(start, end - start)); 38 | if (number > transportStreamPacketNumber) { 39 | transportStreamPacketNumber = number; 40 | } 41 | } 42 | } 43 | clientSocket = socket; 44 | 45 | package = AVReadPacket::allocPacket(); 46 | 47 | 48 | return 0; 49 | } 50 | 51 | int HttpFlv::disposeFlv() { 52 | int ret; 53 | ret = sendHeader(); 54 | if (ret < 0) { 55 | fprintf(stderr, "sendHeader 失败\n"); 56 | return ret; 57 | } 58 | 59 | ret = sendMetadata(); 60 | if (ret < 0) { 61 | fprintf(stderr, "sendMetadata 失败\n"); 62 | return ret; 63 | } 64 | ret = sendSequenceHeader(); 65 | if (ret < 0) { 66 | fprintf(stderr, "sendSequenceHeader 失败\n"); 67 | return ret; 68 | } 69 | ret = sendData(); 70 | if (ret < 0) { 71 | fprintf(stderr, "sendData 失败\n"); 72 | return ret; 73 | } 74 | return 0; 75 | } 76 | 77 | int HttpFlv::sendHeader() { 78 | int ret; 79 | 80 | memset(response, 0, 1024); 81 | 82 | sprintf(reinterpret_cast(response), 83 | "HTTP/1.1 200 OK\r\n" 84 | "Content-Type: video/x-flv\r\n" 85 | "Connection: keep-alive\r\n" 86 | "\r\n" 87 | ); 88 | ret = TcpSocket::sendData(clientSocket, response, (int) strlen(reinterpret_cast(response))); 89 | if (ret < 0) { 90 | log_error("发送数据失败"); 91 | return ret; 92 | } 93 | 94 | 95 | WriteStream ws(response, FLVHeader::size); 96 | FLVHeader header; 97 | header.write(ws); 98 | ret = TcpSocket::sendData(clientSocket, response, (int) ws.bufferSize); 99 | if (ret < 0) { 100 | log_error("发送数据失败 FLV header"); 101 | return ret; 102 | } 103 | previousTagSize = 0; 104 | 105 | 106 | return 0; 107 | } 108 | 109 | int HttpFlv::sendMetadata() { 110 | int ret; 111 | AVReadPacket packet; 112 | ret = packet.init(dir, transportStreamPacketNumber); 113 | if (ret < 0) { 114 | log_error("packet.init 初始化失败"); 115 | return ret; 116 | } 117 | ret = packet.getParameter(); 118 | if (ret < 0) { 119 | log_error("packet.getParameter 失败"); 120 | return ret; 121 | } 122 | 123 | 124 | constexpr int META_SIZE = 156; 125 | WriteStream ws(response, TAG_SIZE + TAG_HEADER_SIZE + META_SIZE); 126 | /*写入上个tag的大小*/ 127 | ws.writeMultiBit(32, previousTagSize); 128 | 129 | //FLVTagHeader tagHeader; 130 | tagHeader.setConfig(SCRIPT, META_SIZE, 0); 131 | tagHeader.write(ws); 132 | 133 | 134 | FLVScriptTag scriptTag; 135 | scriptTag.setConfig(packet.sps.PicWidthInSamplesL, packet.sps.PicHeightInSamplesL, packet.sps.fps, 136 | packet.aacHeader.sample_rate, packet.aacHeader.channel_configuration); 137 | scriptTag.write(ws); 138 | 139 | 140 | ret = TcpSocket::sendData(clientSocket, response, (int) ws.bufferSize); 141 | if (ret < 0) { 142 | log_error("发送数据失败"); 143 | return ret; 144 | } 145 | 146 | 147 | previousTagSize = TAG_HEADER_SIZE + META_SIZE; 148 | return 0; 149 | } 150 | 151 | 152 | int HttpFlv::sendSequenceHeader() { 153 | int ret; 154 | AVReadPacket packet; 155 | ret = packet.init(dir, transportStreamPacketNumber); 156 | if (ret < 0) { 157 | log_error("packet.init 初始化失败"); 158 | return ret; 159 | } 160 | ret = packet.getParameter(); 161 | if (ret < 0) { 162 | log_error("packet.getParameter 失败"); 163 | return ret; 164 | } 165 | ret = sendVideoSequenceHeader(packet); 166 | if (ret < 0) { 167 | log_error("sendVideoSequenceHeader 失败"); 168 | return ret; 169 | } 170 | 171 | ret = sendAudioSequenceHeader(packet); 172 | if (ret < 0) { 173 | log_error("sendAudioSequenceHeader 失败"); 174 | return ret; 175 | } 176 | return 0; 177 | } 178 | 179 | int HttpFlv::sendVideoSequenceHeader(AVReadPacket &packet) { 180 | int ret; 181 | constexpr int AVC_CONFIG_SIZE = 16; 182 | WriteStream ws(response, TAG_SIZE + TAG_HEADER_SIZE + AVC_CONFIG_SIZE + packet.spsSize + packet.ppsSize); 183 | /*写入上个tag的大小*/ 184 | ws.writeMultiBit(32, previousTagSize); 185 | 186 | //FLVTagHeader tagHeader; 187 | tagHeader.setConfig(VIDEO, AVC_CONFIG_SIZE + packet.spsSize + packet.ppsSize, 0); 188 | tagHeader.write(ws); 189 | 190 | 191 | /* 5 */ 192 | videoTag.setConfig(1, AVC_sequence_header, 0); 193 | /* 11 + packet.spsSize + packet.ppsSize */ 194 | videoTag.setConfigurationRecord(packet.sps.profile_idc, packet.sps.level_idc, packet.sps.compatibility); 195 | videoTag.writeConfig(ws, packet.spsData, packet.spsSize, packet.ppsData, packet.ppsSize); 196 | 197 | ret = TcpSocket::sendData(clientSocket, response, (int) ws.bufferSize); 198 | if (ret < 0) { 199 | log_error("发送数据失败"); 200 | return ret; 201 | } 202 | previousTagSize = TAG_HEADER_SIZE + AVC_CONFIG_SIZE + packet.spsSize + packet.ppsSize; 203 | return 0; 204 | } 205 | 206 | int HttpFlv::sendAudioSequenceHeader(AVReadPacket &packet) { 207 | int ret; 208 | /* write audio Sequence Header */ 209 | constexpr int AAC_CONFIG_SIZE = 4; 210 | WriteStream ws(response, TAG_SIZE + TAG_HEADER_SIZE + AAC_CONFIG_SIZE); 211 | /*写入上个tag的大小*/ 212 | ws.writeMultiBit(32, previousTagSize); 213 | 214 | //FLVTagHeader tagHeader; 215 | tagHeader.setConfig(AUDIO, AAC_CONFIG_SIZE, 0); 216 | tagHeader.write(ws); 217 | 218 | 219 | // FLVAudioTag audioTag; 220 | audioTag.setConfig(0); 221 | 222 | audioTag.setConfigurationRecord(packet.aacHeader.profile + 1, packet.aacHeader.sampling_frequency_index, 223 | packet.aacHeader.channel_configuration); 224 | audioTag.writeConfig(ws); 225 | ret = TcpSocket::sendData(clientSocket, response, (int) ws.bufferSize); 226 | if (ret < 0) { 227 | log_error("发送数据失败"); 228 | return ret; 229 | } 230 | previousTagSize = TAG_HEADER_SIZE + AAC_CONFIG_SIZE; 231 | 232 | return 0; 233 | } 234 | 235 | void HttpFlv::setStopFlag(bool flag) { 236 | stopFlag = false; 237 | } 238 | 239 | int HttpFlv::sendData() { 240 | int ret; 241 | AVReadPacket packet; 242 | ret = packet.init(dir, transportStreamPacketNumber); 243 | if (ret < 0) { 244 | log_error("packet.init 初始化失败"); 245 | return ret; 246 | } 247 | /*由外部http控制*/ 248 | while (stopFlag) { 249 | ret = packet.readFrame(package); 250 | if (ret < 0) { 251 | if (ret == AVERROR_EOF) { 252 | log_info("读取完毕"); 253 | break; 254 | } 255 | log_error("packet.readFrame 失败"); 256 | return -1; 257 | } 258 | if (package->type == "video") { 259 | ret = sendVideoData(); 260 | if (ret < 0) { 261 | log_error("sendVideoData 失败"); 262 | return ret; 263 | } 264 | } else if (package->type == "audio") { 265 | ret = sendAudioData(); 266 | if (ret < 0) { 267 | log_error("sendAudioData 失败"); 268 | return ret; 269 | } 270 | } 271 | 272 | } 273 | return 0; 274 | } 275 | 276 | int HttpFlv::sendAudioData() { 277 | 278 | int ret; 279 | constexpr int AAC_CONFIG_SIZE = 2; 280 | WriteStream ws(response, TAG_SIZE + TAG_HEADER_SIZE + AAC_CONFIG_SIZE); 281 | /*写入上个tag的大小*/ 282 | ws.writeMultiBit(32, previousTagSize); 283 | 284 | //FLVTagHeader tagHeader; 285 | tagHeader.setConfig(AUDIO, AAC_CONFIG_SIZE + package->size, package->pts); 286 | tagHeader.write(ws); 287 | 288 | 289 | audioTag.setConfig(1); 290 | audioTag.writeData(ws); 291 | 292 | /*先发送flv的壳子*/ 293 | ret = TcpSocket::sendData(clientSocket, response, (int) ws.bufferSize); 294 | if (ret < 0) { 295 | log_error("发送数据失败"); 296 | return ret; 297 | } 298 | /*在发送具体数据*/ 299 | ret = TcpSocket::sendData(clientSocket, package->data2, (int) package->size); 300 | if (ret < 0) { 301 | log_error("发送数据失败"); 302 | return ret; 303 | } 304 | 305 | previousTagSize = TAG_HEADER_SIZE + AAC_CONFIG_SIZE + package->size; 306 | 307 | return 0; 308 | } 309 | 310 | 311 | int HttpFlv::sendVideoData() { 312 | int ret; 313 | 314 | constexpr int AVC_CONFIG_SIZE = 5; 315 | WriteStream ws(response, TAG_SIZE + TAG_HEADER_SIZE + AVC_CONFIG_SIZE); 316 | /*写入上个tag的大小*/ 317 | ws.writeMultiBit(32, previousTagSize); 318 | 319 | //FLVTagHeader tagHeader; 320 | tagHeader.setConfig(VIDEO, AVC_CONFIG_SIZE + package->size + package->data1.size() * 4, package->dts); 321 | tagHeader.write(ws); 322 | 323 | 324 | videoTag.setConfig(package->idrFlag ? 1 : 2, AVC_NALU, (package->pts + (int) (package->fps * 2) - package->dts)); 325 | videoTag.writeData(ws); 326 | 327 | /*先发送flv的壳子*/ 328 | ret = TcpSocket::sendData(clientSocket, response, (int) ws.bufferSize); 329 | if (ret < 0) { 330 | log_error("发送数据失败"); 331 | return ret; 332 | } 333 | for (auto &frame: package->data1) { 334 | const uint32_t length = bswap_32(frame.nalUintSize); 335 | ret = TcpSocket::sendData(clientSocket, (uint8_t *) &length, 4); 336 | if (ret < 0) { 337 | log_error("发送数据失败"); 338 | return ret; 339 | } 340 | ret = TcpSocket::sendData(clientSocket, frame.data, (int) frame.nalUintSize); 341 | if (ret < 0) { 342 | log_error("发送数据失败"); 343 | return ret; 344 | } 345 | } 346 | 347 | previousTagSize = TAG_HEADER_SIZE + AVC_CONFIG_SIZE + package->size + package->data1.size() * 4; 348 | return 0; 349 | } 350 | 351 | HttpFlv::~HttpFlv() { 352 | AVReadPacket::freePacket(package); 353 | } 354 | -------------------------------------------------------------------------------- /src/protocol/httpFlv.h: -------------------------------------------------------------------------------- 1 |  2 | #ifndef MEDIASERVER_HTTPFLV_H 3 | #define MEDIASERVER_HTTPFLV_H 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include "socket/TcpSocket.h" 10 | #include "AVPacket/AVReadPacket.h" 11 | 12 | #include "flashVideo/FLVTagHeader.h" 13 | #include "flashVideo/FLVAudioTag.h" 14 | #include "flashVideo/FLVVideoTag.h" 15 | 16 | class HttpFlv { 17 | private: 18 | FLVTagHeader tagHeader; 19 | FLVAudioTag audioTag; 20 | FLVVideoTag videoTag; 21 | 22 | uint8_t response[2048]; 23 | AVPackage *package{nullptr}; 24 | int transportStreamPacketNumber{0}; 25 | std::string dir; 26 | SOCKET clientSocket; 27 | 28 | 29 | uint32_t previousTagSize{0}; 30 | 31 | bool stopFlag{true}; 32 | public: 33 | void setStopFlag(bool flag); 34 | 35 | int init(std::filesystem::path &path, SOCKET socket); 36 | 37 | int disposeFlv(); 38 | 39 | ~HttpFlv(); 40 | 41 | private: 42 | int sendHeader(); 43 | 44 | int sendMetadata(); 45 | 46 | int sendSequenceHeader(); 47 | 48 | int sendVideoSequenceHeader(AVReadPacket &packet); 49 | 50 | int sendAudioSequenceHeader(AVReadPacket &packet); 51 | 52 | int sendData(); 53 | 54 | int sendAudioData(); 55 | 56 | int sendVideoData(); 57 | }; 58 | 59 | 60 | #endif //MEDIASERVER_HTTPFLV_H 61 | -------------------------------------------------------------------------------- /src/protocol/httpHls.cpp: -------------------------------------------------------------------------------- 1 |  2 | #include "httpHls.h" 3 | #include 4 | #include 5 | 6 | 7 | int HttpHls::init(std::filesystem::path &_path, SOCKET socket) { 8 | 9 | if (_path.extension() == ".m3u8") { 10 | mimeType = "application/x-mpegurl"; 11 | } else if (_path.extension() == ".ts") { 12 | mimeType = "video/mp2t"; 13 | } 14 | if (!std::filesystem::exists(_path)) { 15 | fprintf(stderr, "找不到对应的文件 %ls\n", _path.c_str()); 16 | return -1; 17 | } 18 | path = _path.string(); 19 | clientSocket = socket; 20 | return 0; 21 | } 22 | 23 | int HttpHls::disposeHls() { 24 | 25 | int ret; 26 | std::ifstream fs(path, std::ios::binary | std::ios::ate); 27 | if (!fs.good()) { 28 | fprintf(stderr, "当前文件不可读 %s\n", ("." + path).c_str()); 29 | //responseData(500, "当前文件不可读"); 30 | return -1; 31 | } 32 | 33 | uint32_t size = fs.tellg(); 34 | fs.seekg(0, std::ios::beg); 35 | 36 | 37 | std::ostringstream oss; 38 | oss << "HTTP/1.1 200 OK\r\n"; 39 | oss << "Content-Length: " << size << "\r\n"; 40 | oss << "Content-Type: " << mimeType << "\r\n"; 41 | oss << "Connection: keep-alive\r\n"; 42 | oss << "\r\n"; 43 | oss << fs.rdbuf(); 44 | 45 | std::string res = oss.str(); 46 | ret = TcpSocket::sendData(clientSocket, reinterpret_cast(const_cast(res.c_str())), 47 | static_cast(res.size())); 48 | if (ret < 0) { 49 | fprintf(stderr, "发送数据失败\n"); 50 | return ret; 51 | } 52 | return 0; 53 | } 54 | 55 | 56 | -------------------------------------------------------------------------------- /src/protocol/httpHls.h: -------------------------------------------------------------------------------- 1 |  2 | #ifndef MEDIASERVER_HTTPHLS_H 3 | #define MEDIASERVER_HTTPHLS_H 4 | 5 | #include 6 | #include 7 | #include "socket/TcpSocket.h" 8 | 9 | class HttpHls { 10 | private: 11 | std::string mimeType; 12 | std::string path; 13 | SOCKET clientSocket; 14 | public: 15 | int init(std::filesystem::path &path, SOCKET socket); 16 | 17 | int disposeHls(); 18 | }; 19 | 20 | 21 | #endif //MEDIASERVER_HTTPHLS_H 22 | -------------------------------------------------------------------------------- /src/protocol/rtsp.h: -------------------------------------------------------------------------------- 1 |  2 | #ifndef RTSP_RTSP_H 3 | #define RTSP_RTSP_H 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include "socket/TcpSocket.h" 11 | 12 | 13 | struct SdpInfo { 14 | std::string version; 15 | std::map origin; 16 | std::string name; 17 | std::map timing; 18 | std::map media[2]; 19 | uint8_t spsData[50]; 20 | uint8_t spsSize{0}; 21 | uint8_t ppsData[50]; 22 | uint8_t ppsSize{0}; 23 | 24 | uint8_t audioObjectType{0}; 25 | uint8_t samplingFrequencyIndex{0}; 26 | uint8_t channelConfiguration{0}; 27 | }; 28 | 29 | 30 | class ReadStream; 31 | 32 | class Rtsp { 33 | 34 | public: 35 | bool stopFlag{true}; 36 | 37 | public: 38 | int init(SOCKET socket); 39 | 40 | int parseRtsp(std::string &msg, const std::string &data); 41 | 42 | ~Rtsp(); 43 | 44 | private: 45 | SdpInfo info; 46 | int transportStreamPacketNumber{0}; 47 | static char response[2048]; 48 | std::map obj; 49 | SOCKET clientSocket; 50 | 51 | std::thread *SendThread{nullptr}; 52 | 53 | uint8_t videoChannel{0}; 54 | uint8_t audioChannel{0}; 55 | 56 | std::string videoControl; 57 | std::string audioControl; 58 | 59 | /*这个是当前rtsp流生成的唯一id*/ 60 | std::string uniqueSession; 61 | 62 | bool stopSendFlag{true}; 63 | 64 | /*拉流用的*/ 65 | std::string dir; 66 | bool flag{false}; 67 | private: 68 | 69 | int receiveData(std::string &msg); 70 | 71 | int sendData(); 72 | 73 | static int parseSdp(const std::string &sdp, SdpInfo &sdpInfo); 74 | 75 | static int parseMediaLevel(int i, const std::vector &list, SdpInfo &sdpInfo); 76 | 77 | static int parseAACConfig(const std::string &config, SdpInfo &sdpInfo); 78 | 79 | 80 | int responseData(int status, const std::string &msg); 81 | 82 | }; 83 | 84 | 85 | #endif //RTSP_RTSP_H 86 | -------------------------------------------------------------------------------- /src/protocol/rtspReceiveData.cpp: -------------------------------------------------------------------------------- 1 |  2 | #include "rtspReceiveData.h" 3 | #include "log/logger.h" 4 | 5 | enum { 6 | /*多个nalu在一个rtp包*/ 7 | STAP_A = 24, 8 | /*单一时间聚合包*/ 9 | STAP_B = 25, 10 | /*多个时间聚合包 就是可以传输多个nalu,但是编码时间可能不一样*/ 11 | MTAP_16 = 26, 12 | /*多个时间聚合包 */ 13 | MTAP_24 = 27, 14 | /*一个nalu容纳不下,分包*/ 15 | FU_A = 28, 16 | /*第二种分包模式*/ 17 | FU_B = 29 18 | }; 19 | static constexpr uint8_t startCode[4] = {0, 0, 0, 1}; 20 | 21 | 22 | int RtspReceiveData::init(SOCKET socket, const std::string &path, uint8_t video, uint8_t audio) { 23 | int ret; 24 | /*要写入的目录,和从第几个写入*/ 25 | ret = packet.init(path, 0); 26 | if (ret < 0) { 27 | log_error("packet.init 失败"); 28 | return ret; 29 | } 30 | 31 | 32 | videoChannel = video; 33 | audioChannel = audio; 34 | clientSocket = socket; 35 | /*一个rtp包最大大小不会超过16个bit也就是65535*/ 36 | buffer = new uint8_t[65535]; 37 | 38 | 39 | return 0; 40 | } 41 | 42 | 43 | int RtspReceiveData::receiveData(const std::string &msg) { 44 | int ret; 45 | if (buffer == nullptr) { 46 | fprintf(stderr, "请初始化\n"); 47 | return -1; 48 | } 49 | 50 | memcpy(buffer, msg.c_str(), msg.length()); 51 | uint32_t bufferSize = msg.length(); 52 | 53 | uint8_t *rtpBuffer = nullptr; 54 | uint32_t rtpBufferSize = 0; 55 | 56 | int size = 0; 57 | 58 | while (true) { 59 | if (bufferSize < 4) { 60 | ret = TcpSocket::receive(clientSocket, (char *) buffer + bufferSize, size); 61 | if (ret < 0) { 62 | log_warn("TcpSocket::receive"); 63 | return ret; 64 | } 65 | bufferSize += size; 66 | /*这里跳过这个循环,因为有可能,还取不到四个字节数据*/ 67 | continue; 68 | } 69 | uint8_t magic = buffer[0]; 70 | if (magic != '$') { 71 | log_warn("推流断开连接,没找到分割"); 72 | return -1; 73 | } 74 | uint8_t channel = buffer[1]; 75 | /*这个rtp包剩余数据大小*/ 76 | uint16_t length = buffer[2] << 8 | buffer[3]; 77 | 78 | rtpBuffer = buffer + 4; 79 | rtpBufferSize = bufferSize - 4; 80 | while (true) { 81 | if (rtpBufferSize < length) { 82 | /*不够rtp包大小继续取数据,直到取到为止*/ 83 | ret = TcpSocket::receive(clientSocket, (char *) (rtpBuffer + rtpBufferSize), size); 84 | if (ret < 0) { 85 | log_warn("TcpSocket::receive"); 86 | return ret; 87 | } 88 | rtpBufferSize += size; 89 | } else { 90 | /*处理数据*/ 91 | ret = disposeRtpData(rtpBuffer, rtpBufferSize, channel, length); 92 | if (ret < 0) { 93 | log_error("处理rtp包失败"); 94 | return ret; 95 | } 96 | rtpBufferSize -= length; 97 | /*这里不用使用memmove,不会发生内存重叠*/ 98 | memcpy(buffer, rtpBuffer + length, rtpBufferSize); 99 | bufferSize = rtpBufferSize; 100 | break; 101 | } 102 | } 103 | } 104 | return 0; 105 | } 106 | 107 | 108 | int RtspReceiveData::disposeRtpData(uint8_t *rtpBuffer, uint32_t rtpBufferSize, uint8_t channel, uint16_t length) { 109 | int ret; 110 | if (channel == videoChannel) { 111 | ReadStream rs(rtpBuffer, rtpBufferSize); 112 | /*获取rtp header*/ 113 | ret = getRtpHeader(rs); 114 | if (ret < 0) { 115 | return ret; 116 | } 117 | length -= 12; 118 | 119 | 120 | uint8_t forbidden_zero_bit = rs.readMultiBit(1); 121 | uint8_t nal_ref_idc = rs.readMultiBit(2); 122 | uint8_t nal_unit_type = rs.readMultiBit(5); 123 | length -= 1; 124 | if (nal_unit_type == STAP_A) { 125 | printf("STAP_A\n"); 126 | return -1; 127 | } else if (nal_unit_type == STAP_B) { 128 | printf("STAP_B\n"); 129 | return -1; 130 | } else if (nal_unit_type == MTAP_16) { 131 | printf("MTAP_16\n"); 132 | return -1; 133 | } else if (nal_unit_type == MTAP_24) { 134 | printf("MTAP_24\n"); 135 | return -1; 136 | } else if (nal_unit_type == FU_A) { 137 | /**/ 138 | uint8_t start = rs.readMultiBit(1); 139 | uint8_t end = rs.readMultiBit(1); 140 | /*reserved = 0*/ 141 | rs.readMultiBit(1); 142 | 143 | nal_unit_type = rs.readMultiBit(5); 144 | length -= 1; 145 | 146 | 147 | if (start == 1 && end == 0) { 148 | 149 | /*这里手动给nalu加上起始码,固定0001*/ 150 | 151 | uint8_t *ptr = rs.currentPtr - 5; 152 | memcpy(ptr, startCode, 4); 153 | *(ptr + 4) = forbidden_zero_bit << 7 | (nal_ref_idc << 5) | nal_unit_type; 154 | ret = packet.writeFrame(ptr, length + 5, "video", false); 155 | if (ret < 0) { 156 | log_error("packet.writeFrame失败"); 157 | return ret; 158 | } 159 | 160 | } else if (start == 0 && end == 0) { 161 | 162 | ret = packet.writeFrame(rs.currentPtr, length, "video", false); 163 | if (ret < 0) { 164 | log_error("packet.writeFrame失败"); 165 | return ret; 166 | } 167 | } else if (start == 0 && end == 1) { 168 | ret = packet.writeFrame(rs.currentPtr, length, "video", true); 169 | if (ret < 0) { 170 | log_error("packet.writeFrame失败"); 171 | return ret; 172 | } 173 | 174 | } else { 175 | fprintf(stderr, "start = %d 和 end = %d 有问题\n", start, end); 176 | return -1; 177 | } 178 | } else if (nal_unit_type == FU_B) { 179 | printf("FU_B\n"); 180 | return -1; 181 | } else { 182 | uint8_t *ptr = rs.currentPtr - 5; 183 | memcpy(ptr, startCode, 4); 184 | *(ptr + 4) = forbidden_zero_bit << 7 | (nal_ref_idc << 5) | nal_unit_type; 185 | 186 | ret = packet.writeFrame(ptr, length + 5, "video", true); 187 | if (ret < 0) { 188 | log_error("packet.writeFrame失败"); 189 | return ret; 190 | } 191 | 192 | } 193 | } else if (channel == audioChannel) { 194 | // printf("audiochanggel\n"); 195 | ReadStream rs(rtpBuffer, rtpBufferSize); 196 | /*获取rtp header*/ 197 | ret = getRtpHeader(rs); 198 | if (ret < 0) { 199 | return ret; 200 | } 201 | 202 | uint16_t headerLength = rs.readMultiBit(16) / 16; 203 | 204 | std::vector sizeList; 205 | for (int i = 0; i < headerLength; ++i) { 206 | uint16_t sizeLength = rs.readMultiBit(13); 207 | uint8_t indexDelta = rs.readMultiBit(3); 208 | sizeList.push_back(sizeLength); 209 | } 210 | for (uint16_t size: sizeList) { 211 | ret = packet.writeFrame(rs.currentPtr - 7, size + 7, "audio", true); 212 | if (ret < 0) { 213 | log_error("packet.writeFrame失败"); 214 | return ret; 215 | } 216 | rs.setBytePtr(size); 217 | } 218 | 219 | } else { 220 | printf("rtcp channel = %d\n", channel); 221 | } 222 | 223 | return 0; 224 | } 225 | 226 | int RtspReceiveData::getRtpHeader(ReadStream &rs) { 227 | version = rs.readMultiBit(2); 228 | padding = rs.readMultiBit(1); 229 | extension = rs.readMultiBit(1); 230 | if (extension) { 231 | fprintf(stderr, "不支持扩展包头\n"); 232 | return -1; 233 | } 234 | csrcLen = rs.readMultiBit(4); 235 | marker = rs.readMultiBit(1); 236 | payloadType = rs.readMultiBit(7); 237 | seq = rs.readMultiBit(16); 238 | timestamp = rs.readMultiBit(32); 239 | ssrc = rs.readMultiBit(32); 240 | return 0; 241 | } 242 | 243 | int RtspReceiveData::writeVideoData(uint8_t *data, uint8_t size) { 244 | return packet.setVideoParameter(data, size); 245 | 246 | } 247 | 248 | int 249 | RtspReceiveData::writeAudioData(uint8_t audioObjectType, uint8_t samplingFrequencyIndex, uint8_t channelConfiguration) { 250 | 251 | 252 | return packet.setAudioParameter(audioObjectType, samplingFrequencyIndex, channelConfiguration); 253 | } 254 | 255 | RtspReceiveData::~RtspReceiveData() { 256 | delete[] buffer; 257 | } 258 | -------------------------------------------------------------------------------- /src/protocol/rtspReceiveData.h: -------------------------------------------------------------------------------- 1 |  2 | #ifndef RTSP_RTSPRECEIVEDATA_H 3 | #define RTSP_RTSPRECEIVEDATA_H 4 | 5 | #include "socket/TcpSocket.h" 6 | #include "AVPacket/AVWritePacket.h" 7 | 8 | class RtspReceiveData { 9 | private: 10 | 11 | /* byte 0 */ 12 | /*数据源的个数(即源的个数),如果只有一个源那么此时的值为0*/ 13 | uint8_t csrcLen{0}; 14 | /*扩充位,如果设置为允许的话,固定头结构后面(即包的12个字节后面,有效负载的前面)紧跟着一个扩展头结构,该结构是已定义的一种格式*/ 15 | uint8_t extension{0}; 16 | 17 | /*如果P=1,则在该报文的尾部填充一个或多个额外的八位组,它们不是有效载荷的一部分 */ 18 | uint8_t padding{0}; 19 | /*版本号*/ 20 | uint8_t version{2}; 21 | 22 | /* byte 1 */ 23 | /*用于说明RTP报文中有效载荷的类型,如GSM音频、JPEM图像等,在流媒体中大部分是用来区分音频流和视频流的,这样便于客户端进行解析*/ 24 | uint8_t payloadType{0}; 25 | /*不同的有效载荷有不同的含义,对于视频,标记一帧的结束;对于音频,标记会话的开始*/ 26 | uint8_t marker{0}; 27 | 28 | /* bytes 2,3 */ 29 | /*用于标识发送者所发送的RTP报文的序列号,每发送一个报文,序列号增1。 30 | * 这个字段当下层的承载协议用UDP的时候,网络状况不好的时候可以用来检查丢包。 31 | * 同时出现网络抖动的情况可以用来对数据进行重新排序,序列号的初始值是随机的,同时音频包和视频包的sequence是分别记数的*/ 32 | uint16_t seq{0}; 33 | 34 | /* bytes 4-7 */ 35 | /*必须使用90 kHz 时钟频率。时戳反映了该RTP报文的第一个八位组的采样时刻。接收者使用时戳来计算延迟和延迟抖动,并进行同步控制*/ 36 | uint32_t timestamp{0}; 37 | 38 | /* bytes 8-11 */ 39 | /*用于标识同步信源。该标识符是随机选择的,参加同一视频会议的两个同步信源不能有相同的SSRC*/ 40 | uint32_t ssrc{0}; 41 | private: 42 | SOCKET clientSocket{0}; 43 | uint8_t videoChannel{0}; 44 | uint8_t audioChannel{0}; 45 | 46 | uint8_t *buffer{nullptr}; 47 | 48 | AVWritePacket packet; 49 | public: 50 | 51 | int init(SOCKET socket, const std::string &path, uint8_t video, uint8_t audio); 52 | 53 | int writeVideoData(uint8_t *data, uint8_t size); 54 | 55 | int writeAudioData(uint8_t audioObjectType, uint8_t samplingFrequencyIndex, uint8_t channelConfiguration); 56 | 57 | int receiveData(const std::string &msg); 58 | 59 | ~RtspReceiveData(); 60 | 61 | private: 62 | int getRtpHeader(ReadStream &rs); 63 | 64 | int disposeRtpData(uint8_t *rtpBuffer, uint32_t rtpBufferSize, uint8_t channel, uint16_t length); 65 | }; 66 | 67 | 68 | #endif //RTSP_RTSPRECEIVEDATA_H 69 | -------------------------------------------------------------------------------- /src/protocol/rtspSendData.cpp: -------------------------------------------------------------------------------- 1 |  2 | 3 | #include "rtspSendData.h" 4 | #include 5 | #include 6 | #include 7 | 8 | 9 | #define RTP_PAYLOAD_TYPE_H264 96 10 | #define RTP_PAYLOAD_TYPE_AAC 97 11 | 12 | #define RTP_MAX_PKT_SIZE 1400 13 | 14 | #define RTP_HEADER_SIZE 12 15 | 16 | /*const char *_ip, uint16_t _port,*/ 17 | int RtpPacket::init() { 18 | /*ip = _ip; 19 | port = _port; 20 | addr.sin_family = AF_INET; 21 | addr.sin_port = htons(port); 22 | addr.sin_addr.s_addr = inet_addr(ip);*/ 23 | 24 | /*rtp头加上一帧的最大数据加上载荷数据*/ 25 | /*4是最大的AU头大小*/ 26 | // maxFrameRtpPacketSize = RTP_HEADER_SIZE + maxFrameSize + 4 + 2; 27 | /*4是tcp那个分隔符,2是video表示开始和结尾的标识,4是音频表示有多少个AAC数据的标识*/ 28 | maxFrameRtpPacketSize = RTP_HEADER_SIZE + RTP_MAX_PKT_SIZE + 4 + 2 + 4; 29 | /*提前分配内存,避免重新分配*/ 30 | frameBuffer = new uint8_t[maxFrameRtpPacketSize]; 31 | 32 | return 0; 33 | } 34 | 35 | 36 | int RtpPacket::writeHeader(WriteStream &ws) const { 37 | ws.writeMultiBit(2, version); 38 | ws.writeMultiBit(1, padding); 39 | ws.writeMultiBit(1, extension); 40 | ws.writeMultiBit(4, csrcLen); 41 | 42 | ws.writeMultiBit(1, marker); 43 | ws.writeMultiBit(7, payloadType); 44 | 45 | ws.writeMultiBit(16, seq); 46 | ws.writeMultiBit(32, timestamp); 47 | ws.writeMultiBit(32, ssrc); 48 | return 0; 49 | } 50 | 51 | int RtpPacket::writePayload(WriteStream &ws, uint8_t *data, uint32_t dataSize) { 52 | 53 | memcpy(ws.currentPtr, data, dataSize); 54 | ws.setBytePtr(dataSize); 55 | 56 | return 0; 57 | } 58 | 59 | int RtpPacket::sendVideoFrame(SOCKET clientSocket, uint8_t *data, uint32_t size, uint8_t flag, uint8_t channel) { 60 | 61 | int ret; 62 | 63 | payloadType = RTP_PAYLOAD_TYPE_H264; 64 | WriteStream ws(frameBuffer, maxFrameRtpPacketSize); 65 | 66 | 67 | /*Udp协议的MTU为1500,超过了会导致Udp分片传输,而分片的缺点是丢了一个片,整包数据就废弃了*/ 68 | if (size <= RTP_MAX_PKT_SIZE) { 69 | 70 | marker = flag; 71 | ws.writeMultiBit(8, '$'); 72 | ws.writeMultiBit(8, channel); 73 | ws.writeMultiBit(16, size + RTP_HEADER_SIZE); 74 | writeHeader(ws); 75 | writePayload(ws, data, size); 76 | ret = TcpSocket::sendData(clientSocket, frameBuffer, (int) ws.position); 77 | if (ret < 0) { 78 | fprintf(stderr, "发送失败\n"); 79 | return -1; 80 | } 81 | ++seq; 82 | } else { 83 | /*打 fu-a 包时,如果待拆分的 nalu 是 nalu stream 的最后一个 nalu,且 fu-a header end 位置 1 时,才能标识 marker*/ 84 | /*先设置为0,不管这个nalu是不是一帧的最后一个*/ 85 | marker = 0; 86 | /*分片封包方式*/ 87 | /*28 FU-A 分片的单元*/ 88 | const uint8_t nalUintHeader = data[0]; 89 | /*这个nalu分成了几包 RTP_MAX_PKT_SIZE大小*/ 90 | uint32_t pktNum = (size - 1) / RTP_MAX_PKT_SIZE; 91 | // 剩余不完整包的大小 92 | uint32_t remainPktSize = (size - 1) % RTP_MAX_PKT_SIZE; 93 | 94 | /* 95 | * 如果使用UDP协议,当IP层组包发生错误,那么包就会被丢弃,接收方无法重组数据报,将导致丢弃整个IP数据报 96 | * 相当于如果丢了一个包,或者错误,那么整个upd的数据报都会丢失,所以要控制数据大小,尽量不要分包 97 | * */ 98 | 99 | /*跳过nalUintHeader 1字节*/ 100 | uint32_t pos = 1; 101 | 102 | for (int i = 0; i < pktNum; ++i) { 103 | 104 | uint8_t FU_indicator = nalUintHeader & 0xE0 | 28; 105 | uint8_t FU_header = nalUintHeader & 0x1F; 106 | 107 | if (i == 0) { 108 | /*第一个包*/ 109 | FU_header = FU_header | 0x80; 110 | } else if (remainPktSize == 0 && i == pktNum - 1) { 111 | /*最后一包,因为有可能刚好整除,整除remainPktSize=0*/ 112 | FU_header = FU_header | 0x40; 113 | marker = flag; 114 | } 115 | 116 | ws.reset(); 117 | ws.writeMultiBit(8, '$'); 118 | ws.writeMultiBit(8, 0); 119 | ws.writeMultiBit(16, RTP_MAX_PKT_SIZE + 2 + RTP_HEADER_SIZE); 120 | 121 | writeHeader(ws); 122 | ws.writeMultiBit(8, FU_indicator); 123 | ws.writeMultiBit(8, FU_header); 124 | 125 | writePayload(ws, data + pos, RTP_MAX_PKT_SIZE); 126 | 127 | 128 | ret = TcpSocket::sendData(clientSocket, frameBuffer, (int) ws.position); 129 | if (ret < 0) { 130 | fprintf(stderr, "发送失败\n"); 131 | return -1; 132 | } 133 | ++seq; 134 | pos += RTP_MAX_PKT_SIZE; 135 | } 136 | 137 | 138 | /*发送剩余数据,不足RTP_MAX_PKT_SIZE大的*/ 139 | if (remainPktSize > 0) { 140 | ws.reset(); 141 | marker = flag; 142 | ws.writeMultiBit(8, '$'); 143 | ws.writeMultiBit(8, 0); 144 | ws.writeMultiBit(16, remainPktSize + 2 + RTP_HEADER_SIZE); 145 | 146 | writeHeader(ws); 147 | 148 | uint8_t FU_indicator = nalUintHeader & 0xE0 | 28; 149 | 150 | uint8_t FU_header = nalUintHeader & 0x1F | 0x40; 151 | 152 | ws.writeMultiBit(8, FU_indicator); 153 | ws.writeMultiBit(8, FU_header); 154 | 155 | writePayload(ws, data + pos, remainPktSize); 156 | 157 | ret = TcpSocket::sendData(clientSocket, frameBuffer, (int) ws.position); 158 | if (ret < 0) { 159 | fprintf(stderr, "发送失败\n"); 160 | return -1; 161 | } 162 | ++seq; 163 | } 164 | 165 | } 166 | 167 | 168 | return 0; 169 | } 170 | 171 | int RtpPacket::sendAudioPacket(SOCKET clientSocket, uint8_t *data, uint32_t size, uint8_t channel) { 172 | 173 | int ret; 174 | payloadType = RTP_PAYLOAD_TYPE_AAC; 175 | marker = 1; 176 | WriteStream ws(frameBuffer, maxFrameRtpPacketSize); 177 | ws.writeMultiBit(8, '$'); 178 | ws.writeMultiBit(8, channel); 179 | ws.writeMultiBit(16, size + RTP_HEADER_SIZE + 4); 180 | /*这里写入的rtp头,就是12字节那个*/ 181 | writeHeader(ws); 182 | /*4个字节AU头*/ 183 | /* 184 | * 头两个字节表示au-header的长度,单位是bit 185 | * 一个AU-header长度是两个字节(16bit)因为可以有多个au-header, 186 | * 所以AU-headers-length的值是 16的倍数, 187 | * 一般音频都是单个音频数据流的发送,所以AU-headers-length的值是16 188 | * */ 189 | ws.writeMultiBit(16, 16); 190 | 191 | /*13个bit存放数据大小*/ 192 | ws.writeMultiBit(13, size); 193 | ws.writeMultiBit(3, 0); 194 | 195 | 196 | writePayload(ws, data, size); 197 | 198 | 199 | ret = TcpSocket::sendData(clientSocket, frameBuffer, (int) ws.position); 200 | if (ret < 0) { 201 | fprintf(stderr, "发送失败\n"); 202 | return ret; 203 | } 204 | ++seq; 205 | return 0; 206 | } 207 | 208 | RtpPacket::~RtpPacket() { 209 | 210 | delete[] frameBuffer; 211 | 212 | } 213 | -------------------------------------------------------------------------------- /src/protocol/rtspSendData.h: -------------------------------------------------------------------------------- 1 |  2 | #ifndef RTSP_RTSPSENDDATA_H 3 | #define RTSP_RTSPSENDDATA_H 4 | 5 | #include 6 | #include "bitStream/writeStream.h" 7 | #include "socket/TcpSocket.h" 8 | 9 | 10 | class RtpPacket { 11 | public: 12 | /* byte 0 */ 13 | /*数据源的个数(即源的个数),如果只有一个源那么此时的值为0*/ 14 | uint8_t csrcLen{0}; 15 | /*扩充位,如果设置为允许的话,固定头结构后面(即包的12个字节后面,有效负载的前面)紧跟着一个扩展头结构,该结构是已定义的一种格式*/ 16 | uint8_t extension{0}; 17 | 18 | /*如果P=1,则在该报文的尾部填充一个或多个额外的八位组,它们不是有效载荷的一部分 */ 19 | uint8_t padding{0}; 20 | /*版本号*/ 21 | uint8_t version{2}; 22 | 23 | /* byte 1 */ 24 | /*用于说明RTP报文中有效载荷的类型,如GSM音频、JPEM图像等,在流媒体中大部分是用来区分音频流和视频流的,这样便于客户端进行解析*/ 25 | uint8_t payloadType{0}; 26 | /*不同的有效载荷有不同的含义,对于视频,标记一帧的结束;对于音频,标记会话的开始*/ 27 | uint8_t marker{0}; 28 | 29 | /* bytes 2,3 */ 30 | /*用于标识发送者所发送的RTP报文的序列号,每发送一个报文,序列号增1。 31 | * 这个字段当下层的承载协议用UDP的时候,网络状况不好的时候可以用来检查丢包。 32 | * 同时出现网络抖动的情况可以用来对数据进行重新排序,序列号的初始值是随机的,同时音频包和视频包的sequence是分别记数的*/ 33 | uint16_t seq{0}; 34 | 35 | /* bytes 4-7 */ 36 | /*必须使用90 kHz 时钟频率。时戳反映了该RTP报文的第一个八位组的采样时刻。接收者使用时戳来计算延迟和延迟抖动,并进行同步控制*/ 37 | uint32_t timestamp{0}; 38 | 39 | /* bytes 8-11 */ 40 | /*用于标识同步信源。该标识符是随机选择的,参加同一视频会议的两个同步信源不能有相同的SSRC*/ 41 | uint32_t ssrc{0x12345678}; 42 | 43 | 44 | private: 45 | /* sockaddr_in addr{}; 46 | const char *ip{""}; 47 | uint16_t port{0};*/ 48 | 49 | 50 | uint8_t *frameBuffer{nullptr}; 51 | uint32_t maxFrameRtpPacketSize{0}; 52 | public: 53 | /*const char *ip, uint16_t port, */ 54 | int init(); 55 | 56 | int sendVideoFrame(SOCKET clientSocket, uint8_t *data, uint32_t size, uint8_t flag, uint8_t channel); 57 | 58 | int sendAudioPacket(SOCKET clientSocket, uint8_t *data, uint32_t size, uint8_t channel); 59 | 60 | ~RtpPacket(); 61 | 62 | private: 63 | /*int sendPacket(SOCKET socket, uint8_t *buffer, int bufferSize);*/ 64 | 65 | int writeHeader(WriteStream &ws) const; 66 | 67 | static int writePayload(WriteStream &ws, uint8_t *data, uint32_t dataSize); 68 | 69 | }; 70 | 71 | 72 | #endif //RTSP_RTSPSENDDATA_H 73 | -------------------------------------------------------------------------------- /src/server/CMakeLists.txt: -------------------------------------------------------------------------------- 1 |  2 | 3 | add_library(server server.cpp) 4 | 5 | target_include_directories(server PRIVATE ${PROJECT_SOURCE_DIR}/src) 6 | 7 | target_link_libraries(server PRIVATE log socket threadPool PRIVATE $<$:pthread>) 8 | 9 | 10 | -------------------------------------------------------------------------------- /src/server/server.cpp: -------------------------------------------------------------------------------- 1 | #include "server.h" 2 | 3 | #include "threadPool/rtspTask.h" 4 | #include "threadPool/httpTask.h" 5 | #include "log/logger.h" 6 | 7 | int Server::init(int rtspPort, int httpPort) { 8 | int ret; 9 | #if _WIN32 10 | /*windows 需要初始化socket库*/ 11 | static WSADATA wsadata; 12 | WSAStartup(MAKEWORD(2, 2), &wsadata); 13 | #endif 14 | Logger::getInstance()->setLevel(LOG_TRACE); 15 | 16 | pool.init(20); 17 | pool.start(); 18 | 19 | rtsp.createSocket(); 20 | ret = rtsp.bindSocket("0.0.0.0", rtspPort); 21 | if (ret < 0) { 22 | return -1; 23 | } 24 | 25 | rtsp.listenPort(); 26 | log_info("启动RTSP,监听%d端口", rtspPort); 27 | 28 | http.createSocket(); 29 | ret = http.bindSocket("0.0.0.0", httpPort); 30 | if (ret < 0) { 31 | return -1; 32 | } 33 | http.listenPort(); 34 | log_info("启动HTTP,监听%d端口", httpPort); 35 | return 0; 36 | } 37 | 38 | int Server::start() { 39 | int ret; 40 | 41 | 42 | /*std::thread rtspThread(&Server::startRtspServer, this); 43 | rtspThread.detach(); 44 | std::thread httpThread(&Server::startHttpServer, this); 45 | httpThread.detach();*/ 46 | 47 | rtspThread = new std::thread(&Server::startRtspServer, this); 48 | httpThread = new std::thread(&Server::startHttpServer, this); 49 | return 0; 50 | } 51 | 52 | int Server::startRtspServer() { 53 | while (true) { 54 | SOCKET clientSocket = rtsp.acceptClient(); 55 | if (clientSocket < 0) { 56 | log_error("rtsp accept 失败"); 57 | return -1; 58 | } 59 | log_info("rtsp 连接 ip=%s, port=%d", rtsp.clientIp, rtsp.clientPort); 60 | RtspTask *task = new RtspTask(clientSocket); // NOLINT(modernize-use-auto) 61 | pool.addTask(task); 62 | 63 | } 64 | return 0; 65 | } 66 | 67 | int Server::startHttpServer() { 68 | while (true) { 69 | SOCKET clientSocket = http.acceptClient(); 70 | if (clientSocket < 0) { 71 | log_error("http accept 失败"); 72 | return -1; 73 | } 74 | log_info("http 连接 ip=%s, port=%d", http.clientIp, http.clientPort); 75 | HttpTask *task = new HttpTask(clientSocket); // NOLINT(modernize-use-auto) 76 | pool.addTask(task); 77 | 78 | } 79 | 80 | return 0; 81 | } 82 | 83 | 84 | Server::~Server() { 85 | 86 | 87 | if (rtspThread->joinable()) { 88 | rtspThread->join(); 89 | delete rtspThread; 90 | } 91 | if (httpThread->joinable()) { 92 | httpThread->join(); 93 | delete httpThread; 94 | } 95 | pool.stop(); 96 | 97 | } 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | -------------------------------------------------------------------------------- /src/server/server.h: -------------------------------------------------------------------------------- 1 |  2 | #ifndef RTSP_SERVER_H 3 | #define RTSP_SERVER_H 4 | 5 | #include 6 | #include "socket/TcpSocket.h" 7 | #include "threadPool/threadPool.h" 8 | 9 | 10 | class Server { 11 | private: 12 | std::thread *rtspThread; 13 | std::thread *httpThread; 14 | TcpSocket rtsp; 15 | TcpSocket http; 16 | 17 | 18 | ThreadPool pool; 19 | public: 20 | int init(int rtspPort, int httpPort); 21 | 22 | int start(); 23 | 24 | ~Server(); 25 | 26 | private: 27 | 28 | int startRtspServer(); 29 | 30 | int startHttpServer(); 31 | 32 | 33 | }; 34 | 35 | 36 | #endif //RTSP_SERVER_H 37 | -------------------------------------------------------------------------------- /src/socket/CMakeLists.txt: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | add_library(socket TcpSocket.cpp UdpSocket.cpp) 5 | target_include_directories(socket PRIVATE ${PROJECT_SOURCE_DIR}/src) 6 | 7 | if (WIN32) 8 | target_link_libraries(socket PRIVATE $<$:ws2_32.lib> log) 9 | endif () 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/socket/Socket.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifdef _WIN32 4 | #include 5 | #pragma comment(lib, "ws2_32.lib") 6 | #endif 7 | 8 | #if defined(__linux__) || defined(__APPLE__) 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #define SOCKET int 17 | 18 | #endif -------------------------------------------------------------------------------- /src/socket/TcpSocket.cpp: -------------------------------------------------------------------------------- 1 |  2 | #include "TcpSocket.h" 3 | #include 4 | #include 5 | #include "log/logger.h" 6 | 7 | 8 | int TcpSocket::createSocket() { 9 | /* 10 | 参数1:一个地址描述,即地址类型,我们选择 IPv4(AF_INET) 11 | 参数2:指定socket类型,我们选择流式套接字(SOCK_STREAM) 12 | 参数3:指定socket所用的协议,当然是 TCP 协议了(IPPROTO_TCP) 13 | */ 14 | /* 15 | 流格式套接字(Stream Sockets)也叫“面向连接的套接字”,在代码中使用 SOCK_STREAM 表示。 16 | SOCK_STREAM 是一种可靠的、双向的通信数据流,数据可以准确无误地到达另一台计算机,如果损坏或丢失,可以重新发送 17 | */ 18 | 19 | /*获取 socket 描述符*/ 20 | serverSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 21 | if (serverSocket < 0) 22 | return -1; 23 | /* 24 | * SO_REUSEADDR,打开或关闭地址复用功能 25 | * 某一端主动关闭会进入一个TIME_WAIT状态,这个时候不能复用这个端口 26 | * */ 27 | bool on = true; 28 | setsockopt(serverSocket, SOL_SOCKET, SO_REUSEADDR, (const char *) &on, sizeof(on)); 29 | 30 | return 0; 31 | } 32 | 33 | 34 | int TcpSocket::bindSocket(const char *ip, int port) const { 35 | sockaddr_in addr{}; 36 | /*地址描述*/ 37 | addr.sin_family = AF_INET; 38 | /*端口信息 需要将 “主机字节顺序” 转换到 “网络字节顺序” ,而 htons () 函数就是用来做这种事情的*/ 39 | addr.sin_port = htons(port); 40 | /*inet_addr () 则是将 “十进制点分ip” 转换为一个符合结构体格式的整数,而其转换后即为 “网络字节顺序”*/ 41 | addr.sin_addr.s_addr = inet_addr(ip); 42 | /* 43 | inet_addr() 将 十进制点分ip 转换为 网络字节顺序 44 | inet_ntoa() 将 网络字节顺序 转换为 十进制点分ip 45 | 46 | htons() 将 short 主机字节顺序 转换为 网络字节顺序 47 | ntohs() 将 short 网络字节顺序 转换为 主机字节顺序 48 | 49 | ntohl()将 long 主机字节顺序 转换为 网络字节顺序 50 | htonl()将 long 网络字节顺序 转换为 主机字节顺序 51 | */ 52 | 53 | /* 54 | 参数1:socket 描述符 55 | 参数2:一个结构体,包含服务端的 IP 地址及端口信息 56 | 参数3:第二个参数的长度 57 | */ 58 | int ret = bind(serverSocket, (sockaddr *) &addr, sizeof(sockaddr)); 59 | if (ret < 0) { 60 | fprintf(stderr, "绑定失败"); 61 | return -1; 62 | } 63 | return 0; 64 | } 65 | 66 | int TcpSocket::listenPort(int backlog) const { 67 | 68 | /* 69 | 这时候我们需要调用 listen (),对我们刚才对结构体赋值的时候填上去的端口进行监听。 70 | 首先说明白,这个函数的意义是开始监听,开始监听后该函数将直接返回,而不是监听直到用户进入*/ 71 | /* 72 | 参数1:socket 描述符 73 | 参数2:进入队列中允许的连接数目 74 | 参数2是进入队列即在你调用 accept() 同意客户接入之前的客户等待队列。 75 | 同一时间可能有很多客户端请求连接,若超出了服务端的处理速度,进入队列会很长, 76 | 那么多于你定义的队列长度的客户就会被 socket底层 直接忽略掉。 77 | */ 78 | int ret = listen(serverSocket, backlog); 79 | if (ret < 0) { 80 | fprintf(stderr, "监听失败\n"); 81 | return -1; 82 | } 83 | return 0; 84 | } 85 | 86 | 87 | SOCKET TcpSocket::acceptClient() { 88 | sockaddr_in addr{}; 89 | 90 | int len = sizeof(addr); 91 | /*接受客户的连接请求*/ 92 | SOCKET clientSocket = accept(serverSocket, (sockaddr *) &addr, (&len)); 93 | if (clientSocket < 0) 94 | return -1; 95 | 96 | /*inet_ntoa() 将 网络字节顺序 转换为 十进制点分ip*/ 97 | strcpy(clientIp, inet_ntoa(addr.sin_addr)); 98 | /*ntohs() 将 short 网络字节顺序 转换为 主机字节顺序*/ 99 | clientPort = ntohs(addr.sin_port); 100 | 101 | return clientSocket; 102 | } 103 | 104 | 105 | int TcpSocket::receive(SOCKET clientSocket, char *data, int &dataSize) { 106 | 107 | 108 | dataSize = recv(clientSocket, data, MAX_BUFFER, 0); 109 | /*这里返回0的话表示对端关闭了连接,发送了FIN包*/ 110 | if (dataSize == 0) { 111 | log_trace("客户端关闭了连接"); 112 | return -1; 113 | } 114 | if (dataSize < 0) { 115 | log_error("接收数据失败,ret = %d", dataSize); 116 | return -1; 117 | } 118 | return 0; 119 | } 120 | 121 | 122 | int TcpSocket::sendData(SOCKET clientSocket, uint8_t *buffer, int length) { 123 | 124 | int ret = send(clientSocket, reinterpret_cast(buffer), length, 0); 125 | if (ret < 0) { 126 | fprintf(stderr, "发送失败\n"); 127 | return ret; 128 | } 129 | return 0; 130 | } 131 | 132 | 133 | int TcpSocket::closeSocket(SOCKET clientSocket) { 134 | #if _WIN32 135 | closesocket(clientSocket); 136 | #else 137 | close(clientSocket); 138 | #endif 139 | return 0; 140 | } 141 | 142 | TcpSocket::~TcpSocket() { 143 | #if _WIN32 144 | closesocket(serverSocket); 145 | #else 146 | close(serverSocket); 147 | #endif 148 | } 149 | 150 | 151 | 152 | 153 | 154 | -------------------------------------------------------------------------------- /src/socket/TcpSocket.h: -------------------------------------------------------------------------------- 1 |  2 | 3 | #ifndef RTSP_TCPSOCKET_H 4 | #define RTSP_TCPSOCKET_H 5 | 6 | #include 7 | 8 | #include "Socket.h" 9 | 10 | class TcpSocket { 11 | public: 12 | SOCKET serverSocket{0}; 13 | /*SOCKET clientSocket{0};*/ 14 | char clientIp[40]{0}; 15 | int clientPort{0}; 16 | static constexpr int MAX_BUFFER = 1024; 17 | public: 18 | /*创建tcp套接字*/ 19 | int createSocket(); 20 | 21 | int bindSocket(const char *ip, int port) const; 22 | 23 | int listenPort(int backlog = 10) const; 24 | 25 | ~TcpSocket(); 26 | 27 | public: 28 | SOCKET acceptClient(); 29 | 30 | static int receive(SOCKET clientSocket, char *data, int &dataSize); 31 | 32 | static int sendData(SOCKET clientSocket, uint8_t *buffer, int length); 33 | 34 | static int closeSocket(SOCKET clientSocket); 35 | 36 | }; 37 | 38 | 39 | #endif //RTSP_TCPSOCKET_H 40 | -------------------------------------------------------------------------------- /src/socket/UdpSocket.cpp: -------------------------------------------------------------------------------- 1 |  2 | #include "UdpSocket.h" 3 | #include "log/logger.h" 4 | 5 | int UdpSocket::createSocket() { 6 | /* 7 | 参数1:一个地址描述,即地址类型,我们选择 IPv4(AF_INET) 8 | 参数2:指定socket类型,我们选择流式套接字(SOCK_STREAM) 9 | 参数3:指定socket所用的协议,当然是 TCP 协议了(IPPROTO_TCP) 10 | */ 11 | /* 12 | 流格式套接字(Stream Sockets)也叫“面向连接的套接字”,在代码中使用 SOCK_STREAM 表示。 13 | SOCK_STREAM 是一种可靠的、双向的通信数据流,数据可以准确无误地到达另一台计算机,如果损坏或丢失,可以重新发送 14 | */ 15 | 16 | /*获取 socket 描述符*/ 17 | sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); 18 | if (sock < 0) 19 | return -1; 20 | /* 21 | * SO_REUSEADDR,打开或关闭地址复用功能 22 | * 某一端主动关闭会进入一个TIME_WAIT状态,这个时候不能复用这个端口 23 | * */ 24 | bool on = true; 25 | setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const char *) &on, sizeof(on)); 26 | 27 | return 0; 28 | } 29 | 30 | int UdpSocket::bindSocket(const char *ip, int port) const { 31 | sockaddr_in addr{}; 32 | /*地址描述*/ 33 | addr.sin_family = AF_INET; 34 | /*端口信息 需要将 “主机字节顺序” 转换到 “网络字节顺序” ,而 htons () 函数就是用来做这种事情的*/ 35 | addr.sin_port = htons(port); 36 | /*inet_addr () 则是将 “十进制点分ip” 转换为一个符合结构体格式的整数,而其转换后即为 “网络字节顺序”*/ 37 | addr.sin_addr.s_addr = inet_addr(ip); 38 | /* 39 | inet_addr() 将 十进制点分ip 转换为 网络字节顺序 40 | inet_ntoa() 将 网络字节顺序 转换为 十进制点分ip 41 | 42 | htons() 将 short 主机字节顺序 转换为 网络字节顺序 43 | ntohs() 将 short 网络字节顺序 转换为 主机字节顺序 44 | 45 | ntohl()将 long 主机字节顺序 转换为 网络字节顺序 46 | htonl()将 long 网络字节顺序 转换为 主机字节顺序 47 | */ 48 | 49 | /* 50 | 参数1:socket 描述符 51 | 参数2:一个结构体,包含服务端的 IP 地址及端口信息 52 | 参数3:第二个参数的长度 53 | */ 54 | int ret = bind(sock, (sockaddr *) &addr, sizeof(sockaddr)); 55 | if (ret < 0) { 56 | log_error("绑定失败"); 57 | return -1; 58 | } 59 | return 0; 60 | } 61 | -------------------------------------------------------------------------------- /src/socket/UdpSocket.h: -------------------------------------------------------------------------------- 1 |  2 | #ifndef RTSP_UDPSOCKET_H 3 | #define RTSP_UDPSOCKET_H 4 | 5 | #include "Socket.h" 6 | 7 | class UdpSocket { 8 | public: 9 | SOCKET sock{0}; 10 | public: 11 | int createSocket(); 12 | 13 | int bindSocket(const char *ip, int port) const; 14 | }; 15 | 16 | 17 | #endif //RTSP_UDPSOCKET_H 18 | -------------------------------------------------------------------------------- /src/threadPool/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | add_library(threadPool threadPool.cpp task.cpp rtspTask.cpp httpTask.cpp) 5 | 6 | target_include_directories(threadPool 7 | PRIVATE ${PROJECT_SOURCE_DIR}/src 8 | ) 9 | target_link_libraries(threadPool 10 | PRIVATE socket log protocol 11 | ) 12 | -------------------------------------------------------------------------------- /src/threadPool/httpTask.cpp: -------------------------------------------------------------------------------- 1 | #include "httpTask.h" 2 | #include "protocol/http.h" 3 | #include "log/logger.h" 4 | 5 | 6 | HttpTask::HttpTask(SOCKET socket) : clientSocket(socket) { 7 | } 8 | 9 | int HttpTask::run() { 10 | 11 | int ret; 12 | 13 | Http http; 14 | http.init(clientSocket); 15 | 16 | 17 | std::string packet; 18 | char buffer[TcpSocket::MAX_BUFFER]{0}; 19 | int length = 0; 20 | 21 | while (http.stopFlag) { 22 | 23 | ret = TcpSocket::receive(clientSocket, buffer, length); 24 | if (ret < 0) { 25 | return ret; 26 | } 27 | 28 | // 将缓冲区中的数据添加到字符串对象中 29 | packet.append(buffer, length); 30 | // 查找分隔符在字符串中的位置 31 | std::string::size_type pos = packet.find("\r\n\r\n"); 32 | while (pos != std::string::npos) { 33 | // 截取出一个完整的数据包(不含分隔符) 34 | std::string data = packet.substr(0, pos); 35 | // 去掉已处理的部分(含分隔符) 36 | packet.erase(0, pos + 4); 37 | 38 | /*处理请求,接收客户端发过来的数据*/ 39 | ret = http.parse(packet, data); 40 | if (ret < 0) { 41 | fprintf(stderr, "http.parseRtsp失败\n"); 42 | return ret; 43 | } 44 | 45 | // 继续查找下一个分隔符位置 46 | pos = packet.find("\r\n\r\n"); 47 | } 48 | } 49 | 50 | return 0; 51 | } 52 | 53 | HttpTask::~HttpTask() { 54 | /*退出的时候关闭这个连接*/ 55 | TcpSocket::closeSocket(clientSocket); 56 | } 57 | -------------------------------------------------------------------------------- /src/threadPool/httpTask.h: -------------------------------------------------------------------------------- 1 |  2 | #ifndef RTSP_HTTPTASK_H 3 | #define RTSP_HTTPTASK_H 4 | 5 | #include "task.h" 6 | #include "socket/TcpSocket.h" 7 | 8 | class HttpTask : public Task { 9 | private: 10 | SOCKET clientSocket; 11 | public: 12 | explicit HttpTask(SOCKET socket); 13 | 14 | int run() override; 15 | 16 | ~HttpTask(); 17 | }; 18 | 19 | 20 | #endif //RTSP_HTTPTASK_H 21 | -------------------------------------------------------------------------------- /src/threadPool/rtspTask.cpp: -------------------------------------------------------------------------------- 1 |  2 | 3 | #include "rtspTask.h" 4 | #include "protocol/rtsp.h" 5 | #include "log/logger.h" 6 | 7 | int RtspTask::run() { 8 | int ret; 9 | 10 | Rtsp rtsp; 11 | ret = rtsp.init(clientSocket); 12 | if (ret < 0) { 13 | return ret; 14 | } 15 | 16 | char buffer[TcpSocket::MAX_BUFFER]{0}; 17 | int length = 0; 18 | std::string packet; 19 | 20 | while (rtsp.stopFlag) { 21 | /*length本次获取的数据大小*/ 22 | ret = TcpSocket::receive(clientSocket, buffer, length); 23 | if (ret < 0) { 24 | log_info("rtsp receive exit"); 25 | return ret; 26 | } 27 | 28 | 29 | // 将缓冲区中的数据添加到字符串对象中 30 | packet.append(buffer, length); 31 | // 查找分隔符在字符串中的位置 32 | std::string::size_type pos = packet.find("\r\n\r\n"); 33 | while (pos != std::string::npos) { 34 | // 截取出一个完整的数据包(不含分隔符) 35 | std::string data = packet.substr(0, pos); 36 | // 去掉已处理的部分(含分隔符) 37 | packet.erase(0, pos + 4); 38 | 39 | /*处理请求,接收客户端发过来的数据*/ 40 | ret = rtsp.parseRtsp(packet, data); 41 | if (ret < 0) { 42 | log_error("rtsp.parseRtsp失败"); 43 | return ret; 44 | } 45 | 46 | 47 | // 继续查找下一个分隔符位置 48 | pos = packet.find("\r\n\r\n"); 49 | } 50 | } 51 | 52 | return 0; 53 | } -------------------------------------------------------------------------------- /src/threadPool/rtspTask.h: -------------------------------------------------------------------------------- 1 |  2 | #ifndef RTSP_RTSPTASK_H 3 | #define RTSP_RTSPTASK_H 4 | 5 | 6 | #include "task.h" 7 | 8 | #include "socket/TcpSocket.h" 9 | 10 | 11 | class RtspTask : public Task { 12 | 13 | private: 14 | /* TcpSocket &rtsp;*/ 15 | SOCKET clientSocket{}; 16 | 17 | 18 | public: 19 | explicit RtspTask(SOCKET socket) : clientSocket(socket) { 20 | 21 | } 22 | 23 | /*多个不同请求 比如有rtsp 和 http*/ 24 | int run() override; 25 | 26 | ~RtspTask() override { 27 | /*退出的时候关闭这个连接*/ 28 | TcpSocket::closeSocket(clientSocket); 29 | } 30 | 31 | }; 32 | 33 | 34 | #endif //RTSP_RTSPTASK_H 35 | -------------------------------------------------------------------------------- /src/threadPool/task.cpp: -------------------------------------------------------------------------------- 1 | #include "task.h" 2 | 3 | void Task::setVal(int val) { 4 | promise.set_value(val); 5 | } 6 | 7 | int Task::getVal() { 8 | return promise.get_future().get(); 9 | } 10 | -------------------------------------------------------------------------------- /src/threadPool/task.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef THREAD_TASH_H 3 | #define THREAD_TASH_H 4 | 5 | #include 6 | 7 | class Task { 8 | public: 9 | virtual int run() = 0; 10 | 11 | void setVal(int val); 12 | 13 | int getVal(); 14 | 15 | virtual ~Task() = default; 16 | 17 | private: 18 | std::promise promise; 19 | }; 20 | 21 | #endif //THREAD_TASH_H 22 | -------------------------------------------------------------------------------- /src/threadPool/threadPool.cpp: -------------------------------------------------------------------------------- 1 | #include "threadPool.h" 2 | #include "task.h" 3 | 4 | int ThreadPool::init(int num) { 5 | threadNum = num; 6 | 7 | return 0; 8 | } 9 | 10 | 11 | int ThreadPool::start() { 12 | if (threadNum <= 0) { 13 | fprintf(stderr, "请初始化线程池\n"); 14 | return -1; 15 | } 16 | 17 | if (!threads.empty()) { 18 | fprintf(stderr, "已经初始化\n"); 19 | return -1; 20 | } 21 | 22 | for (int i = 0; i < threadNum; ++i) { 23 | threads.push_back(new std::thread(&ThreadPool::run, this)); 24 | } 25 | return 0; 26 | } 27 | 28 | 29 | 30 | int ThreadPool::addTask(Task *task) { 31 | std::unique_lock lock(mutex); 32 | 33 | tasks.push_back(task); 34 | 35 | /*唤醒一个线程去执行任务*/ 36 | cv.notify_one(); 37 | 38 | return 0; 39 | } 40 | 41 | void ThreadPool::run() { 42 | //这里所有线程都会去抢任务,抢到了就执行,抢不到就阻塞 43 | int ret = 0; 44 | while (!exitFlag) { 45 | Task *task = getTask(); 46 | if (!task) { 47 | continue; 48 | } 49 | 50 | //这里最好try一下,防止整个线程池崩溃 51 | //try { 52 | ret = task->run(); 53 | task->setVal(ret); 54 | 55 | 56 | delete task; 57 | // } catch (...) { 58 | // continue; 59 | // } 60 | } 61 | 62 | } 63 | 64 | Task *ThreadPool::getTask() { 65 | std::unique_lock lock(mutex); 66 | 67 | 68 | cv.wait(lock, [this] { 69 | return !exitFlag && !tasks.empty(); 70 | }); 71 | 72 | 73 | if (exitFlag) { 74 | return nullptr; 75 | } 76 | 77 | //防止多次通知 78 | if (tasks.empty()) { 79 | return nullptr; 80 | } 81 | 82 | Task *task = tasks.front(); 83 | tasks.pop_front(); 84 | return task; 85 | } 86 | 87 | void ThreadPool::stop() { 88 | 89 | exitFlag = true; 90 | 91 | cv.notify_all(); 92 | for (std::thread *th: threads) { 93 | th->join(); 94 | } 95 | } 96 | 97 | ThreadPool::~ThreadPool() { 98 | for (auto &th: threads) { 99 | delete th; 100 | } 101 | 102 | threads.clear(); 103 | } -------------------------------------------------------------------------------- /src/threadPool/threadPool.h: -------------------------------------------------------------------------------- 1 | #ifndef THREAD_THREADPOOL_H 2 | #define THREAD_THREADPOOL_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | class Task; 11 | 12 | class ThreadPool { 13 | public: 14 | //初始化线程池 15 | int init(int num); 16 | 17 | //启动线程 18 | int start(); 19 | 20 | int addTask(Task* task); 21 | 22 | Task* getTask(); 23 | 24 | void stop(); 25 | 26 | ~ThreadPool(); 27 | 28 | private: 29 | //入口函数 30 | void run(); 31 | 32 | int threadNum = 0; 33 | 34 | 35 | std::mutex mutex; 36 | std::vector threads; 37 | 38 | std::list tasks; 39 | std::condition_variable cv; 40 | 41 | 42 | bool exitFlag{false}; 43 | }; 44 | 45 | #endif //THREAD_THREADPOOL_H 46 | -------------------------------------------------------------------------------- /src/transportStream/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | add_library(transportStream OBJECT transportPacket.cpp demuxPacket.cpp SI.cpp PES.cpp) 7 | 8 | 9 | target_include_directories(transportStream 10 | PRIVATE ${PROJECT_SOURCE_DIR}/src 11 | ) 12 | target_link_libraries(transportStream PRIVATE bitStream log nalu adts) 13 | -------------------------------------------------------------------------------- /src/transportStream/PES.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "PES.h" 3 | #include "bitStream/writeStream.h" 4 | #include "bitStream/readStream.h" 5 | 6 | 7 | int PES::PES_packet(WriteStream *ws) const { 8 | ws->writeMultiBit(24, packet_start_code_prefix); 9 | 10 | ws->writeMultiBit(8, stream_id); 11 | /* 12 | * PES_packet_length顾名思义就是PES包的长度,但是注意,它是2个字节存储的,这意味着,最大只能表示65535, 13 | * 一旦视频帧很大,超过这个长度,怎么办,就把PES_packet_length置为0,这是ISO标准规定的。 14 | * 所以在解析的时候,不能以PES_packet_length为准,要参考payload_unit_start_indicator。 15 | */ 16 | ws->writeMultiBit(16, PES_packet_length); 17 | 18 | 19 | ws->writeMultiBit(2, 2); //'10' 20 | 21 | ws->writeMultiBit(2, PES_scrambling_control); 22 | ws->writeMultiBit(1, PES_priority); 23 | ws->writeMultiBit(1, data_alignment_indicator); 24 | ws->writeMultiBit(1, copyright); 25 | ws->writeMultiBit(1, original_or_copy); 26 | ws->writeMultiBit(2, PTS_DTS_flags); 27 | ws->writeMultiBit(1, ESCR_flag); 28 | ws->writeMultiBit(1, ES_rate_flag); 29 | ws->writeMultiBit(1, DSM_trick_mode_flag); 30 | ws->writeMultiBit(1, additional_copy_info_flag); 31 | ws->writeMultiBit(1, PES_CRC_flag); 32 | ws->writeMultiBit(1, PES_extension_flag); 33 | ws->writeMultiBit(8, PES_header_data_length); 34 | 35 | if (PTS_DTS_flags == 2) { 36 | ws->writeMultiBit(4, 2);//'0010' 37 | uint8_t pts32_30 = pts >> 30; 38 | ws->writeMultiBit(3, pts32_30); 39 | ws->writeMultiBit(1, 1); //mark bit 40 | uint16_t pts29_15 = pts >> 15 & 0x7FFF; 41 | ws->writeMultiBit(15, pts29_15); 42 | ws->writeMultiBit(1, 1); //mark bit 43 | uint16_t pts14_0 = pts & 0x7FFF; 44 | ws->writeMultiBit(15, pts14_0); 45 | ws->writeMultiBit(1, 1); //mark bit 46 | } 47 | 48 | if (PTS_DTS_flags == 3) { 49 | ws->writeMultiBit(4, 3);//'0011' 50 | uint8_t pts32_30 = pts >> 30; 51 | ws->writeMultiBit(3, pts32_30); 52 | ws->writeMultiBit(1, 1); //mark bit 53 | uint16_t pts29_15 = pts >> 15 & 0x7FFF; 54 | ws->writeMultiBit(15, pts29_15); 55 | ws->writeMultiBit(1, 1); //mark bit 56 | uint16_t pts14_0 = pts & 0x7FFF; 57 | ws->writeMultiBit(15, pts14_0); 58 | ws->writeMultiBit(1, 1); //mark bit 59 | 60 | 61 | ws->writeMultiBit(4, 1);//'0001' 62 | uint8_t dts32_30 = dts >> 30; 63 | ws->writeMultiBit(3, dts32_30); 64 | ws->writeMultiBit(1, 1); //mark bit 65 | uint16_t dts29_15 = dts >> 15 & 0x7FFF; 66 | ws->writeMultiBit(15, dts29_15); 67 | ws->writeMultiBit(1, 1); //mark bit 68 | uint16_t dts14_0 = dts & 0x7FFF; 69 | ws->writeMultiBit(15, dts14_0); 70 | ws->writeMultiBit(1, 1); //mark bit 71 | 72 | } 73 | 74 | 75 | return 0; 76 | } 77 | 78 | int PES::read_PES_packet(ReadStream &rs) { 79 | /*packet_start_code_prefix = rs.readMultiBit(24);*/ 80 | rs.setBytePtr(3); 81 | 82 | /*stream_id = rs.readMultiBit(8);*/ 83 | rs.setBytePtr(1); 84 | 85 | /*PES_packet_length = rs.readMultiBit(16);*/ 86 | rs.setBytePtr(2); 87 | 88 | rs.readMultiBit(2); 89 | /*PES_scrambling_control =*/ rs.readMultiBit(2); 90 | /*PES_priority =*/ rs.readMultiBit(1); 91 | /*data_alignment_indicator =*/ rs.readMultiBit(1); 92 | /*copyright =*/ rs.readMultiBit(1); 93 | /*original_or_copy =*/ rs.readMultiBit(1); 94 | uint8_t flags = rs.readMultiBit(2); 95 | /*ESCR_flag =*/ rs.readMultiBit(1); 96 | /*ES_rate_flag =*/ rs.readMultiBit(1); 97 | /*DSM_trick_mode_flag =*/ rs.readMultiBit(1); 98 | /*additional_copy_info_flag =*/ rs.readMultiBit(1); 99 | /*PES_CRC_flag =*/ rs.readMultiBit(1); 100 | /*PES_extension_flag =*/ rs.readMultiBit(1); 101 | uint8_t length = rs.readMultiBit(8); 102 | 103 | uint8_t N = length; 104 | if (flags == 2) { 105 | rs.readMultiBit(4); 106 | uint8_t pts32_30 = rs.readMultiBit(3); 107 | rs.readBit(); 108 | uint16_t pts29_15 = rs.readMultiBit(15); 109 | rs.readBit(); 110 | uint16_t pts14_0 = rs.readMultiBit(15); 111 | rs.readBit(); 112 | // pts = (pts32_30 << 30) | (pts29_15 << 15) | pts14_0; 113 | /*fprintf(stdout, "pts = %d\n", pts);*/ 114 | N -= 5; 115 | } 116 | 117 | if (flags == 3) { 118 | rs.readMultiBit(4); 119 | uint8_t pts32_30 = rs.readMultiBit(3); 120 | rs.readBit(); 121 | uint16_t pts29_15 = rs.readMultiBit(15); 122 | rs.readBit(); 123 | uint16_t pts14_0 = rs.readMultiBit(15); 124 | rs.readBit(); 125 | // pts = (pts32_30 << 30) | (pts29_15 << 15) | pts14_0; 126 | //fprintf(stdout, "pts = %d\n", pts); 127 | rs.readMultiBit(4); 128 | uint8_t dts32_30 = rs.readMultiBit(3); 129 | rs.readBit(); 130 | uint16_t dts29_15 = rs.readMultiBit(15); 131 | rs.readBit(); 132 | uint16_t dts14_0 = rs.readMultiBit(15); 133 | rs.readBit(); 134 | // dts = (dts32_30 << 30) | (dts29_15 << 15) | dts14_0; 135 | N -= 10; 136 | } 137 | rs.setBytePtr(N); 138 | 139 | /* } else if (stream_id == program_stream_map 140 | || stream_id == private_stream_2 141 | || stream_id == ECM_STREAM 142 | || stream_id == EMM_STREAM 143 | || stream_id == program_stream_directory 144 | || stream_id == DSMCC_stream 145 | || stream_id == E_STREAM) { 146 | fprintf(stderr, "stream_id = %d\n", stream_id); 147 | return -1; 148 | } else if (stream_id == padding_stream) { 149 | *//*剩下的填充字节*//* 150 | fprintf(stderr, "没有PES头,剩下的都是填充\n"); 151 | return 0; 152 | }*/ 153 | return 0; 154 | } 155 | 156 | int PES::set_PTS_DTS_flags(uint8_t flags, uint64_t _pts, uint64_t _dts) { 157 | if (flags == 2) { 158 | PES_header_data_length = 5; 159 | } else if (flags == 3) { 160 | PES_header_data_length = 10; 161 | } else { 162 | fprintf(stderr, "设置PTS_DTS_flags错误\n"); 163 | return -1; 164 | } 165 | pts = (_pts + 1500) * 90; 166 | dts = (_dts + 1400) * 90; 167 | PTS_DTS_flags = flags; 168 | return 0; 169 | } 170 | 171 | -------------------------------------------------------------------------------- /src/transportStream/PES.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef TS_PES_H 3 | #define TS_PES_H 4 | 5 | #include 6 | #include 7 | 8 | class WriteStream; 9 | 10 | class ReadStream; 11 | 12 | /*enum { 13 | program_stream_map = 0xBC, 14 | padding_stream = 0xBE, 15 | private_stream_2 = 0xBF, 16 | ECM_STREAM = 0xF0, 17 | EMM_STREAM = 0xF1, 18 | program_stream_directory = 0xFF, 19 | DSMCC_stream = 0xF2, 20 | E_STREAM = 0xF8 21 | };*/ 22 | 23 | class PES { 24 | private: 25 | uint32_t packet_start_code_prefix{0x000001}; 26 | uint8_t stream_id{0xE0}; 27 | uint16_t PES_packet_length{0}; 28 | 29 | /*0是不加扰*/ 30 | uint8_t PES_scrambling_control{0}; 31 | /*优先级,多路*/ 32 | uint8_t PES_priority{0}; 33 | /**/ 34 | uint8_t data_alignment_indicator{0}; 35 | /*此为1 比特字段。置于‘1’时,它指示相关PES 包有效载荷的素材依靠版权所保护*/ 36 | uint8_t copyright{0}; 37 | /*置于‘1’时,相关PES 包有效载荷的内容是原始的。置于‘0’时,它指示相关PES 包有效载荷的内容是复制的。*/ 38 | uint8_t original_or_copy{0}; 39 | /* 40 | * 当PTS_DTS_flags 字段设置为‘10’时,PES 包头中PTS 字段存在。当PTS_DTS_flags 字段设置为‘11’时,PES 包头中PTS 字段和DTS 字段均存在。 41 | * 当PTS_DTS_flags字段设置为‘00’时,PES 包头中既无任何PTS 字段也无任何DTS 字段存在。值‘01’禁用 42 | * */ 43 | uint8_t PTS_DTS_flags{0}; 44 | uint8_t ESCR_flag{0}; 45 | uint8_t ES_rate_flag{0}; 46 | uint8_t DSM_trick_mode_flag{0}; 47 | uint8_t additional_copy_info_flag{0}; 48 | uint8_t PES_CRC_flag{0}; 49 | uint8_t PES_extension_flag{0}; 50 | uint8_t PES_header_data_length{0}; 51 | 52 | 53 | uint64_t pts{0}; 54 | uint64_t dts{0}; 55 | public: 56 | int PES_packet(WriteStream *ws) const; 57 | 58 | static int read_PES_packet(ReadStream &rs) ; 59 | 60 | int set_PTS_DTS_flags(uint8_t flags, uint64_t pts, uint64_t dts); 61 | }; 62 | 63 | 64 | #endif //TS_PES_H 65 | -------------------------------------------------------------------------------- /src/transportStream/SI.cpp: -------------------------------------------------------------------------------- 1 | 2 | 3 | #include "SI.h" 4 | 5 | #include "bitStream/writeStream.h" 6 | 7 | /*具体参考mpeg-1 part1 table 2-34*/ 8 | #define AVC 0x1B 9 | #define AAC 0x0F 10 | 11 | uint32_t SI::table[256] = {0}; 12 | 13 | SI::SI() { 14 | makeTable(); 15 | } 16 | 17 | int SI::service_description_section(WriteStream *ws) { 18 | 19 | uint8_t *buffer = ws->currentPtr; 20 | ws->writeMultiBit(8, sdt.table_id); 21 | /*The section_syntax_indicator is a 1-bit field which shall be set to '1'.*/ 22 | ws->writeMultiBit(1, sdt.section_syntax_indicator); 23 | /*所有“reserved_future_use”位均应设置为“1”。*/ 24 | ws->writeMultiBit(1, 0x01); 25 | ws->writeMultiBit(2, 0x03); 26 | 27 | ws->writeMultiBit(12, sdt.section_length); 28 | ws->writeMultiBit(16, sdt.transport_stream_id); 29 | ws->writeMultiBit(2, 0x03); 30 | ws->writeMultiBit(5, sdt.version_number); 31 | ws->writeMultiBit(1, sdt.current_next_indicator); 32 | ws->writeMultiBit(8, sdt.section_number); 33 | ws->writeMultiBit(8, sdt.last_section_number); 34 | 35 | /*这个跟网络信息表相关*/ 36 | ws->writeMultiBit(16, sdt.original_network_id); 37 | ws->writeMultiBit(8, 0xFF); 38 | 39 | // for (int i = 0; i < rs.size - rs.position; ++i) { 40 | /* 41 | * 唯一标识TS中的一个业务,它与program_map_section中的program_number(参看PMT表结构)相同。 42 | * 但当业务类型为0x04时(即NVOD参考业务,service_id没有对应的program_number)。 43 | */ 44 | ws->writeMultiBit(16, sdt.service_id); 45 | ws->writeMultiBit(6, 0x3F); 46 | ws->writeMultiBit(1, sdt.EIT_schedule_flag); 47 | ws->writeMultiBit(1, sdt.EIT_present_following_flag); 48 | /*指示服务状态 4表示运行状态*/ 49 | ws->writeMultiBit(3, sdt.running_status); 50 | ws->writeMultiBit(1, sdt.free_CA_mode); 51 | 52 | ws->writeMultiBit(12, sdt.descriptors_loop_length); 53 | service_descriptor(ws); 54 | // } 55 | uint8_t size = ws->currentPtr - buffer; 56 | 57 | uint32_t CRC_32 = crc32Calculate(buffer, size); 58 | 59 | ws->writeMultiBit(32, CRC_32); 60 | return 0; 61 | } 62 | 63 | int SI::service_descriptor(WriteStream *ws) const { 64 | /*0x48表示service_descriptor 参见Table 12: Possible locations of descriptors*/ 65 | ws->writeMultiBit(8, sdt.descriptor_tag); 66 | ws->writeMultiBit(8, sdt.descriptor_length); 67 | /*参见Table 50: Service type coding,0x01表示数字电视服务*/ 68 | ws->writeMultiBit(8, sdt.service_type); 69 | 70 | 71 | /*服务提供者名称*/ 72 | ws->writeMultiBit(8, sdt.service_provider_name_length); 73 | ws->setString("xiaofeng", 8); 74 | 75 | /*服务名称*/ 76 | ws->writeMultiBit(8, sdt.service_name_length); 77 | ws->setString("Service01", 9); 78 | return 0; 79 | } 80 | 81 | int SI::program_association_section(WriteStream *ws) const { 82 | uint8_t *buffer = ws->currentPtr; 83 | 84 | ws->writeMultiBit(8, pat.table_id); 85 | ws->writeMultiBit(1, pat.section_syntax_indicator); 86 | ws->writeMultiBit(1, 0); 87 | ws->writeMultiBit(2, 3); 88 | /* 89 | * 这是一个12位的字段,前两位是'00'。 90 | * 其余10位指定section的字节数,从section_length字段后面开始,包括CRC。该字段的值不能超过1021 (0x3FD)。 91 | * */ 92 | ws->writeMultiBit(12, pat.section_length); 93 | /*该传输流的ID,区别于一个网络中其它多路复用的流。*/ 94 | ws->writeMultiBit(16, pat.transport_stream_id); 95 | ws->writeMultiBit(2, 3); 96 | /*5bits版本号码,标注当前节目的版本.这是个非常有用的参数,当检测到这个字段改变时,说明TS流中的节目已经变化 了,程序必须重新搜索节目*/ 97 | ws->writeMultiBit(5, pat.version_number); 98 | /*表是当前这个表有效,还是下一个表有效*/ 99 | ws->writeMultiBit(1, pat.current_next_indicator); 100 | /*分段的号码。PAT可能分为多段传输,第一段为00,以后每个分段加1,最多可能有256个分段*/ 101 | ws->writeMultiBit(8, pat.section_number); 102 | /* 103 | * 最后段号码(section_number和 last_section_number的功能是当PAT内容>184字节时, 104 | * PAT表会分成多个段(sections),解复用程序必须在全部接 收完成后再进行PAT的分析) 105 | * */ 106 | ws->writeMultiBit(8, pat.last_section_number); 107 | /* 108 | * Program_number是一个16位字段。它指定program_map_PID适用于的程序。 109 | * 当设置为0x0000时,下面的PID引用将是网络PID。 110 | * 对于所有其他情况,此字段的值是用户定义的。 111 | * 在程序关联表的一个版本中,该字段不得使用任何单一值超过一次。 112 | * */ 113 | ws->writeMultiBit(16, pat.program_number); 114 | ws->writeMultiBit(3, 7); 115 | /*定义program_map_PID 但是范围必须在0x0010 - 0x1FFE 以内,具体参考Table 2-3 – PID table*/ 116 | ws->writeMultiBit(13, pat.program_map_PID); 117 | uint8_t size = ws->currentPtr - buffer; 118 | 119 | uint32_t CRC_32 = crc32Calculate(buffer, size); 120 | 121 | 122 | /*本段的CRC校验值,一般是会忽略的*/ 123 | ws->writeMultiBit(32, CRC_32);//pat.CRC_32 124 | return 0; 125 | } 126 | 127 | /*如果 TS 流中包含多个节目,那么就会有多个 PMT 表*/ 128 | int SI::program_map_section(WriteStream *ws) const { 129 | uint8_t *buffer = ws->currentPtr; 130 | 131 | 132 | ws->writeMultiBit(8, pmt.table_id); 133 | ws->writeMultiBit(1, pmt.section_syntax_indicator); 134 | ws->writeMultiBit(1, 0); 135 | ws->writeMultiBit(2, 3); 136 | ws->writeMultiBit(12, pmt.section_length); 137 | 138 | 139 | /*频道号码,表示当前的PMT关联到的频道.换句话就是说,当前描述的是program_number频道的信息*/ 140 | ws->writeMultiBit(16, pat.program_number); 141 | ws->writeMultiBit(2, 3); 142 | /*版本号码,如果PMT内容有更新,则version_number会递增1通知解复用程序需要重新接收节目信息,否则 version_number是固定不变的*/ 143 | ws->writeMultiBit(5, pmt.version_number); 144 | 145 | ws->writeMultiBit(1, pmt.current_next_indicator); 146 | ws->writeMultiBit(8, pmt.section_number); 147 | ws->writeMultiBit(8, pmt.last_section_number); 148 | ws->writeMultiBit(3, 7); 149 | /*PCR(节目时钟参考)所在TS分组的PID,根据PID可以去搜索相应的TS分组,解出PCR信息*/ 150 | ws->writeMultiBit(13, pmt.PCR_PID);//256 151 | ws->writeMultiBit(4, 15); 152 | /*program_info_length*/ 153 | ws->writeMultiBit(12, 0); 154 | 155 | 156 | ws->writeMultiBit(8, AVC); 157 | ws->writeMultiBit(3, 7); 158 | ws->writeMultiBit(13, pmt.videoPid); 159 | ws->writeMultiBit(4, 15); 160 | /*ES_info_length*/ 161 | ws->writeMultiBit(12, 0); 162 | 163 | ws->writeMultiBit(8, AAC); 164 | ws->writeMultiBit(3, 7); 165 | ws->writeMultiBit(13, pmt.audioPid); 166 | ws->writeMultiBit(4, 15); 167 | /*ES_info_length*/ 168 | ws->writeMultiBit(12, 0); 169 | 170 | uint8_t size = ws->currentPtr - buffer; 171 | 172 | uint32_t CRC_32 = crc32Calculate(buffer, size); 173 | ws->writeMultiBit(32, CRC_32);//pmt.CRC_32 174 | 175 | return 0; 176 | } 177 | 178 | 179 | void SI::makeTable() { 180 | for (uint32_t i = 0; i < 256; i++) { 181 | uint32_t k = 0; 182 | for (uint32_t j = (i << 24) | 0x800000; j != 0x80000000; j <<= 1) { 183 | k = (k << 1) ^ (((k ^ j) & 0x80000000) ? 0x04c11db7 : 0); 184 | } 185 | table[i] = k; 186 | } 187 | } 188 | 189 | 190 | uint32_t SI::crc32Calculate(uint8_t *buffer, uint32_t size) { 191 | uint32_t crc32_reg = 0xFFFFFFFF; 192 | for (uint32_t i = 0; i < size; i++) { 193 | crc32_reg = (crc32_reg << 8) ^ table[((crc32_reg >> 24) ^ *buffer++) & 0xFF]; 194 | } 195 | return crc32_reg; 196 | } 197 | 198 | 199 | 200 | 201 | 202 | 203 | -------------------------------------------------------------------------------- /src/transportStream/SI.h: -------------------------------------------------------------------------------- 1 | 2 | 3 | #ifndef TS_SI_H 4 | #define TS_SI_H 5 | 6 | #include 7 | 8 | #define VIDEO_PID 256 9 | #define AUDIO_PID 257 10 | 11 | class WriteStream; 12 | 13 | enum { 14 | PROGRAM_ASSOCIATION_SECTION = 0x00, 15 | conditional_access_section = 0x01, 16 | PROGRAM_MAP_SECTION = 0x02, 17 | /*实际的网络*/ 18 | network_information_section = 0x40, 19 | /*其他网络*/ 20 | /*network_information_section_other = 0x41,*/ 21 | /*实际运输流*/ 22 | SERVICE_DESCRIPTION_SECTION = 0x42, 23 | /*其他运输流*/ 24 | /*service_description_section_other = 0x46,*/ 25 | BOUQUET_ASSOCIATION_SECTION = 0x4A, 26 | 27 | /*后面还有一些table_id对应的一些表,具体参考SI规范 Table 2: Allocation of table_id values*/ 28 | }; 29 | struct SDT { 30 | uint8_t table_id{SERVICE_DESCRIPTION_SECTION}; 31 | uint8_t section_syntax_indicator{1}; 32 | /*它指定section的字节数,从紧接着section_length字段开始,包括CRC*/ 33 | /*section_length不能超过1021,这样整个section的最大长度为1024字节。*/ 34 | uint16_t section_length{39}; 35 | uint16_t transport_stream_id{1}; 36 | uint8_t version_number{0}; 37 | uint8_t current_next_indicator{1}; 38 | uint8_t section_number{0}; 39 | uint8_t last_section_number{0}; 40 | uint16_t original_network_id{65281}; 41 | uint16_t service_id{1}; 42 | uint8_t EIT_schedule_flag{0}; 43 | uint8_t EIT_present_following_flag{0}; 44 | uint8_t running_status{4}; 45 | uint8_t free_CA_mode{0}; 46 | uint8_t descriptors_loop_length{22}; 47 | /*uint8_t CRC_32{0};*/ 48 | 49 | 50 | uint8_t descriptor_tag{0x48}; 51 | uint8_t descriptor_length{20}; 52 | uint8_t service_type{0x01}; 53 | uint8_t service_provider_name_length{8}; 54 | uint8_t service_name_length{9}; 55 | }; 56 | struct PAT { 57 | uint8_t table_id{PROGRAM_ASSOCIATION_SECTION}; 58 | uint8_t section_syntax_indicator{1}; 59 | /*它指定section的字节数,从紧接着section_length字段开始,包括CRC*/ 60 | /*section_length不能超过1021,这样整个section的最大长度为1024字节。*/ 61 | uint16_t section_length{13}; 62 | uint16_t transport_stream_id{1}; 63 | uint8_t version_number{0}; 64 | /*设置为1表示当前表可以用,为0当前表不可以用*/ 65 | uint8_t current_next_indicator{1}; 66 | uint8_t section_number{0}; 67 | uint8_t last_section_number{0}; 68 | 69 | uint16_t program_number{1}; 70 | uint16_t program_map_PID{4096}; 71 | 72 | /*uint32_t CRC_32{0};*/ 73 | }; 74 | 75 | struct PMT { 76 | uint8_t table_id{PROGRAM_MAP_SECTION}; 77 | uint8_t section_syntax_indicator{1}; 78 | uint16_t section_length{23}; 79 | uint8_t version_number{0}; 80 | uint8_t current_next_indicator{1}; 81 | uint8_t section_number{0}; 82 | uint8_t last_section_number{0}; 83 | uint16_t PCR_PID{VIDEO_PID};/*0x1FFF*/ 84 | 85 | uint16_t videoPid{VIDEO_PID}; 86 | uint16_t audioPid{AUDIO_PID}; 87 | /*uint32_t CRC_32{0};*/ 88 | 89 | 90 | }; 91 | 92 | class SI { 93 | public: 94 | PAT pat; 95 | SDT sdt; 96 | PMT pmt; 97 | 98 | public: 99 | SI(); 100 | 101 | int program_association_section(WriteStream *ws) const; 102 | 103 | int program_map_section(WriteStream *ws) const; 104 | 105 | int service_description_section(WriteStream *ws); 106 | 107 | 108 | private: 109 | 110 | 111 | int service_descriptor(WriteStream *ws) const; 112 | 113 | static uint32_t table[256]; 114 | 115 | static void makeTable(); 116 | 117 | static uint32_t crc32Calculate(uint8_t *buffer, uint32_t size); 118 | }; 119 | 120 | 121 | #endif //TS_SI_H 122 | -------------------------------------------------------------------------------- /src/transportStream/demuxPacket.cpp: -------------------------------------------------------------------------------- 1 | #include "demuxPacket.h" 2 | #include "PES.h" 3 | #include 4 | #include 5 | 6 | 7 | int DemuxPacket::readFrame(ReadStream &rs) { 8 | int ret; 9 | sync_byte = rs.readMultiBit(8); 10 | transport_error_indicator = rs.readMultiBit(1); 11 | payload_unit_start_indicator = rs.readMultiBit(1); 12 | transport_priority = rs.readMultiBit(1); 13 | PID = rs.readMultiBit(13); 14 | transport_scrambling_control = rs.readMultiBit(2); 15 | adaptation_field_control = rs.readMultiBit(2); 16 | continuity_counter = rs.readMultiBit(4); 17 | 18 | if (adaptation_field_control == 2 || adaptation_field_control == 3) { 19 | ret = adaptation_field(rs); 20 | if (ret < 0) { 21 | fprintf(stderr, "解析adaptation_field失败\n"); 22 | return ret; 23 | } 24 | } 25 | 26 | if (adaptation_field_control == 1 || adaptation_field_control == 3) { 27 | if (VIDEO_PID == PID || AUDIO_PID == PID) { 28 | if (payload_unit_start_indicator) { 29 | ret = PES::read_PES_packet(rs); 30 | if (ret < 0) { 31 | fprintf(stderr, "解析PES_packet失败\n"); 32 | return ret; 33 | } 34 | } 35 | return PID; 36 | } 37 | } 38 | return 0; 39 | } 40 | 41 | int DemuxPacket::adaptation_field(ReadStream &rs) { 42 | /*指定紧接在adaptation_field_length后面的adaptation_field的字节数*/ 43 | /*值0表示在传输流数据包中插入单个填充字节*/ 44 | /*当adaptation_field_control值为'11'时,adaptation_field_length的取值范围为0 ~ 182。*/ 45 | /*当adaptation_field_control值为'10'时,adaptation_field_length值为183*/ 46 | /*对于携带PES报文的Transport Stream报文,当PES报文数据不足以完全填充Transport Stream报文有效负载字节时,需要进行填充*/ 47 | adaptation_field_length = rs.readMultiBit(8); 48 | 49 | uint8_t N = adaptation_field_length; 50 | if (adaptation_field_length > 0) { 51 | discontinuity_indicator = rs.readBit(); 52 | random_access_indicator = rs.readBit(); 53 | elementary_stream_priority_indicator = rs.readBit(); 54 | PCR_flag = rs.readBit(); 55 | OPCR_flag = rs.readBit(); 56 | splicing_point_flag = rs.readBit(); 57 | transport_private_data_flag = rs.readBit(); 58 | adaptation_field_extension_flag = rs.readBit(); 59 | N -= 1; 60 | if (PCR_flag) { 61 | 62 | /*Mpeg-2规定的系统时钟频率为27MHz 也就是一秒27MHz*/ 63 | /* 64 | * system_clock_frequency = 27000000 65 | * PCR_base(i) = ((system_clock_frequency*t(i)) / 300)%2^33 */ 66 | /* 67 | * CR_base:以1/300 的系统时钟频率周期为单位,称之为program_clock_reference_base 68 | * PCR-base的作用: 69 | * a. 与PTS和DTS作比较, 当二者相同时, 相应的单元被显示或者解码. 70 | * b. 在解码器切换节目时,提供对解码器PCR计数器的初始值,以让该PCR值与PTS、DTS最大可能地达到相同的时间起点 71 | * */ 72 | program_clock_reference_base = rs.readMultiBit(33); 73 | rs.readMultiBit(6); 74 | /*PCR_ext(i) = ((system_clock_frequency*t(i)) / 1)%300 */ 75 | program_clock_reference_extension = rs.readMultiBit(9); 76 | 77 | /*PCR(i) = PCR_base(i)*300 + PCR_ext(i) */ 78 | uint64_t PCR = program_clock_reference_base * 300 + program_clock_reference_extension; 79 | /*PCR 指示包含 program_clock_reference_base 最后一个 bit 的字节在系统目标解码器的输入端的预期到达时间*/ 80 | N -= 6; 81 | } 82 | 83 | if (OPCR_flag) { 84 | original_program_clock_reference_base = rs.readMultiBit(33); 85 | rs.readMultiBit(6); 86 | original_program_clock_reference_extension = rs.readMultiBit(9); 87 | N -= 6; 88 | } 89 | if (splicing_point_flag) { 90 | splice_countdown = rs.readMultiBit(8); 91 | N -= 1; 92 | } 93 | if (transport_private_data_flag) { 94 | transport_private_data_length = rs.readMultiBit(8); 95 | private_data_byte = new uint8_t[transport_private_data_length]; 96 | for (int i = 0; i < transport_private_data_length; i++) { 97 | private_data_byte[i] = rs.readMultiBit(8); 98 | } 99 | N -= 1 + transport_private_data_length; 100 | } 101 | 102 | 103 | rs.setBytePtr(N); 104 | } 105 | 106 | 107 | return 0; 108 | } -------------------------------------------------------------------------------- /src/transportStream/demuxPacket.h: -------------------------------------------------------------------------------- 1 |  2 | 3 | #ifndef RTSP_DEMUXPACKET_H 4 | #define RTSP_DEMUXPACKET_H 5 | 6 | #include 7 | #include "bitStream/readStream.h" 8 | 9 | #define VIDEO_PID 256 10 | #define AUDIO_PID 257 11 | 12 | class DemuxPacket { 13 | 14 | private: 15 | uint8_t sync_byte{0x47}; 16 | uint8_t transport_error_indicator{0}; 17 | uint8_t payload_unit_start_indicator{0}; 18 | uint8_t transport_priority{0}; 19 | uint16_t PID{0}; 20 | uint8_t transport_scrambling_control{0}; 21 | uint8_t adaptation_field_control{0}; 22 | uint8_t continuity_counter{0}; 23 | uint8_t pointer_field{0}; 24 | 25 | /*adaptation_field*/ 26 | uint8_t adaptation_field_length{1}; 27 | uint8_t discontinuity_indicator{0}; 28 | uint8_t random_access_indicator{0}; 29 | uint8_t elementary_stream_priority_indicator{0}; 30 | uint8_t PCR_flag{0}; 31 | uint8_t OPCR_flag{0}; 32 | uint8_t splicing_point_flag{0}; 33 | uint8_t transport_private_data_flag{0}; 34 | uint8_t adaptation_field_extension_flag{0}; 35 | uint64_t program_clock_reference_base{0}; 36 | uint16_t program_clock_reference_extension{0}; 37 | uint64_t original_program_clock_reference_base{0}; 38 | uint16_t original_program_clock_reference_extension{0}; 39 | uint8_t splice_countdown{0}; 40 | uint8_t transport_private_data_length{0}; 41 | uint8_t *private_data_byte{nullptr}; 42 | uint8_t adaptation_field_extension_length{0}; 43 | uint8_t ltw_flag{0}; 44 | uint8_t piecewise_rate_flag{0}; 45 | uint8_t seamless_splice_flag{0}; 46 | uint8_t ltw_valid_flag{0}; 47 | uint16_t ltw_offset{0}; 48 | uint32_t piecewise_rate{0}; 49 | uint8_t splice_type{0}; 50 | public: 51 | int readFrame(ReadStream &rs); 52 | 53 | private: 54 | int adaptation_field(ReadStream &rs); 55 | }; 56 | 57 | 58 | #endif //RTSP_DEMUXPACKET_H 59 | -------------------------------------------------------------------------------- /src/transportStream/transportPacket.h: -------------------------------------------------------------------------------- 1 | 2 | 3 | #ifndef TS_TRANSPORTPACKET_H 4 | #define TS_TRANSPORTPACKET_H 5 | 6 | 7 | #include 8 | #include 9 | #include "SI.h" 10 | #include "PES.h" 11 | #include "nalu/NALPicture.h" 12 | #include "adts/adtsHeader.h" 13 | #include "bitStream/writeStream.h" 14 | 15 | 16 | class TransportPacket { 17 | 18 | private: 19 | uint8_t *buffer{nullptr}; 20 | WriteStream *ws{nullptr}; 21 | 22 | 23 | PES pes; 24 | SI info; 25 | /*同步字段,固定是0x47*/ 26 | uint8_t sync_byte{0x47}; 27 | /*传输错误标记,在 TCP/UDP 场景,这个字段应该一直是 0,因为网络传输不管是UDP还是TCP都自带差错校验*/ 28 | uint8_t transport_error_indicator{0}; 29 | /*第一个ts包为1*/ 30 | uint8_t payload_unit_start_indicator{0}; 31 | /*传输优先级,0为低优先级,1为高优先级,通常取0*/ 32 | uint8_t transport_priority{0}; 33 | /*PID 可以判断 playload 里面是什么数据*/ 34 | uint16_t PID{0}; 35 | /*这个是限制字段,一般用做付费节目之类的,以前卫星电视,需要插一张卡,充钱才能看某些节目。互联网场景很少使用这个字段*/ 36 | uint8_t transport_scrambling_control{0}; 37 | /*可变字段标记,这个字段有 4 个值,10 跟 11 代表 后面有扩展的字段需要解析,01 跟 11 代表 这个 TS 包有 playload */ 38 | /*解码器将丢弃adaptation_field_control字段设置为'00'的传输流数据包。如果是空包,adaptation_field_control的值应该设置为“01”。*/ 39 | /*参见Table 2-5 – Adaptation field control values*/ 40 | uint8_t adaptation_field_control{0}; 41 | /*从0到15连续循环递增,代表连续的包,不一定从0开始*/ 42 | uint8_t continuity_counter{0}; 43 | 44 | uint8_t pointer_field{0}; 45 | /*adaptation_field*/ 46 | uint8_t adaptation_field_length{1}; 47 | uint8_t discontinuity_indicator{0}; 48 | uint8_t random_access_indicator{0}; 49 | uint8_t elementary_stream_priority_indicator{0}; 50 | uint8_t PCR_flag{0}; 51 | uint8_t OPCR_flag{0}; 52 | uint8_t splicing_point_flag{0}; 53 | uint8_t transport_private_data_flag{0}; 54 | uint8_t adaptation_field_extension_flag{0}; 55 | uint64_t program_clock_reference_base{0}; 56 | uint16_t program_clock_reference_extension{0}; 57 | uint64_t original_program_clock_reference_base{0}; 58 | uint16_t original_program_clock_reference_extension{0}; 59 | uint8_t splice_countdown{0}; 60 | uint8_t transport_private_data_length{0}; 61 | uint8_t *private_data_byte{nullptr}; 62 | uint8_t adaptation_field_extension_length{0}; 63 | uint8_t ltw_flag{0}; 64 | uint8_t piecewise_rate_flag{0}; 65 | uint8_t seamless_splice_flag{0}; 66 | uint8_t ltw_valid_flag{0}; 67 | uint16_t ltw_offset{0}; 68 | uint32_t piecewise_rate{0}; 69 | uint8_t splice_type{0}; 70 | 71 | 72 | uint32_t videoPacketSize{0}; 73 | uint32_t audioPacketSize{0}; 74 | 75 | uint64_t time{0}; 76 | public: 77 | int init(); 78 | 79 | void resetPacketSize(); 80 | 81 | int writeTable(std::ofstream &fs); 82 | 83 | 84 | int writeVideoFrame(const NALPicture *picture, std::ofstream &fs); 85 | 86 | int writeAudioFrame(const AdtsHeader &header, std::ofstream &fs); 87 | 88 | ~TransportPacket(); 89 | 90 | private: 91 | 92 | 93 | int writeServiceDescriptionTable(); 94 | 95 | int writeProgramAssociationTable(); 96 | 97 | int writeProgramMapTable(); 98 | 99 | int transport_packet() const; 100 | 101 | int setTransportPacketConfig(uint8_t payloadUnitStartIndicator, uint16_t pid, uint8_t control, uint32_t counter); 102 | 103 | int setAdaptationFieldConfig(uint8_t randomAccessIndicator, uint16_t adaptationFieldLength, bool flag); 104 | 105 | int adaptation_field() const; 106 | 107 | }; 108 | 109 | 110 | #endif //TS_TRANSPORTPACKET_H 111 | -------------------------------------------------------------------------------- /src/utils/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library(utils util.cpp parseUrl.cpp) -------------------------------------------------------------------------------- /src/utils/parseUrl.cpp: -------------------------------------------------------------------------------- 1 |  2 | #include "parseUrl.h" 3 | 4 | 5 | ParseUrl::ParseUrl(std::string url, int defaultPort) : url_(std::move(url)), port(defaultPort) { 6 | 7 | } 8 | 9 | int ParseUrl::parse() { 10 | std::string url = url_; 11 | size_t pos = url.find("://"); 12 | if (pos != std::string::npos) { 13 | protocol = url.substr(0, pos); 14 | url = url.substr(pos + 3); 15 | } else { 16 | fprintf(stderr, "解析错误,找不到://"); 17 | return -1; 18 | } 19 | pos = url.find(':'); 20 | if (pos != std::string::npos) { 21 | domain = url.substr(0, pos); 22 | url = url.substr(pos + 1); 23 | pos = url.find('/'); 24 | if (pos != std::string::npos) { 25 | port = std::stoi(url.substr(0, pos)); 26 | url = url.substr(pos); 27 | } else { 28 | port = std::stoi(url); 29 | url = ""; 30 | } 31 | } else { 32 | pos = url.find('/'); 33 | if (pos != std::string::npos) { 34 | domain = url.substr(0, pos); 35 | url = url.substr(pos); 36 | } else { 37 | domain = url; 38 | url = ""; 39 | } 40 | } 41 | path = url; 42 | return 0; 43 | } 44 | 45 | std::string ParseUrl::getProtocol() { 46 | return protocol; 47 | } 48 | 49 | std::string ParseUrl::getDomain() { 50 | return domain; 51 | } 52 | 53 | int ParseUrl::getPort() { 54 | return port; 55 | } 56 | 57 | std::string ParseUrl::getPath() { 58 | return path; 59 | } 60 | -------------------------------------------------------------------------------- /src/utils/parseUrl.h: -------------------------------------------------------------------------------- 1 |  2 | 3 | #ifndef RTSP_PARSEURL_H 4 | #define RTSP_PARSEURL_H 5 | 6 | #include 7 | 8 | class ParseUrl { 9 | private: 10 | 11 | std::string url_; 12 | std::string protocol; 13 | std::string domain; 14 | std::string path; 15 | int port; 16 | public: 17 | 18 | explicit ParseUrl(std::string url, int defaultPort); 19 | 20 | 21 | int parse(); 22 | 23 | std::string getProtocol(); 24 | 25 | std::string getDomain(); 26 | 27 | std::string getPath(); 28 | 29 | int getPort(); 30 | 31 | }; 32 | 33 | 34 | #endif //RTSP_PARSEURL_H 35 | -------------------------------------------------------------------------------- /src/utils/util.cpp: -------------------------------------------------------------------------------- 1 |  2 | #include "util.h" 3 | #include 4 | #include 5 | 6 | static char alphabet_map[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 7 | static uint8_t reverse_map[] = 8 | { 9 | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 10 | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 11 | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 62, 255, 255, 255, 63, 12 | 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255, 255, 255, 255, 255, 13 | 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 14 | 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 255, 255, 255, 255, 255, 15 | 255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 16 | 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 255, 255, 255, 255, 255 17 | }; 18 | 19 | std::string trim(const std::string &str) { 20 | if (str.empty()) { 21 | return str; 22 | } 23 | 24 | size_t start = str.find_first_not_of(' '); 25 | size_t end = str.find_last_not_of(' '); 26 | return str.substr(start, end - start + 1); 27 | } 28 | 29 | /*int base64_encode(const std::string &text, uint8_t *encode) { 30 | uint32_t text_len = text.length(); 31 | int i, j; 32 | for (i = 0, j = 0; i + 3 <= text_len; i += 3) { 33 | encode[j++] = alphabet_map[text[i] >> 2]; //取出第一个字符的前6位并找出对应的结果字符 34 | encode[j++] = alphabet_map[((text[i] << 4) & 0x30) | 35 | (text[i + 1] >> 4)]; //将第一个字符的后2位与第二个字符的前4位进行组合并找到对应的结果字符 36 | encode[j++] = alphabet_map[((text[i + 1] << 2) & 0x3c) | 37 | (text[i + 2] >> 6)]; //将第二个字符的后4位与第三个字符的前2位组合并找出对应的结果字符 38 | encode[j++] = alphabet_map[text[i + 2] & 0x3f]; //取出第三个字符的后6位并找出结果字符 39 | } 40 | 41 | if (i < text_len) { 42 | uint32_t tail = text_len - i; 43 | if (tail == 1) { 44 | encode[j++] = alphabet_map[text[i] >> 2]; 45 | encode[j++] = alphabet_map[(text[i] << 4) & 0x30]; 46 | encode[j++] = '='; 47 | encode[j++] = '='; 48 | } else //tail==2 49 | { 50 | encode[j++] = alphabet_map[text[i] >> 2]; 51 | encode[j++] = alphabet_map[((text[i] << 4) & 0x30) | (text[i + 1] >> 4)]; 52 | encode[j++] = alphabet_map[(text[i + 1] << 2) & 0x3c]; 53 | encode[j++] = '='; 54 | } 55 | } 56 | return j; 57 | }*/ 58 | 59 | int base64_decode(const std::string &code, uint8_t *plain) { 60 | uint32_t code_len = code.length(); 61 | // assert((code_len & 0x03) == 0); //如果它的条件返回错误,则终止程序执行。4的倍数。 62 | if ((code_len & 0x03) != 0) { 63 | return -1; 64 | } 65 | int i, j = 0; 66 | uint8_t quad[4]; 67 | for (i = 0; i < code_len; i += 4) { 68 | for (uint32_t k = 0; k < 4; k++) { 69 | quad[k] = reverse_map[code[i + k]];//分组,每组四个分别依次转换为base64表内的十进制数 70 | } 71 | 72 | if (quad[0] >= 64 && quad[1] >= 64) { 73 | return -1; 74 | } 75 | // assert(quad[0] < 64 && quad[1] < 64); 76 | 77 | plain[j++] = (quad[0] << 2) | (quad[1] >> 4); //取出第一个字符对应base64表的十进制数的前6位与第二个字符对应base64表的十进制数的前2位进行组合 78 | 79 | if (quad[2] >= 64) 80 | break; 81 | else if (quad[3] >= 64) { 82 | plain[j++] = (quad[1] << 4) | (quad[2] >> 2); //取出第二个字符对应base64表的十进制数的后4位与第三个字符对应base64表的十进制数的前4位进行组合 83 | break; 84 | } else { 85 | plain[j++] = (quad[1] << 4) | (quad[2] >> 2); 86 | plain[j++] = (quad[2] << 6) | quad[3];//取出第三个字符对应base64表的十进制数的后2位与第4个字符进行组合 87 | } 88 | } 89 | return j; 90 | } 91 | 92 | std::string base64_encode(const uint8_t *data, uint32_t size) { 93 | 94 | std::string encoded; 95 | size_t i = 0; 96 | uint32_t triad = 0; 97 | 98 | while (i < size) { 99 | switch (i % 3) { 100 | case 0: 101 | triad = (data[i] << 16) + (data[i + 1] << 8) + data[i + 2]; 102 | encoded.push_back(alphabet_map[(triad >> 18) & 0x3F]); 103 | encoded.push_back(alphabet_map[(triad >> 12) & 0x3F]); 104 | encoded.push_back(alphabet_map[(triad >> 6) & 0x3F]); 105 | encoded.push_back(alphabet_map[triad & 0x3F]); 106 | i += 3; 107 | break; 108 | case 1: 109 | triad = (data[i] << 16) + (data[i + 1] << 8); 110 | encoded.push_back(alphabet_map[(triad >> 18) & 0x3F]); 111 | encoded.push_back(alphabet_map[(triad >> 12) & 0x3F]); 112 | encoded.push_back(alphabet_map[(triad >> 6) & 0x3F]); 113 | encoded.push_back('='); 114 | i += 2; 115 | break; 116 | case 2: 117 | triad = (data[i] << 16); 118 | encoded.push_back(alphabet_map[(triad >> 18) & 0x3F]); 119 | encoded.push_back(alphabet_map[(triad >> 12) & 0x3F]); 120 | encoded.push_back('='); 121 | encoded.push_back('='); 122 | i += 1; 123 | break; 124 | } 125 | } 126 | return encoded; 127 | } 128 | 129 | std::string generatorDate() { 130 | // 使用time函数获取当前时间,并存储在now变量中 131 | time_t now = time(nullptr); 132 | 133 | // 使用gmtime函数将now转换为GMT时间,并返回一个tm结构的指针 134 | tm *gmtm = gmtime(&now); 135 | 136 | // 创建一个足够大的缓冲区 137 | char buffer[64]; 138 | 139 | // 使用strftime函数将tm结构转换为字符串,并指定格式为Date: %a, %d %b %Y %H:%M:%S GMT 140 | strftime(buffer, sizeof(buffer), "%a, %d %b %Y %H:%M:%S GMT", gmtm); 141 | 142 | // 输出结果 143 | return buffer; 144 | } 145 | 146 | 147 | std::string GenerateSpropParameterSets(const uint8_t *sps, uint32_t spsSize, uint8_t *pps, uint32_t ppsSize) { 148 | std::stringstream ss; 149 | 150 | ss << base64_encode(sps, spsSize); 151 | ss << ","; 152 | ss << base64_encode(pps, ppsSize); 153 | 154 | return ss.str(); 155 | } 156 | 157 | std::string decimalToHex(int decimalNum) { 158 | std::stringstream ss; 159 | ss << std::hex << std::uppercase << std::setfill('0') << std::setw(2) << decimalNum; 160 | return ss.str(); 161 | } 162 | 163 | std::vector split(const std::string &str, const std::string &spacer) { 164 | std::vector list; 165 | using STRING_SIZE = std::string::size_type; 166 | STRING_SIZE pos1, pos2; 167 | STRING_SIZE len = spacer.length(); //记录分隔符的长度 168 | pos1 = 0; 169 | pos2 = str.find(spacer); 170 | while (pos2 != std::string::npos) { 171 | list.push_back(trim(str.substr(pos1, pos2 - pos1))); 172 | pos1 = pos2 + len; 173 | pos2 = str.find(spacer, pos1); // 从str的pos1位置开始搜寻spacer 174 | } 175 | if (pos1 != str.length()) //分割最后一个部分 176 | list.push_back(str.substr(pos1)); 177 | return list; 178 | } 179 | 180 | uint64_t av_rescale_q(uint64_t a, const AVRational &bq, const AVRational &cq) { 181 | //(1 / 25) / (1 / 1000); 182 | int64_t b = bq.num * cq.den; 183 | int64_t c = cq.num * bq.den; 184 | return a * b / c; //25 * (1000 / 25) 把1000分成25份,然后当前占1000的多少 185 | } 186 | 187 | 188 | std::map getObj(const std::vector &list, const std::string &spacer) { 189 | std::map obj; 190 | for (const std::string &str: list) { 191 | std::string::size_type pos = str.find(spacer); 192 | if (pos != std::string::npos) { 193 | std::string key = trim(str.substr(0, pos)); 194 | std::string value = trim(str.substr(pos + 1)); 195 | obj[key] = value; 196 | } 197 | } 198 | 199 | return obj; 200 | } 201 | 202 | std::string generate_unique_string() { 203 | static int counter = 0; 204 | return "xiaofeng_" + std::to_string(counter++); 205 | } -------------------------------------------------------------------------------- /src/utils/util.h: -------------------------------------------------------------------------------- 1 |  2 | #ifndef RTSP_UTIL_H 3 | #define RTSP_UTIL_H 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | struct AVRational { 13 | int num; 14 | int den; 15 | }; 16 | 17 | std::map getObj(const std::vector &list, const std::string &spacer); 18 | 19 | uint64_t av_rescale_q(uint64_t a, const AVRational &bq, const AVRational &cq); 20 | 21 | std::string trim(const std::string &str); 22 | 23 | /*int base64_encode(const std::string &text, uint8_t *encode);*/ 24 | 25 | int base64_decode(const std::string &code, uint8_t *plain); 26 | 27 | std::string generatorDate(); 28 | 29 | std::string base64_encode(const uint8_t *data, uint32_t size); 30 | 31 | 32 | std::string GenerateSpropParameterSets(const uint8_t *sps, uint32_t spsSize, uint8_t *pps, uint32_t ppsSize); 33 | 34 | std::string decimalToHex(int decimalNum); 35 | 36 | std::vector split(const std::string &str, const std::string &spacer); 37 | 38 | std::string generate_unique_string(); 39 | 40 | #endif //RTSP_UTIL_H 41 | --------------------------------------------------------------------------------