Compare commits
No commits in common. "master" and "tail_sec" have entirely different histories.
14
.gitignore
vendored
Normal file
14
.gitignore
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
|
||||
.vscode/
|
||||
|
||||
build/
|
||||
|
||||
release/
|
||||
|
||||
*.data
|
||||
|
||||
*.len
|
||||
|
||||
*.pcap
|
||||
|
||||
PcapRawSender/.fuse_hidden000053fa00000002
|
114
.vscode/launch.json
vendored
Normal file
114
.vscode/launch.json
vendored
Normal file
@ -0,0 +1,114 @@
|
||||
{
|
||||
// 使用 IntelliSense 了解相关属性。
|
||||
// 悬停以查看现有属性的描述。
|
||||
// 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "test",
|
||||
"type": "cppdbg",
|
||||
"request": "launch",
|
||||
"program": "${workspaceFolder}/release/out/tests",
|
||||
"args": [],
|
||||
"stopAtEntry": false,
|
||||
"cwd": "${workspaceFolder}",
|
||||
"environment": [],
|
||||
"externalConsole": false,
|
||||
"MIMode": "gdb",
|
||||
"setupCommands": [
|
||||
{
|
||||
"description": "为 gdb 启用整齐打印",
|
||||
"text": "-enable-pretty-printing",
|
||||
"ignoreFailures": true
|
||||
}
|
||||
],
|
||||
"miDebuggerPath": "/usr/bin/gdb"
|
||||
},
|
||||
{
|
||||
"name": "pcapsender",
|
||||
"type": "cppdbg",
|
||||
"request": "launch",
|
||||
"program": "${workspaceFolder}/release/out/PcapSender",
|
||||
"args": ["/media/alan/Data/Alan/Documents/WorkSpace/SecMedia/PcapSender/hw28181.pcap",
|
||||
"127.0.0.1","30001","udp src port 20180"],
|
||||
// "args": ["/media/alan/Data/Alan/Documents/WorkSpace/SecMedia/PcapSender/all.pcap",
|
||||
// "127.0.0.1","40001","udp src port 20002"],
|
||||
// "args": ["/media/alan/Data/Alan/Documents/WorkSpace/SecMedia/PcapSender/signhw28181.pcap",
|
||||
// "127.0.0.1","30001","udp src port 55763"],
|
||||
// "args": ["/media/alan/Data/Alan/Documents/WorkSpace/SecMedia/PcapRawSender/h265-hikvision-10min.pcap",
|
||||
// "127.0.0.1","30001","udp src port 15060"], //h265
|
||||
// "args": ["/media/alan/Data/Alan/Documents/WorkSpace/SecMedia/PcapSender/hkh264.pcap",
|
||||
// "127.0.0.1","60006","udp src port 15060"],
|
||||
"stopAtEntry": false,
|
||||
"cwd": "${workspaceFolder}",
|
||||
"environment": [],
|
||||
"externalConsole": false,
|
||||
"MIMode": "gdb",
|
||||
"setupCommands": [
|
||||
{
|
||||
"description": "为 gdb 启用整齐打印",
|
||||
"text": "-enable-pretty-printing",
|
||||
"ignoreFailures": true
|
||||
}
|
||||
],
|
||||
"miDebuggerPath": "/usr/bin/gdb"
|
||||
},
|
||||
{
|
||||
"name": "pcapRawsender",
|
||||
"type": "cppdbg",
|
||||
"request": "launch",
|
||||
"program": "${workspaceFolder}/release/out/PcapRawSender",
|
||||
// "args": ["/media/alan/Data/Alan/Documents/WorkSpace/SecMedia/PcapRawSender/h265-hikvision-10min.pcap",
|
||||
// "127.0.0.1","30001","udp src port 15060"],
|
||||
// "args": ["/media/alan/Data/Alan/Documents/WorkSpace/SecMedia/PcapRawSender/afterSign.pcap",
|
||||
// "127.0.0.1","30001","udp src port 15060"],
|
||||
// "args": ["/media/alan/Data/Alan/Documents/WorkSpace/SecMedia/PcapRawSender/HaiKang_platform.pcap",
|
||||
// "127.0.0.1","60006","udp src port 22006"],
|
||||
// "args": ["/media/alan/Data/Alan/Documents/WorkSpace/SecMedia/PcapRawSender/EncMedia_rtp_encoded.pcapng",
|
||||
// "127.0.0.1","60006","udp src port 10005"],
|
||||
// "args": ["/media/alan/Data/Alan/Documents/WorkSpace/SecMedia/PcapRawSender/EncMedia_rtp.pcapng",
|
||||
// "127.0.0.1","30001","udp src port 10005"],
|
||||
// "args": ["/media/alan/Data/Alan/Documents/WorkSpace/SecMedia/PcapRawSender/rawcamera.pcap",
|
||||
// "127.0.0.1","30001","udp src port 15060"],
|
||||
// "args": ["/media/alan/Data/Alan/Documents/WorkSpace/SecMedia/PcapRawSender/h264.pcap", //下及平台出
|
||||
// "127.0.0.1","20001","udp src port 21999"],
|
||||
// "args": ["/media/alan/Data/Alan/Documents/WorkSpace/SecMedia/PcapRawSender/123.pcap",
|
||||
// "127.0.0.1","40001","udp dst port 10001"],
|
||||
// "args": ["/media/alan/Data/Alan/Documents/WorkSpace/SecMedia/PcapRawSender/51.pcap",
|
||||
// "127.0.0.1","40001","udp dst port 30008"], //svac
|
||||
// // "args": ["/media/alan/Data/Alan/Documents/WorkSpace/SecMedia/PcapRawSender/svac_dec.pcap",
|
||||
// // "127.0.0.1","40001","udp dst port 20001"], //svac
|
||||
// "args": ["/media/alan/Data/Alan/Documents/WorkSpace/SecMedia/PcapRawSender/1.pcap",
|
||||
// "127.0.0.1","40001","udp dst port 40001"], //svac
|
||||
// "args": ["/media/alan/Data/Alan/Documents/WorkSpace/SecMedia/PcapRawSender/hz-pt.pcap",
|
||||
// "127.0.0.1","40001","udp src port 10000"],
|
||||
// "args": ["/media/alan/Data/Alan/Documents/WorkSpace/SecMedia/PcapRawSender/ipc-hz.pcap",
|
||||
// "127.0.0.1","40001","udp src port 15060"],
|
||||
|
||||
// "args": ["/media/alan/Data/Alan/Documents/WorkSpace/SecMedia/PcapRawSender/videoblur/H265_ps_bug.pcap",
|
||||
// "127.0.0.1","40001","udp src port 10005"],
|
||||
// "args": ["/media/alan/Data/Alan/Documents/WorkSpace/SecMedia/PcapRawSender/videoblur/86h264.pcap",
|
||||
// "127.0.0.1","30001","udp src port 15060"],
|
||||
// "args": ["/media/alan/Data/Alan/Documents/WorkSpace/SecMedia/PcapRawSender/cameraAndboxh265.pcap",
|
||||
// "127.0.0.1","30001","udp src port 15060 && src host 192.168.0.93"],
|
||||
"args": ["/media/alan/Data/Alan/Documents/WorkSpace/SecMedia/PcapRawSender/cameraAndBoxh264.pcap",
|
||||
"127.0.0.1","40001","udp src port 15060 && src host 192.168.1.95"],
|
||||
|
||||
// "args": ["/home/alan/Downloads/br0.pcap",
|
||||
// "127.0.0.1","60006","udp dst port 10001"]
|
||||
"stopAtEntry": false,
|
||||
"cwd": "${workspaceFolder}",
|
||||
"environment": [],
|
||||
"externalConsole": false,
|
||||
"MIMode": "gdb",
|
||||
"setupCommands": [
|
||||
{
|
||||
"description": "为 gdb 启用整齐打印",
|
||||
"text": "-enable-pretty-printing",
|
||||
"ignoreFailures": true
|
||||
}
|
||||
],
|
||||
"miDebuggerPath": "/usr/bin/gdb"
|
||||
}
|
||||
]
|
||||
}
|
74
.vscode/settings.json
vendored
Normal file
74
.vscode/settings.json
vendored
Normal file
@ -0,0 +1,74 @@
|
||||
{
|
||||
"files.associations": {
|
||||
"*.tcc": "cpp",
|
||||
"functional": "cpp",
|
||||
"fstream": "cpp",
|
||||
"thread": "cpp",
|
||||
"cctype": "cpp",
|
||||
"clocale": "cpp",
|
||||
"cmath": "cpp",
|
||||
"cstdarg": "cpp",
|
||||
"cstddef": "cpp",
|
||||
"cstdio": "cpp",
|
||||
"cstdlib": "cpp",
|
||||
"cstring": "cpp",
|
||||
"ctime": "cpp",
|
||||
"cwchar": "cpp",
|
||||
"cwctype": "cpp",
|
||||
"array": "cpp",
|
||||
"atomic": "cpp",
|
||||
"strstream": "cpp",
|
||||
"bitset": "cpp",
|
||||
"chrono": "cpp",
|
||||
"complex": "cpp",
|
||||
"condition_variable": "cpp",
|
||||
"cstdint": "cpp",
|
||||
"deque": "cpp",
|
||||
"list": "cpp",
|
||||
"unordered_map": "cpp",
|
||||
"vector": "cpp",
|
||||
"exception": "cpp",
|
||||
"algorithm": "cpp",
|
||||
"iterator": "cpp",
|
||||
"map": "cpp",
|
||||
"memory": "cpp",
|
||||
"memory_resource": "cpp",
|
||||
"numeric": "cpp",
|
||||
"optional": "cpp",
|
||||
"random": "cpp",
|
||||
"ratio": "cpp",
|
||||
"set": "cpp",
|
||||
"string": "cpp",
|
||||
"string_view": "cpp",
|
||||
"system_error": "cpp",
|
||||
"tuple": "cpp",
|
||||
"type_traits": "cpp",
|
||||
"utility": "cpp",
|
||||
"initializer_list": "cpp",
|
||||
"iomanip": "cpp",
|
||||
"iosfwd": "cpp",
|
||||
"iostream": "cpp",
|
||||
"istream": "cpp",
|
||||
"limits": "cpp",
|
||||
"mutex": "cpp",
|
||||
"new": "cpp",
|
||||
"ostream": "cpp",
|
||||
"sstream": "cpp",
|
||||
"stdexcept": "cpp",
|
||||
"streambuf": "cpp",
|
||||
"cfenv": "cpp",
|
||||
"cinttypes": "cpp",
|
||||
"typeindex": "cpp",
|
||||
"typeinfo": "cpp",
|
||||
"variant": "cpp",
|
||||
"bit": "cpp",
|
||||
"core": "cpp",
|
||||
"geometry": "cpp",
|
||||
"*.txx": "cpp",
|
||||
"compare": "cpp",
|
||||
"concepts": "cpp",
|
||||
"numbers": "cpp",
|
||||
"semaphore": "cpp",
|
||||
"stop_token": "cpp"
|
||||
}
|
||||
}
|
28
.vscode/tasks.json
vendored
Normal file
28
.vscode/tasks.json
vendored
Normal file
@ -0,0 +1,28 @@
|
||||
{
|
||||
"tasks": [
|
||||
{
|
||||
"type": "cppbuild",
|
||||
"label": "C/C++: g++ 生成活动文件",
|
||||
"command": "/usr/bin/g++",
|
||||
"args": [
|
||||
"-fdiagnostics-color=always",
|
||||
"-g",
|
||||
"${file}",
|
||||
"-o",
|
||||
"${fileDirname}/${fileBasenameNoExtension}"
|
||||
],
|
||||
"options": {
|
||||
"cwd": "${fileDirname}"
|
||||
},
|
||||
"problemMatcher": [
|
||||
"$gcc"
|
||||
],
|
||||
"group": {
|
||||
"kind": "build",
|
||||
"isDefault": true
|
||||
},
|
||||
"detail": "调试器生成的任务。"
|
||||
}
|
||||
],
|
||||
"version": "2.0.0"
|
||||
}
|
130
CMakeLists.txt
Normal file
130
CMakeLists.txt
Normal file
@ -0,0 +1,130 @@
|
||||
cmake_minimum_required(VERSION 3.9)
|
||||
project(SecMedia VERSION 0.0.1 DESCRIPTION "Security Media Package")
|
||||
set(CMAKE_CXX_STANDARD 11)
|
||||
SET(CMAKE_FIND_LIBRARY_SUFFIXES ".a")
|
||||
if(${CMAKE_BUILD_TYPE} MATCHES "Release")
|
||||
message(STATUS "Release版本")
|
||||
set(BuildType "Release")
|
||||
add_definitions(-DNDEBUG)
|
||||
elseif(${CMAKE_BUILD_TYPE} MATCHES "MinSizeRel")
|
||||
message(STATUS "MinSizeRel版本")
|
||||
set(BuildType "MinSizeRel")
|
||||
else()
|
||||
set(BuildType "Debug")
|
||||
message(STATUS "Debug版本")
|
||||
add_definitions(-DDEBUG_LOG)
|
||||
add_definitions(-DNDEBUG)
|
||||
add_definitions(-DDUMP_FILE)
|
||||
endif()
|
||||
#加载自定义模块
|
||||
add_definitions(-DSIGN_ENABLE)
|
||||
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
|
||||
|
||||
SET(LIBRARY_OUTPUT_PATH ${CMAKE_CURRENT_SOURCE_DIR}/release/lib/${BuildType})
|
||||
SET(EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_SOURCE_DIR}/release/out)
|
||||
|
||||
set(CMAKE_C_VISIBILITY_PRESET hidden)
|
||||
set(CMAKE_CXX_VISIBILITY_PRESET hidden)
|
||||
set(CMAKE_C_FLAGS$ "${CMAKE_C_FLAGS} -include ${CMAKE_CURRENT_SOURCE_DIR}/force_link_glibc_2.27.h")
|
||||
set(CMAKE_CXX_FLAGS$ "${CMAKE_CXX_FLAGS} -include ${CMAKE_CURRENT_SOURCE_DIR}/force_link_glibc_2.27.h")
|
||||
|
||||
# set(CMAKE_C_FLAGS$ "${CMAKE_C_FLAGS} -fvisibility = hidden")
|
||||
# set(CMAKE_CXX_FLAGS$ "${CMAKE_CXX_FLAGS} -fvisibility = hidden")
|
||||
set(SecMedia_Root ${CMAKE_CURRENT_SOURCE_DIR}/src)
|
||||
add_compile_options(-fPIC)
|
||||
# add_compile_options(-fvisibility=hidden)
|
||||
# add_compile_options(-std=c++11)
|
||||
#add_compile_options(-mcpu=cortex-a7 -mfloat-abi=softfp -mfpu=neon-vfpv4 -mno-unaligned-access -fno-aggressive-loop-optimizations -Wcast-align)
|
||||
include(GNUInstallDirs)
|
||||
include(GenerateExportHeader)
|
||||
|
||||
#media-server ps dec enc
|
||||
set(MediaServer_Root ${SecMedia_Root}/3rdpart/media-server)
|
||||
include_directories(${MediaServer_Root}/librtp/include)
|
||||
include_directories(${MediaServer_Root}/libmpeg/include)
|
||||
include_directories(${MediaServer_Root}/libmpeg/source)
|
||||
|
||||
aux_source_directory(${MediaServer_Root}/libmpeg/include src_rtp)
|
||||
aux_source_directory(${MediaServer_Root}/libmpeg/source src_rtp)
|
||||
aux_source_directory(${MediaServer_Root}/librtp/include src_rtp)
|
||||
aux_source_directory(${MediaServer_Root}/librtp/source src_rtp)
|
||||
aux_source_directory(${MediaServer_Root}/librtp/payload src_rtp)
|
||||
add_library(rtp STATIC ${src_rtp})
|
||||
|
||||
|
||||
|
||||
include_directories(${SecMedia_Root}/SVAC/src/svac_src)
|
||||
#添加svac解密
|
||||
aux_source_directory(${SecMedia_Root}/SVAC/src/sm2sm3 src_DEC)
|
||||
aux_source_directory(${SecMedia_Root}/SVAC/src/svac_src src_DEC)
|
||||
add_library(SVAC_DEC STATIC ${src_DEC})
|
||||
#添加svac加密
|
||||
#include_directories(${DEC_ENC_Algorithm}/SVAC/svac_enc)
|
||||
#file(GLOB src_DEC_ENC ${DEC_ENC_Algorithm}/SVAC/svac_enc/*/*.c ${DEC_ENC_Algorithm}/SVAC/svac_enc/*/*.h)
|
||||
aux_source_directory(${SecMedia_Root}/SVAC/src/sm2sm3_enc src_ENC)
|
||||
aux_source_directory(${SecMedia_Root}/SVAC/src/svac_src src_ENC)
|
||||
add_library(SVAC_ENC STATIC ${src_ENC})
|
||||
|
||||
list(APPEND LINK_LIB_SVAC_LIST SVAC_DEC)
|
||||
list(APPEND LINK_LIB_SVAC_LIST SVAC_ENC)
|
||||
|
||||
#添加密码卡库
|
||||
# add_definitions(-DENABLE_HARDWARE_SIGN)
|
||||
# list(APPEND LINK_LIB_SVAC_LIST sm.so)
|
||||
|
||||
include_directories(include src)
|
||||
|
||||
# add_definitions(-DGENERATE_EXPORT)
|
||||
|
||||
#file(GLOB SecMedia_src_list ${SecMedia_Root}/SVAC/./*.c ${SecMedia_Root}/SVAC/./*.h)
|
||||
file(GLOB SecMedia_src_list ${SecMedia_Root}/*/*.cpp ${SecMedia_Root}/*/*.h ${SecMedia_Root}/*/*.c ${SecMedia_Root}/*/*/*.cpp ${SecMedia_Root}/*/*/*.h ${SecMedia_Root}/*/*/*.c)
|
||||
file(GLOB SecMedia_api_list ${CMAKE_CURRENT_SOURCE_DIR}/include/common.h )
|
||||
|
||||
# # target_compile_options(${PROJECT_NAME} PRIVATE -fvisibility=hidden)
|
||||
# list(APPEND LINK_LIB_LIST ${LINK_LIB_SVAC_LIST})
|
||||
|
||||
add_library(${PROJECT_NAME} SHARED ${SecMedia_src_list})
|
||||
# add_library(${PROJECT_NAME} STATIC ${SecMedia_src_list})
|
||||
target_link_libraries(${PROJECT_NAME} ${LINK_LIB_SVAC_LIST} rtp)
|
||||
target_include_directories(${PROJECT_NAME} PRIVATE ${SecMedia_Root}/.)
|
||||
|
||||
# set_target_properties(${PROJECT_NAME} PROPERTIES
|
||||
# VERSION ${PROJECT_VERSION}
|
||||
# SOVERSION 1
|
||||
# PUBLIC_HEADER ${SecMedia_api_list}
|
||||
# )
|
||||
# CXX_VISIBILITY_PRESET hidden
|
||||
# CMAKE_C_FLAGS hidden)
|
||||
|
||||
list(APPEND LINK_LIB_LIST ${PROJECT_NAME})
|
||||
list(APPEND LINK_LIB_LIST pthread)
|
||||
|
||||
#查找jemalloc是否安装
|
||||
find_package(JEMALLOC QUIET)
|
||||
if(JEMALLOC_FOUND)
|
||||
message(STATUS "found library:\"${JEMALLOC_LIBRARIES}\"")
|
||||
include_directories(${JEMALLOC_INCLUDE_DIR})
|
||||
list(APPEND LINK_LIB_LIST ${JEMALLOC_LIBRARIES})
|
||||
else()
|
||||
message(WARNING "JEMALLOC not found")
|
||||
endif()
|
||||
|
||||
|
||||
#set(LINK_LIB_LIST )
|
||||
#MESSAGE(STATUS ${SecMedia_api_list})
|
||||
#configure_file(SecMedia.pc.in SecMedia.pc @ONLY)
|
||||
|
||||
# install(TARGETS ${PROJECT_NAME}
|
||||
# LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
# PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
|
||||
# install(FILES ${CMAKE_BINARY_DIR}/${PROJECT_NAME}.pc
|
||||
# DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/pkgconfig)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
add_subdirectory(test)
|
||||
add_subdirectory(PcapSender)
|
||||
add_subdirectory(PcapRawSender)
|
||||
add_subdirectory(SecSetGen)
|
16
PcapRawSender/CMakeLists.txt
Normal file
16
PcapRawSender/CMakeLists.txt
Normal file
@ -0,0 +1,16 @@
|
||||
include_directories(../include)
|
||||
|
||||
file(GLOB sender_src_list ./*.cpp ./*.h ../include/*.h)
|
||||
MESSAGE(STATUS ${sender_src_list})
|
||||
|
||||
|
||||
find_package(PcapPlusPlus CONFIG REQUIRED)
|
||||
find_package(DPDK REQUIRED)
|
||||
message(STATUS "Using Pcap++ ${PcapPlusPlus_VERSION}")
|
||||
message(STATUS "Include dir: ${PcapPlusPlus_INCLUDE_DIR}")
|
||||
message(STATUS "lib dir: ${PCAP_LIBRARY} ,${DPDK_LIBRARIES} ")
|
||||
add_executable(PcapRawSender ${sender_src_list})
|
||||
|
||||
target_link_libraries(PcapRawSender PUBLIC ${LINK_LIB_LIST} PUBLIC PcapPlusPlus::Pcap++ PUBLIC DPDK::DPDK)
|
||||
# target_link_libraries(PcapSender PUBLIC PcapPlusPlus::Pcap++)
|
||||
|
BIN
PcapRawSender/EncMedia_rtp.pcapng
Normal file
BIN
PcapRawSender/EncMedia_rtp.pcapng
Normal file
Binary file not shown.
BIN
PcapRawSender/EncMedia_rtp_encoded.pcapng
Normal file
BIN
PcapRawSender/EncMedia_rtp_encoded.pcapng
Normal file
Binary file not shown.
205
PcapRawSender/main.cpp
Normal file
205
PcapRawSender/main.cpp
Normal file
@ -0,0 +1,205 @@
|
||||
#include <iostream>
|
||||
#include <Packet.h>
|
||||
#include <PcapFileDevice.h>
|
||||
#include <UdpLayer.h>
|
||||
#include <string>
|
||||
#include <arpa/inet.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/select.h>
|
||||
#include "HuaWei/HWsign.h"
|
||||
#include "HuaWei/HWsec.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace pcpp;
|
||||
|
||||
std::string getProtocolTypeAsString(pcpp::ProtocolType protocolType)
|
||||
{
|
||||
switch (protocolType)
|
||||
{
|
||||
case pcpp::Ethernet:
|
||||
return "Ethernet";
|
||||
case pcpp::IPv4:
|
||||
return "IPv4";
|
||||
case pcpp::TCP:
|
||||
return "TCP";
|
||||
case pcpp::HTTPRequest:
|
||||
case pcpp::HTTPResponse:
|
||||
return "HTTP";
|
||||
case pcpp::UDP:
|
||||
return "UDP";
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
inline void sleep(timeval & delta){
|
||||
// delta.tv_sec
|
||||
select(0,NULL,NULL,NULL,&delta);
|
||||
}
|
||||
template<typename T,typename U>
|
||||
timespec TimeDiff(T && minu,U && sub){
|
||||
timespec deltatime;
|
||||
deltatime.tv_nsec=minu.tv_nsec-sub.tv_nsec;
|
||||
deltatime.tv_sec=minu.tv_sec-sub.tv_sec;
|
||||
if(deltatime.tv_nsec<0 && deltatime.tv_sec>0){
|
||||
deltatime.tv_nsec+=1000000000;
|
||||
deltatime.tv_sec--;
|
||||
}
|
||||
return move(deltatime);
|
||||
}
|
||||
|
||||
int ReadPcapAndSend(int socket,sockaddr_in & addr,const string & filename,const string & filter,void * sign_handle){
|
||||
pcpp::IFileReaderDevice * reader;
|
||||
reader=pcpp::IFileReaderDevice::getReader(filename);
|
||||
while (1)
|
||||
{
|
||||
|
||||
|
||||
|
||||
|
||||
// verify that a reader interface was indeed created
|
||||
if (reader == NULL)
|
||||
{
|
||||
std::cerr << "Cannot determine reader for file type" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
// open the reader for reading
|
||||
if (!reader->open())
|
||||
{
|
||||
std::cerr << "Cannot open input.pcap for reading" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!reader->setFilter(filter))
|
||||
{
|
||||
std::cerr << "Cannot set filter for file reader" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint8_t * payload;
|
||||
size_t payload_len;
|
||||
pcpp::RawPacket rawPacket;
|
||||
bool first_flag=true;
|
||||
timespec nowtime,gaptime;
|
||||
timespec real_now;
|
||||
timespec inital_time,current_time;
|
||||
static char sign_out_buf[3096];
|
||||
unsigned int sign_out_len;
|
||||
void *param=nullptr;
|
||||
uint16_t offset_len,append_len;
|
||||
while (reader->getNextPacket(rawPacket))
|
||||
{
|
||||
pcpp::Packet parsedPacket(&rawPacket,OsiModelTransportLayer);
|
||||
auto layer = parsedPacket.getLayerOfType<UdpLayer>(false);
|
||||
|
||||
if(layer){
|
||||
payload=layer->getLayerPayload();
|
||||
payload_len=layer->getLayerPayloadSize();
|
||||
// cout<<" payload_len:" << payload_len<<endl;
|
||||
nowtime=rawPacket.getPacketTimeStamp();
|
||||
clock_gettime(CLOCK_MONOTONIC, &real_now);
|
||||
if(first_flag){
|
||||
first_flag=false;
|
||||
inital_time=TimeDiff(nowtime,real_now);
|
||||
}
|
||||
current_time.tv_sec=inital_time.tv_sec+real_now.tv_sec;
|
||||
current_time.tv_nsec=inital_time.tv_nsec+real_now.tv_nsec;
|
||||
gaptime=TimeDiff(nowtime,current_time);
|
||||
if (gaptime.tv_nsec>=0 && gaptime.tv_sec>=0)
|
||||
{
|
||||
nanosleep(&gaptime,NULL);
|
||||
}else{
|
||||
// cout<<" s:" << gaptime.tv_sec<<" ns:" << gaptime.tv_nsec <<endl;
|
||||
}
|
||||
// ///////////////calculate send time//////////////////
|
||||
if(sendto(socket,payload,payload_len,0,(const sockaddr*)&addr,sizeof(addr))==-1){
|
||||
printf("send failed : %s\n", strerror(errno));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
// cout<<" stamp:" << rawPacket.getPacketTimeStamp().tv_sec<<" len:"<< rawPacket.getRawDataLen()<<endl;
|
||||
}
|
||||
cout<<" resend pcap" <<endl;
|
||||
reader->close();
|
||||
// delete reader;
|
||||
}
|
||||
|
||||
// reader->getNextPacket(rawPacket);
|
||||
|
||||
// for (pcpp::Layer* curLayer = parsedPacket.getFirstLayer(); curLayer != NULL; curLayer = curLayer->getNextLayer())
|
||||
// {
|
||||
// std::cout
|
||||
// << "Layer type: " <<getProtocolTypeAsString(curLayer->getProtocol()) << "; " // get layer type
|
||||
// << "Total data: " << curLayer->getDataLen() << " [bytes]; " // get total length of the layer
|
||||
// << "Layer data: " << curLayer->getHeaderLen() << " [bytes]; " // get the header length of the layer
|
||||
// << "Layer payload: " << curLayer->getLayerPayloadSize() << " [bytes]" // get the payload length of the layer (equals total length minus header length)
|
||||
// << std::endl;
|
||||
// }
|
||||
// create the stats object
|
||||
pcpp::IPcapDevice::PcapStats stats;
|
||||
reader->getStatistics(stats);
|
||||
std::cout << "Read " << stats.packetsRecv << " packets successfully and " << stats.packetsDrop << " packets could not be read" << std::flush;
|
||||
delete reader;
|
||||
return 0;
|
||||
}
|
||||
int main(int argc, char *argv[]){
|
||||
|
||||
char ip[16] = {0};
|
||||
int sockfd, port;
|
||||
if (argc>4)
|
||||
{
|
||||
string filename(argv[1]);
|
||||
strcpy(ip, argv[2]);
|
||||
port = atoi(argv[3]);
|
||||
string filter(argv[4]);
|
||||
printf("filename:%s\nip:%s\nport:%d\nfilter:%s\n", filename.data(), ip,port,filter.data());
|
||||
|
||||
sockfd = socket(AF_INET, SOCK_DGRAM , IPPROTO_UDP);//SOCK_STREAM
|
||||
if (sockfd == -1) {
|
||||
printf("create socket failed : %s\n", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
int rcvBufSize = 2097152;
|
||||
int rcvlen = sizeof(rcvBufSize);
|
||||
setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, (char*)&rcvBufSize, sizeof(rcvBufSize));
|
||||
if (getsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, (char*)&rcvBufSize, (socklen_t *)&rcvlen) >= 0)
|
||||
{
|
||||
printf("set udp socket send buff size to : %d\n", rcvBufSize);
|
||||
if (rcvBufSize < 4194304)
|
||||
{
|
||||
printf("socket send buff too small, please set up to 2097152(2M)");
|
||||
}
|
||||
}else {
|
||||
printf("socket failed : %s\n", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
struct sockaddr_in addr;
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = htons(port);
|
||||
addr.sin_addr.s_addr =inet_addr(ip);
|
||||
// if(connect(sockfd, (struct sockaddr*)&addr, sizeof(addr))==-1){
|
||||
// printf("connection error : %s\n", strerror(errno));
|
||||
// return -1;
|
||||
// }
|
||||
// bind(sockfd, (struct sockaddr*)&addr, sizeof(addr));
|
||||
// while (1)
|
||||
// {
|
||||
cout.flush();
|
||||
ReadPcapAndSend(sockfd,addr,filename,filter,NULL);
|
||||
// }
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("CMD as: filename.pcap ip port\n");
|
||||
system("pause");
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
|
||||
}
|
16
PcapSender/CMakeLists.txt
Normal file
16
PcapSender/CMakeLists.txt
Normal file
@ -0,0 +1,16 @@
|
||||
include_directories(../include)
|
||||
|
||||
file(GLOB sender_src_list ./*.cpp ./*.h ../include/*.h)
|
||||
MESSAGE(STATUS ${sender_src_list})
|
||||
|
||||
find_package(PcapPlusPlus CONFIG REQUIRED)
|
||||
find_package(DPDK REQUIRED)
|
||||
message(STATUS "Using Pcap++ ${PcapPlusPlus_VERSION}")
|
||||
message(STATUS "Include dir: ${PcapPlusPlus_INCLUDE_DIR}")
|
||||
|
||||
|
||||
add_executable(PcapSender ${sender_src_list})
|
||||
|
||||
target_link_libraries(PcapSender PUBLIC ${LINK_LIB_LIST} PUBLIC PcapPlusPlus::Pcap++ PUBLIC DPDK::DPDK)
|
||||
# target_link_libraries(PcapSender PUBLIC PcapPlusPlus::Pcap++)
|
||||
|
238
PcapSender/main.cpp
Normal file
238
PcapSender/main.cpp
Normal file
@ -0,0 +1,238 @@
|
||||
#include <iostream>
|
||||
#include <Packet.h>
|
||||
#include <PcapFileDevice.h>
|
||||
#include <UdpLayer.h>
|
||||
#include <string>
|
||||
#include <arpa/inet.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/select.h>
|
||||
#include "HuaWei/HWsign.h"
|
||||
#include "HuaWei/HWsec.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace pcpp;
|
||||
sec_set_info sign_info={
|
||||
2,
|
||||
"34020000001320000003",
|
||||
"2021-07-06T17:27:19.000",
|
||||
32,
|
||||
64,
|
||||
{
|
||||
0x24,0x88,0xc8,0xdc,0x7f,0xd7,0xe0,0x91,0x30,0x1b,0x5c,0x58,0x2f,0xe7,0x44,0x7d,
|
||||
0x2f,0x43,0xe4,0xee,0xc8,0x7d,0xc0,0xfb,0xa4,0xb8,0x7d,0x4b,0x8a,0x69,0x7c,0x4e
|
||||
},
|
||||
{
|
||||
0xaa,0xb1,0x3f,0xd7,0x66,0xe2,0x75,0x97,0xc0,0x03,0xe6,0xe4,0x1d,0x77,0x54,0x78,
|
||||
0xc8,0x29,0xb2,0x0b,0x9e,0xd1,0xff,0xa3,0x6a,0x6f,0xd2,0x7f,0xd6,0x2d,0xaa,0x3f,
|
||||
0xc9,0x24,0xec,0x6c,0x96,0x0a,0x7b,0x73,0xf6,0xe6,0xfc,0xda,0x3a,0x08,0xfd,0x92,
|
||||
0xfc,0x00,0x08,0x97,0x78,0x2c,0x71,0x6b,0xe1,0x26,0xf5,0x1e,0xba,0x31,0xf5,0xb2,
|
||||
}
|
||||
};
|
||||
void * EncrypInit(){
|
||||
// auto Verify_handle=HWVerify_init();
|
||||
|
||||
auto sign_handle=GB28181_stream_init(&sign_info); //HWSign_init(&sign_info);
|
||||
return sign_handle;
|
||||
}
|
||||
std::string getProtocolTypeAsString(pcpp::ProtocolType protocolType)
|
||||
{
|
||||
switch (protocolType)
|
||||
{
|
||||
case pcpp::Ethernet:
|
||||
return "Ethernet";
|
||||
case pcpp::IPv4:
|
||||
return "IPv4";
|
||||
case pcpp::TCP:
|
||||
return "TCP";
|
||||
case pcpp::HTTPRequest:
|
||||
case pcpp::HTTPResponse:
|
||||
return "HTTP";
|
||||
case pcpp::UDP:
|
||||
return "UDP";
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
inline void sleep(timeval & delta){
|
||||
// delta.tv_sec
|
||||
select(0,NULL,NULL,NULL,&delta);
|
||||
}
|
||||
template<typename T,typename U>
|
||||
timespec TimeDiff(T && minu,U && sub){
|
||||
timespec deltatime;
|
||||
deltatime.tv_nsec=minu.tv_nsec-sub.tv_nsec;
|
||||
deltatime.tv_sec=minu.tv_sec-sub.tv_sec;
|
||||
if(deltatime.tv_nsec<0 && deltatime.tv_sec>0){
|
||||
deltatime.tv_nsec+=1000000000;
|
||||
deltatime.tv_sec--;
|
||||
}
|
||||
return move(deltatime);
|
||||
}
|
||||
|
||||
int ReadPcapAndSend(int socket,sockaddr_in & addr,const string & filename,const string & filter,void * sign_handle){
|
||||
// auto sign_h2=EncrypInit();
|
||||
auto reader=pcpp::IFileReaderDevice::getReader(filename);
|
||||
// verify that a reader interface was indeed created
|
||||
if (reader == NULL)
|
||||
{
|
||||
std::cerr << "Cannot determine reader for file type" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
// open the reader for reading
|
||||
if (!reader->open())
|
||||
{
|
||||
std::cerr << "Cannot open input.pcap for reading" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!reader->setFilter(filter))
|
||||
{
|
||||
std::cerr << "Cannot set filter for file reader" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint8_t * payload;
|
||||
size_t payload_len;
|
||||
pcpp::RawPacket rawPacket;
|
||||
bool first_flag=true;
|
||||
timespec nowtime,gaptime;
|
||||
timespec real_now;
|
||||
timespec inital_time,current_time;
|
||||
static char sign_out_buf[3096];
|
||||
unsigned int sign_out_len;
|
||||
void *param=nullptr;
|
||||
uint16_t offset_len,append_len;
|
||||
while (reader->getNextPacket(rawPacket))
|
||||
{
|
||||
pcpp::Packet parsedPacket(&rawPacket,OsiModelTransportLayer);
|
||||
auto layer = parsedPacket.getLayerOfType<UdpLayer>(false);
|
||||
|
||||
if(layer){
|
||||
payload=layer->getLayerPayload();
|
||||
payload_len=layer->getLayerPayloadSize();
|
||||
// cout<<" payload_len:" << payload_len<<endl;
|
||||
nowtime=rawPacket.getPacketTimeStamp();
|
||||
clock_gettime(CLOCK_MONOTONIC, &real_now);
|
||||
if(first_flag){
|
||||
first_flag=false;
|
||||
inital_time=TimeDiff(nowtime,real_now);
|
||||
}
|
||||
current_time.tv_sec=inital_time.tv_sec+real_now.tv_sec;
|
||||
current_time.tv_nsec=inital_time.tv_nsec+real_now.tv_nsec;
|
||||
gaptime=TimeDiff(nowtime,current_time);
|
||||
if (gaptime.tv_nsec>=0 && gaptime.tv_sec>=0)
|
||||
{
|
||||
nanosleep(&gaptime,NULL);
|
||||
}else{
|
||||
// cout<<" s:" << gaptime.tv_sec<<" ns:" << gaptime.tv_nsec <<endl;
|
||||
}
|
||||
// ///////////////calculate send time//////////////////
|
||||
if(sign_handle){
|
||||
|
||||
GB28181_stream_in(sign_handle,(char*)payload,payload_len,nullptr);
|
||||
GB28181_stream_out(sign_handle,sign_out_buf,&sign_out_len,&offset_len,&append_len, ¶m);
|
||||
if (append_len==0)
|
||||
{
|
||||
sendto(socket,sign_out_buf,sign_out_len,0,(const sockaddr*)&addr,sizeof(addr));
|
||||
}else
|
||||
{
|
||||
sendto(socket,sign_out_buf,offset_len,0,(const sockaddr*)&addr,sizeof(addr));
|
||||
sendto(socket,sign_out_buf+offset_len,sign_out_len-offset_len,0,(const sockaddr*)&addr,sizeof(addr));
|
||||
}
|
||||
// GB28181_stream_in(sign_h2,(char*)payload,payload_len,nullptr);
|
||||
// GB28181_stream_out(sign_h2,sign_out_buf,&sign_out_len,&offset_len,&append_len, ¶m);
|
||||
|
||||
|
||||
|
||||
}else{
|
||||
if(sendto(socket,payload,payload_len,0,(const sockaddr*)&addr,sizeof(addr))==-1){
|
||||
printf("send failed : %s\n", strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
// cout<<" stamp:" << rawPacket.getPacketTimeStamp().tv_sec<<" len:"<< rawPacket.getRawDataLen()<<endl;
|
||||
}
|
||||
|
||||
|
||||
// reader->getNextPacket(rawPacket);
|
||||
|
||||
// for (pcpp::Layer* curLayer = parsedPacket.getFirstLayer(); curLayer != NULL; curLayer = curLayer->getNextLayer())
|
||||
// {
|
||||
// std::cout
|
||||
// << "Layer type: " <<getProtocolTypeAsString(curLayer->getProtocol()) << "; " // get layer type
|
||||
// << "Total data: " << curLayer->getDataLen() << " [bytes]; " // get total length of the layer
|
||||
// << "Layer data: " << curLayer->getHeaderLen() << " [bytes]; " // get the header length of the layer
|
||||
// << "Layer payload: " << curLayer->getLayerPayloadSize() << " [bytes]" // get the payload length of the layer (equals total length minus header length)
|
||||
// << std::endl;
|
||||
// }
|
||||
// create the stats object
|
||||
pcpp::IPcapDevice::PcapStats stats;
|
||||
reader->getStatistics(stats);
|
||||
std::cout << "Read " << stats.packetsRecv << " packets successfully and " << stats.packetsDrop << " packets could not be read" << std::flush;
|
||||
return 0;
|
||||
}
|
||||
int main(int argc, char *argv[]){
|
||||
|
||||
char ip[16] = {0};
|
||||
int sockfd, port;
|
||||
if (argc>4)
|
||||
{
|
||||
string filename(argv[1]);
|
||||
strcpy(ip, argv[2]);
|
||||
port = atoi(argv[3]);
|
||||
string filter(argv[4]);
|
||||
printf("filename:%s\nip:%s\nport:%d\nfilter:%s\n", filename.data(), ip,port,filter.data());
|
||||
|
||||
sockfd = socket(AF_INET, SOCK_DGRAM , IPPROTO_UDP);//SOCK_STREAM
|
||||
if (sockfd == -1) {
|
||||
printf("create socket failed : %s\n", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
int rcvBufSize = 2097152;
|
||||
int rcvlen = sizeof(rcvBufSize);
|
||||
setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, (char*)&rcvBufSize, sizeof(rcvBufSize));
|
||||
if (getsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, (char*)&rcvBufSize, (socklen_t *)&rcvlen) >= 0)
|
||||
{
|
||||
printf("set udp socket send buff size to : %d\n", rcvBufSize);
|
||||
if (rcvBufSize < 4194304)
|
||||
{
|
||||
printf("socket send buff too small, please set up to 2097152(2M)");
|
||||
}
|
||||
}else {
|
||||
printf("socket failed : %s\n", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
struct sockaddr_in addr;
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = htons(port);
|
||||
addr.sin_addr.s_addr =inet_addr(ip);
|
||||
// if(connect(sockfd, (struct sockaddr*)&addr, sizeof(addr))==-1){
|
||||
// printf("connection error : %s\n", strerror(errno));
|
||||
// return -1;
|
||||
// }
|
||||
// bind(sockfd, (struct sockaddr*)&addr, sizeof(addr));
|
||||
// while (1)
|
||||
// {
|
||||
cout.flush();
|
||||
auto sign_h=EncrypInit();
|
||||
|
||||
ReadPcapAndSend(sockfd,addr,filename,filter,sign_h);
|
||||
// }
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("CMD as: filename.pcap ip port\n");
|
||||
system("pause");
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
|
||||
}
|
BIN
SecMedia.zip
Normal file
BIN
SecMedia.zip
Normal file
Binary file not shown.
59
SecMedia/Linux/include/Decrypt.h
Normal file
59
SecMedia/Linux/include/Decrypt.h
Normal file
@ -0,0 +1,59 @@
|
||||
#ifndef _DECRYPT_H
|
||||
#define _DECRYPT_H
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef void *dec_media;
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
/// alloc new packet
|
||||
/// @param[in] param user-defined parameter(by dec_media_create)
|
||||
/// @param[in] bytes alloc memory size in byte
|
||||
/// @return memory pointer
|
||||
void* (API_CALL *alloc)(void* param, size_t bytes);
|
||||
|
||||
/// free packet
|
||||
/// @param[in] param user-defined parameter(by dec_media_create)
|
||||
/// @param[in] packet frame packet pointer(alloc return pointer)
|
||||
void (API_CALL *free)(void* param, void* packet);
|
||||
|
||||
/// callback on PS packet done
|
||||
/// @param[in] param user-defined parameter(by dec_media_create)
|
||||
/// @param[in] packet frame packet pointer(alloc return pointer)
|
||||
/// @param[in] bytes packet size
|
||||
/// @param[in] timestamp packet timestamp
|
||||
/// @param[in] frametype packet type
|
||||
void (API_CALL *write)(void* param, void* packet, size_t bytes,uint64_t timestamp,uint8_t frametype);
|
||||
}dec_media_func_t;
|
||||
|
||||
|
||||
/// create a object for decrypt media data
|
||||
/// @param func call back (dec_media_func_t)
|
||||
/// @param param user-defined parameter
|
||||
API_EXPORT dec_media API_CALL dec_media_create(dec_media_func_t * func,void * param) ;
|
||||
|
||||
/// input media data(only accept single frame, merged frame(such as sps pps I ) should be feeded in separately)
|
||||
/// @param frame_type the type of NALU
|
||||
/// @param prefix the number of prefix bytes, (0x00 0x00 0x00 0x01) => prefix=4
|
||||
API_EXPORT int API_CALL dec_media_decoded(dec_media ctx,uint8_t* frame,size_t len,uint64_t timestamp, uint8_t frame_type,uint8_t prefix);
|
||||
|
||||
/// input media data(only accept single frame, merged frame(such as sps pps I ) should be feeded in separately)
|
||||
/// @param frame frame data
|
||||
/// @param prefix the number of prefix bytes, (0x00 0x00 0x00 0x01) => prefix=4
|
||||
/// @param code 0:h264 1:h265 6:svac
|
||||
/// @param return <0:error >=0:security level
|
||||
API_EXPORT int API_CALL dec_security_SEI(uint8_t* frame,size_t len,uint8_t prefix,uint8_t code);
|
||||
|
||||
API_EXPORT void API_CALL dec_media_release(dec_media ctx);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _DECRYPT_H */
|
44
SecMedia/Linux/include/Encrypt.h
Normal file
44
SecMedia/Linux/include/Encrypt.h
Normal file
@ -0,0 +1,44 @@
|
||||
#ifndef _ENCRYPT_H
|
||||
#define _ENCRYPT_H
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef void *enc_media;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
/// alloc new packet
|
||||
/// @param[in] param user-defined parameter(by enc_media_create)
|
||||
/// @param[in] bytes alloc memory size in byte
|
||||
/// @return memory pointer
|
||||
void* (API_CALL *alloc)(void* param, size_t bytes);
|
||||
|
||||
/// free packet
|
||||
/// @param[in] param user-defined parameter(by enc_media_create)
|
||||
/// @param[in] packet frame packet pointer(alloc return pointer)
|
||||
void (API_CALL *free)(void* param, void* packet);
|
||||
|
||||
/// callback on PS packet done
|
||||
/// @param[in] param user-defined parameter(by enc_media_create)
|
||||
/// @param[in] packet frame packet pointer(alloc return pointer)
|
||||
/// @param[in] bytes packet size
|
||||
/// @param[in] timestamp packet timestamp
|
||||
/// @param[in] frametype packet type
|
||||
void (API_CALL *write)(void* param, void* packet, size_t bytes,uint64_t timestamp,uint8_t frametype);
|
||||
}enc_media_func_t;
|
||||
|
||||
API_EXPORT enc_media API_CALL enc_media_create(enc_media_func_t * func, void * param) ;
|
||||
|
||||
API_EXPORT int API_CALL enc_media_decoded(enc_media ctx,uint8_t* frame,size_t len,uint64_t timestamp, uint8_t frame_type,uint8_t prefix);
|
||||
|
||||
API_EXPORT void API_CALL enc_media_release(enc_media ctx);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _DECRYPT_H */
|
62
SecMedia/Linux/include/common.h
Normal file
62
SecMedia/Linux/include/common.h
Normal file
@ -0,0 +1,62 @@
|
||||
#ifndef _COMMON_H
|
||||
#define _COMMON_H
|
||||
|
||||
#if defined(_WIN32) && defined(_MSC_VER)
|
||||
# define API_CALL __cdecl
|
||||
# define SecMedia_Api_EXPORTS
|
||||
#else
|
||||
# define API_CALL
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32) && defined(_MSC_VER)
|
||||
# if defined(SecMedia_Api_EXPORTS)
|
||||
# define API_EXPORT __declspec(dllexport)
|
||||
# else
|
||||
# define API_EXPORT __declspec(dllimport)
|
||||
# endif
|
||||
#endif
|
||||
|
||||
# ifndef API_EXPORT
|
||||
# define API_EXPORT __attribute__((visibility("default")))
|
||||
# endif
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
CodecInvalid = -1,
|
||||
CodecH264 = 0,
|
||||
CodecH265,
|
||||
CodecAAC,
|
||||
CodecG711A,
|
||||
CodecG711U,
|
||||
CodecOpus,
|
||||
CodecSVAC,
|
||||
CodecMax = 0x7FFF
|
||||
} CodecId;
|
||||
|
||||
enum class DecEncType{
|
||||
NONE=15,
|
||||
SM1=0,
|
||||
SM4=1,
|
||||
RSA=2,
|
||||
AES=3,
|
||||
SVACEnc=4,
|
||||
SVACDec=5,
|
||||
SM3,
|
||||
SM2_auth
|
||||
};
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* MK_COMMON_H */
|
BIN
SecMedia/Linux/libSecMedia.so
Normal file
BIN
SecMedia/Linux/libSecMedia.so
Normal file
Binary file not shown.
10
SecMedia/Linux/test/CMakeLists.txt
Normal file
10
SecMedia/Linux/test/CMakeLists.txt
Normal file
@ -0,0 +1,10 @@
|
||||
include_directories(../include)
|
||||
|
||||
file(GLOB test_src_list ./*.cpp ./*.h)
|
||||
|
||||
MESSAGE(STATUS ${test_src_list})
|
||||
|
||||
add_executable(tests ${test_src_list})
|
||||
|
||||
target_link_libraries(tests ${LINK_LIB_LIST})
|
||||
|
102
SecMedia/Linux/test/main.cpp
Normal file
102
SecMedia/Linux/test/main.cpp
Normal file
@ -0,0 +1,102 @@
|
||||
#include<stdlib.h>
|
||||
#include<stdio.h>
|
||||
#include "common.h"
|
||||
#include "Decrypt.h"
|
||||
#include "Encrypt.h"
|
||||
|
||||
#define H264_TYPE(v) ((uint8_t)(v) & 0x1F)
|
||||
#define FRAME_SIZE 6
|
||||
#define FRAME_LEN 10
|
||||
const uint8_t rawframe[FRAME_SIZE][FRAME_LEN]={
|
||||
{0x00,0x00,0x00,0x01,0x61,0x01,0x02,0x03,0x04,0x05},
|
||||
{0x00,0x00,0x00,0x01,0x65,0x01,0x02,0x03,0x04,0x05},
|
||||
{0x00,0x00,0x00,0x01,0x67,0x01,0x02,0x03,0x04,0x05},
|
||||
{0x00,0x00,0x00,0x01,0x61,0xf1,0xf2,0xf3,0xf4,0xf5},
|
||||
{0x00,0x00,0x00,0x01,0x61,0x01,0x02,0x03,0x04,0x05},
|
||||
{0x00,0x00,0x00,0x01,0x61,0x01,0x02,0x03,0x04,0x05},
|
||||
};
|
||||
|
||||
int main(int argc, char *argv[]){
|
||||
dec_media dec_media_obj;
|
||||
dec_media_func_t dec_fun={
|
||||
//alloc
|
||||
[](void* param, size_t bytes){
|
||||
return (void*)malloc(sizeof(uint8_t)*bytes);
|
||||
},
|
||||
//free
|
||||
[](void* param, void* packet){
|
||||
free(packet);
|
||||
},
|
||||
//write
|
||||
[](void* param, void* packet, size_t bytes,uint64_t timestamp,uint8_t frametype){
|
||||
printf("\n");
|
||||
printf("type: %d timestamp:%lld lens:%zd\n", frametype, timestamp, bytes);
|
||||
uint8_t * ptr=(uint8_t*)packet;
|
||||
for (size_t i = 0; i < bytes; i++)
|
||||
{
|
||||
printf("%02X ", *(ptr++));
|
||||
}
|
||||
printf("\n");
|
||||
printf("-----------Decrypted data----------------- ");
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
dec_media_obj=dec_media_create(&dec_fun,NULL);
|
||||
|
||||
|
||||
enc_media enc_media_obj;
|
||||
enc_media_func_t enc_fun;
|
||||
enc_fun={
|
||||
//alloc
|
||||
[](void* param, size_t bytes){
|
||||
return (void*)malloc(sizeof(uint8_t)*bytes);
|
||||
},
|
||||
//free
|
||||
[](void* param, void* packet){
|
||||
free(packet);
|
||||
},
|
||||
//write
|
||||
[](void* param, void* packet, size_t bytes,uint64_t timestamp,uint8_t frametype){
|
||||
printf("\n");
|
||||
printf("type: %d timestamp:%lld lens:%zd\n", frametype, timestamp, bytes);
|
||||
uint8_t * ptr=(uint8_t*)packet;
|
||||
for (size_t i = 0; i < bytes; i++)
|
||||
{
|
||||
printf("%02X ", *(ptr++));
|
||||
}
|
||||
printf("\n");
|
||||
int ret=dec_security_SEI((uint8_t*)packet,bytes,4,0);
|
||||
if (ret>0)
|
||||
{
|
||||
printf("\nSecurity level: %d\n",ret);
|
||||
}
|
||||
|
||||
printf("############Encrypted data############ ");
|
||||
dec_media_decoded((dec_media) param,(uint8_t*)packet,bytes,timestamp,frametype,4);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
enc_media_obj=enc_media_create(&enc_fun,(void*)dec_media_obj);
|
||||
|
||||
uint32_t timestamp=0;
|
||||
for (size_t i = 0; i < FRAME_SIZE; i++)
|
||||
{
|
||||
uint8_t * ptr=(uint8_t*)rawframe[i];
|
||||
printf("\n");
|
||||
printf("type: %d timestamp:%d lens:%d\n", H264_TYPE(*(rawframe[i]+4)), timestamp, FRAME_LEN);
|
||||
for (size_t i = 0; i < FRAME_LEN; i++)
|
||||
{
|
||||
printf("%02X ", *(ptr++));
|
||||
}
|
||||
printf("\n");
|
||||
printf("//////////////////Raw data//////////////////// ");
|
||||
enc_media_decoded(enc_media_obj,(uint8_t*)rawframe[i],FRAME_LEN,timestamp,H264_TYPE(*(rawframe[i]+4)),4);
|
||||
timestamp+=100;
|
||||
}
|
||||
|
||||
dec_media_release(dec_media_obj);
|
||||
enc_media_release(enc_media_obj);
|
||||
return 0;
|
||||
}
|
BIN
SecMedia/Linux/tests
Normal file
BIN
SecMedia/Linux/tests
Normal file
Binary file not shown.
BIN
SecMedia/Windows/SecMedia.dll
Normal file
BIN
SecMedia/Windows/SecMedia.dll
Normal file
Binary file not shown.
59
SecMedia/Windows/include/Decrypt.h
Normal file
59
SecMedia/Windows/include/Decrypt.h
Normal file
@ -0,0 +1,59 @@
|
||||
#ifndef _DECRYPT_H
|
||||
#define _DECRYPT_H
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef void *dec_media;
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
/// alloc new packet
|
||||
/// @param[in] param user-defined parameter(by dec_media_create)
|
||||
/// @param[in] bytes alloc memory size in byte
|
||||
/// @return memory pointer
|
||||
void* (API_CALL *alloc)(void* param, size_t bytes);
|
||||
|
||||
/// free packet
|
||||
/// @param[in] param user-defined parameter(by dec_media_create)
|
||||
/// @param[in] packet frame packet pointer(alloc return pointer)
|
||||
void (API_CALL *free)(void* param, void* packet);
|
||||
|
||||
/// callback on PS packet done
|
||||
/// @param[in] param user-defined parameter(by dec_media_create)
|
||||
/// @param[in] packet frame packet pointer(alloc return pointer)
|
||||
/// @param[in] bytes packet size
|
||||
/// @param[in] timestamp packet timestamp
|
||||
/// @param[in] frametype packet type
|
||||
void (API_CALL *write)(void* param, void* packet, size_t bytes,uint64_t timestamp,uint8_t frametype);
|
||||
}dec_media_func_t;
|
||||
|
||||
|
||||
/// create a object for decrypt media data
|
||||
/// @param func call back (dec_media_func_t)
|
||||
/// @param param user-defined parameter
|
||||
API_EXPORT dec_media API_CALL dec_media_create(dec_media_func_t * func,void * param) ;
|
||||
|
||||
/// input media data(only accept single frame, merged frame(such as sps pps I ) should be feeded in separately)
|
||||
/// @param frame_type the type of NALU
|
||||
/// @param prefix the number of prefix bytes, (0x00 0x00 0x00 0x01) => prefix=4
|
||||
API_EXPORT int API_CALL dec_media_decoded(dec_media ctx,uint8_t* frame,size_t len,uint64_t timestamp, uint8_t frame_type,uint8_t prefix);
|
||||
|
||||
/// input media data(only accept single frame, merged frame(such as sps pps I ) should be feeded in separately)
|
||||
/// @param frame frame data
|
||||
/// @param prefix the number of prefix bytes, (0x00 0x00 0x00 0x01) => prefix=4
|
||||
/// @param code 0:h264 1:h265 6:svac
|
||||
/// @param return <0:error >=0:security level
|
||||
API_EXPORT int API_CALL dec_security_SEI(uint8_t* frame,size_t len,uint8_t prefix,uint8_t code);
|
||||
|
||||
API_EXPORT void API_CALL dec_media_release(dec_media ctx);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _DECRYPT_H */
|
44
SecMedia/Windows/include/Encrypt.h
Normal file
44
SecMedia/Windows/include/Encrypt.h
Normal file
@ -0,0 +1,44 @@
|
||||
#ifndef _ENCRYPT_H
|
||||
#define _ENCRYPT_H
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef void *enc_media;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
/// alloc new packet
|
||||
/// @param[in] param user-defined parameter(by enc_media_create)
|
||||
/// @param[in] bytes alloc memory size in byte
|
||||
/// @return memory pointer
|
||||
void* (API_CALL *alloc)(void* param, size_t bytes);
|
||||
|
||||
/// free packet
|
||||
/// @param[in] param user-defined parameter(by enc_media_create)
|
||||
/// @param[in] packet frame packet pointer(alloc return pointer)
|
||||
void (API_CALL *free)(void* param, void* packet);
|
||||
|
||||
/// callback on PS packet done
|
||||
/// @param[in] param user-defined parameter(by enc_media_create)
|
||||
/// @param[in] packet frame packet pointer(alloc return pointer)
|
||||
/// @param[in] bytes packet size
|
||||
/// @param[in] timestamp packet timestamp
|
||||
/// @param[in] frametype packet type
|
||||
void (API_CALL *write)(void* param, void* packet, size_t bytes,uint64_t timestamp,uint8_t frametype);
|
||||
}enc_media_func_t;
|
||||
|
||||
API_EXPORT enc_media API_CALL enc_media_create(enc_media_func_t * func, void * param) ;
|
||||
|
||||
API_EXPORT int API_CALL enc_media_decoded(enc_media ctx,uint8_t* frame,size_t len,uint64_t timestamp, uint8_t frame_type,uint8_t prefix);
|
||||
|
||||
API_EXPORT void API_CALL enc_media_release(enc_media ctx);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _DECRYPT_H */
|
62
SecMedia/Windows/include/common.h
Normal file
62
SecMedia/Windows/include/common.h
Normal file
@ -0,0 +1,62 @@
|
||||
#ifndef _COMMON_H
|
||||
#define _COMMON_H
|
||||
|
||||
#if defined(_WIN32) && defined(_MSC_VER)
|
||||
# define API_CALL __cdecl
|
||||
# define SecMedia_Api_EXPORTS
|
||||
#else
|
||||
# define API_CALL
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32) && defined(_MSC_VER)
|
||||
# if defined(SecMedia_Api_EXPORTS)
|
||||
# define API_EXPORT __declspec(dllexport)
|
||||
# else
|
||||
# define API_EXPORT __declspec(dllimport)
|
||||
# endif
|
||||
#endif
|
||||
|
||||
# ifndef API_EXPORT
|
||||
# define API_EXPORT __attribute__((visibility("default")))
|
||||
# endif
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
CodecInvalid = -1,
|
||||
CodecH264 = 0,
|
||||
CodecH265,
|
||||
CodecAAC,
|
||||
CodecG711A,
|
||||
CodecG711U,
|
||||
CodecOpus,
|
||||
CodecSVAC,
|
||||
CodecMax = 0x7FFF
|
||||
} CodecId;
|
||||
|
||||
enum class DecEncType{
|
||||
NONE=15,
|
||||
SM1=0,
|
||||
SM4=1,
|
||||
RSA=2,
|
||||
AES=3,
|
||||
SVACEnc=4,
|
||||
SVACDec=5,
|
||||
SM3,
|
||||
SM2_auth
|
||||
};
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* MK_COMMON_H */
|
10
SecMedia/Windows/test/CMakeLists.txt
Normal file
10
SecMedia/Windows/test/CMakeLists.txt
Normal file
@ -0,0 +1,10 @@
|
||||
include_directories(../include)
|
||||
|
||||
file(GLOB test_src_list ./*.cpp ./*.h)
|
||||
|
||||
MESSAGE(STATUS ${test_src_list})
|
||||
|
||||
add_executable(tests ${test_src_list})
|
||||
|
||||
target_link_libraries(tests ${LINK_LIB_LIST})
|
||||
|
102
SecMedia/Windows/test/main.cpp
Normal file
102
SecMedia/Windows/test/main.cpp
Normal file
@ -0,0 +1,102 @@
|
||||
#include<stdlib.h>
|
||||
#include<stdio.h>
|
||||
#include "common.h"
|
||||
#include "Decrypt.h"
|
||||
#include "Encrypt.h"
|
||||
|
||||
#define H264_TYPE(v) ((uint8_t)(v) & 0x1F)
|
||||
#define FRAME_SIZE 6
|
||||
#define FRAME_LEN 10
|
||||
const uint8_t rawframe[FRAME_SIZE][FRAME_LEN]={
|
||||
{0x00,0x00,0x00,0x01,0x61,0x01,0x02,0x03,0x04,0x05},
|
||||
{0x00,0x00,0x00,0x01,0x65,0x01,0x02,0x03,0x04,0x05},
|
||||
{0x00,0x00,0x00,0x01,0x67,0x01,0x02,0x03,0x04,0x05},
|
||||
{0x00,0x00,0x00,0x01,0x61,0xf1,0xf2,0xf3,0xf4,0xf5},
|
||||
{0x00,0x00,0x00,0x01,0x61,0x01,0x02,0x03,0x04,0x05},
|
||||
{0x00,0x00,0x00,0x01,0x61,0x01,0x02,0x03,0x04,0x05},
|
||||
};
|
||||
|
||||
int main(int argc, char *argv[]){
|
||||
dec_media dec_media_obj;
|
||||
dec_media_func_t dec_fun={
|
||||
//alloc
|
||||
[](void* param, size_t bytes){
|
||||
return (void*)malloc(sizeof(uint8_t)*bytes);
|
||||
},
|
||||
//free
|
||||
[](void* param, void* packet){
|
||||
free(packet);
|
||||
},
|
||||
//write
|
||||
[](void* param, void* packet, size_t bytes,uint64_t timestamp,uint8_t frametype){
|
||||
printf("\n");
|
||||
printf("type: %d %lld,%zd\n", frametype, timestamp, bytes);
|
||||
uint8_t * ptr=(uint8_t*)packet;
|
||||
for (size_t i = 0; i < bytes; i++)
|
||||
{
|
||||
printf("%02X ", *(ptr++));
|
||||
}
|
||||
printf("\n");
|
||||
printf("-----------Decrypted data----------------- ");
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
dec_media_obj=dec_media_create(&dec_fun,NULL);
|
||||
|
||||
|
||||
enc_media enc_media_obj;
|
||||
enc_media_func_t enc_fun;
|
||||
enc_fun={
|
||||
//alloc
|
||||
[](void* param, size_t bytes){
|
||||
return (void*)malloc(sizeof(uint8_t)*bytes);
|
||||
},
|
||||
//free
|
||||
[](void* param, void* packet){
|
||||
free(packet);
|
||||
},
|
||||
//write
|
||||
[](void* param, void* packet, size_t bytes,uint64_t timestamp,uint8_t frametype){
|
||||
printf("\n");
|
||||
printf("type: %d %lld,%zd\n", frametype, timestamp, bytes);
|
||||
uint8_t * ptr=(uint8_t*)packet;
|
||||
for (size_t i = 0; i < bytes; i++)
|
||||
{
|
||||
printf("%02X ", *(ptr++));
|
||||
}
|
||||
printf("\n");
|
||||
int ret=dec_security_SEI((uint8_t*)packet,bytes,4,0);
|
||||
if (ret>0)
|
||||
{
|
||||
printf("\nSecurity level: %d\n",ret);
|
||||
}
|
||||
|
||||
printf("############Encrypted data############ ");
|
||||
dec_media_decoded((dec_media) param,(uint8_t*)packet,bytes,timestamp,frametype,4);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
enc_media_obj=enc_media_create(&enc_fun,(void*)dec_media_obj);
|
||||
|
||||
uint32_t timestamp=0;
|
||||
for (size_t i = 0; i < FRAME_SIZE; i++)
|
||||
{
|
||||
uint8_t * ptr=(uint8_t*)rawframe[i];
|
||||
printf("\n");
|
||||
printf("type: %d %d,%d\n", H264_TYPE(*(rawframe[i]+4)), timestamp, FRAME_LEN);
|
||||
for (size_t i = 0; i < FRAME_LEN; i++)
|
||||
{
|
||||
printf("%02X ", *(ptr++));
|
||||
}
|
||||
printf("\n");
|
||||
printf("//////////////////Raw data//////////////////// ");
|
||||
enc_media_decoded(enc_media_obj,(uint8_t*)rawframe[i],FRAME_LEN,timestamp,H264_TYPE(*(rawframe[i]+4)),4);
|
||||
timestamp+=100;
|
||||
}
|
||||
|
||||
dec_media_release(dec_media_obj);
|
||||
enc_media_release(enc_media_obj);
|
||||
return 0;
|
||||
}
|
BIN
SecMedia/Windows/tests.exe
Normal file
BIN
SecMedia/Windows/tests.exe
Normal file
Binary file not shown.
10
SecSetGen/CMakeLists.txt
Normal file
10
SecSetGen/CMakeLists.txt
Normal file
@ -0,0 +1,10 @@
|
||||
include_directories(../include)
|
||||
|
||||
file(GLOB sender_src_list ./*.cpp ./*.h ../include/*.h)
|
||||
MESSAGE(STATUS ${sender_src_list})
|
||||
|
||||
add_executable(SecSetGen ${sender_src_list})
|
||||
|
||||
target_link_libraries(SecSetGen PUBLIC ${LINK_LIB_LIST})
|
||||
# target_link_libraries(PcapSender PUBLIC PcapPlusPlus::Pcap++)
|
||||
|
60
SecSetGen/main.cpp
Normal file
60
SecSetGen/main.cpp
Normal file
@ -0,0 +1,60 @@
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <stdio.h>
|
||||
#include <memory>
|
||||
#include <string.h>
|
||||
#include <vector>
|
||||
using namespace std;
|
||||
|
||||
|
||||
class SecSet
|
||||
{
|
||||
public:
|
||||
typedef shared_ptr<SecSet> Ptr;
|
||||
private:
|
||||
vector<char> _buf;
|
||||
// char * _buf=nullptr;
|
||||
size_t _len=0;
|
||||
public:
|
||||
SecSet(/* args */){};
|
||||
~SecSet(){
|
||||
// if(_buf) delete _buf;
|
||||
_len=0;
|
||||
}
|
||||
void setBuf(const char * buf, size_t len){
|
||||
|
||||
// _buf.clear();
|
||||
_buf.assign(buf,buf+len);
|
||||
// if(!_buf){
|
||||
// _buf=new char[len] ;_len=len;
|
||||
// }
|
||||
// if (len>_len)
|
||||
// {
|
||||
// _buf=(char*)realloc(_buf,len) ;_len=len;
|
||||
// }
|
||||
// memcpy(_buf,buf,len);
|
||||
}
|
||||
void printBuf(){
|
||||
printf("%s len %lu\n",_buf.data(),_buf.size());
|
||||
}
|
||||
|
||||
Ptr clone(){
|
||||
return make_shared<remove_reference<decltype(*this)>::type>(*this);
|
||||
}
|
||||
};
|
||||
|
||||
int main(){
|
||||
const char hl[]={"Hello World!"};
|
||||
const char hl2[]={"Hello World_twic!"};
|
||||
SecSet::Ptr A=make_shared<SecSet>() ;
|
||||
A->setBuf(hl,sizeof(hl));
|
||||
A->printBuf();
|
||||
auto B=A->clone();
|
||||
A->setBuf(hl2,sizeof(hl2));
|
||||
A->printBuf();
|
||||
B->printBuf();
|
||||
A->setBuf(hl,sizeof(hl));A->printBuf();
|
||||
B->printBuf();
|
||||
return 0;
|
||||
}
|
||||
|
3727
force_link_glibc_2.27.h
Normal file
3727
force_link_glibc_2.27.h
Normal file
File diff suppressed because it is too large
Load Diff
59
include/Decrypt.h
Normal file
59
include/Decrypt.h
Normal file
@ -0,0 +1,59 @@
|
||||
#ifndef _DECRYPT_H
|
||||
#define _DECRYPT_H
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef void *dec_media;
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
/// alloc new packet
|
||||
/// @param[in] param user-defined parameter(by dec_media_create)
|
||||
/// @param[in] bytes alloc memory size in byte
|
||||
/// @return memory pointer
|
||||
void* (API_CALL *alloc)(void* param, size_t bytes);
|
||||
|
||||
/// free packet
|
||||
/// @param[in] param user-defined parameter(by dec_media_create)
|
||||
/// @param[in] packet frame packet pointer(alloc return pointer)
|
||||
void (API_CALL *free)(void* param, void* packet);
|
||||
|
||||
/// callback on PS packet done
|
||||
/// @param[in] param user-defined parameter(by dec_media_create)
|
||||
/// @param[in] packet frame packet pointer(alloc return pointer)
|
||||
/// @param[in] bytes packet size
|
||||
/// @param[in] timestamp packet timestamp
|
||||
/// @param[in] frametype packet type
|
||||
void (API_CALL *write)(void* param, void* packet, size_t bytes,uint64_t timestamp,uint8_t frametype);
|
||||
}dec_media_func_t;
|
||||
|
||||
|
||||
/// create a object for decrypt media data
|
||||
/// @param func call back (dec_media_func_t)
|
||||
/// @param param user-defined parameter
|
||||
API_EXPORT dec_media API_CALL dec_media_create(dec_media_func_t * func,void * param) ;
|
||||
|
||||
/// input media data(only accept single frame, merged frame(such as sps pps I ) should be feeded in separately)
|
||||
/// @param frame_type the type of NALU
|
||||
/// @param prefix the number of prefix bytes, (0x00 0x00 0x00 0x01) => prefix=4
|
||||
API_EXPORT int API_CALL dec_media_decoded(dec_media ctx,uint8_t* frame,size_t len,uint64_t timestamp, uint8_t frame_type,uint8_t prefix);
|
||||
|
||||
/// input media data(only accept single frame, merged frame(such as sps pps I ) should be feeded in separately)
|
||||
/// @param frame frame data
|
||||
/// @param prefix the number of prefix bytes, (0x00 0x00 0x00 0x01) => prefix=4
|
||||
/// @param code 0:h264 1:h265 6:svac
|
||||
/// @param return <0:error >=0:security level
|
||||
API_EXPORT int API_CALL dec_security_SEI(uint8_t* frame,size_t len,uint8_t prefix,uint8_t code);
|
||||
|
||||
API_EXPORT void API_CALL dec_media_release(dec_media ctx);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _DECRYPT_H */
|
44
include/Encrypt.h
Normal file
44
include/Encrypt.h
Normal file
@ -0,0 +1,44 @@
|
||||
#ifndef _ENCRYPT_H
|
||||
#define _ENCRYPT_H
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef void *enc_media;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
/// alloc new packet
|
||||
/// @param[in] param user-defined parameter(by enc_media_create)
|
||||
/// @param[in] bytes alloc memory size in byte
|
||||
/// @return memory pointer
|
||||
void* (API_CALL *alloc)(void* param, size_t bytes);
|
||||
|
||||
/// free packet
|
||||
/// @param[in] param user-defined parameter(by enc_media_create)
|
||||
/// @param[in] packet frame packet pointer(alloc return pointer)
|
||||
void (API_CALL *free)(void* param, void* packet);
|
||||
|
||||
/// callback on PS packet done
|
||||
/// @param[in] param user-defined parameter(by enc_media_create)
|
||||
/// @param[in] packet frame packet pointer(alloc return pointer)
|
||||
/// @param[in] bytes packet size
|
||||
/// @param[in] timestamp packet timestamp
|
||||
/// @param[in] frametype packet type
|
||||
void (API_CALL *write)(void* param, void* packet, size_t bytes,uint64_t timestamp,uint8_t frametype);
|
||||
}enc_media_func_t;
|
||||
|
||||
API_EXPORT enc_media API_CALL enc_media_create(enc_media_func_t * func, void * param) ;
|
||||
|
||||
API_EXPORT int API_CALL enc_media_decoded(enc_media ctx,uint8_t* frame,size_t len,uint64_t timestamp, uint8_t frame_type,uint8_t prefix);
|
||||
|
||||
API_EXPORT void API_CALL enc_media_release(enc_media ctx);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _DECRYPT_H */
|
37
include/HWsign.h
Normal file
37
include/HWsign.h
Normal file
@ -0,0 +1,37 @@
|
||||
|
||||
#ifndef _HWSIGN_H
|
||||
#define _HWSIGN_H
|
||||
|
||||
#include<stdlib.h>
|
||||
#include<stdio.h>
|
||||
//#include <functional>
|
||||
#define API_EXPORT __attribute__((visibility("default")))
|
||||
// void * HWSign_init(const std::function<void(const char * rtp_ptr, const uint32_t rtp_len)> rtp_callback);
|
||||
API_EXPORT int SDF_Device_open();
|
||||
API_EXPORT int SDF_Device_close();
|
||||
|
||||
struct sec_set_info{
|
||||
uint8_t camera_id[20];
|
||||
uint8_t vkek_version[32]; // 秘钥的加密秘钥的版本号
|
||||
uint8_t prikey_size;
|
||||
uint8_t pubkey_size;
|
||||
uint8_t prikey[64];
|
||||
uint8_t pubkey[128];
|
||||
};
|
||||
|
||||
|
||||
API_EXPORT void * HWSign_init(struct sec_set_info * sign_info);
|
||||
API_EXPORT void HWSign_release(void* Handle);
|
||||
API_EXPORT int HWSign_rtp_input(void* Handle, const char * buf, const uint32_t len, void * param);
|
||||
API_EXPORT int HWSign_rtp_out(void* Handle, char * buf, uint32_t * len, void ** param);
|
||||
|
||||
API_EXPORT void * HWSign_tcp_init();
|
||||
API_EXPORT void HWSign_tcp_release(void* Handle);
|
||||
API_EXPORT int HWSign_tcp_rtp_input(void* Handle, const char * buf, const uint32_t len, void * param);
|
||||
API_EXPORT int HWSign_tcp_rtp_out(void* Handle, char * buf, uint32_t * len, uint16_t* sei_end_offset,uint16_t* append_length,void ** param);
|
||||
|
||||
|
||||
API_EXPORT void * HWVerify_init();
|
||||
API_EXPORT void HWVerify_release(void* Handle);
|
||||
API_EXPORT int HWVerify_rtp_input(void* Handle, const char * buf, const uint32_t len,int tcp, void * param);
|
||||
#endif /* _DECRYPT_H */
|
63
include/common.h
Normal file
63
include/common.h
Normal file
@ -0,0 +1,63 @@
|
||||
#ifndef _COMMON_H
|
||||
#define _COMMON_H
|
||||
|
||||
#if defined(_WIN32) && defined(_MSC_VER)
|
||||
# define API_CALL __cdecl
|
||||
# define SecMedia_Api_EXPORTS
|
||||
#else
|
||||
# define API_CALL
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32) && defined(_MSC_VER)
|
||||
# if defined(SecMedia_Api_EXPORTS)
|
||||
# define API_EXPORT __declspec(dllexport)
|
||||
# else
|
||||
# define API_EXPORT __declspec(dllimport)
|
||||
# endif
|
||||
#endif
|
||||
|
||||
# ifndef API_EXPORT
|
||||
# define API_EXPORT __attribute__((visibility("default")))
|
||||
# endif
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
CodecInvalid = -1,
|
||||
CodecH264 = 0,
|
||||
CodecH265,
|
||||
CodecAAC,
|
||||
CodecG711A,
|
||||
CodecG711U,
|
||||
CodecOpus,
|
||||
CodecSVAC,
|
||||
CodecMax = 0x7FFF
|
||||
} CodecId;
|
||||
|
||||
enum class DecEncType{
|
||||
NONE=15,
|
||||
SM1=0,
|
||||
SM4=1,
|
||||
RSA=2,
|
||||
AES=3,
|
||||
SVACEnc=4,
|
||||
SVACDec=5,
|
||||
SM3,
|
||||
SM2_auth
|
||||
};
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* MK_COMMON_H */
|
BIN
sign.pcapng
Normal file
BIN
sign.pcapng
Normal file
Binary file not shown.
BIN
sign_HWsei.pcapng
Normal file
BIN
sign_HWsei.pcapng
Normal file
Binary file not shown.
BIN
src/3rdpart/media-server/.DS_Store
vendored
Normal file
BIN
src/3rdpart/media-server/.DS_Store
vendored
Normal file
Binary file not shown.
28
src/3rdpart/media-server/.travis.yml
Normal file
28
src/3rdpart/media-server/.travis.yml
Normal file
@ -0,0 +1,28 @@
|
||||
language: c
|
||||
install: true
|
||||
before_script:
|
||||
- wget https://github.com/ireader/sdk/archive/master.zip -O /tmp/sdk.zip
|
||||
- unzip /tmp/sdk.zip
|
||||
- echo $PWD
|
||||
- mv sdk-master ../sdk
|
||||
|
||||
env:
|
||||
global:
|
||||
# The next declaration is the encrypted COVERITY_SCAN_TOKEN, created
|
||||
# via the "travis encrypt" command using the project repo's public key
|
||||
- secure: "I/9S/L5PVzty9kcCcWKPnF3rlZ1FqVIBMCqZkjf2zx6Pl+FHQoAe/9KSdRFtKfzM+GxRu1ttxvmNignghgO60QGS7tvU79N/u/5o4xZ1UdCotGmFmwytEZ+szuTrH2PuSlA3p1opcvuWsrcIpUFXBU/qp9VYZl8v8L6qpir9vtAeMGjMGSJO4pC5ePnv4oxtrLLY1u+uPVMdqMmK2d1sHOYZy166hn89IgM1hU7kqyYAeyhU6bXEWHKtEEApIwvWSciSFFl0J+EiWDynjnPtIWaNXrIG5Wf1uJ9gQYU/u76NQhxbBouSrGyps4hrmuF2gmGAhPGIIlQlzU/DDnLqRT2fKgy4yhfMylTy+zXMMi0jBDyFGjPYjnDYjWEUNkG79AUJ6t/fe8QPUc5w88p5Hbq3ljom+yflshPshlVdWyqCxBB5aw/oOnslgnEVNkNBEivXcpHhELbYu79NwmrkRSUaBzb77nuue5MsfMSkFISiMvHRPF9FzOO+2NnycGQrLpj14bNIJoNbwtQO40BoeSVYPjBlKNf62vhM2Xf2pm7SpGuezH2IvS0ulLB4Di4ap5vL+MIJer6mQ8xsRT7CQO7r1d1dFp2yqB3dOEERqywd5xl+tfgNy76TwXyRM4u5RbOMJSgwLJE59rHg3RQ8ApEB3P1Bvot838P7Pp+vv5I="
|
||||
|
||||
before_install:
|
||||
- echo -n | openssl s_client -connect https://scan.coverity.com:443 | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' | sudo tee -a /etc/ssl/certs/ca-
|
||||
|
||||
addons:
|
||||
coverity_scan:
|
||||
project:
|
||||
name: "ireader/media-server"
|
||||
description: "media-server"
|
||||
notification_email: tao3@outlook.com
|
||||
build_command_prepend: "make clean"
|
||||
build_command: "make"
|
||||
branch_pattern: coverity_scan
|
||||
|
||||
script: make
|
72
src/3rdpart/media-server/Android.mk
Normal file
72
src/3rdpart/media-server/Android.mk
Normal file
@ -0,0 +1,72 @@
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := dash
|
||||
LOCAL_SRC_FILES := libdash/obj/local/$(TARGET_ARCH_ABI)/libdash.a
|
||||
include $(PREBUILT_STATIC_LIBRARY)
|
||||
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := flv
|
||||
LOCAL_SRC_FILES := libflv/obj/local/$(TARGET_ARCH_ABI)/libflv.a
|
||||
include $(PREBUILT_STATIC_LIBRARY)
|
||||
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := hls
|
||||
LOCAL_SRC_FILES := libhls/obj/local/$(TARGET_ARCH_ABI)/libhls.a
|
||||
include $(PREBUILT_STATIC_LIBRARY)
|
||||
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := mov
|
||||
LOCAL_SRC_FILES := libmov/obj/local/$(TARGET_ARCH_ABI)/libmov.a
|
||||
include $(PREBUILT_STATIC_LIBRARY)
|
||||
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := mpeg
|
||||
LOCAL_SRC_FILES := libmpeg/obj/local/$(TARGET_ARCH_ABI)/libmpeg.a
|
||||
include $(PREBUILT_STATIC_LIBRARY)
|
||||
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := rtmp
|
||||
LOCAL_SRC_FILES := librtmp/obj/local/$(TARGET_ARCH_ABI)/librtmp.a
|
||||
include $(PREBUILT_STATIC_LIBRARY)
|
||||
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := rtp
|
||||
LOCAL_SRC_FILES := librtp/obj/local/$(TARGET_ARCH_ABI)/librtp.a
|
||||
include $(PREBUILT_STATIC_LIBRARY)
|
||||
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := rtsp
|
||||
LOCAL_SRC_FILES := librtsp/obj/local/$(TARGET_ARCH_ABI)/librtsp.a
|
||||
include $(PREBUILT_STATIC_LIBRARY)
|
||||
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := sip
|
||||
LOCAL_SRC_FILES := libsip/obj/local/$(TARGET_ARCH_ABI)/libsip.a
|
||||
include $(PREBUILT_STATIC_LIBRARY)
|
||||
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_CFLAGS += -DOS_ANDROID -DOS_LINUX
|
||||
LOCAL_LDLIBS += -llog -landroid
|
||||
|
||||
LOCAL_C_INCLUDES := .
|
||||
LOCAL_C_INCLUDES += $(LOCAL_PATH)
|
||||
LOCAL_C_INCLUDES += $(LOCAL_PATH)/include
|
||||
LOCAL_C_INCLUDES += $(LOCAL_PATH)/../../sdk/include
|
||||
|
||||
LOCAL_SRC_FILES := test/test.cpp
|
||||
|
||||
LOCAL_SHARED_LIBRARIES :=
|
||||
LOCAL_STATIC_LIBRARIES :=
|
||||
|
||||
LOCAL_MODULE := test
|
||||
include $(BUILD_SHARED_LIBRARY)
|
4
src/3rdpart/media-server/Application.mk
Normal file
4
src/3rdpart/media-server/Application.mk
Normal file
@ -0,0 +1,4 @@
|
||||
APP_BUILD_SCRIPT := ./Android.mk
|
||||
APP_STL := gnustl_static
|
||||
APP_ABI := armeabi-v7a #arm64-v8a
|
||||
#APP_PLATFORM := android-21 #SLES SLAndroidDataFormat_PCM_EX
|
21
src/3rdpart/media-server/LICENSE
Normal file
21
src/3rdpart/media-server/LICENSE
Normal file
@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2018 chen
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
41
src/3rdpart/media-server/Makefile
Normal file
41
src/3rdpart/media-server/Makefile
Normal file
@ -0,0 +1,41 @@
|
||||
ifdef PLATFORM
|
||||
CROSS:=$(PLATFORM)-
|
||||
else
|
||||
CROSS:=
|
||||
PLATFORM:=linux
|
||||
endif
|
||||
|
||||
ifeq ($(RELEASE),1)
|
||||
BUILD:=release
|
||||
else
|
||||
BUILD:=debug
|
||||
endif
|
||||
|
||||
all:
|
||||
$(MAKE) -C libflv
|
||||
$(MAKE) -C librtmp
|
||||
$(MAKE) -C libmpeg
|
||||
$(MAKE) -C libhls
|
||||
$(MAKE) -C librtp
|
||||
$(MAKE) -C librtsp
|
||||
$(MAKE) -C libmov
|
||||
$(MAKE) -C libdash
|
||||
$(MAKE) -C libsip
|
||||
|
||||
clean:
|
||||
$(MAKE) -C libflv clean
|
||||
$(MAKE) -C librtmp clean
|
||||
$(MAKE) -C libmpeg clean
|
||||
$(MAKE) -C libhls clean
|
||||
$(MAKE) -C librtp clean
|
||||
$(MAKE) -C librtsp clean
|
||||
$(MAKE) -C libmov clean
|
||||
$(MAKE) -C libdash clean
|
||||
$(MAKE) -C libsip clean
|
||||
$(MAKE) -C test clean
|
||||
|
||||
.PHONY : test
|
||||
test:
|
||||
$(MAKE) -C ../sdk
|
||||
$(MAKE) -C test
|
||||
ln -sf ../sdk/libaio/$(BUILD).$(PLATFORM)/libaio.so . && ./test/$(BUILD).$(PLATFORM)/test
|
64
src/3rdpart/media-server/README.md
Normal file
64
src/3rdpart/media-server/README.md
Normal file
@ -0,0 +1,64 @@
|
||||
* Build status: [![Build Status](https://travis-ci.org/ireader/media-server.svg?branch=master)](https://travis-ci.org/ireader/media-server) <a href="https://scan.coverity.com/projects/ireader-media-server"> <img alt="Coverity Scan Build Status" src="https://scan.coverity.com/projects/14645/badge.svg"/> </a>
|
||||
* Build Dependence: https://github.com/ireader/sdk
|
||||
|
||||
# libflv
|
||||
1. Adobe FLV muxer/demuxer
|
||||
2. MPEG-4 AVCDecoderConfigurationRecord/HEVCDecoderConfigurationRecord/AV1CodecConfigurationRecord/VPCodecConfigurationRecord/AudioSpecificConfig
|
||||
3. H.264/H.265 AnnexB to/from MP4 stream
|
||||
4. AAC ADTS to/from ASC/MUX
|
||||
5. FLV with H.264/H.264/AV1/VPX(vp8/vp9/vp10)
|
||||
6. FLV with AAC/mp3/G.711/Opus
|
||||
|
||||
# librtmp
|
||||
1. rtmp-client: RTMP publish/play
|
||||
2. rtmp-server: RTMP Server live/vod streaming
|
||||
|
||||
# libmpeg
|
||||
1. MPEG-2 PS packer/unpacker
|
||||
2. MPEG-2 TS packer/unpacker
|
||||
3. ps/ts with H.264/H.265/AAC/MP3/G.711/Opus
|
||||
|
||||
# librtp
|
||||
1. RFC3550 RTP/RTCP
|
||||
2. RTP with H.264/H.265/MPEG-2/MPEG-4/VP8/VP9/AV1
|
||||
2. RTP with G.711/G.726/G.729/MP3/AAC/Opus
|
||||
3. RTP with MPEG-2 PS/TS
|
||||
|
||||
# librtsp
|
||||
1. RFC 2326 RTSP client
|
||||
2. RFC 2326 RTSP Server
|
||||
3. RTSP parser
|
||||
4. RFC 4566 SDP parser
|
||||
5. SDP with H.264/H.265/AAC/Opus/G.711 fmtp
|
||||
|
||||
# libhls
|
||||
1. HLS Media: TS segmenter
|
||||
2. HLS M3U8: generate m3u8 file
|
||||
3. HLS fmp4 segmenter
|
||||
4. HLS Master/Playlist m3u8 parser
|
||||
|
||||
# libdash
|
||||
1. ISO/IEC 23009-1 MPEG-DASH static(vod)
|
||||
2. ISO/IEC 23009-1 MPEG-DASH dynamic(live)
|
||||
3. DASH MPD v3/v4 parser
|
||||
|
||||
# libmov
|
||||
1. MP4 File reader/writer
|
||||
2. MP4 faststart(moov box before mdat)
|
||||
3. Fragment MP4 writer
|
||||
4. MP4 with H.264/H.265/AV1/VP9
|
||||
5. MP4 with AAC/Opus/MP3/G.711
|
||||
|
||||
# libsip
|
||||
1. sip user-agent (UAC/UAS)
|
||||
2. sip with ICE
|
||||
|
||||
# libhttp(https://github.com/ireader/sdk)
|
||||
1. HTTP Server(base AIO)
|
||||
2. HTTP Client
|
||||
3. HTTP Cookie
|
||||
|
||||
### Make
|
||||
1. make clean && make
|
||||
2. make RELEASE=1 (make release library, default debug)
|
||||
3. make PLATFORM=arm-hisiv100nptl-linux (cross compile)
|
96
src/3rdpart/media-server/gcc.mk
Normal file
96
src/3rdpart/media-server/gcc.mk
Normal file
@ -0,0 +1,96 @@
|
||||
RELEASE ?= 0 # default debug
|
||||
UNICODE ?= 0 # default ansi
|
||||
|
||||
ifdef PLATFORM
|
||||
CROSS:=$(PLATFORM)-
|
||||
else
|
||||
CROSS:=
|
||||
PLATFORM:=linux
|
||||
endif
|
||||
|
||||
ifeq ($(RELEASE),1)
|
||||
BUILD:=release
|
||||
else
|
||||
BUILD:=debug
|
||||
endif
|
||||
|
||||
KERNEL := $(shell uname -s)
|
||||
ifeq ($(KERNEL),Linux)
|
||||
DEFINES += OS_LINUX
|
||||
endif
|
||||
ifeq ($(KERNEL),Darwin)
|
||||
DEFINES += OS_MAC
|
||||
endif
|
||||
|
||||
#--------------------------------Compile-----------------------------
|
||||
#
|
||||
#--------------------------------------------------------------------
|
||||
AR := $(CROSS)ar
|
||||
CC := $(CROSS)gcc
|
||||
CXX := $(CROSS)g++
|
||||
CFLAGS += -Wall -fPIC
|
||||
CXXFLAGS += -Wall
|
||||
DEPFLAGS = -MMD -MP -MF $(OUTPATH)/$(*F).d
|
||||
|
||||
ifeq ($(RELEASE),1)
|
||||
CFLAGS += -Wall -O2
|
||||
CXXFLAGS += $(CFLAGS)
|
||||
DEFINES += NDEBUG
|
||||
else
|
||||
CFLAGS += -g -Wall
|
||||
# CFLAGS += -fsanitize=address
|
||||
CXXFLAGS += $(CFLAGS)
|
||||
DEFINES += DEBUG _DEBUG
|
||||
endif
|
||||
|
||||
# default don't export anything
|
||||
CFLAGS += -fvisibility=hidden
|
||||
|
||||
COMPILE.CC = $(CC) $(addprefix -I,$(INCLUDES)) $(addprefix -D,$(DEFINES)) $(CFLAGS)
|
||||
COMPILE.CXX = $(CXX) $(addprefix -I,$(INCLUDES)) $(addprefix -D,$(DEFINES)) $(CXXFLAGS)
|
||||
|
||||
#-------------------------Compile Output---------------------------
|
||||
#
|
||||
#--------------------------------------------------------------------
|
||||
ifeq ($(UNICODE),1)
|
||||
OUTPATH += unicode.$(BUILD).$(PLATFORM)
|
||||
else
|
||||
OUTPATH += $(BUILD).$(PLATFORM)
|
||||
endif
|
||||
|
||||
# make output dir
|
||||
$(shell mkdir -p $(OUTPATH) > /dev/null)
|
||||
|
||||
OBJECT_FILES := $(patsubst %.c,%.o,$(patsubst %.cpp,%.o,$(SOURCE_FILES)))
|
||||
DEPENDENCE_FILES := $(OBJECT_FILES:%.o=%.d)
|
||||
DEPENDENCE_FILES := $(foreach file,$(DEPENDENCE_FILES),$(OUTPATH)/$(notdir $(file)))
|
||||
|
||||
#--------------------------Makefile Rules----------------------------
|
||||
#
|
||||
#--------------------------------------------------------------------
|
||||
$(OUTPATH)/$(OUTFILE): $(OBJECT_FILES) $(STATIC_LIBS)
|
||||
ifeq ($(OUTTYPE),0)
|
||||
$(CXX) -o $@ -Wl,-rpath . $(LDFLAGS) $^ $(addprefix -L,$(LIBPATHS)) $(addprefix -l,$(LIBS))
|
||||
else
|
||||
ifeq ($(OUTTYPE),1)
|
||||
$(CXX) -o $@ -shared -fpic -rdynamic -Wl,-rpath . $(LDFLAGS) $^ $(addprefix -L,$(LIBPATHS)) $(addprefix -l,$(LIBS))
|
||||
else
|
||||
$(AR) -rc $@ $^
|
||||
endif
|
||||
endif
|
||||
@echo make ok, output: $(OUTPATH)/$(OUTFILE)
|
||||
|
||||
%.o : %.c
|
||||
$(COMPILE.CC) -c $(DEPFLAGS) -o $@ $<
|
||||
|
||||
%.o : %.cpp
|
||||
$(COMPILE.CXX) -c $(DEPFLAGS) -o $@ $<
|
||||
|
||||
-include $(DEPENDENCE_FILES)
|
||||
|
||||
version.h : version.ver
|
||||
$(ROOT)/svnver.sh version.ver version.h
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -f $(OBJECT_FILES) $(OUTPATH)/$(OUTFILE) $(DEPENDENCE_FILES)
|
16
src/3rdpart/media-server/libdash/Android.mk
Normal file
16
src/3rdpart/media-server/libdash/Android.mk
Normal file
@ -0,0 +1,16 @@
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_CFLAGS += -DOS_LINUX -DOS_ANDROID
|
||||
LOCAL_LDLIBS +=
|
||||
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)
|
||||
LOCAL_C_INCLUDES += $(LOCAL_PATH)/include
|
||||
LOCAL_C_INCLUDES += $(LOCAL_PATH)/../libmov/include
|
||||
LOCAL_C_INCLUDES += $(LOCAL_PATH)/../libhls/include
|
||||
|
||||
LOCAL_SRC_FILES := $(wildcard src/*.c)
|
||||
LOCAL_SRC_FILES += $(wildcard src/*.cpp)
|
||||
|
||||
LOCAL_MODULE := dash
|
||||
include $(BUILD_STATIC_LIBRARY)
|
45
src/3rdpart/media-server/libdash/Makefile
Normal file
45
src/3rdpart/media-server/libdash/Makefile
Normal file
@ -0,0 +1,45 @@
|
||||
#--------------------------------Output------------------------------
|
||||
# OUTTYPE: 0-exe, 1-dll, 2-static
|
||||
#--------------------------------------------------------------------
|
||||
OUTTYPE = 2
|
||||
OUTFILE = libdash.a
|
||||
|
||||
#-------------------------------Include------------------------------
|
||||
#
|
||||
# INCLUDES = $(addprefix -I,$(INCLUDES)) # add -I prefix
|
||||
#--------------------------------------------------------------------
|
||||
INCLUDES = . \
|
||||
./include \
|
||||
../libmov/include \
|
||||
../libhls/include
|
||||
|
||||
#-------------------------------Source-------------------------------
|
||||
#
|
||||
#--------------------------------------------------------------------
|
||||
SOURCE_PATHS = src
|
||||
SOURCE_FILES = $(foreach dir,$(SOURCE_PATHS),$(wildcard $(dir)/*.cpp))
|
||||
SOURCE_FILES += $(foreach dir,$(SOURCE_PATHS),$(wildcard $(dir)/*.c))
|
||||
|
||||
#-----------------------------Library--------------------------------
|
||||
#
|
||||
# LIBPATHS = $(addprefix -L,$(LIBPATHS)) # add -L prefix
|
||||
#--------------------------------------------------------------------
|
||||
LIBPATHS =
|
||||
ifdef RELEASE
|
||||
# relase library path
|
||||
LIBPATHS +=
|
||||
else
|
||||
LIBPATHS +=
|
||||
endif
|
||||
|
||||
LIBS =
|
||||
|
||||
STATIC_LIBS =
|
||||
|
||||
#-----------------------------DEFINES--------------------------------
|
||||
#
|
||||
# DEFINES := $(addprefix -D,$(DEFINES)) # add -L prefix
|
||||
#--------------------------------------------------------------------
|
||||
DEFINES =
|
||||
|
||||
include ../gcc.mk
|
31
src/3rdpart/media-server/libdash/include/dash-mpd.h
Normal file
31
src/3rdpart/media-server/libdash/include/dash-mpd.h
Normal file
@ -0,0 +1,31 @@
|
||||
#ifndef _dash_mpd_h_
|
||||
#define _dash_mpd_h_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct dash_mpd_t dash_mpd_t;
|
||||
|
||||
typedef int (*dash_mpd_segment)(void* param, int adapation, const void* data, size_t bytes, int64_t pts, int64_t dts, int64_t duration, const char* name);
|
||||
|
||||
dash_mpd_t* dash_mpd_create(int flags, dash_mpd_segment handler, void* param);
|
||||
void dash_mpd_destroy(dash_mpd_t* mpd);
|
||||
|
||||
/// @param[in] prefix dash adapation set name prefix
|
||||
/// @return >=0-adapation id, <0-error
|
||||
int dash_mpd_add_video_adaptation_set(dash_mpd_t* mpd, const char* prefix, uint8_t object, int width, int height, const void* extra_data, size_t extra_data_size);
|
||||
int dash_mpd_add_audio_adaptation_set(dash_mpd_t* mpd, const char* prefix, uint8_t object, int channel_count, int bits_per_sample, int sample_rate, const void* extra_data, size_t extra_data_size);
|
||||
|
||||
/// @param[in] adapation create by dash_mpd_add_video_adapation_set/dash_mpd_add_audio_adapation_set
|
||||
int dash_mpd_input(dash_mpd_t* mpd, int adapation, const void* data, size_t bytes, int64_t pts, int64_t dts, int flags);
|
||||
|
||||
size_t dash_mpd_playlist(dash_mpd_t* mpd, char* playlist, size_t bytes);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif /* !_dash_mpd_h_ */
|
483
src/3rdpart/media-server/libdash/include/dash-parser.h
Normal file
483
src/3rdpart/media-server/libdash/include/dash-parser.h
Normal file
@ -0,0 +1,483 @@
|
||||
#ifndef _dash_parser_h_
|
||||
#define _dash_parser_h_
|
||||
|
||||
#include "dash-proto.h"
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
enum
|
||||
{
|
||||
DASH_SEGMENT_NONE = 0,
|
||||
DASH_SEGMENT_BASE,
|
||||
DASH_SEGMENT_LIST,
|
||||
DASH_SEGMENT_TEMPLATE,
|
||||
};
|
||||
|
||||
// https://tools.ietf.org/html/rfc6838
|
||||
enum
|
||||
{
|
||||
DASH_MEDIA_UNKNOWN,
|
||||
DASH_MEDIA_FONT, // font
|
||||
DASH_MEDIA_TEXT, // text
|
||||
DASH_MEDIA_IMAGE, // image
|
||||
DASH_MEDIA_AUDIO, // audio
|
||||
DASH_MEDIA_VIDEO, // video
|
||||
DASH_MEDIA_APPLICATION, // application
|
||||
};
|
||||
|
||||
// 5.3.9.4.4 Template-based Segment URL construction
|
||||
// @media, @index, @initialization, @bitstreamSwitching
|
||||
// 1. Either $Number$ or $Time$ may be used but not both at the same time.
|
||||
// 2. $SubNumber$ shall only be present if either $Number$ or $Time$ are present as well
|
||||
enum
|
||||
{
|
||||
DASH_TEMPLATE_UNKNOWN,
|
||||
DASH_TEMPLATE_REPRESENTATIONID, // Representation@id
|
||||
DASH_TEMPLATE_NUMBER,
|
||||
DASH_TEMPLATE_BANDWIDTH, // Representation@bandwidth
|
||||
DASH_TEMPLATE_TIME, // SegmentTimeline@t
|
||||
DASH_TEMPLATE_SUBNUMBER,
|
||||
};
|
||||
|
||||
enum { DASH_SCAN_UNKNOWN = 0, DASH_SCAN_PROGRESSIVE, DASH_SCAN_INTERLACED, };
|
||||
|
||||
struct dash_urltype_t
|
||||
{
|
||||
char* source_url;
|
||||
char* range;
|
||||
};
|
||||
|
||||
// BaseURL
|
||||
struct dash_url_t
|
||||
{
|
||||
size_t count;
|
||||
struct
|
||||
{
|
||||
char* uri;
|
||||
char* service_location;
|
||||
char* byte_range;
|
||||
double availability_time_offset;
|
||||
int availability_time_complete; // boolean
|
||||
} *urls;
|
||||
};
|
||||
|
||||
struct dash_event_t
|
||||
{
|
||||
uint64_t presentation_time;
|
||||
uint64_t duration;
|
||||
unsigned int id;
|
||||
char* message_data;
|
||||
};
|
||||
|
||||
struct dash_event_stream_t
|
||||
{
|
||||
char* href;
|
||||
char* actuate; // default: onRequest
|
||||
char* scheme_id_uri; // SchemeIdUri
|
||||
char* value;
|
||||
unsigned int timescale;
|
||||
|
||||
size_t event_count;
|
||||
struct dash_event_t* events;
|
||||
};
|
||||
|
||||
struct dash_label_t
|
||||
{
|
||||
size_t count;
|
||||
struct
|
||||
{
|
||||
char* label;
|
||||
unsigned int id;
|
||||
char* lang;
|
||||
}*labels;
|
||||
};
|
||||
|
||||
struct dash_program_information_t
|
||||
{
|
||||
char* lang;
|
||||
char* more_information;
|
||||
|
||||
char* title;
|
||||
char* source;
|
||||
char* copyright;
|
||||
};
|
||||
|
||||
struct dash_descriptor_t
|
||||
{
|
||||
size_t count;
|
||||
struct
|
||||
{
|
||||
char* scheme_uri;
|
||||
char* value;
|
||||
char* id;
|
||||
}* descs;
|
||||
};
|
||||
|
||||
struct dash_metric_t
|
||||
{
|
||||
char* metrics;
|
||||
|
||||
size_t range_count;
|
||||
struct
|
||||
{
|
||||
int64_t time;
|
||||
int64_t duration;
|
||||
}* ranges;
|
||||
|
||||
struct dash_descriptor_t reportings;
|
||||
};
|
||||
|
||||
struct dash_segment_url_t
|
||||
{
|
||||
char* media;
|
||||
char* media_range;
|
||||
char* index;
|
||||
char* index_range;
|
||||
};
|
||||
|
||||
struct dash_segment_timeline_t
|
||||
{
|
||||
size_t count;
|
||||
|
||||
struct
|
||||
{
|
||||
uint64_t t;
|
||||
uint64_t n; // specifies the Segment number of the first Segment in the series.
|
||||
uint64_t d; // Any @d value shall not exceed the value of MPD@maxSegmentDuration
|
||||
uint64_t k; // default 1
|
||||
int r; // default 0
|
||||
}* S;
|
||||
};
|
||||
|
||||
struct dash_segment_t
|
||||
{
|
||||
int type; // DASH_SEGMENT_BASE/DASH_SEGMENT_LIST/DASH_SEGMENT_TEMPLATE
|
||||
|
||||
// segment base
|
||||
unsigned int timescale;
|
||||
uint64_t presentation_time_offset;
|
||||
uint64_t presentation_duration;
|
||||
int64_t time_shift_buffer_depth;
|
||||
char* index_range;
|
||||
int index_range_exact; // 0-false, 1-true
|
||||
double availability_time_offset;
|
||||
int availability_time_complete;
|
||||
struct dash_urltype_t initialization; // Initialization
|
||||
struct dash_urltype_t representation_index; // RepresentationIndex
|
||||
|
||||
// Multiple segment base
|
||||
uint64_t start_number;
|
||||
// All Segments within this Representation element have the same duration
|
||||
// unless it is the last Segment within the Period, which can be significantly shorter.
|
||||
unsigned int duration; // specifies the constant approximate Segment duration.
|
||||
struct dash_segment_timeline_t segment_timeline; // SegmentTimeline
|
||||
struct dash_urltype_t bitstream_switching; // BitstreamSwitching
|
||||
|
||||
// segment list
|
||||
char* href;
|
||||
char* actuate; // default: onRequest
|
||||
size_t segment_url_count;
|
||||
struct dash_segment_url_t* segment_urls; // SegmentURL
|
||||
|
||||
// segment template
|
||||
char* media;
|
||||
char* index;
|
||||
char* initialization_url; // initialization
|
||||
char* bitstream_switching_url;
|
||||
};
|
||||
|
||||
struct dash_content_component_t
|
||||
{
|
||||
unsigned int id;
|
||||
char* lang;
|
||||
char* content_type;
|
||||
char* par;
|
||||
char* tag;
|
||||
|
||||
struct dash_descriptor_t accessibilities; // Accessibility
|
||||
struct dash_descriptor_t roles; // Role
|
||||
struct dash_descriptor_t ratings; // Rating
|
||||
struct dash_descriptor_t viewpoints; // Viewpoint
|
||||
};
|
||||
|
||||
struct dash_representation_base_t
|
||||
{
|
||||
char* profiles;
|
||||
unsigned int width;
|
||||
unsigned int height;
|
||||
char* sar;
|
||||
char* frame_rate;
|
||||
char* audio_sampling_rate;
|
||||
char* mime_type;
|
||||
char* segment_profiles;
|
||||
char* codecs;
|
||||
double maxmum_sap_period;
|
||||
char* start_with_sap;
|
||||
double max_playout_rate;
|
||||
int coding_dependency;
|
||||
int scan_type; // progressive, interlaced
|
||||
unsigned int selection_priority; // default 1
|
||||
int tag;
|
||||
|
||||
struct dash_descriptor_t frame_packings; // FramePacking
|
||||
struct dash_descriptor_t audio_channel_configurations; // AudioChannelConfiguration
|
||||
struct dash_descriptor_t content_protections; // ContentProtection
|
||||
struct dash_descriptor_t essentials; // EssentialProperty
|
||||
struct dash_descriptor_t supplementals; // SupplementalProperty
|
||||
|
||||
size_t inband_event_stream_count;
|
||||
struct dash_event_stream_t* inband_event_streams; // InbandEventStream
|
||||
|
||||
size_t switching_count;
|
||||
struct
|
||||
{
|
||||
unsigned int interval;
|
||||
int type; // media, bitstream
|
||||
} *switchings; // Switching
|
||||
|
||||
size_t random_access_count;
|
||||
struct
|
||||
{
|
||||
unsigned int interval;
|
||||
int type; // closed, open, gradual
|
||||
int64_t min_buffer_time;
|
||||
unsigned int bandwidth;
|
||||
} *random_accesses; // RandomAccess
|
||||
|
||||
struct dash_label_t group_labels; // GroupLabel
|
||||
struct dash_label_t labels; // Label
|
||||
};
|
||||
|
||||
struct dash_preselection_t
|
||||
{
|
||||
char* id;
|
||||
char* preselection_compoents;
|
||||
char* lang;
|
||||
|
||||
struct dash_representation_base_t base;
|
||||
|
||||
struct dash_descriptor_t accessibilities; // Accessibility
|
||||
struct dash_descriptor_t roles; // Role
|
||||
struct dash_descriptor_t ratings; // Rating
|
||||
struct dash_descriptor_t viewpoints; // Viewpoint
|
||||
};
|
||||
|
||||
struct dash_subrepresentation_t
|
||||
{
|
||||
unsigned int level;
|
||||
unsigned int dependency_level;
|
||||
unsigned int bandwidth;
|
||||
char* content_component;
|
||||
|
||||
struct dash_representation_t* parent;
|
||||
struct dash_representation_base_t base;
|
||||
};
|
||||
|
||||
struct dash_representation_t
|
||||
{
|
||||
char* id;
|
||||
unsigned int bandwidth;
|
||||
unsigned int quality_ranking;
|
||||
char* dependncy_id;
|
||||
char* association_id;
|
||||
char* association_type;
|
||||
char* media_stream_structure_id;
|
||||
|
||||
struct dash_adaptation_set_t* parent;
|
||||
struct dash_representation_base_t base;
|
||||
|
||||
struct dash_url_t base_urls; // BaseURL
|
||||
|
||||
size_t subrepresentation_count;
|
||||
struct dash_subrepresentation_t* subrepresentations; // SubRepresentation
|
||||
|
||||
struct dash_segment_t segment;
|
||||
};
|
||||
|
||||
struct dash_adaptation_set_t
|
||||
{
|
||||
char* href;
|
||||
char* actuate; // default: onRequest
|
||||
unsigned int id;
|
||||
unsigned int group;
|
||||
char* lang; // und
|
||||
char* content_type; // text/image/audio/video/application/font
|
||||
char* par; // n:m 16:9
|
||||
unsigned int min_bandwidth;
|
||||
unsigned int max_bandwidth;
|
||||
unsigned int min_width;
|
||||
unsigned int max_width;
|
||||
unsigned int min_height;
|
||||
unsigned int max_height;
|
||||
char* min_framerate; // n/m
|
||||
char* max_framerate;
|
||||
int segment_alignment; // 0-false, 1-true
|
||||
int subsegment_aligment; // 0-false, 1-true
|
||||
int subsegment_start_with_sap; // default 0
|
||||
int bitstream_switching; // 0-false, 1-true
|
||||
|
||||
struct dash_period_t* parent;
|
||||
struct dash_representation_base_t base;
|
||||
|
||||
struct dash_descriptor_t accessibilities; // Accessibility
|
||||
struct dash_descriptor_t roles; // Role
|
||||
struct dash_descriptor_t ratings; // Rating
|
||||
struct dash_descriptor_t viewpoints; // Viewpoint
|
||||
|
||||
size_t content_component_count;
|
||||
struct dash_content_component_t* content_components; // ContentComponent
|
||||
|
||||
struct dash_url_t base_urls; // BaseURL
|
||||
|
||||
struct dash_segment_t segment;
|
||||
|
||||
size_t representation_count;
|
||||
struct dash_representation_t* representations; // Representation
|
||||
};
|
||||
|
||||
struct dash_period_t
|
||||
{
|
||||
char* href;
|
||||
char* actuate; // default: onRequest
|
||||
char* id;
|
||||
int64_t start; // start
|
||||
int64_t duration; // duration
|
||||
int bitstream_switching; // 0-false
|
||||
|
||||
struct dash_mpd_t* parent;
|
||||
struct dash_url_t base_urls; // BaseURL
|
||||
|
||||
struct dash_segment_t segment; // SegmentBase/SegmentList/SegmentTemplate
|
||||
|
||||
struct dash_descriptor_t asset_identifier; // AssetIdentifier
|
||||
|
||||
size_t event_stream_count;
|
||||
size_t event_stream_capacity;
|
||||
struct dash_event_stream_t* event_streams; // EventStream
|
||||
|
||||
size_t adaptation_set_count;
|
||||
struct dash_adaptation_set_t* adaptation_sets; // AdaptationSet
|
||||
|
||||
size_t subset_count;
|
||||
struct
|
||||
{
|
||||
char* contains;
|
||||
char* id;
|
||||
} *subsets; // SubSet
|
||||
|
||||
struct dash_descriptor_t supplementals; // SupplementalProperty
|
||||
|
||||
size_t empty_adaptation_set_count;
|
||||
struct dash_adaptation_set_t* empty_adaptation_sets; // EmptyAdaptationSet
|
||||
|
||||
struct dash_label_t group_labels; // GroupLabel
|
||||
|
||||
size_t preselection_count;
|
||||
struct dash_preselection_t* preselections; // Preselection
|
||||
};
|
||||
|
||||
struct dash_mpd_t
|
||||
{
|
||||
int type; // presentation type: 0-static, 1-dynamic
|
||||
char* id;
|
||||
char* profiles; // profiles
|
||||
char* availability_start_time;
|
||||
char* availability_end_time;
|
||||
char* publish_time;
|
||||
int64_t media_presentation_duration; // mediaPresentationDuration, MPD total duration
|
||||
int64_t minimum_update_period; // minimumUpdatePeriod
|
||||
int64_t min_buffer_time; // minBufferTime
|
||||
int64_t time_shift_buffer_depth; // timeShiftBufferDepth
|
||||
int64_t suggested_presentation_delay; // suggestedPresentationDelay
|
||||
int64_t max_segment_duration; // maxSegmentDuration
|
||||
int64_t max_subsegment_duration; // maxSubsegmentDuration
|
||||
char* xsi; // xmlns:xsi
|
||||
char* xmlns; // xmlns
|
||||
char* schema_location; // xsi:schemaLocation
|
||||
|
||||
size_t info_count;
|
||||
struct dash_program_information_t* infos; // ProgramInfomation
|
||||
|
||||
struct dash_url_t urls; // BaseURL
|
||||
|
||||
size_t location_count;
|
||||
char** locations; // Location
|
||||
|
||||
size_t period_count;
|
||||
struct dash_period_t* periods; // Period
|
||||
|
||||
size_t metric_count;
|
||||
struct dash_metric_t* metrics; // Metrics
|
||||
|
||||
struct dash_descriptor_t essentials; // EssentialProperty
|
||||
struct dash_descriptor_t supplementals; // SupplementalProperty
|
||||
struct dash_descriptor_t timings; // UTCTming
|
||||
};
|
||||
|
||||
/// Parse MPD(Media Presentation Description for MPEG-DASH ) manifest file
|
||||
/// @param[out] mpd mpd object(free by dash_mpd_free)
|
||||
/// @return 0-ok, other-error
|
||||
int dash_mpd_parse(struct dash_mpd_t** mpd, const char* data, size_t bytes);
|
||||
|
||||
int dash_mpd_free(struct dash_mpd_t** mpd);
|
||||
|
||||
/// @return -1-live, >=0-duration(ms), other-error
|
||||
int64_t dash_get_duration(const struct dash_mpd_t* mpd);
|
||||
|
||||
/// Period
|
||||
|
||||
/// location period by time
|
||||
/// @param[in] time from previous period end to current perid end, range: (period-m-end, period-n-end]
|
||||
/// @return >=0-period index, -1-if don't find, other-undefined
|
||||
int dash_period_find(const struct dash_mpd_t* mpd, int64_t time);
|
||||
|
||||
/// @param[in] media DASH_MEDIA_AUDIO/DASH_MEDIA_VIDEO/xxx
|
||||
/// @param[in] id adaptation set id, 0 if unknown
|
||||
/// @param[in] group adaptation set group id, 0 if unknown
|
||||
/// @param[in] lang adaptation set lang, such as 'en'/'fr', NULL if don't care
|
||||
/// @param[in] codecs adaptation set codec type, such as 'avc1', NULL if don't care
|
||||
/// @return NULL if don't find any adaptation set
|
||||
const struct dash_adaptation_set_t* dash_period_select(const struct dash_period_t* period, int media, unsigned int id, unsigned int group, const char* lang, const char* codecs);
|
||||
|
||||
/// Adaptation Set
|
||||
|
||||
/// @return adaptation set media type DASH_MEDIA_AUDIO/DASH_MEDIA_VIDEO, DASH_MEDIA_UNKNOWN if unknown
|
||||
int dash_adaptation_set_media_type(const struct dash_adaptation_set_t* set);
|
||||
|
||||
/// Priority: 1. selectionPriority; 2. qualityRanking; 3. bandwidth
|
||||
/// @return >=0-representation index, -1-error
|
||||
int dash_adaptation_set_best_representation(const struct dash_adaptation_set_t* set);
|
||||
|
||||
/// Representation
|
||||
|
||||
const struct dash_url_t* dash_representation_get_base_url(const struct dash_representation_t* representation);
|
||||
|
||||
/// Get initialization segment url(MUST use with dash_representation_get_base_url)
|
||||
/// @return >0-ok with url length, =0-don't have initialization segment, <0-error
|
||||
int dash_representation_get_initialization(const struct dash_representation_t* representation, char* url, size_t size);
|
||||
|
||||
/// Find segment by start time
|
||||
/// @param[in] time segment time, range: (previous segment end, segment start + duration)
|
||||
/// @return -1-not found, >=0-segment item index(index is not the startnumber)
|
||||
int dash_representation_find_segment(const struct dash_representation_t* representation, int64_t time);
|
||||
|
||||
/// @return <0-error, >=0-segment count(INT_MAX for segment template)
|
||||
int dash_representation_segment_count(const struct dash_representation_t* representation);
|
||||
|
||||
/// Get segment url(MUST use with dash_representation_get_base_url)
|
||||
/// @param[in] index segment index(!= start number)
|
||||
/// @param[out] number start number of representation
|
||||
/// @param[out] start start time of representation(MUST add period.start)
|
||||
/// @param[out] duration segment duration, 0 if unknown
|
||||
/// @param[out] range url range, NULL if don't have range
|
||||
/// @return >=0-ok with url length, <0-error
|
||||
int dash_representation_segment_url(const struct dash_representation_t* representation, int index, int64_t* number, int64_t* start, int64_t* duration, const char** range, char* url, size_t size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif /* !_dash_parser_h_ */
|
10
src/3rdpart/media-server/libdash/include/dash-proto.h
Normal file
10
src/3rdpart/media-server/libdash/include/dash-proto.h
Normal file
@ -0,0 +1,10 @@
|
||||
#ifndef _dash_proto_h_
|
||||
#define _dash_proto_h_
|
||||
|
||||
enum
|
||||
{
|
||||
DASH_STATIC = 0,
|
||||
DASH_DYNAMIC,
|
||||
};
|
||||
|
||||
#endif /* !_dash_proto_h_ */
|
19
src/3rdpart/media-server/libdash/include/xs-datatype.h
Normal file
19
src/3rdpart/media-server/libdash/include/xs-datatype.h
Normal file
@ -0,0 +1,19 @@
|
||||
#ifndef _xs_datatype_h_
|
||||
#define _xs_datatype_h_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/// @param[in] duration millisecond duration
|
||||
/// @param[out] data ISO8601 duration: P[n]Y[n]M[n]DT[n]H[n]M[n]S
|
||||
int xs_duration_write(int64_t duration, char* data, int size);
|
||||
int xs_duration_read(int64_t* duration, const char* data, int size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif /* !_xs_datatype_h_ */
|
151
src/3rdpart/media-server/libdash/libdash.vcxproj
Normal file
151
src/3rdpart/media-server/libdash/libdash.vcxproj
Normal file
@ -0,0 +1,151 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="include\dash-mpd.h" />
|
||||
<ClInclude Include="include\dash-parser.h" />
|
||||
<ClInclude Include="include\dash-proto.h" />
|
||||
<ClInclude Include="include\xs-datatype.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="src\dash-adaptation.c" />
|
||||
<ClCompile Include="src\dash-mpd.c" />
|
||||
<ClCompile Include="src\dash-parser.c" />
|
||||
<ClCompile Include="src\dash-period.c" />
|
||||
<ClCompile Include="src\dash-representation.c" />
|
||||
<ClCompile Include="src\dash-segment.c" />
|
||||
<ClCompile Include="src\xs-duration.c" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{A5DA231F-6146-43B5-8BBE-891F7E552357}</ProjectGuid>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<RootNamespace>libdash</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup />
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_LIB;OS_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>.;include;../libmov/include;../libhls/include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>_DEBUG;_LIB;OS_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>.;include;../libmov/include;../libhls/include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_LIB;OS_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>.;include;../libmov/include;../libhls/include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>NDEBUG;_LIB;OS_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>.;include;../libmov/include;../libhls/include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
54
src/3rdpart/media-server/libdash/libdash.vcxproj.filters
Normal file
54
src/3rdpart/media-server/libdash/libdash.vcxproj.filters
Normal file
@ -0,0 +1,54 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Resource Files">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="src\dash-mpd.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\dash-parser.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\xs-duration.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\dash-period.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\dash-adaptation.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\dash-representation.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\dash-segment.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="include\dash-mpd.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\dash-proto.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\dash-parser.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\xs-datatype.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
@ -0,0 +1,328 @@
|
||||
// !$*UTF8*$!
|
||||
{
|
||||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 50;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
46C5B2AF2183ED6100419E57 /* list.h in Headers */ = {isa = PBXBuildFile; fileRef = 46C5B2AC2183ED6100419E57 /* list.h */; };
|
||||
46C5B2B02183ED6100419E57 /* dash-mpd.c in Sources */ = {isa = PBXBuildFile; fileRef = 46C5B2AD2183ED6100419E57 /* dash-mpd.c */; };
|
||||
46E55E6824A7395F00D8BDBA /* xs-duration.c in Sources */ = {isa = PBXBuildFile; fileRef = 46E55E6224A7395F00D8BDBA /* xs-duration.c */; };
|
||||
46E55E6924A7395F00D8BDBA /* dash-period.c in Sources */ = {isa = PBXBuildFile; fileRef = 46E55E6324A7395F00D8BDBA /* dash-period.c */; };
|
||||
46E55E6A24A7395F00D8BDBA /* dash-adaptation.c in Sources */ = {isa = PBXBuildFile; fileRef = 46E55E6424A7395F00D8BDBA /* dash-adaptation.c */; };
|
||||
46E55E6B24A7395F00D8BDBA /* dash-representation.c in Sources */ = {isa = PBXBuildFile; fileRef = 46E55E6524A7395F00D8BDBA /* dash-representation.c */; };
|
||||
46E55E6C24A7395F00D8BDBA /* dash-parser.c in Sources */ = {isa = PBXBuildFile; fileRef = 46E55E6624A7395F00D8BDBA /* dash-parser.c */; };
|
||||
46E55E6D24A7395F00D8BDBA /* dash-segment.c in Sources */ = {isa = PBXBuildFile; fileRef = 46E55E6724A7395F00D8BDBA /* dash-segment.c */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
46C5B22C2183EAAD00419E57 /* libdash.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libdash.a; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
46C5B2A92183ED5400419E57 /* include */ = {isa = PBXFileReference; lastKnownFileType = folder; path = include; sourceTree = "<group>"; };
|
||||
46C5B2AC2183ED6100419E57 /* list.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = list.h; sourceTree = "<group>"; };
|
||||
46C5B2AD2183ED6100419E57 /* dash-mpd.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "dash-mpd.c"; sourceTree = "<group>"; };
|
||||
46E55E6224A7395F00D8BDBA /* xs-duration.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "xs-duration.c"; sourceTree = "<group>"; };
|
||||
46E55E6324A7395F00D8BDBA /* dash-period.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "dash-period.c"; sourceTree = "<group>"; };
|
||||
46E55E6424A7395F00D8BDBA /* dash-adaptation.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "dash-adaptation.c"; sourceTree = "<group>"; };
|
||||
46E55E6524A7395F00D8BDBA /* dash-representation.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "dash-representation.c"; sourceTree = "<group>"; };
|
||||
46E55E6624A7395F00D8BDBA /* dash-parser.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "dash-parser.c"; sourceTree = "<group>"; };
|
||||
46E55E6724A7395F00D8BDBA /* dash-segment.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "dash-segment.c"; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
46C5B22A2183EAAD00419E57 /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
46C5B2232183EAAD00419E57 = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
46C5B2AA2183ED6100419E57 /* src */,
|
||||
46C5B2A92183ED5400419E57 /* include */,
|
||||
46C5B22D2183EAAD00419E57 /* Products */,
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
46C5B22D2183EAAD00419E57 /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
46C5B22C2183EAAD00419E57 /* libdash.a */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
46C5B2AA2183ED6100419E57 /* src */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
46C5B2AC2183ED6100419E57 /* list.h */,
|
||||
46E55E6424A7395F00D8BDBA /* dash-adaptation.c */,
|
||||
46E55E6624A7395F00D8BDBA /* dash-parser.c */,
|
||||
46E55E6324A7395F00D8BDBA /* dash-period.c */,
|
||||
46E55E6524A7395F00D8BDBA /* dash-representation.c */,
|
||||
46E55E6724A7395F00D8BDBA /* dash-segment.c */,
|
||||
46E55E6224A7395F00D8BDBA /* xs-duration.c */,
|
||||
46C5B2AD2183ED6100419E57 /* dash-mpd.c */,
|
||||
);
|
||||
path = src;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXHeadersBuildPhase section */
|
||||
46C5B2282183EAAD00419E57 /* Headers */ = {
|
||||
isa = PBXHeadersBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
46C5B2AF2183ED6100419E57 /* list.h in Headers */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXHeadersBuildPhase section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
46C5B22B2183EAAD00419E57 /* libdash */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 46C5B2302183EAAD00419E57 /* Build configuration list for PBXNativeTarget "libdash" */;
|
||||
buildPhases = (
|
||||
46C5B2282183EAAD00419E57 /* Headers */,
|
||||
46C5B2292183EAAD00419E57 /* Sources */,
|
||||
46C5B22A2183EAAD00419E57 /* Frameworks */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
name = libdash;
|
||||
productName = libdash;
|
||||
productReference = 46C5B22C2183EAAD00419E57 /* libdash.a */;
|
||||
productType = "com.apple.product-type.library.static";
|
||||
};
|
||||
/* End PBXNativeTarget section */
|
||||
|
||||
/* Begin PBXProject section */
|
||||
46C5B2242183EAAD00419E57 /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastUpgradeCheck = 1000;
|
||||
ORGANIZATIONNAME = ireader;
|
||||
TargetAttributes = {
|
||||
46C5B22B2183EAAD00419E57 = {
|
||||
CreatedOnToolsVersion = 10.0;
|
||||
};
|
||||
};
|
||||
};
|
||||
buildConfigurationList = 46C5B2272183EAAD00419E57 /* Build configuration list for PBXProject "libdash" */;
|
||||
compatibilityVersion = "Xcode 9.3";
|
||||
developmentRegion = en;
|
||||
hasScannedForEncodings = 0;
|
||||
knownRegions = (
|
||||
en,
|
||||
Base,
|
||||
);
|
||||
mainGroup = 46C5B2232183EAAD00419E57;
|
||||
productRefGroup = 46C5B22D2183EAAD00419E57 /* Products */;
|
||||
projectDirPath = "";
|
||||
projectRoot = "";
|
||||
targets = (
|
||||
46C5B22B2183EAAD00419E57 /* libdash */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
46C5B2292183EAAD00419E57 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
46E55E6B24A7395F00D8BDBA /* dash-representation.c in Sources */,
|
||||
46E55E6A24A7395F00D8BDBA /* dash-adaptation.c in Sources */,
|
||||
46E55E6C24A7395F00D8BDBA /* dash-parser.c in Sources */,
|
||||
46E55E6824A7395F00D8BDBA /* xs-duration.c in Sources */,
|
||||
46C5B2B02183ED6100419E57 /* dash-mpd.c in Sources */,
|
||||
46E55E6924A7395F00D8BDBA /* dash-period.c in Sources */,
|
||||
46E55E6D24A7395F00D8BDBA /* dash-segment.c in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXSourcesBuildPhase section */
|
||||
|
||||
/* Begin XCBuildConfiguration section */
|
||||
46C5B22E2183EAAD00419E57 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
CODE_SIGN_IDENTITY = "-";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
ENABLE_TESTABILITY = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_OPTIMIZATION_LEVEL = 0;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"DEBUG=1",
|
||||
"$(inherited)",
|
||||
);
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.13;
|
||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||
MTL_FAST_MATH = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
SDKROOT = macosx;
|
||||
USER_HEADER_SEARCH_PATHS = (
|
||||
.,
|
||||
./include,
|
||||
../libmov/include,
|
||||
../libhls/include,
|
||||
);
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
46C5B22F2183EAAD00419E57 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
CODE_SIGN_IDENTITY = "-";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.13;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
MTL_FAST_MATH = YES;
|
||||
SDKROOT = macosx;
|
||||
USER_HEADER_SEARCH_PATHS = (
|
||||
.,
|
||||
./include,
|
||||
../libmov/include,
|
||||
../libhls/include,
|
||||
);
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
46C5B2312183EAAD00419E57 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
EXECUTABLE_PREFIX = "";
|
||||
GCC_PREPROCESSOR_DEFINITIONS = "$(inherited)";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SKIP_INSTALL = YES;
|
||||
USER_HEADER_SEARCH_PATHS = "$(inherited)";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
46C5B2322183EAAD00419E57 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
EXECUTABLE_PREFIX = "";
|
||||
GCC_PREPROCESSOR_DEFINITIONS = "$(inherited)";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SKIP_INSTALL = YES;
|
||||
USER_HEADER_SEARCH_PATHS = "$(inherited)";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
/* End XCBuildConfiguration section */
|
||||
|
||||
/* Begin XCConfigurationList section */
|
||||
46C5B2272183EAAD00419E57 /* Build configuration list for PBXProject "libdash" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
46C5B22E2183EAAD00419E57 /* Debug */,
|
||||
46C5B22F2183EAAD00419E57 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
46C5B2302183EAAD00419E57 /* Build configuration list for PBXNativeTarget "libdash" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
46C5B2312183EAAD00419E57 /* Debug */,
|
||||
46C5B2322183EAAD00419E57 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
/* End XCConfigurationList section */
|
||||
};
|
||||
rootObject = 46C5B2242183EAAD00419E57 /* Project object */;
|
||||
}
|
77
src/3rdpart/media-server/libdash/src/dash-adaptation.c
Normal file
77
src/3rdpart/media-server/libdash/src/dash-adaptation.c
Normal file
@ -0,0 +1,77 @@
|
||||
#include "dash-parser.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
static int dash_mime_type_to_media_type(const char* mime)
|
||||
{
|
||||
switch (mime[0])
|
||||
{
|
||||
case 't':
|
||||
return 0 == strncmp(mime, "text/", 5) ? DASH_MEDIA_TEXT : DASH_MEDIA_UNKNOWN;
|
||||
case 'i':
|
||||
return 0 == strncmp(mime, "image/", 6) ? DASH_MEDIA_IMAGE : DASH_MEDIA_UNKNOWN;
|
||||
case 'a':
|
||||
if (0 == strncmp(mime, "audio/", 6))
|
||||
return DASH_MEDIA_AUDIO;
|
||||
else if (0 == strncmp(mime, "application/", 12))
|
||||
return DASH_MEDIA_APPLICATION;
|
||||
else
|
||||
return DASH_MEDIA_UNKNOWN;
|
||||
case 'v':
|
||||
return 0 == strncmp(mime, "video/", 6) ? DASH_MEDIA_VIDEO : DASH_MEDIA_UNKNOWN;
|
||||
case 'f':
|
||||
return 0 == strncmp(mime, "font/", 5) ? DASH_MEDIA_FONT : DASH_MEDIA_UNKNOWN;
|
||||
default:
|
||||
return DASH_MEDIA_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
int dash_adaptation_set_media_type(const struct dash_adaptation_set_t* set)
|
||||
{
|
||||
const struct dash_representation_base_t* base;
|
||||
|
||||
base = &set->base;
|
||||
if (base->mime_type && *base->mime_type)
|
||||
return dash_mime_type_to_media_type(base->mime_type);
|
||||
else if (set->content_type && *set->content_type)
|
||||
return dash_mime_type_to_media_type(set->content_type);
|
||||
|
||||
if (set->representation_count > 0)
|
||||
{
|
||||
base = &set->representations[0].base;
|
||||
if (base->mime_type && *base->mime_type)
|
||||
return dash_mime_type_to_media_type(base->mime_type);
|
||||
|
||||
if (set->representations[0].subrepresentation_count > 0)
|
||||
{
|
||||
base = &set->representations[0].subrepresentations[0].base;
|
||||
return dash_mime_type_to_media_type(base->mime_type);
|
||||
}
|
||||
}
|
||||
|
||||
return DASH_MEDIA_UNKNOWN;
|
||||
}
|
||||
|
||||
int dash_adaptation_set_best_representation(const struct dash_adaptation_set_t* set)
|
||||
{
|
||||
int best;
|
||||
size_t i;
|
||||
const struct dash_representation_t* v;
|
||||
|
||||
best = -1;
|
||||
for (i = 0; i < set->representation_count; i++)
|
||||
{
|
||||
v = &set->representations[i];
|
||||
// qualityRanking: specifies a quality ranking of the Representation
|
||||
// relative to other Representations in the same Adaptation Set.
|
||||
// Lower values represent higher quality content.
|
||||
if (-1 == best
|
||||
|| v->base.selection_priority > set->representations[best].base.selection_priority
|
||||
|| v->quality_ranking < set->representations[best].quality_ranking
|
||||
|| v->bandwidth > set->representations[best].bandwidth)
|
||||
best = (int)i;
|
||||
}
|
||||
|
||||
return best;
|
||||
}
|
520
src/3rdpart/media-server/libdash/src/dash-mpd.c
Normal file
520
src/3rdpart/media-server/libdash/src/dash-mpd.c
Normal file
@ -0,0 +1,520 @@
|
||||
#include "dash-mpd.h"
|
||||
#include "dash-proto.h"
|
||||
#include "mov-format.h"
|
||||
#include "fmp4-writer.h"
|
||||
#include "list.h"
|
||||
#include <time.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#define N_TRACK 8
|
||||
#define N_NAME 128
|
||||
#define N_COUNT 5
|
||||
|
||||
#define N_SEGMENT (1 * 1024 * 1024)
|
||||
#define N_FILESIZE (100 * 1024 * 1024) // 100M
|
||||
|
||||
#define MAX(a, b) ((a) > (b) ? (a) : (b))
|
||||
|
||||
struct dash_segment_t
|
||||
{
|
||||
struct list_head link;
|
||||
int64_t timestamp;
|
||||
int64_t duration;
|
||||
};
|
||||
|
||||
struct dash_adaptation_set_t
|
||||
{
|
||||
fmp4_writer_t* fmp4;
|
||||
char prefix[N_NAME];
|
||||
|
||||
uint8_t* ptr;
|
||||
size_t bytes;
|
||||
size_t capacity;
|
||||
size_t offset;
|
||||
size_t maxsize; // max bytes per mp4 file
|
||||
|
||||
int64_t pts;
|
||||
int64_t dts;
|
||||
int64_t dts_last;
|
||||
int64_t raw_bytes;
|
||||
int bitrate;
|
||||
int track; // MP4 track id
|
||||
int setid; // dash adapation set id
|
||||
|
||||
int seq;
|
||||
uint8_t object;
|
||||
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
int width;
|
||||
int height;
|
||||
int frame_rate;
|
||||
struct
|
||||
{
|
||||
uint8_t profile;
|
||||
uint8_t compatibility;
|
||||
uint8_t level;
|
||||
} avc;
|
||||
} video;
|
||||
|
||||
struct
|
||||
{
|
||||
uint8_t profile; // AAC profile
|
||||
int channel;
|
||||
int sample_bit;
|
||||
int sample_rate;
|
||||
} audio;
|
||||
} u;
|
||||
|
||||
size_t count;
|
||||
struct list_head root; // segments
|
||||
};
|
||||
|
||||
struct dash_mpd_t
|
||||
{
|
||||
int flags;
|
||||
time_t time;
|
||||
int64_t duration;
|
||||
int64_t max_segment_duration;
|
||||
|
||||
dash_mpd_segment handler;
|
||||
void* param;
|
||||
|
||||
int count; // adaptation set count
|
||||
struct dash_adaptation_set_t tracks[N_TRACK];
|
||||
};
|
||||
|
||||
static int mov_buffer_read(void* param, void* data, uint64_t bytes)
|
||||
{
|
||||
struct dash_adaptation_set_t* dash;
|
||||
dash = (struct dash_adaptation_set_t*)param;
|
||||
if (dash->offset + bytes > dash->bytes)
|
||||
return E2BIG;
|
||||
memcpy(data, dash->ptr + dash->offset, (size_t)bytes);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mov_buffer_write(void* param, const void* data, uint64_t bytes)
|
||||
{
|
||||
void* ptr;
|
||||
size_t capacity;
|
||||
struct dash_adaptation_set_t* dash;
|
||||
dash = (struct dash_adaptation_set_t*)param;
|
||||
if (dash->offset + bytes > dash->maxsize)
|
||||
return E2BIG;
|
||||
|
||||
if (dash->offset + (size_t)bytes > dash->capacity)
|
||||
{
|
||||
capacity = dash->offset + (size_t)bytes + N_SEGMENT;
|
||||
capacity = capacity > dash->maxsize ? dash->maxsize : capacity;
|
||||
ptr = realloc(dash->ptr, capacity);
|
||||
if (NULL == ptr)
|
||||
return ENOMEM;
|
||||
dash->ptr = ptr;
|
||||
dash->capacity = capacity;
|
||||
}
|
||||
|
||||
memcpy(dash->ptr + dash->offset, data, (size_t)bytes);
|
||||
dash->offset += (size_t)bytes;
|
||||
if (dash->offset > dash->bytes)
|
||||
dash->bytes = dash->offset;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mov_buffer_seek(void* param, uint64_t offset)
|
||||
{
|
||||
struct dash_adaptation_set_t* dash;
|
||||
dash = (struct dash_adaptation_set_t*)param;
|
||||
if (offset >= dash->maxsize)
|
||||
return E2BIG;
|
||||
dash->offset = (size_t)offset;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint64_t mov_buffer_tell(void* param)
|
||||
{
|
||||
return ((struct dash_adaptation_set_t*)param)->offset;
|
||||
}
|
||||
|
||||
static struct mov_buffer_t s_io = {
|
||||
mov_buffer_read,
|
||||
mov_buffer_write,
|
||||
mov_buffer_seek,
|
||||
mov_buffer_tell,
|
||||
};
|
||||
|
||||
static int dash_adaptation_set_segment(struct dash_mpd_t* mpd, struct dash_adaptation_set_t* track)
|
||||
{
|
||||
int r;
|
||||
char name[N_NAME + 32];
|
||||
struct list_head *link;
|
||||
struct dash_segment_t* seg;
|
||||
|
||||
r = fmp4_writer_save_segment(track->fmp4);
|
||||
if (0 != r)
|
||||
return r;
|
||||
|
||||
seg = (struct dash_segment_t*)calloc(1, sizeof(*seg));
|
||||
if(!seg)
|
||||
return -1; // ENOMEM
|
||||
seg->timestamp = track->dts;
|
||||
seg->duration = track->dts_last - track->dts;
|
||||
|
||||
if(MOV_OBJECT_AAC == track->object)
|
||||
snprintf(name, sizeof(name), "%s-%" PRId64 ".m4a", track->prefix, seg->timestamp);
|
||||
else
|
||||
snprintf(name, sizeof(name), "%s-%" PRId64 ".m4v", track->prefix, seg->timestamp);
|
||||
r = mpd->handler(mpd->param, track->setid, track->ptr, track->bytes, track->pts, track->dts, seg->duration, name);
|
||||
if (0 != r)
|
||||
{
|
||||
free(seg);
|
||||
return r;
|
||||
}
|
||||
|
||||
// link
|
||||
list_insert_after(&seg->link, track->root.prev);
|
||||
|
||||
track->count += 1;
|
||||
if (DASH_DYNAMIC == mpd->flags && track->count > N_COUNT)
|
||||
{
|
||||
link = track->root.next;
|
||||
list_remove(link);
|
||||
seg = list_entry(link, struct dash_segment_t, link);
|
||||
free(seg);
|
||||
--track->count;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dash_mpd_flush(struct dash_mpd_t* mpd)
|
||||
{
|
||||
int i, r;
|
||||
struct dash_adaptation_set_t* track;
|
||||
|
||||
for (r = i = 0; i < mpd->count && 0 == r; i++)
|
||||
{
|
||||
track = mpd->tracks + i;
|
||||
if (track->raw_bytes)
|
||||
{
|
||||
r = dash_adaptation_set_segment(mpd, track);
|
||||
|
||||
// update maximum segment duration
|
||||
mpd->max_segment_duration = MAX(track->dts_last - track->dts, mpd->max_segment_duration);
|
||||
if(track->dts_last > track->dts)
|
||||
track->bitrate = MAX(track->bitrate, (int)(track->raw_bytes * 1000 / (track->dts_last - track->dts) * 8));
|
||||
}
|
||||
|
||||
track->pts = INT64_MIN;
|
||||
track->dts = INT64_MIN;
|
||||
track->raw_bytes = 0;
|
||||
|
||||
// reset track buffer
|
||||
track->offset = 0;
|
||||
track->bytes = 0;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
struct dash_mpd_t* dash_mpd_create(int flags, dash_mpd_segment segment, void* param)
|
||||
{
|
||||
struct dash_mpd_t* mpd;
|
||||
mpd = (struct dash_mpd_t*)calloc(1, sizeof(*mpd));
|
||||
if (mpd)
|
||||
{
|
||||
mpd->flags = flags;
|
||||
mpd->handler = segment;
|
||||
mpd->param = param;
|
||||
mpd->time = time(NULL);
|
||||
}
|
||||
return mpd;
|
||||
}
|
||||
|
||||
void dash_mpd_destroy(struct dash_mpd_t* mpd)
|
||||
{
|
||||
int i;
|
||||
struct list_head *p, *n;
|
||||
struct dash_segment_t *seg;
|
||||
struct dash_adaptation_set_t* track;
|
||||
|
||||
dash_mpd_flush(mpd);
|
||||
|
||||
for (i = 0; i < mpd->count; i++)
|
||||
{
|
||||
track = &mpd->tracks[i];
|
||||
|
||||
if (track->ptr)
|
||||
{
|
||||
free(track->ptr);
|
||||
track->ptr = NULL;
|
||||
}
|
||||
|
||||
list_for_each_safe(p, n, &track->root)
|
||||
{
|
||||
seg = list_entry(p, struct dash_segment_t, link);
|
||||
free(seg);
|
||||
}
|
||||
}
|
||||
|
||||
free(mpd);
|
||||
}
|
||||
|
||||
int dash_mpd_add_video_adaptation_set(struct dash_mpd_t* mpd, const char* prefix, uint8_t object, int width, int height, const void* extra_data, size_t extra_data_size)
|
||||
{
|
||||
int r;
|
||||
char name[N_NAME + 16];
|
||||
struct dash_adaptation_set_t* track;
|
||||
|
||||
r = (int)strlen(prefix);
|
||||
if (mpd->count + 1 >= N_TRACK || extra_data_size < 4 || r >= N_NAME)
|
||||
return -1;
|
||||
|
||||
assert(MOV_OBJECT_H264 == object);
|
||||
track = &mpd->tracks[mpd->count];
|
||||
memcpy(track->prefix, prefix, r);
|
||||
LIST_INIT_HEAD(&track->root);
|
||||
track->setid = mpd->count++;
|
||||
track->object = object;
|
||||
track->bitrate = 0;
|
||||
track->u.video.width = width;
|
||||
track->u.video.height = height;
|
||||
track->u.video.frame_rate = 25;
|
||||
assert(((const uint8_t*)extra_data)[0] == 1); // configurationVersion
|
||||
if (MOV_OBJECT_H264 == object)
|
||||
{
|
||||
track->u.video.avc.profile = ((const uint8_t*)extra_data)[1];
|
||||
track->u.video.avc.compatibility = ((const uint8_t*)extra_data)[2];
|
||||
track->u.video.avc.level = ((const uint8_t*)extra_data)[3];
|
||||
}
|
||||
|
||||
track->seq = 1;
|
||||
track->maxsize = N_FILESIZE;
|
||||
track->fmp4 = fmp4_writer_create(&s_io, track, MOV_FLAG_SEGMENT);
|
||||
if (!track->fmp4)
|
||||
return -1;
|
||||
track->track = fmp4_writer_add_video(track->fmp4, object, width, height, extra_data, extra_data_size);
|
||||
|
||||
// save init segment file
|
||||
r = fmp4_writer_init_segment(track->fmp4);
|
||||
if (0 == r)
|
||||
{
|
||||
snprintf(name, sizeof(name), "%s-init.m4v", prefix);
|
||||
r = mpd->handler(mpd->param, mpd->count, track->ptr, track->bytes, 0, 0, 0, name);
|
||||
}
|
||||
|
||||
track->bytes = 0;
|
||||
track->offset = 0;
|
||||
return 0 == r ? track->setid : r;
|
||||
}
|
||||
|
||||
int dash_mpd_add_audio_adaptation_set(struct dash_mpd_t* mpd, const char* prefix, uint8_t object, int channel_count, int bits_per_sample, int sample_rate, const void* extra_data, size_t extra_data_size)
|
||||
{
|
||||
int r;
|
||||
char name[N_NAME + 16];
|
||||
struct dash_adaptation_set_t* track;
|
||||
|
||||
r = (int)strlen(prefix);
|
||||
if (mpd->count + 1 >= N_TRACK || extra_data_size < 2 || r >= N_NAME)
|
||||
return -1;
|
||||
|
||||
assert(MOV_OBJECT_AAC == object);
|
||||
track = &mpd->tracks[mpd->count];
|
||||
memcpy(track->prefix, prefix, r);
|
||||
LIST_INIT_HEAD(&track->root);
|
||||
track->setid = mpd->count++;
|
||||
track->object = object;
|
||||
track->bitrate = 0;
|
||||
track->u.audio.channel = channel_count;
|
||||
track->u.audio.sample_bit = bits_per_sample;
|
||||
track->u.audio.sample_rate = sample_rate;
|
||||
track->u.audio.profile = ((const uint8_t*)extra_data)[0] >> 3;
|
||||
if(MOV_OBJECT_AAC == object && 31 == track->u.audio.profile)
|
||||
track->u.audio.profile = 32 + (((((const uint8_t*)extra_data)[0] & 0x07) << 3) | ((((const uint8_t*)extra_data)[1] >> 5) & 0x07));
|
||||
|
||||
track->seq = 1;
|
||||
track->maxsize = N_FILESIZE;
|
||||
track->fmp4 = fmp4_writer_create(&s_io, track, MOV_FLAG_SEGMENT);
|
||||
if (!track->fmp4)
|
||||
return -1;
|
||||
track->track = fmp4_writer_add_audio(track->fmp4, object, channel_count, bits_per_sample, sample_rate, extra_data, extra_data_size);
|
||||
|
||||
r = fmp4_writer_init_segment(track->fmp4);
|
||||
if (0 == r)
|
||||
{
|
||||
snprintf(name, sizeof(name), "%s-init.m4a", prefix);
|
||||
r = mpd->handler(mpd->param, mpd->count, track->ptr, track->bytes, 0, 0, 0, name);
|
||||
}
|
||||
|
||||
track->bytes = 0;
|
||||
track->offset = 0;
|
||||
return 0 == r ? track->setid : r;
|
||||
}
|
||||
|
||||
int dash_mpd_input(struct dash_mpd_t* mpd, int adapation, const void* data, size_t bytes, int64_t pts, int64_t dts, int flags)
|
||||
{
|
||||
int r = 0;
|
||||
struct dash_adaptation_set_t* track;
|
||||
if (adapation >= mpd->count || adapation < 0)
|
||||
return -1;
|
||||
|
||||
track = &mpd->tracks[adapation];
|
||||
if (NULL == data || 0 == bytes // flash fragment
|
||||
|| ((MOV_AV_FLAG_KEYFREAME & flags) && (MOV_OBJECT_H264 == track->object || MOV_OBJECT_HEVC == track->object)))
|
||||
{
|
||||
r = dash_mpd_flush(mpd);
|
||||
|
||||
// FIXME: live duration
|
||||
mpd->duration += mpd->max_segment_duration;
|
||||
}
|
||||
|
||||
if (NULL == data || 0 == bytes)
|
||||
return r;
|
||||
|
||||
if (0 == track->raw_bytes)
|
||||
{
|
||||
track->pts = pts;
|
||||
track->dts = dts;
|
||||
}
|
||||
track->dts_last = dts;
|
||||
track->raw_bytes += bytes;
|
||||
return fmp4_writer_write(track->fmp4, track->track, data, bytes, pts, dts, flags);
|
||||
}
|
||||
|
||||
// ISO/IEC 23009-1:2014(E) 5.4 Media Presentation Description updates (p67)
|
||||
// 1. the value of MPD@id, if present, shall be the same in the original and the updated MPD;
|
||||
// 2. the values of any Period@id attributes shall be the same in the original and the updated MPD, unless the containing Period element has been removed;
|
||||
// 3. the values of any AdaptationSet@id attributes shall be the same in the original and the updated MPD unless the containing Period element has been removed;
|
||||
size_t dash_mpd_playlist(struct dash_mpd_t* mpd, char* playlist, size_t bytes)
|
||||
{
|
||||
// ISO/IEC 23009-1:2014(E)
|
||||
// G.2 Example for ISO Base media file format Live profile (141)
|
||||
static const char* s_mpd_dynamic =
|
||||
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
|
||||
"<MPD\n"
|
||||
" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n"
|
||||
" xmlns=\"urn:mpeg:dash:schema:mpd:2011\"\n"
|
||||
" xsi:schemaLocation=\"urn:mpeg:DASH:schema:MPD:2011 DASH-MPD.xsd\"\n"
|
||||
" type=\"dynamic\"\n"
|
||||
" minimumUpdatePeriod=\"PT%uS\"\n"
|
||||
" timeShiftBufferDepth=\"PT%uS\"\n"
|
||||
" availabilityStartTime=\"%s\"\n"
|
||||
" minBufferTime=\"PT%uS\"\n"
|
||||
" publishTime=\"%s\"\n"
|
||||
" profiles=\"urn:mpeg:dash:profile:isoff-live:2011\">\n";
|
||||
|
||||
// ISO/IEC 23009-1:2014(E)
|
||||
// G.1 Example MPD for ISO Base media file format On Demand profile
|
||||
static const char* s_mpd_static =
|
||||
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
|
||||
"<MPD\n"
|
||||
" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n"
|
||||
" xmlns=\"urn:mpeg:dash:schema:mpd:2011\"\n"
|
||||
" xsi:schemaLocation=\"urn:mpeg:DASH:schema:MPD:2011 DASH-MPD.xsd\"\n"
|
||||
" type=\"static\"\n"
|
||||
" mediaPresentationDuration=\"PT%uS\"\n"
|
||||
" minBufferTime=\"PT%uS\"\n"
|
||||
" profiles=\"urn:mpeg:dash:profile:isoff-on-demand:2011\">\n";
|
||||
|
||||
static const char* s_h264 =
|
||||
" <AdaptationSet contentType=\"video\" segmentAlignment=\"true\" bitstreamSwitching=\"true\">\n"
|
||||
" <Representation id=\"H264\" mimeType=\"video/mp4\" codecs=\"avc1.%02x%02x%02x\" width=\"%d\" height=\"%d\" frameRate=\"%d\" startWithSAP=\"1\" bandwidth=\"%d\">\n"
|
||||
" <SegmentTemplate timescale=\"1000\" media=\"%s-$Time$.m4v\" initialization=\"%s-init.m4v\">\n"
|
||||
" <SegmentTimeline>\n";
|
||||
|
||||
static const char* s_h265 =
|
||||
" <AdaptationSet contentType=\"video\" segmentAlignment=\"true\" bitstreamSwitching=\"true\">\n"
|
||||
" <Representation id=\"H265\" mimeType=\"video/mp4\" codecs=\"hvc1.%02x%02x%02x\" width=\"%d\" height=\"%d\" frameRate=\"%d\" startWithSAP=\"1\" bandwidth=\"%d\">\n"
|
||||
" <SegmentTemplate timescale=\"1000\" media=\"%s-$Time$.m4v\" initialization=\"%s-init.m4v\">\n"
|
||||
" <SegmentTimeline>\n";
|
||||
|
||||
static const char* s_aac =
|
||||
" <AdaptationSet contentType=\"audio\" segmentAlignment=\"true\" bitstreamSwitching=\"true\">\n"
|
||||
" <Representation id=\"AAC\" mimeType=\"audio/mp4\" codecs=\"mp4a.40.%u\" audioSamplingRate=\"%d\" startWithSAP=\"1\" bandwidth=\"%d\">\n"
|
||||
" <AudioChannelConfiguration schemeIdUri=\"urn:mpeg:dash:23003:3:audio_channel_configuration:2011\" value=\"%d\"/>\n"
|
||||
" <SegmentTemplate timescale=\"1000\" media=\"%s-$Time$.m4a\" initialization=\"%s-init.m4a\">\n"
|
||||
" <SegmentTimeline>\n";
|
||||
|
||||
static const char* s_footer =
|
||||
" </SegmentTimeline>\n"
|
||||
" </SegmentTemplate>\n"
|
||||
" </Representation>\n"
|
||||
" </AdaptationSet>\n";
|
||||
|
||||
int i;
|
||||
size_t n;
|
||||
time_t now;
|
||||
char publishTime[32];
|
||||
char availabilityStartTime[32];
|
||||
unsigned int minimumUpdatePeriod;
|
||||
unsigned int timeShiftBufferDepth;
|
||||
struct dash_adaptation_set_t* track;
|
||||
struct dash_segment_t *seg;
|
||||
struct list_head *link;
|
||||
|
||||
now = time(NULL);
|
||||
strftime(availabilityStartTime, sizeof(availabilityStartTime), "%Y-%m-%dT%H:%M:%SZ", gmtime(&mpd->time));
|
||||
strftime(publishTime, sizeof(publishTime), "%Y-%m-%dT%H:%M:%SZ", gmtime(&now));
|
||||
|
||||
minimumUpdatePeriod = (unsigned int)MAX(mpd->max_segment_duration / 1000, 1);
|
||||
|
||||
if (mpd->flags == DASH_DYNAMIC)
|
||||
{
|
||||
timeShiftBufferDepth = minimumUpdatePeriod * N_COUNT + 1;
|
||||
n = snprintf(playlist, bytes, s_mpd_dynamic, minimumUpdatePeriod, timeShiftBufferDepth, availabilityStartTime, minimumUpdatePeriod, publishTime);
|
||||
n += snprintf(playlist + n, bytes - n, " <Period start=\"PT0S\" id=\"dash\">\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
n = snprintf(playlist, bytes, s_mpd_static, (unsigned int)(mpd->duration / 1000), minimumUpdatePeriod);
|
||||
n += snprintf(playlist + n, bytes - n, " <Period start=\"PT0S\" id=\"dash\">\n");
|
||||
}
|
||||
|
||||
for (i = 0; i < mpd->count; i++)
|
||||
{
|
||||
track = &mpd->tracks[i];
|
||||
if (MOV_OBJECT_H264 == track->object)
|
||||
{
|
||||
n += snprintf(playlist + n, bytes - n, s_h264, (unsigned int)track->u.video.avc.profile, (unsigned int)track->u.video.avc.compatibility, (unsigned int)track->u.video.avc.level, track->u.video.width, track->u.video.height, track->u.video.frame_rate, track->bitrate, track->prefix, track->prefix);
|
||||
list_for_each(link, &track->root)
|
||||
{
|
||||
seg = list_entry(link, struct dash_segment_t, link);
|
||||
n += snprintf(playlist + n, bytes - n, " <S t=\"%" PRId64 "\" d=\"%u\"/>\n", seg->timestamp, (unsigned int)seg->duration);
|
||||
}
|
||||
n += snprintf(playlist + n, bytes - n, "%s", s_footer);
|
||||
}
|
||||
else if (MOV_OBJECT_HEVC == track->object)
|
||||
{
|
||||
n += snprintf(playlist + n, bytes - n, s_h265, (unsigned int)track->u.video.avc.profile, (unsigned int)track->u.video.avc.compatibility, (unsigned int)track->u.video.avc.level, track->u.video.width, track->u.video.height, track->u.video.frame_rate, track->bitrate, track->prefix, track->prefix);
|
||||
list_for_each(link, &track->root)
|
||||
{
|
||||
seg = list_entry(link, struct dash_segment_t, link);
|
||||
n += snprintf(playlist + n, bytes - n, " <S t=\"%" PRId64 "\" d=\"%u\"/>\n", seg->timestamp, (unsigned int)seg->duration);
|
||||
}
|
||||
n += snprintf(playlist + n, bytes - n, "%s", s_footer);
|
||||
}
|
||||
else if (MOV_OBJECT_AAC == track->object)
|
||||
{
|
||||
n += snprintf(playlist + n, bytes - n, s_aac, (unsigned int)track->u.audio.profile, track->u.audio.sample_rate, track->bitrate, track->u.audio.channel, track->prefix, track->prefix);
|
||||
list_for_each(link, &track->root)
|
||||
{
|
||||
seg = list_entry(link, struct dash_segment_t, link);
|
||||
n += snprintf(playlist + n, bytes - n, " <S t=\"%" PRId64 "\" d=\"%u\"/>\n", seg->timestamp, (unsigned int)seg->duration);
|
||||
}
|
||||
n += snprintf(playlist + n, bytes - n, "%s", s_footer);
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
n += snprintf(playlist + n, bytes - n, " </Period>\n</MPD>\n");
|
||||
return n;
|
||||
}
|
1537
src/3rdpart/media-server/libdash/src/dash-parser.c
Normal file
1537
src/3rdpart/media-server/libdash/src/dash-parser.c
Normal file
File diff suppressed because it is too large
Load Diff
182
src/3rdpart/media-server/libdash/src/dash-period.c
Normal file
182
src/3rdpart/media-server/libdash/src/dash-period.c
Normal file
@ -0,0 +1,182 @@
|
||||
#include "dash-parser.h"
|
||||
#include "hls-string.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
int64_t dash_get_duration(const struct dash_mpd_t* mpd)
|
||||
{
|
||||
size_t i;
|
||||
int64_t t, start;
|
||||
const struct dash_period_t* period;
|
||||
|
||||
if (DASH_DYNAMIC == mpd->type)
|
||||
return -1;
|
||||
|
||||
if (mpd->media_presentation_duration > 0)
|
||||
return mpd->media_presentation_duration;
|
||||
|
||||
t = 0;
|
||||
for (i = 0; i < mpd->period_count; i++)
|
||||
{
|
||||
period = &mpd->periods[i];
|
||||
if (period->start > 0)
|
||||
{
|
||||
// a regular Period or an early terminated Period
|
||||
start = period->start;
|
||||
}
|
||||
else if (i > 0 && mpd->periods[i - 1].duration > 0)
|
||||
{
|
||||
start = t;
|
||||
}
|
||||
else if (0 == i && DASH_STATIC == mpd->type)
|
||||
{
|
||||
start = 0;
|
||||
}
|
||||
else if ((0 == i || mpd->periods[i - 1].duration == 0) && DASH_DYNAMIC == mpd->type)
|
||||
{
|
||||
continue; // Early Available Period
|
||||
}
|
||||
else
|
||||
{
|
||||
start = t;
|
||||
}
|
||||
|
||||
if (period->duration > 0)
|
||||
{
|
||||
t = start + period->duration;
|
||||
}
|
||||
else if (i + 1 < mpd->period_count)
|
||||
{
|
||||
assert(0 != mpd->periods[i + 1].start);
|
||||
t = mpd->periods[i + 1].start;
|
||||
}
|
||||
else if (DASH_DYNAMIC == mpd->type)
|
||||
{
|
||||
// MPD@mediaPresentationDuration shall be present when neither
|
||||
// the attribute MPD@minimumUpdatePeriod nor the Period@duration
|
||||
// of the last Period are present.
|
||||
assert(mpd->media_presentation_duration > 0 || mpd->minimum_update_period > 0);
|
||||
t = mpd->media_presentation_duration > 0 ? mpd->media_presentation_duration : (start + mpd->minimum_update_period);
|
||||
}
|
||||
else
|
||||
{
|
||||
t = start; // ???
|
||||
}
|
||||
}
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
int dash_period_find(const struct dash_mpd_t* mpd, int64_t time)
|
||||
{
|
||||
size_t i;
|
||||
int64_t t, start;
|
||||
const struct dash_period_t* period;
|
||||
|
||||
if (1 == mpd->period_count)
|
||||
return 0; // only one period
|
||||
|
||||
t = 0;
|
||||
for (i = 0; i < mpd->period_count; i++)
|
||||
{
|
||||
// 5.3.2.1 Overview (p27)
|
||||
// 1. If the attribute @start is present in the Period, then the Period
|
||||
// is a regular Period or an early terminated Period and the PeriodStart
|
||||
// is equal to the value of this attribute.
|
||||
// 2. If the @start attribute is absent, but the previous Period element
|
||||
// contains a @duration attributethen this new Period is also a regular
|
||||
// Period or an early terminated Period. The start time of the new Period
|
||||
// PeriodStart is the sum of the start time of the previous Period PeriodStart
|
||||
// and the value of the attribute @duration of the previous Period.
|
||||
// 3. If (i) @start attribute is absent, and (ii) the Period element is the
|
||||
// first in the MPD, and (iii) the MPD@type is 'static', then the PeriodStart
|
||||
// time shall be set to zero
|
||||
// 4. If (i) @start attribute is absent, and (ii) the previous Period element does
|
||||
// not contain a @durationattribute or the Period element is the first in the
|
||||
// MPD, and (iii) the MPD@type is 'dynamic', then thisPeriod is an Early Available
|
||||
// Period (see below for details)
|
||||
// 5. If (i) @duration attribute is present, and (ii) the next Period element contains
|
||||
// a @start attribute orthe @minimumUpdatePeriod is present, then this Period
|
||||
// is an Early Terminated Period (see below for details)
|
||||
|
||||
period = &mpd->periods[i];
|
||||
if (period->start > 0)
|
||||
{
|
||||
// a regular Period or an early terminated Period
|
||||
start = period->start;
|
||||
}
|
||||
else if (i > 0 && mpd->periods[i - 1].duration > 0)
|
||||
{
|
||||
start = t;
|
||||
}
|
||||
else if (0 == i && DASH_STATIC == mpd->type)
|
||||
{
|
||||
start = 0;
|
||||
}
|
||||
else if( (0 == i || mpd->periods[i - 1].duration == 0) && DASH_DYNAMIC == mpd->type)
|
||||
{
|
||||
continue; // Early Available Period
|
||||
}
|
||||
else
|
||||
{
|
||||
start = t;
|
||||
}
|
||||
|
||||
if (period->duration > 0)
|
||||
{
|
||||
t = start + period->duration;
|
||||
}
|
||||
else if (i + 1 < mpd->period_count)
|
||||
{
|
||||
assert(0 != mpd->periods[i + 1].start);
|
||||
t = mpd->periods[i + 1].start;
|
||||
}
|
||||
else if(DASH_DYNAMIC == mpd->type)
|
||||
{
|
||||
// MPD@mediaPresentationDuration shall be present when neither
|
||||
// the attribute MPD@minimumUpdatePeriod nor the Period@duration
|
||||
// of the last Period are present.
|
||||
assert(mpd->media_presentation_duration > 0 || mpd->minimum_update_period > 0);
|
||||
t = mpd->media_presentation_duration > 0 ? mpd->media_presentation_duration : (start + mpd->minimum_update_period);
|
||||
}
|
||||
else
|
||||
{
|
||||
t = start; // ???
|
||||
}
|
||||
|
||||
if (time < t)
|
||||
return (int)i;
|
||||
}
|
||||
|
||||
return -1; // not found
|
||||
}
|
||||
|
||||
const struct dash_adaptation_set_t* dash_period_select(const struct dash_period_t* period, int media, unsigned int id, unsigned int group, const char* lang, const char* codecs)
|
||||
{
|
||||
size_t i;
|
||||
const struct dash_adaptation_set_t* set;
|
||||
|
||||
for (i = 0; i < period->adaptation_set_count; i++)
|
||||
{
|
||||
set = &period->adaptation_sets[i];
|
||||
if (DASH_MEDIA_UNKNOWN != media && media != dash_adaptation_set_media_type(set))
|
||||
continue;
|
||||
|
||||
if (0 != id && id != set->id)
|
||||
continue;
|
||||
|
||||
if (0 != group && group != set->group)
|
||||
continue;
|
||||
|
||||
if (lang && *lang && set->lang && 0 != strcasecmp(set->lang, lang))
|
||||
continue;
|
||||
|
||||
if (codecs && *codecs && set->base.codecs && 0 != strncasecmp(set->base.codecs, codecs, strlen(codecs)))
|
||||
continue;
|
||||
|
||||
return set;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
189
src/3rdpart/media-server/libdash/src/dash-representation.c
Normal file
189
src/3rdpart/media-server/libdash/src/dash-representation.c
Normal file
@ -0,0 +1,189 @@
|
||||
#include "dash-parser.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdint.h>
|
||||
|
||||
const char* dash_segment_initialization(const struct dash_segment_t* segment);
|
||||
int dash_segment_count(const struct dash_segment_t* segment);
|
||||
int dash_segment_find(const struct dash_segment_t* segment, int64_t time);
|
||||
int dash_segment_information(const struct dash_segment_t* segment, int index, int64_t* number, int64_t* start, int64_t* duration, const char** url, const char** range);
|
||||
|
||||
const struct dash_url_t* dash_representation_get_base_url(const struct dash_representation_t* representation)
|
||||
{
|
||||
const struct dash_mpd_t* mpd;
|
||||
const struct dash_period_t* period;
|
||||
const struct dash_adaptation_set_t* set;
|
||||
|
||||
if (representation->base_urls.count > 0)
|
||||
return &representation->base_urls;
|
||||
|
||||
set = representation->parent;
|
||||
if (set->base_urls.count > 0)
|
||||
return &set->base_urls;
|
||||
|
||||
period = set->parent;
|
||||
if (period->base_urls.count > 0)
|
||||
return &period->base_urls;
|
||||
|
||||
mpd = period->parent;
|
||||
return &mpd->urls;
|
||||
}
|
||||
|
||||
const struct dash_segment_t* dash_representation_get_segment(const struct dash_representation_t* representation)
|
||||
{
|
||||
const struct dash_period_t* period;
|
||||
const struct dash_adaptation_set_t* set;
|
||||
|
||||
if (DASH_SEGMENT_NONE != representation->segment.type)
|
||||
return &representation->segment;
|
||||
|
||||
set = representation->parent;
|
||||
if (DASH_SEGMENT_NONE != set->segment.type)
|
||||
return &set->segment;
|
||||
|
||||
period = set->parent;
|
||||
if (DASH_SEGMENT_NONE != period->segment.type)
|
||||
return &period->segment;
|
||||
|
||||
return &representation->segment;
|
||||
}
|
||||
|
||||
/// @return >=0-ok with length, <0-error
|
||||
static int dash_representation_template_replace(const struct dash_representation_t* representation, const char* url, int64_t number, int64_t start, char* ptr, size_t len)
|
||||
{
|
||||
// Each identifier may be suffixed, within the enclosing '$' characters,
|
||||
// with an additional format tag aligned with the printf format tag:
|
||||
// %0[width]d
|
||||
//const char* patterns[] = { "RepresentationID", "Number", "Bandwidth", "Time", "SubNumber" };
|
||||
size_t i, j;
|
||||
int width, off;
|
||||
char format[16];
|
||||
|
||||
for (j = i = 0; i < strlen(url) && j < len; i++)
|
||||
{
|
||||
if ('$' == url[i])
|
||||
{
|
||||
off = 0;
|
||||
width = 1;
|
||||
|
||||
// Identifier matching is case-sensitive.
|
||||
if ('$' == url[i + 1])
|
||||
{
|
||||
// skip
|
||||
ptr[j++] = url[i++];
|
||||
continue;
|
||||
}
|
||||
else if (0 == strncmp("$RepresentationID$", url + i, 18))
|
||||
{
|
||||
j += snprintf(ptr + j, len - j, "%s", representation->id ? representation->id : "");
|
||||
i += 17;
|
||||
}
|
||||
else if (0 == strncmp("$Number", url + i, 7) && ('$' == url[i + 7] || ('%' == url[i + 7] && 1 == sscanf(url + i + 7 + 1, "%dd$%n", &width, &off) && '$' == url[i + 7 + off])))
|
||||
{
|
||||
snprintf(format, sizeof(format), "%%0%d" PRId64, width);
|
||||
j += snprintf(ptr + j, len - j, format, number);
|
||||
i += 7 + off;
|
||||
}
|
||||
else if (0 == strncmp("$Bandwidth", url + i, 10) && ('$' == url[i + 10] || ('%' == url[i + 10] && 1 == sscanf(url + i + 10 + 1, "%dd$%n", &width, &off) && '$' == url[i + 10 + off])))
|
||||
{
|
||||
snprintf(format, sizeof(format), "%%0%du", width);
|
||||
j += snprintf(ptr + j, len - j, format, representation->bandwidth);
|
||||
i += 10 + off;
|
||||
}
|
||||
else if (0 == strncmp("$Time", url + i, 5) && ('$' == url[i + 5] || ('%' == url[i + 5] && 1 == sscanf(url + i + 5 + 1, "%dd$%n", &width, &off) && '$' == url[i + 5 + off])))
|
||||
{
|
||||
snprintf(format, sizeof(format), "%%0%d" PRId64, width);
|
||||
j += snprintf(ptr + j, len - j, format, start);
|
||||
i += 5 + off;
|
||||
}
|
||||
else if (0 == strncmp("$SubNumber", url + i, 10) && ('$' == url[i + 10] || '%' == url[i + 10]))
|
||||
{
|
||||
// TODO:
|
||||
assert(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(0); // ignore
|
||||
ptr[j++] = url[i];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ptr[j++] = url[i];
|
||||
}
|
||||
}
|
||||
|
||||
if (j < len)
|
||||
ptr[j] = '\0';
|
||||
return j < len ? (int)j : -1;
|
||||
}
|
||||
|
||||
int dash_representation_get_initialization(const struct dash_representation_t* representation, char* url, size_t size)
|
||||
{
|
||||
const char* ptr;
|
||||
const struct dash_period_t* period;
|
||||
const struct dash_adaptation_set_t* set;
|
||||
|
||||
ptr = dash_segment_initialization(&representation->segment);
|
||||
if (!ptr && representation->parent)
|
||||
{
|
||||
set = representation->parent;
|
||||
ptr = dash_segment_initialization(&set->segment);
|
||||
if (!ptr && set->parent)
|
||||
{
|
||||
period = set->parent;
|
||||
ptr = dash_segment_initialization(&period->segment);
|
||||
if (!ptr)
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return dash_representation_template_replace(representation, ptr, 0, 0, url, size);
|
||||
}
|
||||
|
||||
int dash_representation_segment_url(const struct dash_representation_t* representation, int index, int64_t* number, int64_t* start, int64_t* duration, const char** range, char* url, size_t size)
|
||||
{
|
||||
int r;
|
||||
const struct dash_segment_t* segment;
|
||||
const char* url0;
|
||||
|
||||
segment = dash_representation_get_segment(representation);
|
||||
assert(index >= 0 && index < dash_segment_count(segment));
|
||||
r = dash_segment_information(segment, index, number, start, duration, &url0, range);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return dash_representation_template_replace(representation, url0, *number, *start, url, size);
|
||||
}
|
||||
|
||||
int dash_representation_find_segment(const struct dash_representation_t* representation, int64_t time)
|
||||
{
|
||||
const struct dash_segment_t* segment;
|
||||
segment = dash_representation_get_segment(representation);
|
||||
return dash_segment_find(segment, time);
|
||||
}
|
||||
|
||||
int dash_representation_segment_count(const struct dash_representation_t* representation)
|
||||
{
|
||||
const struct dash_segment_t* segment;
|
||||
segment = dash_representation_get_segment(representation);
|
||||
return dash_segment_count(segment);
|
||||
}
|
||||
|
||||
#if defined(_DEBUG) || defined(DEBUG)
|
||||
void dash_representation_test(void)
|
||||
{
|
||||
char ptr[128];
|
||||
struct dash_representation_t r;
|
||||
memset(&r, 0, sizeof(r));
|
||||
r.id = "0";
|
||||
r.bandwidth = 19200;
|
||||
assert(23 == dash_representation_template_replace(&r, "dash-$$$$$RepresentationID$$Bandwidth$$Number$$Time$-", 1, 19700101, ptr, sizeof(ptr)));
|
||||
assert(0 == strcmp(ptr, "dash-$$019200119700101-"));
|
||||
assert(22 == dash_representation_template_replace(&r, "dash-$Bandwidth%03d$$Number%03d$$Time%03d$-", 1, 19700101, ptr, sizeof(ptr)));
|
||||
assert(0 == strcmp(ptr, "dash-1920000119700101-"));
|
||||
}
|
||||
#endif
|
210
src/3rdpart/media-server/libdash/src/dash-segment.c
Normal file
210
src/3rdpart/media-server/libdash/src/dash-segment.c
Normal file
@ -0,0 +1,210 @@
|
||||
#include "dash-parser.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <limits.h>
|
||||
|
||||
int dash_segment_count(const struct dash_segment_t* segment)
|
||||
{
|
||||
int n;
|
||||
size_t i;
|
||||
|
||||
switch (segment->type)
|
||||
{
|
||||
case DASH_SEGMENT_BASE:
|
||||
return 1;
|
||||
|
||||
case DASH_SEGMENT_LIST:
|
||||
return (int)segment->segment_url_count;
|
||||
|
||||
case DASH_SEGMENT_TEMPLATE:
|
||||
if (segment->segment_timeline.count < 1)
|
||||
return INT_MAX; // dynamic + infinite
|
||||
|
||||
// static + timeline
|
||||
for (i = n = 0; i < segment->segment_timeline.count; i++)
|
||||
n += 1 + segment->segment_timeline.S[i].r;
|
||||
return n;
|
||||
|
||||
default:
|
||||
return 0; // none
|
||||
}
|
||||
}
|
||||
|
||||
const char* dash_segment_initialization(const struct dash_segment_t* segment)
|
||||
{
|
||||
if (segment->initialization.source_url && *segment->initialization.source_url)
|
||||
return segment->initialization.source_url;
|
||||
|
||||
if (DASH_SEGMENT_TEMPLATE == segment->type && segment->initialization_url && *segment->initialization_url)
|
||||
return segment->initialization_url;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/// @return 0-ok, <0-error
|
||||
static int dash_segment_timeline(const struct dash_segment_timeline_t* timeline, size_t index, int64_t* number, int64_t* start, int64_t* duration)
|
||||
{
|
||||
int64_t t;
|
||||
size_t i, j, step;
|
||||
|
||||
t = 0;
|
||||
for (j = i = 0; i < timeline->count; i++)
|
||||
{
|
||||
// 5.3.9.6 Segment timeline
|
||||
// The @r attribute has a default value of zero when not present.
|
||||
// The value of the @r attribute of the S element may be set to a
|
||||
// negative value indicating that the duration indicated in @d is
|
||||
// promised to repeat until the S@t of the next S element or if it
|
||||
// is the last S element in the SegmentTimeline element until the
|
||||
// end of the Period or the next update of the MPD
|
||||
|
||||
assert(timeline->S[i].d > 0);
|
||||
if (timeline->S[i].r >= 0)
|
||||
{
|
||||
step = timeline->S[i].r + 1;
|
||||
}
|
||||
else if (i + 1 == timeline->count)
|
||||
{
|
||||
// last
|
||||
step = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(timeline->S[i].t > 0);
|
||||
step = (size_t)((timeline->S[i + 1].t - t) / (timeline->S[i].d > 0 ? timeline->S[i].d : 1));
|
||||
}
|
||||
|
||||
if (0 == step || index < j + step)
|
||||
{
|
||||
*number = timeline->S[i].n + (index - j);
|
||||
*start = (timeline->S[i].t ? timeline->S[i].t : t) + (index - j) * timeline->S[i].d;
|
||||
*duration = timeline->S[i].d;
|
||||
return 0;
|
||||
}
|
||||
|
||||
j += step;
|
||||
t = (timeline->S[i].t ? timeline->S[i].t : t) + step * timeline->S[i].d;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/// @param[out] number start number of representation
|
||||
/// @param[out] start start time of representation(MUST add period.start)
|
||||
/// @param[out] duration segment duration, 0 if unknown
|
||||
/// @param[out] url segment url(MUST resolve with representation base url)
|
||||
/// @param[out] range url range, NULL if don't have range
|
||||
/// @return 0-ok, <0-error, >0-undefined
|
||||
int dash_segment_information(const struct dash_segment_t* segment, int index, int64_t* number, int64_t* start, int64_t* duration, const char** url, const char** range)
|
||||
{
|
||||
int r;
|
||||
int64_t timescale;
|
||||
static const char* sc_empty = "";
|
||||
|
||||
// 5.3.9.2 Segment base information
|
||||
// 1. If the Representation contains more than one Media Segment, then either
|
||||
// the attribute @duration or the element SegmentTimeline shall be present.
|
||||
// 2. The attribute @duration and the element SegmentTimeline shall not be present at the same time.
|
||||
|
||||
// 5.3.9.5.3 Media Segment information
|
||||
// 1. a valid Media Segment URL and possibly a byte range,
|
||||
// 2. the number and position of the Media Segment in the Representation,
|
||||
// 3. the MPD start time of the Media Segment in the Representation providing an approximate presentation start time of the Segment in the Period,
|
||||
// 4. the MPD duration of the Media Segment providing an approximate presentation duration of the Segment.
|
||||
//
|
||||
// SegmentTemplate
|
||||
// 1. If the Representation contains or inherits a SegmentTemplate element with $Number$
|
||||
// then the URL of the Media Segment at position k in the Representation is determined
|
||||
// by replacing the $Number$ identifier by (k-1) + (k.start-1) with kstart the value of
|
||||
// the @startNumber attribute, if present, or 1 otherwise.
|
||||
// 2. If the Representation contains or inherits a SegmentTemplate element with $Time$ then
|
||||
// the URL of the media segment at position k is determined by replacing the $Time$
|
||||
// identifier by MPD start time of this segment, as described below.
|
||||
//
|
||||
// SegmentList
|
||||
// The number of the first Segment in the list within this Period is determined by the value
|
||||
// of the SegmentList@startNumber attribute, if present, or it is 1 in case this attribute
|
||||
// is not present.The sequence of multiple SegmentList elements within a Representation shall
|
||||
// result in Media Segment List with consecutive numbers.
|
||||
|
||||
r = 0;
|
||||
|
||||
if (DASH_SEGMENT_BASE == segment->type)
|
||||
{
|
||||
if (0 != index)
|
||||
return -1; // segment base only have one segment
|
||||
|
||||
*number = 0;
|
||||
*start = 0 - segment->presentation_time_offset;
|
||||
*duration = segment->presentation_duration;
|
||||
*url = sc_empty;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (index < 0 || (DASH_SEGMENT_LIST == segment->type && index >= (int)segment->segment_url_count))
|
||||
return -1;
|
||||
|
||||
if (segment->segment_timeline.count > 0)
|
||||
{
|
||||
r = dash_segment_timeline(&segment->segment_timeline, index, number, start, duration);
|
||||
if (0 != r)
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
*number = (segment->start_number > 0 ? (segment->start_number - 1) : 0) + index;
|
||||
*start = (int64_t)index * segment->duration - segment->presentation_time_offset;
|
||||
*duration = segment->duration;
|
||||
}
|
||||
|
||||
if (DASH_SEGMENT_LIST == segment->type)
|
||||
{
|
||||
*url = segment->segment_urls[index].media;
|
||||
*range = segment->segment_urls[index].media_range;
|
||||
}
|
||||
else if (DASH_SEGMENT_TEMPLATE == segment->type)
|
||||
{
|
||||
*url = segment->media;
|
||||
*range = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(0);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
timescale = segment->timescale > 0 ? segment->timescale : 1;
|
||||
*start = *start / timescale;
|
||||
*duration = *duration / timescale;
|
||||
return r;
|
||||
}
|
||||
|
||||
int dash_segment_find(const struct dash_segment_t* segment, int64_t time)
|
||||
{
|
||||
int r, n, i, mid;
|
||||
int64_t number, t, d;
|
||||
const char* url, * range;
|
||||
|
||||
n = dash_segment_count(segment);
|
||||
i = 0;
|
||||
mid = -1;
|
||||
|
||||
while (i < n)
|
||||
{
|
||||
mid = (i + n) / 2;
|
||||
r = dash_segment_information(segment, mid, &number, &t, &d, &url, &range);
|
||||
if (0 != r)
|
||||
return r;
|
||||
|
||||
if (time < t)
|
||||
n = mid;
|
||||
else if (time > t + d)
|
||||
i = mid + 1;
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
return mid;
|
||||
}
|
61
src/3rdpart/media-server/libdash/src/list.h
Normal file
61
src/3rdpart/media-server/libdash/src/list.h
Normal file
@ -0,0 +1,61 @@
|
||||
#ifndef _list_h_
|
||||
#define _list_h_
|
||||
|
||||
struct list_head
|
||||
{
|
||||
struct list_head *next, *prev;
|
||||
};
|
||||
|
||||
static inline void list_insert_after(struct list_head *item, struct list_head *head)
|
||||
{
|
||||
struct list_head *prev, *next;
|
||||
prev = head;
|
||||
next = head->next;
|
||||
|
||||
item->prev = prev;
|
||||
item->next = next;
|
||||
next->prev = item;
|
||||
prev->next = item;
|
||||
}
|
||||
|
||||
static inline void list_insert_before(struct list_head *item, struct list_head *head)
|
||||
{
|
||||
struct list_head *prev, *next;
|
||||
prev = head->prev;
|
||||
next = head;
|
||||
|
||||
item->prev = prev;
|
||||
item->next = next;
|
||||
next->prev = item;
|
||||
prev->next = item;
|
||||
}
|
||||
|
||||
static inline void list_remove(struct list_head *item)
|
||||
{
|
||||
struct list_head *prev, *next;
|
||||
prev = item->prev;
|
||||
next = item->next;
|
||||
|
||||
prev->next = next;
|
||||
next->prev = prev;
|
||||
|
||||
item->prev = item->next = 0;
|
||||
}
|
||||
|
||||
static inline int list_empty(const struct list_head *head)
|
||||
{
|
||||
return head->next == head;
|
||||
}
|
||||
|
||||
#define LIST_INIT_HEAD(list) do { (list)->next = (list)->prev = (list); } while (0)
|
||||
|
||||
#define list_entry(ptr, type, member) \
|
||||
((type*)((char*)ptr-(ptrdiff_t)(&((type*)0)->member)))
|
||||
|
||||
#define list_for_each(pos, head) \
|
||||
for(pos = (head)->next; pos != (head); pos = pos->next)
|
||||
|
||||
#define list_for_each_safe(pos, n, head) \
|
||||
for(pos = (head)->next, n = pos->next; pos != (head); pos = n, n=pos->next)
|
||||
|
||||
#endif /* !_list_h_ */
|
160
src/3rdpart/media-server/libdash/src/xs-duration.c
Normal file
160
src/3rdpart/media-server/libdash/src/xs-duration.c
Normal file
@ -0,0 +1,160 @@
|
||||
#include "xs-datatype.h"
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
|
||||
// https://en.wikipedia.org/wiki/ISO_8601
|
||||
// Durations:
|
||||
// 1. P[n]Y[n]M[n]DT[n]H[n]M[n]S
|
||||
// 2. P[n]W
|
||||
// 3. P<date>T<time>
|
||||
// 4. PYYYYMMDDThhmmss
|
||||
// 5. P[YYYY]-[MM]-[DD]T[hh]:[mm]:[ss]
|
||||
// For example, "P3Y6M4DT12H30M5S" represents a duration of "three years, six months, four days, twelve hours, thirty minutes, and five seconds".
|
||||
// "P23DT23H" and "P4Y" "P0.5Y" == "P0,5Y"
|
||||
// "PT0S" or "P0D"
|
||||
// "P0003-06-04T12:30:05"
|
||||
|
||||
/// @param[in] duration millisecond duration
|
||||
/// @param[out] data ISO8601 duration: P[n]Y[n]M[n]DT[n]H[n]M[n]S
|
||||
int xs_duration_write(int64_t duration, char* data, int size)
|
||||
{
|
||||
int n = 1;
|
||||
data[0] = 'P';
|
||||
if (duration > 24 * 3600 * 1000)
|
||||
{
|
||||
n += snprintf(data + n, size - n, "%dD", (int)(duration / (24 * 3600 * 1000)));
|
||||
duration %= 24 * 3600 * 1000;
|
||||
}
|
||||
|
||||
data[n++] = 'T';
|
||||
if (duration > 3600 * 1000)
|
||||
{
|
||||
n += snprintf(data + n, size - n, "%dH", (int)(duration / (3600 * 1000)));
|
||||
duration %= 3600 * 1000;
|
||||
|
||||
n += snprintf(data + n, size - n, "%dM", (int)(duration / (60 * 1000)));
|
||||
duration %= 60 * 1000;
|
||||
}
|
||||
|
||||
n += snprintf(data + n, size - n, "%dS", (int)((duration + 999) / 1000));
|
||||
duration %= 1000;
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
int xs_duration_read(int64_t* duration, const char* data, int size)
|
||||
{
|
||||
int n;
|
||||
int flags;
|
||||
unsigned int v1[6];
|
||||
float v2[6];
|
||||
const char* ptr;
|
||||
const char* end;
|
||||
|
||||
if (!data || size < 2)
|
||||
return -1;
|
||||
|
||||
ptr = data;
|
||||
end = data + size;
|
||||
|
||||
n = 0;
|
||||
v1[0] = v1[1] = v1[2] = v1[3] = v1[4] = v1[5] = 0;
|
||||
v2[0] = v2[1] = v2[2] = v2[3] = v2[4] = v2[5] = 0.0;
|
||||
|
||||
flags = 1;
|
||||
if ('-' == ptr[0])
|
||||
{
|
||||
flags = -1;
|
||||
ptr++;
|
||||
}
|
||||
|
||||
if ('P' != ptr[0])
|
||||
return -1;
|
||||
ptr++;
|
||||
|
||||
// P20200529T164700
|
||||
if (6 == sscanf(ptr, "%4u%2u%2uT%2u%2u%2u", &v1[0], &v1[1], &v1[2], &v1[3], &v1[4], &v1[5]))
|
||||
{
|
||||
*duration = v1[0];
|
||||
*duration = *duration * 12 /* month */ + v1[1];
|
||||
*duration = *duration * 30 /* day */ + v1[2];
|
||||
*duration = *duration * 24 /* hour */ + v1[3];
|
||||
*duration = *duration * 60 /* minute */ + v1[4];
|
||||
*duration = *duration * 60 /* second */ + v1[5];
|
||||
*duration = *duration * 1000 /* millisecond */;
|
||||
}
|
||||
// P2020-05-29T16:47:00
|
||||
else if (6 == sscanf(ptr, "%u-%u-%uT%u:%u:%u", &v1[0], &v1[1], &v1[2], &v1[3], &v1[4], &v1[5]))
|
||||
{
|
||||
*duration = v1[0];
|
||||
*duration = *duration * 12 /* month */ + v1[1];
|
||||
*duration = *duration * 30 /* day */ + v1[2];
|
||||
*duration = *duration * 24 /* hour */ + v1[3];
|
||||
*duration = *duration * 60 /* minute */ + v1[4];
|
||||
*duration = *duration * 60 /* second */ + v1[5];
|
||||
*duration = *duration * 1000 /* millisecond */;
|
||||
}
|
||||
// P[n]W
|
||||
else if (1 == sscanf(ptr, "%fW%n", &v2[0], &n) && n > 0)
|
||||
{
|
||||
*duration = (int64_t)(v2[0] * 7.0 * 24 * 60 * 60 * 1000);
|
||||
}
|
||||
else
|
||||
{
|
||||
*duration = 0;
|
||||
if (1 == sscanf(ptr, "%fY%n", &v2[0], &n) && n > 0)
|
||||
{
|
||||
*duration += (int64_t)(v2[0] * 12.0 * 30 * 24 * 60 * 60 * 1000);
|
||||
ptr += n;
|
||||
}
|
||||
if (1 == sscanf(ptr, "%fM%n", &v2[1], &n) && n > 0)
|
||||
{
|
||||
*duration += (int64_t)(v2[1] * 30.0 * 24 * 60 * 60 * 1000);
|
||||
ptr += n;
|
||||
}
|
||||
if (1 == sscanf(ptr, "%fD%n", &v2[2], &n) && n > 0)
|
||||
{
|
||||
*duration += (int64_t)(v2[2] * 24.0 * 60 * 60 * 1000);
|
||||
ptr += n;
|
||||
}
|
||||
|
||||
if ('T' == ptr[0])
|
||||
{
|
||||
ptr++;
|
||||
if (1 == sscanf(ptr, "%fH%n", &v2[3], &n) && n > 0)
|
||||
{
|
||||
*duration += (int64_t)(v2[3] * 60.0 * 60 * 1000);
|
||||
ptr += n;
|
||||
}
|
||||
if (1 == sscanf(ptr, "%fM%n", &v2[4], &n) && n > 0)
|
||||
{
|
||||
*duration += (int64_t)(v2[4] * 60.0 * 1000);
|
||||
ptr += n;
|
||||
}
|
||||
if (1 == sscanf(ptr, "%fS%n", &v2[5], &n) && n > 0)
|
||||
{
|
||||
*duration += (int64_t)(v2[5] * 1000.0);
|
||||
ptr += n;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*duration *= flags;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(_DEBUG) || defined(DEBUG)
|
||||
void xs_datatype_test(void)
|
||||
{
|
||||
int64_t duration;
|
||||
assert(0 == xs_duration_read(&duration, "P3Y6M4DT12H30M5S", 16) && duration == (((((3LL * 12 + 6) * 30 + 4) * 24 + 12) * 60 + 30) * 60 + 5) * 1000);
|
||||
assert(0 == xs_duration_read(&duration, "PT12H30M5S", 10) && duration == ((12LL *60+30)*60+5)*1000);
|
||||
assert(0 == xs_duration_read(&duration, "P0.5Y", 5) && duration == (((((0.5 * 12LL + 0) * 30 + 0) * 24 + 0) * 60 + 0) * 60 + 0) * 1000);
|
||||
assert(0 == xs_duration_read(&duration, "P1W", 3) && duration == ((((1 * 7) * 24 + 0) * 60 + 0) * 60 + 0) * 1000);
|
||||
assert(0 == xs_duration_read(&duration, "PT1.2S", 6) && duration == 1200);
|
||||
assert(0 == xs_duration_read(&duration, "P00030604T123005", 16) && duration == (((((3LL * 12 + 6) * 30 + 4) * 24 + 12) * 60 + 30) * 60 + 5) * 1000);
|
||||
assert(0 == xs_duration_read(&duration, "P0003-06-04T12:30:05", 20) && duration == (((((3LL * 12 + 6) * 30 + 4) * 24 + 12) * 60 + 30) * 60 + 5) * 1000);
|
||||
assert(0 == xs_duration_read(&duration, "-PT30M5S", 8) && duration == -(30LL * 60 + 5) * 1000);
|
||||
}
|
||||
#endif
|
237
src/3rdpart/media-server/libdash/test/dash-dynamic-test.cpp
Normal file
237
src/3rdpart/media-server/libdash/test/dash-dynamic-test.cpp
Normal file
@ -0,0 +1,237 @@
|
||||
#include "aio-worker.h"
|
||||
#include "dash-mpd.h"
|
||||
#include "dash-proto.h"
|
||||
#include "flv-proto.h"
|
||||
#include "flv-reader.h"
|
||||
#include "flv-parser.h"
|
||||
#include "mov-format.h"
|
||||
#include "http-server.h"
|
||||
#include "http-route.h"
|
||||
#include "mpeg4-aac.h"
|
||||
#include "mpeg4-avc.h"
|
||||
#include "mpeg4-hevc.h"
|
||||
#include "cstringext.h"
|
||||
#include "sys/sync.hpp"
|
||||
#include "sys/thread.h"
|
||||
#include "sys/system.h"
|
||||
#include "sys/path.h"
|
||||
#include "cpm/shared_ptr.h"
|
||||
#include "app-log.h"
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <list>
|
||||
#include <map>
|
||||
|
||||
#define LOCALPATH "./"
|
||||
|
||||
struct dash_playlist_t
|
||||
{
|
||||
std::string name;
|
||||
dash_mpd_t* mpd;
|
||||
|
||||
int width;
|
||||
int height;
|
||||
int64_t timestamp;
|
||||
int adapation_video;
|
||||
int adapation_audio;
|
||||
char playlist[256 * 1024];
|
||||
uint8_t packet[2 * 1024 * 1024];
|
||||
|
||||
std::list<std::string> files;
|
||||
};
|
||||
|
||||
static ThreadLocker s_locker;
|
||||
|
||||
extern "C" const struct mov_buffer_t* mov_file_buffer(void);
|
||||
|
||||
static int dash_mpd_onsegment(void* param, int /*track*/, const void* data, size_t bytes, int64_t /*pts*/, int64_t /*dts*/, int64_t /*duration*/, const char* name)
|
||||
{
|
||||
app_log(LOG_DEBUG, "dash_mpd_onsegment %s\n", name);
|
||||
FILE* fp = fopen(name, "wb");
|
||||
if(fp)
|
||||
{
|
||||
fwrite(data, 1, bytes, fp);
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
dash_playlist_t* dash = (dash_playlist_t*)param;
|
||||
if(!strendswith(name, "-init.m4v") && !strendswith(name, "-init.m4a"))
|
||||
dash->files.push_back(name);
|
||||
while (dash->files.size() > 20)
|
||||
{
|
||||
app_log(LOG_DEBUG, "Delete %s\n", dash->files.front().c_str());
|
||||
path_rmfile(dash->files.front().c_str());
|
||||
dash->files.pop_front();
|
||||
}
|
||||
|
||||
AutoThreadLocker locker(s_locker);
|
||||
dash_mpd_playlist(dash->mpd, dash->playlist, sizeof(dash->playlist));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dash_live_onflv(void* param, int codec, const void* data, size_t bytes, uint32_t pts, uint32_t dts, int flags)
|
||||
{
|
||||
struct mpeg4_aac_t aac;
|
||||
struct mpeg4_avc_t avc;
|
||||
struct mpeg4_hevc_t hevc;
|
||||
dash_playlist_t* dash = (dash_playlist_t*)param;
|
||||
|
||||
switch (codec)
|
||||
{
|
||||
case FLV_VIDEO_AVCC:
|
||||
if (-1 == dash->adapation_video && mpeg4_avc_decoder_configuration_record_load((const uint8_t*)data, bytes, &avc) > 0)
|
||||
dash->adapation_video = dash_mpd_add_video_adaptation_set(dash->mpd, dash->name.c_str(), MOV_OBJECT_H264, dash->width, dash->height, data, bytes);
|
||||
break;
|
||||
|
||||
case FLV_VIDEO_HVCC:
|
||||
if (-1 == dash->adapation_video && mpeg4_hevc_decoder_configuration_record_load((const uint8_t*)data, bytes, &hevc) > 0)
|
||||
dash->adapation_video = dash_mpd_add_video_adaptation_set(dash->mpd, dash->name.c_str(), MOV_OBJECT_HEVC, dash->width, dash->height, data, bytes);
|
||||
break;
|
||||
|
||||
case FLV_AUDIO_ASC:
|
||||
if (-1 == dash->adapation_audio && mpeg4_aac_audio_specific_config_load((const uint8_t*)data, bytes, &aac) > 0)
|
||||
{
|
||||
int rate = mpeg4_aac_audio_frequency_to((enum mpeg4_aac_frequency)aac.sampling_frequency_index);
|
||||
dash->adapation_audio = dash_mpd_add_audio_adaptation_set(dash->mpd, dash->name.c_str(), MOV_OBJECT_AAC, aac.channel_configuration, 32, rate, data, bytes);
|
||||
}
|
||||
break;
|
||||
|
||||
case FLV_AUDIO_AAC:
|
||||
return dash_mpd_input(dash->mpd, dash->adapation_audio, data, bytes, pts, dts, 0);
|
||||
|
||||
case FLV_VIDEO_H264:
|
||||
return dash_mpd_input(dash->mpd, dash->adapation_video, data, bytes, pts, dts, flags ? MOV_AV_FLAG_KEYFREAME : 0);
|
||||
|
||||
case FLV_VIDEO_H265:
|
||||
return dash_mpd_input(dash->mpd, dash->adapation_video, data, bytes, pts, dts, flags ? MOV_AV_FLAG_KEYFREAME : 0);
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dash_live_worker(const char* file, dash_playlist_t* dash)
|
||||
{
|
||||
int r, type;
|
||||
int avcrecord = 0;
|
||||
int aacconfig = 0;
|
||||
size_t taglen;
|
||||
uint32_t timestamp;
|
||||
uint32_t s_timestamp = 0;
|
||||
uint32_t diff = 0;
|
||||
uint64_t clock;
|
||||
|
||||
while (1)
|
||||
{
|
||||
void* f = flv_reader_create(file);
|
||||
|
||||
clock = system_clock(); // timestamp start from 0
|
||||
while (1 == flv_reader_read(f, &type, ×tamp, &taglen, dash->packet, sizeof(dash->packet)))
|
||||
{
|
||||
uint64_t t = system_clock();
|
||||
if (clock + timestamp > t && clock + timestamp < t + 3 * 1000)
|
||||
system_sleep(clock + timestamp - t);
|
||||
else if (clock + timestamp > t + 3 * 1000)
|
||||
clock = t - timestamp;
|
||||
|
||||
timestamp += diff;
|
||||
s_timestamp = timestamp > s_timestamp ? timestamp : s_timestamp;
|
||||
r = flv_parser_input(type, dash->packet, taglen, timestamp, dash_live_onflv, dash);
|
||||
if (0 != r)
|
||||
{
|
||||
assert(0);
|
||||
break; // TODO: handle send failed
|
||||
}
|
||||
}
|
||||
|
||||
flv_reader_destroy(f);
|
||||
|
||||
diff = s_timestamp + 30;
|
||||
}
|
||||
}
|
||||
|
||||
static int dash_server_mpd(http_session_t* session, dash_playlist_t* dash)
|
||||
{
|
||||
http_server_set_header(session, "Content-Type", "application/xml+dash");
|
||||
http_server_set_header(session, "Access-Control-Allow-Origin", "*");
|
||||
http_server_set_header(session, "Access-Control-Allow-Methods", "GET, POST, PUT");
|
||||
AutoThreadLocker locker(s_locker);
|
||||
http_server_reply(session, 200, dash->playlist, strlen(dash->playlist));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dash_server_onlive(void* dash, http_session_t* session, const char* /*method*/, const char* path)
|
||||
{
|
||||
char fullpath[1024];
|
||||
int r = path_concat(path + 6 /* /live/ */, LOCALPATH, fullpath);
|
||||
printf("live: %s\n", fullpath);
|
||||
|
||||
const char* name = path_basename(fullpath);
|
||||
if (strendswith(name, ".mpd"))
|
||||
{
|
||||
return dash_server_mpd(session, (dash_playlist_t*)dash);
|
||||
}
|
||||
else if (path_testfile(name))
|
||||
{
|
||||
// cross domain
|
||||
http_server_set_header(session, "Access-Control-Allow-Origin", "*");
|
||||
http_server_set_header(session, "Access-Control-Allow-Methods", "GET, POST, PUT");
|
||||
return http_server_sendfile(session, name, NULL, NULL);
|
||||
}
|
||||
|
||||
return http_server_send(session, 404, "", 0, NULL, NULL);
|
||||
}
|
||||
|
||||
static int dash_server_onvod(void* /*dash*/, http_session_t* session, const char* /*method*/, const char* path)
|
||||
{
|
||||
char fullpath[1024];
|
||||
int r = path_concat(path + 5 /* /vod/ */, LOCALPATH, fullpath);
|
||||
printf("vod: %s\n", fullpath);
|
||||
|
||||
if (0 == r && path_testfile(fullpath))
|
||||
{
|
||||
// MIME
|
||||
if (strendswith(fullpath, ".mpd"))
|
||||
http_server_set_content_type(session, "application/xml+dash");
|
||||
else if (strendswith(fullpath, ".mp4") || strendswith(fullpath, ".m4v"))
|
||||
http_server_set_header(session, "content-type", "video/mp4");
|
||||
else if (strendswith(fullpath, ".m4a"))
|
||||
http_server_set_header(session, "content-type", "audio/mp4");
|
||||
|
||||
//http_server_set_header(session, "Transfer-Encoding", "chunked");
|
||||
|
||||
// cross domain
|
||||
http_server_set_header(session, "Access-Control-Allow-Origin", "*");
|
||||
http_server_set_header(session, "Access-Control-Allow-Methods", "GET, POST, PUT");
|
||||
|
||||
return http_server_sendfile(session, fullpath, NULL, NULL);
|
||||
}
|
||||
|
||||
return http_server_send(session, 404, "", 0, NULL, NULL);
|
||||
}
|
||||
|
||||
void dash_dynamic_test(const char* ip, int port, const char* file, int width, int height)
|
||||
{
|
||||
std::shared_ptr<dash_playlist_t> live(new dash_playlist_t());
|
||||
live->mpd = dash_mpd_create(DASH_DYNAMIC, dash_mpd_onsegment, live.get());
|
||||
live->name = "live";
|
||||
live->width = width;
|
||||
live->height = height;
|
||||
live->adapation_audio = live->adapation_video = -1;
|
||||
|
||||
aio_worker_init(4);
|
||||
http_server_t* http = http_server_create(ip, port);
|
||||
http_server_set_handler(http, http_server_route, live.get());
|
||||
http_server_addroute("/live/", dash_server_onlive);
|
||||
http_server_addroute("/vod/", dash_server_onvod);
|
||||
|
||||
// live worker
|
||||
dash_live_worker(file, live.get());
|
||||
|
||||
http_server_destroy(http);
|
||||
aio_worker_clean(4);
|
||||
|
||||
dash_mpd_destroy(live->mpd);
|
||||
}
|
85
src/3rdpart/media-server/libdash/test/dash-static-test.cpp
Normal file
85
src/3rdpart/media-server/libdash/test/dash-static-test.cpp
Normal file
@ -0,0 +1,85 @@
|
||||
#include "dash-mpd.h"
|
||||
#include "dash-proto.h"
|
||||
#include "mov-format.h"
|
||||
#include "mov-reader.h"
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
extern "C" const struct mov_buffer_t* mov_file_buffer(void);
|
||||
|
||||
static char s_packet[2 * 1024 * 1024];
|
||||
static uint32_t s_track_video;
|
||||
static uint32_t s_track_audio;
|
||||
static int s_adapation_video;
|
||||
static int s_adapation_audio;
|
||||
|
||||
static void mp4_onvideo(void* mpd, uint32_t track, uint8_t object, int width, int height, const void* extra, size_t bytes)
|
||||
{
|
||||
s_track_video = track;
|
||||
s_adapation_video = dash_mpd_add_video_adaptation_set((dash_mpd_t*)mpd, "dash-static-video", object, width, height, extra, bytes);
|
||||
}
|
||||
|
||||
static void mp4_onaudio(void* mpd, uint32_t track, uint8_t object, int channel_count, int bit_per_sample, int sample_rate, const void* extra, size_t bytes)
|
||||
{
|
||||
s_track_audio = track;
|
||||
s_adapation_audio = dash_mpd_add_audio_adaptation_set((dash_mpd_t*)mpd, "dash-static-audio", object, channel_count, bit_per_sample, sample_rate, extra, bytes);
|
||||
}
|
||||
|
||||
static void mp4_onread(void* mpd, uint32_t track, const void* buffer, size_t bytes, int64_t pts, int64_t dts, int flags)
|
||||
{
|
||||
if (s_track_video == track)
|
||||
{
|
||||
bool keyframe = 5 == (0x1f & ((uint8_t*)buffer)[4]);
|
||||
dash_mpd_input((dash_mpd_t*)mpd, s_adapation_video, buffer, bytes, pts, dts, keyframe ? MOV_AV_FLAG_KEYFREAME : 0);
|
||||
}
|
||||
else if (s_track_audio == track)
|
||||
{
|
||||
dash_mpd_input((dash_mpd_t*)mpd, s_adapation_audio, buffer, bytes, pts, dts, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
static int dash_mpd_onsegment(void* /*param*/, int /*track*/, const void* data, size_t bytes, int64_t /*pts*/, int64_t /*dts*/, int64_t /*duration*/, const char* name)
|
||||
{
|
||||
FILE* fp = fopen(name, "wb");
|
||||
fwrite(data, 1, bytes, fp);
|
||||
fclose(fp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dash_save_playlist(const char* name, const char* playlist)
|
||||
{
|
||||
char filename[256];
|
||||
snprintf(filename, sizeof(filename), "%s.mpd", name);
|
||||
FILE* fp = fopen(filename, "wb");
|
||||
fwrite(playlist, 1, strlen(playlist), fp);
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
void dash_static_test(const char* mp4, const char* name)
|
||||
{
|
||||
FILE* fp = fopen(mp4, "rb");
|
||||
mov_reader_t* mov = mov_reader_create(mov_file_buffer(), fp);
|
||||
dash_mpd_t* mpd = dash_mpd_create(DASH_STATIC, dash_mpd_onsegment, NULL);
|
||||
|
||||
struct mov_reader_trackinfo_t info = { mp4_onvideo, mp4_onaudio };
|
||||
mov_reader_getinfo(mov, &info, mpd);
|
||||
int r = mov_reader_read(mov, s_packet, sizeof(s_packet), mp4_onread, mpd);
|
||||
while (1 == r)
|
||||
{
|
||||
r = mov_reader_read(mov, s_packet, sizeof(s_packet), mp4_onread, mpd);
|
||||
}
|
||||
|
||||
//flush
|
||||
dash_mpd_input(mpd, s_adapation_video, NULL, 0, 0, 0, 0);
|
||||
dash_mpd_playlist(mpd, s_packet, sizeof(s_packet));
|
||||
dash_save_playlist(name, s_packet);
|
||||
|
||||
dash_mpd_destroy(mpd);
|
||||
mov_reader_destroy(mov);
|
||||
fclose(fp);
|
||||
}
|
14
src/3rdpart/media-server/libflv/Android.mk
Normal file
14
src/3rdpart/media-server/libflv/Android.mk
Normal file
@ -0,0 +1,14 @@
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_CFLAGS += -DOS_LINUX -DOS_ANDROID
|
||||
LOCAL_LDLIBS +=
|
||||
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)
|
||||
LOCAL_C_INCLUDES += $(LOCAL_PATH)/include
|
||||
|
||||
LOCAL_SRC_FILES := $(wildcard source/*.c)
|
||||
LOCAL_SRC_FILES += $(wildcard source/*.cpp)
|
||||
|
||||
LOCAL_MODULE := flv
|
||||
include $(BUILD_STATIC_LIBRARY)
|
44
src/3rdpart/media-server/libflv/Makefile
Normal file
44
src/3rdpart/media-server/libflv/Makefile
Normal file
@ -0,0 +1,44 @@
|
||||
#--------------------------------Output------------------------------
|
||||
# OUTTYPE: 0-exe, 1-dll, 2-static
|
||||
#--------------------------------------------------------------------
|
||||
OUTTYPE = 2
|
||||
OUTFILE = libflv.a
|
||||
|
||||
#-------------------------------Include------------------------------
|
||||
#
|
||||
# INCLUDES = $(addprefix -I,$(INCLUDES)) # add -I prefix
|
||||
#--------------------------------------------------------------------
|
||||
INCLUDES = . ./include
|
||||
|
||||
#-------------------------------Source-------------------------------
|
||||
#
|
||||
#--------------------------------------------------------------------
|
||||
SOURCE_PATHS = source
|
||||
SOURCE_FILES = $(foreach dir,$(SOURCE_PATHS),$(wildcard $(dir)/*.cpp))
|
||||
SOURCE_FILES += $(foreach dir,$(SOURCE_PATHS),$(wildcard $(dir)/*.c))
|
||||
|
||||
SOURCE_FILES := $(filter-out $(_SOURCE_FILES),$(SOURCE_FILES))
|
||||
|
||||
#-----------------------------Library--------------------------------
|
||||
#
|
||||
# LIBPATHS = $(addprefix -L,$(LIBPATHS)) # add -L prefix
|
||||
#--------------------------------------------------------------------
|
||||
LIBPATHS =
|
||||
ifdef RELEASE
|
||||
# relase library path
|
||||
LIBPATHS +=
|
||||
else
|
||||
LIBPATHS +=
|
||||
endif
|
||||
|
||||
LIBS =
|
||||
|
||||
STATIC_LIBS =
|
||||
|
||||
#-----------------------------DEFINES--------------------------------
|
||||
#
|
||||
# DEFINES := $(addprefix -D,$(DEFINES)) # add -L prefix
|
||||
#--------------------------------------------------------------------
|
||||
DEFINES =
|
||||
|
||||
include ../gcc.mk
|
69
src/3rdpart/media-server/libflv/include/amf0.h
Normal file
69
src/3rdpart/media-server/libflv/include/amf0.h
Normal file
@ -0,0 +1,69 @@
|
||||
#ifndef _amf0_h_
|
||||
#define _amf0_h_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
enum AMFDataType
|
||||
{
|
||||
AMF_NUMBER = 0x00,
|
||||
AMF_BOOLEAN,
|
||||
AMF_STRING,
|
||||
AMF_OBJECT,
|
||||
AMF_MOVIECLIP,
|
||||
AMF_NULL,
|
||||
AMF_UNDEFINED,
|
||||
AMF_REFERENCE,
|
||||
AMF_ECMA_ARRAY,
|
||||
AMF_OBJECT_END,
|
||||
AMF_STRICT_ARRAY,
|
||||
AMF_DATE,
|
||||
AMF_LONG_STRING,
|
||||
AMF_UNSUPPORTED,
|
||||
AMF_RECORDSET,
|
||||
AMF_XML_DOCUMENT,
|
||||
AMF_TYPED_OBJECT,
|
||||
AMF_AVMPLUS_OBJECT,
|
||||
};
|
||||
|
||||
uint8_t* AMFWriteNull(uint8_t* ptr, const uint8_t* end);
|
||||
uint8_t* AMFWriteUndefined(uint8_t* ptr, const uint8_t* end);
|
||||
uint8_t* AMFWriteObject(uint8_t* ptr, const uint8_t* end);
|
||||
uint8_t* AMFWriteObjectEnd(uint8_t* ptr, const uint8_t* end);
|
||||
uint8_t* AMFWriteTypedObject(uint8_t* ptr, const uint8_t* end);
|
||||
uint8_t* AMFWriteECMAArarry(uint8_t* ptr, const uint8_t* end);
|
||||
|
||||
uint8_t* AMFWriteBoolean(uint8_t* ptr, const uint8_t* end, uint8_t value);
|
||||
uint8_t* AMFWriteDouble(uint8_t* ptr, const uint8_t* end, double value);
|
||||
uint8_t* AMFWriteString(uint8_t* ptr, const uint8_t* end, const char* string, size_t length);
|
||||
uint8_t* AMFWriteDate(uint8_t* ptr, const uint8_t* end, double milliseconds, int16_t timezone);
|
||||
|
||||
uint8_t* AMFWriteNamedString(uint8_t* ptr, const uint8_t* end, const char* name, size_t length, const char* value, size_t length2);
|
||||
uint8_t* AMFWriteNamedDouble(uint8_t* ptr, const uint8_t* end, const char* name, size_t length, double value);
|
||||
uint8_t* AMFWriteNamedBoolean(uint8_t* ptr, const uint8_t* end, const char* name, size_t length, uint8_t value);
|
||||
|
||||
const uint8_t* AMFReadNull(const uint8_t* ptr, const uint8_t* end);
|
||||
const uint8_t* AMFReadUndefined(const uint8_t* ptr, const uint8_t* end);
|
||||
const uint8_t* AMFReadBoolean(const uint8_t* ptr, const uint8_t* end, uint8_t* value);
|
||||
const uint8_t* AMFReadDouble(const uint8_t* ptr, const uint8_t* end, double* value);
|
||||
const uint8_t* AMFReadString(const uint8_t* ptr, const uint8_t* end, int isLongString, char* string, size_t length);
|
||||
const uint8_t* AMFReadDate(const uint8_t* ptr, const uint8_t* end, double *milliseconds, int16_t *timezone);
|
||||
|
||||
|
||||
struct amf_object_item_t
|
||||
{
|
||||
enum AMFDataType type;
|
||||
const char* name;
|
||||
void* value;
|
||||
size_t size;
|
||||
};
|
||||
const uint8_t* amf_read_items(const uint8_t* data, const uint8_t* end, struct amf_object_item_t* items, size_t count);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif /* !_amf0_h_ */
|
56
src/3rdpart/media-server/libflv/include/amf3.h
Normal file
56
src/3rdpart/media-server/libflv/include/amf3.h
Normal file
@ -0,0 +1,56 @@
|
||||
#ifndef _amf3_h_
|
||||
#define _amf3_h_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
enum AMF3DataType
|
||||
{
|
||||
AMF3_UNDEFINED = 0x00,
|
||||
AMF3_NULL,
|
||||
AMF3_FALSE,
|
||||
AMF3_TRUE,
|
||||
AMF3_INTEGER,
|
||||
AMF3_DOUBLE,
|
||||
AMF3_STRING,
|
||||
AMF3_XML_DOCUMENT,
|
||||
AMF3_DATE,
|
||||
AMF3_ARRAY,
|
||||
AMF3_OBJECT,
|
||||
AMF3_XML,
|
||||
AMF3_BYTE_ARRAY,
|
||||
AMF3_VECTOR_INT,
|
||||
AMF3_VECTOR_UINT,
|
||||
AMF3_VECTOR_DOUBLE,
|
||||
AMF3_VECTOR_OBJECT,
|
||||
AMF3_DICTIONARY,
|
||||
};
|
||||
|
||||
//uint8_t* AMF3WriteNull(uint8_t* ptr, const uint8_t* end);
|
||||
//uint8_t* AMF3WriteObject(uint8_t* ptr, const uint8_t* end);
|
||||
//uint8_t* AMF3WriteObjectEnd(uint8_t* ptr, const uint8_t* end);
|
||||
//
|
||||
//uint8_t* AMF3WriteBoolean(uint8_t* ptr, const uint8_t* end, uint8_t value);
|
||||
//uint8_t* AMF3WriteInteger(uint8_t* ptr, const uint8_t* end, int32_t value);
|
||||
//uint8_t* AMF3WriteDouble(uint8_t* ptr, const uint8_t* end, double value);
|
||||
//uint8_t* AMF3WriteString(uint8_t* ptr, const uint8_t* end, const char* string, size_t length);
|
||||
//
|
||||
//uint8_t* AMF3WriteNamedBoolean(uint8_t* ptr, const uint8_t* end, const char* name, size_t length, uint8_t value);
|
||||
//uint8_t* AMF3WriteNamedInteger(uint8_t* ptr, const uint8_t* end, const char* name, size_t length, int32_t value);
|
||||
//uint8_t* AMF3WriteNamedString(uint8_t* ptr, const uint8_t* end, const char* name, size_t length, const char* value, size_t length2);
|
||||
//uint8_t* AM3FWriteNamedDouble(uint8_t* ptr, const uint8_t* end, const char* name, size_t length, double value);
|
||||
|
||||
const uint8_t* AMF3ReadNull(const uint8_t* ptr, const uint8_t* end);
|
||||
const uint8_t* AMF3ReadBoolean(const uint8_t* ptr, const uint8_t* end);
|
||||
const uint8_t* AMF3ReadInteger(const uint8_t* ptr, const uint8_t* end, int32_t* value);
|
||||
const uint8_t* AMF3ReadDouble(const uint8_t* ptr, const uint8_t* end, double* value);
|
||||
const uint8_t* AMF3ReadString(const uint8_t* ptr, const uint8_t* end, char* string, uint32_t* length);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif /* !_amf3_h_ */
|
41
src/3rdpart/media-server/libflv/include/aom-av1.h
Normal file
41
src/3rdpart/media-server/libflv/include/aom-av1.h
Normal file
@ -0,0 +1,41 @@
|
||||
#ifndef _aom_av1_h_
|
||||
#define _aom_av1_h_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct aom_av1_t
|
||||
{
|
||||
uint32_t marker : 1;
|
||||
uint32_t version : 7;
|
||||
uint32_t seq_profile : 3;
|
||||
uint32_t seq_level_idx_0 : 5;
|
||||
uint32_t seq_tier_0 : 1;
|
||||
uint32_t high_bitdepth : 1;
|
||||
uint32_t twelve_bit : 1;
|
||||
uint32_t monochrome : 1;
|
||||
uint32_t chroma_subsampling_x : 1;
|
||||
uint32_t chroma_subsampling_y : 1;
|
||||
uint32_t chroma_sample_position : 2;
|
||||
|
||||
uint32_t reserved : 3;
|
||||
uint32_t initial_presentation_delay_present : 1;
|
||||
uint32_t initial_presentation_delay_minus_one : 4;
|
||||
|
||||
uint16_t bytes;
|
||||
uint8_t data[2 * 1024];
|
||||
};
|
||||
|
||||
int aom_av1_codec_configuration_record_load(const uint8_t* data, size_t bytes, struct aom_av1_t* av1);
|
||||
int aom_av1_codec_configuration_record_save(const struct aom_av1_t* av1, uint8_t* data, size_t bytes);
|
||||
|
||||
int aom_av1_codecs(const struct aom_av1_t* av1, char* codecs, size_t bytes);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
#endif /* !_aom_av1_h_ */
|
38
src/3rdpart/media-server/libflv/include/flv-demuxer.h
Normal file
38
src/3rdpart/media-server/libflv/include/flv-demuxer.h
Normal file
@ -0,0 +1,38 @@
|
||||
#ifndef _flv_demuxer_h_
|
||||
#define _flv_demuxer_h_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct flv_demuxer_t flv_demuxer_t;
|
||||
|
||||
/// Audio/Video Elementary Stream
|
||||
/// @param[in] param user-defined parameter
|
||||
/// @param[in] codec audio/video format (see more flv-proto.h)
|
||||
/// @param[in] data audio/video element data, AAC: ADTS + AAC-Frame, H.264: startcode + NALU, MP3-Raw data
|
||||
/// @param[in] bytes data length in byte
|
||||
/// @param[in] pts audio/video presentation timestamp
|
||||
/// @param[in] dts audio/video decoding timestamp
|
||||
/// @param[in] flags 1-video keyframe, other-undefined
|
||||
/// @return 0-ok, other-error
|
||||
typedef int (*flv_demuxer_handler)(void* param, int codec, const void* data, size_t bytes, uint32_t pts, uint32_t dts, int flags);
|
||||
|
||||
flv_demuxer_t* flv_demuxer_create(flv_demuxer_handler handler, void* param);
|
||||
void flv_demuxer_destroy(flv_demuxer_t* demuxer);
|
||||
|
||||
/// Input FLV Audio/Video Stream
|
||||
/// @param[in] type 8-audio, 9-video, 18-script (see more flv-proto.h)
|
||||
/// @param[in] data flv audio/video Stream, AudioTagHeader/VideoTagHeader + A/V Data
|
||||
/// @param[in] bytes data length in byte
|
||||
/// @param[in] timestamp milliseconds relative to the first tag(DTS)
|
||||
/// @return 0-ok, other-error
|
||||
int flv_demuxer_input(flv_demuxer_t* demuxer, int type, const void* data, size_t bytes, uint32_t timestamp);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
#endif /* !_flv_demuxer_h_ */
|
126
src/3rdpart/media-server/libflv/include/flv-header.h
Normal file
126
src/3rdpart/media-server/libflv/include/flv-header.h
Normal file
@ -0,0 +1,126 @@
|
||||
#ifndef _flv_header_h_
|
||||
#define _flv_header_h_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
enum
|
||||
{
|
||||
FLV_SEQUENCE_HEADER = 0,
|
||||
FLV_AVPACKET = 1,
|
||||
FLV_END_OF_SEQUENCE = 2,
|
||||
};
|
||||
|
||||
#define FLV_VIDEO_KEY_FRAME 1
|
||||
|
||||
struct flv_header_t
|
||||
{
|
||||
uint8_t FLV[3];
|
||||
uint8_t version;
|
||||
uint8_t audio;
|
||||
uint8_t video;
|
||||
uint32_t offset; // data offset
|
||||
};
|
||||
|
||||
struct flv_tag_header_t
|
||||
{
|
||||
uint8_t filter; // 0-No pre-processing required
|
||||
uint8_t type; // 8-audio, 9-video, 18-script data
|
||||
uint32_t size; // data size
|
||||
uint32_t timestamp;
|
||||
uint32_t streamId;
|
||||
};
|
||||
|
||||
struct flv_audio_tag_header_t
|
||||
{
|
||||
uint8_t codecid; /// audio codec id: FLV_AUDIO_AAC
|
||||
uint8_t rate; /// audio sample frequence: 0-5.5 kHz, 1-11 kHz, 2-22 kHz, 3-44 kHz
|
||||
uint8_t bits; /// audio sample bits: 0-8 bit samples, 1-16-bit samples
|
||||
uint8_t channels; /// audio channel count: 0-Mono sound, 1-Stereo sound
|
||||
uint8_t avpacket; /// AAC only:FLV_SEQUENCE_HEADER/FLV_AVPACKET
|
||||
};
|
||||
|
||||
struct flv_video_tag_header_t
|
||||
{
|
||||
uint8_t codecid; /// video codec id: FLV_VIDEO_H264
|
||||
uint8_t keyframe; /// video frame type: 1-key frame, 2-inter frame
|
||||
uint8_t avpacket; /// H.264/H.265/AV1 only:FLV_SEQUENCE_HEADER/FLV_AVPACKET/FLV_END_OF_SEQUENCE
|
||||
int32_t cts; /// video composition time(PTS - DTS), AVC/HEVC/AV1 only
|
||||
};
|
||||
|
||||
/// Read FLV File Header
|
||||
/// @return >=0-header length in byte, <0-error
|
||||
int flv_header_read(struct flv_header_t* flv, const uint8_t* buf, int len);
|
||||
|
||||
/// Write FLV File Header
|
||||
/// @param[in] audio 1-has audio, 0-don't have
|
||||
/// @param[in] video 1-has video, 0-don't have
|
||||
/// @param[out] buf flv header buffer
|
||||
/// @param[out] len flv header length
|
||||
/// @return >=0-header length in byte, <0-error
|
||||
int flv_header_write(int audio, int video, uint8_t* buf, int len);
|
||||
|
||||
|
||||
/// Read FLV Tag Header
|
||||
/// @return >=0-header length in byte, <0-error
|
||||
int flv_tag_header_read(struct flv_tag_header_t* tag, const uint8_t* buf, int len);
|
||||
|
||||
/// Write FLV Tag Header
|
||||
/// @param[out] buf flv tag header buffer
|
||||
/// @param[out] len flv tag header length
|
||||
/// @return >=0-header length in byte, <0-error
|
||||
int flv_tag_header_write(const struct flv_tag_header_t* tag, uint8_t* buf, int len);
|
||||
|
||||
|
||||
/// Read FLV Audio Tag Header
|
||||
/// @param[out] audio flv audio parameter
|
||||
/// @param[in] buf flv audio tag header buffer
|
||||
/// @param[in] len flv audio tag header length
|
||||
/// @return >=0-header length in byte, <0-error
|
||||
int flv_audio_tag_header_read(struct flv_audio_tag_header_t* audio, const uint8_t* buf, int len);
|
||||
|
||||
/// Write FLV Audio Tag Header
|
||||
/// @param[in] audio flv audio parameter
|
||||
/// @param[out] buf flv audio tag header buffer
|
||||
/// @param[out] len flv audio tag header length
|
||||
/// @return >=0-header length in byte, <0-error
|
||||
int flv_audio_tag_header_write(const struct flv_audio_tag_header_t* audio, uint8_t* buf, int len);
|
||||
|
||||
|
||||
/// Read FLV Video Tag Header
|
||||
/// @param[out] video flv video parameter
|
||||
/// @param[in] buf flv video tag header buffer
|
||||
/// @param[in] len flv video tag header length
|
||||
/// @return >=0-header length in byte, <0-error
|
||||
int flv_video_tag_header_read(struct flv_video_tag_header_t* video, const uint8_t* buf, int len);
|
||||
|
||||
/// Write FLV Video Tag Header
|
||||
/// @param[in] video flv video parameter
|
||||
/// @param[out] buf flv video tag header buffer
|
||||
/// @param[out] len flv video tag header length
|
||||
/// @return >=0-header length in byte, <0-error
|
||||
int flv_video_tag_header_write(const struct flv_video_tag_header_t* video, uint8_t* buf, int len);
|
||||
|
||||
|
||||
/// Read FLV Data Tag Header
|
||||
/// @return >=0-header length in byte, <0-error
|
||||
int flv_data_tag_header_read(const uint8_t* buf, int len);
|
||||
|
||||
/// Write FLV Data Tag Header
|
||||
/// @param[out] buf flv data tag header buffer
|
||||
/// @param[out] len flv data tag header length
|
||||
/// @return >=0-header length in byte, <0-error
|
||||
int flv_data_tag_header_write(uint8_t* buf, int len);
|
||||
|
||||
|
||||
/// Read/Write FLV previous tag size
|
||||
int flv_tag_size_read(const uint8_t* buf, int len, uint32_t* size);
|
||||
int flv_tag_size_write(uint8_t* buf, int len, uint32_t size);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
#endif /* !_flv_header_h_ */
|
61
src/3rdpart/media-server/libflv/include/flv-muxer.h
Normal file
61
src/3rdpart/media-server/libflv/include/flv-muxer.h
Normal file
@ -0,0 +1,61 @@
|
||||
#ifndef _flv_muxer_h_
|
||||
#define _flv_muxer_h_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct flv_muxer_t flv_muxer_t;
|
||||
|
||||
///Video: FLV VideoTagHeader + AVCVIDEOPACKET: AVCDecoderConfigurationRecord(ISO 14496-15) / One or more NALUs(four-bytes length + NALU)
|
||||
///Audio: FLV AudioTagHeader + AACAUDIODATA: AudioSpecificConfig(14496-3) / Raw AAC frame data in UI8
|
||||
///@param[in] data FLV Audio/Video Data(don't include FLV Tag Header)
|
||||
///@param[in] type 8-audio, 9-video
|
||||
///@return 0-ok, other-error
|
||||
typedef int (*flv_muxer_handler)(void* param, int type, const void* data, size_t bytes, uint32_t timestamp);
|
||||
|
||||
flv_muxer_t* flv_muxer_create(flv_muxer_handler handler, void* param);
|
||||
void flv_muxer_destroy(flv_muxer_t* muxer);
|
||||
|
||||
/// re-create AAC/AVC sequence header
|
||||
int flv_muxer_reset(flv_muxer_t* muxer);
|
||||
|
||||
/// @param[in] data AAC ADTS stream, 0xFFF15C40011FFC...
|
||||
int flv_muxer_aac(flv_muxer_t* muxer, const void* data, size_t bytes, uint32_t pts, uint32_t dts);
|
||||
|
||||
/// @param[in] data mp3 stream
|
||||
int flv_muxer_mp3(flv_muxer_t* muxer, const void* data, size_t bytes, uint32_t pts, uint32_t dts);
|
||||
|
||||
/// @param[in] data opus stream, first opus head, then opus samples
|
||||
int flv_muxer_opus(flv_muxer_t* muxer, const void* data, size_t bytes, uint32_t pts, uint32_t dts);
|
||||
|
||||
/// @param[in] data h.264 annexb bitstream: H.264 start code + H.264 NALU, 0x0000000168...
|
||||
int flv_muxer_avc(flv_muxer_t* muxer, const void* data, size_t bytes, uint32_t pts, uint32_t dts);
|
||||
|
||||
/// @param[in] data h.265 annexb bitstream: H.265 start code + H.265 NALU, 0x00000001...
|
||||
int flv_muxer_hevc(flv_muxer_t* muxer, const void* data, size_t bytes, uint32_t pts, uint32_t dts);
|
||||
|
||||
struct flv_metadata_t
|
||||
{
|
||||
int audiocodecid;
|
||||
double audiodatarate; // kbps
|
||||
int audiosamplerate;
|
||||
int audiosamplesize;
|
||||
int stereo;
|
||||
|
||||
int videocodecid;
|
||||
double videodatarate; // kbps
|
||||
double framerate; // fps
|
||||
int width;
|
||||
int height;
|
||||
};
|
||||
|
||||
int flv_muxer_metadata(flv_muxer_t* muxer, const struct flv_metadata_t* metadata);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
#endif /* !_flv_muxer_h_ */
|
33
src/3rdpart/media-server/libflv/include/flv-parser.h
Normal file
33
src/3rdpart/media-server/libflv/include/flv-parser.h
Normal file
@ -0,0 +1,33 @@
|
||||
#ifndef _flv_parser_h_
|
||||
#define _flv_parser_h_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/// Audio/Video Elementary Stream
|
||||
/// @param[in] param user-defined parameter
|
||||
/// @param[in] codec audio/video format (see more flv-proto.h)
|
||||
/// @param[in] data audio/video element data, AAC: AAC-Frame, H.264: MP4 Stream, MP3-Raw data
|
||||
/// @param[in] bytes data length in byte
|
||||
/// @param[in] pts audio/video presentation timestamp
|
||||
/// @param[in] dts audio/video decoding timestamp
|
||||
/// @param[in] flags 1-video keyframe, other-undefined
|
||||
/// @return 0-ok, other-error
|
||||
typedef int (*flv_parser_handler)(void* param, int codec, const void* data, size_t bytes, uint32_t pts, uint32_t dts, int flags);
|
||||
|
||||
/// Input FLV Audio/Video Stream
|
||||
/// @param[in] type 8-audio, 9-video, 18-script (see more flv-proto.h)
|
||||
/// @param[in] data flv audio/video Stream, AudioTagHeader/VideoTagHeader + A/V Data
|
||||
/// @param[in] bytes data length in byte
|
||||
/// @param[in] timestamp milliseconds relative to the first tag(DTS)
|
||||
/// @return 0-ok, other-error
|
||||
int flv_parser_input(int type, const void* data, size_t bytes, uint32_t timestamp, flv_parser_handler handler, void* param);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
#endif /* !_flv_parser_h_ */
|
30
src/3rdpart/media-server/libflv/include/flv-proto.h
Normal file
30
src/3rdpart/media-server/libflv/include/flv-proto.h
Normal file
@ -0,0 +1,30 @@
|
||||
#ifndef _flv_proto_h_
|
||||
#define _flv_proto_h_
|
||||
|
||||
// FLV Tag Type
|
||||
#define FLV_TYPE_AUDIO 8
|
||||
#define FLV_TYPE_VIDEO 9
|
||||
#define FLV_TYPE_SCRIPT 18
|
||||
|
||||
// FLV Audio Type
|
||||
#define FLV_AUDIO_ADPCM (1 << 4)
|
||||
#define FLV_AUDIO_MP3 (2 << 4)
|
||||
#define FLV_AUDIO_G711A (7 << 4) // G711 A-law
|
||||
#define FLV_AUDIO_G711U (8 << 4) // G711 mu-law
|
||||
#define FLV_AUDIO_AAC (10 << 4)
|
||||
#define FLV_AUDIO_OPUS (13 << 4)
|
||||
#define FLV_AUDIO_MP3_8K (14 << 4)
|
||||
#define FLV_AUDIO_ASC 0x100 // AudioSpecificConfig(ISO-14496-3)
|
||||
#define FLV_AUDIO_OPUS_HEAD 0x101 // opus-codec.org
|
||||
|
||||
// FLV Video Type
|
||||
#define FLV_VIDEO_H263 2
|
||||
#define FLV_VIDEO_VP6 4
|
||||
#define FLV_VIDEO_H264 7
|
||||
#define FLV_VIDEO_H265 12 // https://github.com/CDN-Union/H265
|
||||
#define FLV_VIDEO_AV1 14 // https://aomediacodec.github.io/av1-isobmff
|
||||
#define FLV_VIDEO_AVCC 0x200 // AVCDecoderConfigurationRecord(ISO-14496-15)
|
||||
#define FLV_VIDEO_HVCC 0x201 // HEVCDecoderConfigurationRecord(ISO-14496-15)
|
||||
#define FLV_VIDEO_AV1C 0x202 // AV1CodecConfigurationRecord(av1-isobmff)
|
||||
|
||||
#endif /* !_flv_proto_h_ */
|
26
src/3rdpart/media-server/libflv/include/flv-reader.h
Normal file
26
src/3rdpart/media-server/libflv/include/flv-reader.h
Normal file
@ -0,0 +1,26 @@
|
||||
#ifndef _flv_reader_h_
|
||||
#define _flv_reader_h_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void* flv_reader_create(const char* file);
|
||||
void* flv_reader_create2(int(*read)(void* param, void* buf, int len), void* param);
|
||||
void flv_reader_destroy(void* flv);
|
||||
|
||||
///@param[out] tagtype 8-audio, 9-video, 18-script data
|
||||
///@param[out] timestamp FLV timestamp
|
||||
///@param[out] taglen flv tag length(0 is ok but should be silently discard)
|
||||
///@param[out] buffer FLV stream
|
||||
///@param[in] bytes buffer size
|
||||
///@return 1-got a packet, 0-EOF, other-error
|
||||
int flv_reader_read(void* flv, int* tagtype, uint32_t* timestamp, size_t* taglen, void* buffer, size_t bytes);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
#endif /* !_flv_reader_h_ */
|
26
src/3rdpart/media-server/libflv/include/flv-writer.h
Normal file
26
src/3rdpart/media-server/libflv/include/flv-writer.h
Normal file
@ -0,0 +1,26 @@
|
||||
#ifndef _flv_writer_h_
|
||||
#define _flv_writer_h_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void* flv_writer_create(const char* file);
|
||||
void* flv_writer_create2(int (*write)(void* param, const void* buf, int len), void* param);
|
||||
|
||||
void flv_writer_destroy(void* flv);
|
||||
|
||||
/// Video: FLV VideoTagHeader + AVCVIDEOPACKET: AVCDecoderConfigurationRecord(ISO 14496-15) / One or more NALUs(four-bytes length + NALU)
|
||||
/// Audio: FLV AudioTagHeader + AACAUDIODATA: AudioSpecificConfig(14496-3) / Raw AAC frame data in UI8
|
||||
/// @param[in] data FLV Audio/Video Data(don't include FLV Tag Header)
|
||||
/// @param[in] type 8-audio, 9-video
|
||||
/// @return 0-ok, other-error
|
||||
int flv_writer_input(void* flv, int type, const void* data, size_t bytes, uint32_t timestamp);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
#endif /* !_flv_writer_h_ */
|
109
src/3rdpart/media-server/libflv/include/mp3-header.h
Normal file
109
src/3rdpart/media-server/libflv/include/mp3-header.h
Normal file
@ -0,0 +1,109 @@
|
||||
#ifndef _mp3_header_h_
|
||||
#define _mp3_header_h_
|
||||
|
||||
// https://en.wikipedia.org/wiki/MP3
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
ISO/IEC 11172-3
|
||||
2.4.1.3 Header
|
||||
unsigned int sync: 12
|
||||
unsigned int version: 1
|
||||
unsigned int layer: 2
|
||||
unsigned int error protection: 1
|
||||
unsigned int bitrate_index: 4
|
||||
unsigned int sampling_frequency: 2
|
||||
unsigned int padding: 1
|
||||
unsigned int private: 1
|
||||
unsigned int mode: 2
|
||||
unsigned int mode extension: 2
|
||||
unsigned int copyright: 1
|
||||
unsigned int original: 1
|
||||
unsigned int emphasis: 2
|
||||
|
||||
bit_rate_index Layer I Layer II Layer III
|
||||
'0000' free format free format free format
|
||||
'0001' 32 kbit/s 32 kbit/s 32 kbit/s
|
||||
'0010' 64 kbit/s 48 kbit/s 40 kbit/s
|
||||
'0011' 96 kbit/s 56 kbit/s 48 kbit/s
|
||||
'0100' 128 kbit/s 64 kbit/s 56 kbit/s
|
||||
'0101' 160 kbit/s 80 kbit/s 64 kbit/s
|
||||
'0110' 192 kbit/s 96 kbit/s 80 kbit/s
|
||||
'0111' 224 kbit/s 112 kbit/s 96 kbit/s
|
||||
'1000' 256 kbit/s 128 kbit/s 112 kbit/s
|
||||
'1001' 288 kbit/s 160 kbit/s 128 kbit/s
|
||||
'1010' 320 kbit/s 192 kbit/s 160 kbit/s
|
||||
'1011' 352 kbit/s 224 kbit/s 192 kbit/s
|
||||
'1100' 384 kbit/s 256 kbit/s 224 kbit/s
|
||||
'1101' 416 kbit/s 320 kbit/s 256 kbit/s
|
||||
'1110' 448 kbit/s 384 kbit/s 320 kbit/s
|
||||
|
||||
sampling_frequency
|
||||
'00' 44.1 kHz
|
||||
'01' 48 kHz
|
||||
'10' 32 kHz
|
||||
'11' reserved
|
||||
|
||||
mode
|
||||
'00' stereo
|
||||
'01' joint_stereo (intensity_stereo and/or ms_stereo)
|
||||
'10' dual_channel
|
||||
'11' single_channel
|
||||
|
||||
mode_extension
|
||||
'00' subbands 4-31 in intensity_stereo, bound==4
|
||||
'01' subbands 8-31 in intensity_stereo, bound==8
|
||||
'10' subbands 12-31 in intensity_stereo, bound==12
|
||||
'11' subbands 16-31 in intensity_stereo, bound==16
|
||||
|
||||
emphasis
|
||||
'00' no emphasis
|
||||
'01' 50/15 microsec. emphasis
|
||||
'10' reserved
|
||||
'11' CCITT J.17
|
||||
*/
|
||||
|
||||
struct mp3_header_t
|
||||
{
|
||||
unsigned int version : 2; // 0-MPEG 2.5, 1-undefined, 2-MPEG-2, 3-MPEG-1
|
||||
unsigned int layer : 2; // 3-Layer I, 2-Layer II, 1-Layer III, 0-reserved
|
||||
unsigned int protection : 1;
|
||||
unsigned int bitrate_index : 4; //0-free,
|
||||
unsigned int sampling_frequency : 2;
|
||||
unsigned int priviate : 1;
|
||||
unsigned int mode : 2;
|
||||
unsigned int mode_extension : 2;
|
||||
unsigned int copyright : 1;
|
||||
unsigned int original : 1;
|
||||
unsigned int emphasis : 2;
|
||||
};
|
||||
|
||||
// version
|
||||
#define MP3_MPEG1 3
|
||||
#define MP3_MPEG2 2
|
||||
#define MP3_MPEG2_5 0
|
||||
|
||||
// layer
|
||||
#define MP3_LAYER1 3
|
||||
#define MP3_LAYER2 2
|
||||
#define MP3_LAYER3 1
|
||||
|
||||
#define MP3_BITS_PER_SAMPLE 16
|
||||
|
||||
///MP3 Header size: 4
|
||||
int mp3_header_load(struct mp3_header_t* mp3, const void* data, int bytes);
|
||||
int mp3_header_save(const struct mp3_header_t* mp3, void* data, int bytes);
|
||||
|
||||
int mp3_get_channel(const struct mp3_header_t* mp3);
|
||||
int mp3_get_bitrate(const struct mp3_header_t* mp3);
|
||||
int mp3_set_bitrate(struct mp3_header_t* mp3, int bitrate);
|
||||
int mp3_get_frequency(const struct mp3_header_t* mp3);
|
||||
int mp3_set_frequency(struct mp3_header_t* mp3, int frequency);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
#endif /* !_mp3_header_h_ */
|
148
src/3rdpart/media-server/libflv/include/mpeg4-aac.h
Normal file
148
src/3rdpart/media-server/libflv/include/mpeg4-aac.h
Normal file
@ -0,0 +1,148 @@
|
||||
#ifndef _mpeg4_aac_h_
|
||||
#define _mpeg4_aac_h_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct mpeg4_aac_t
|
||||
{
|
||||
uint8_t profile; // 0-NULL, 1-AAC Main, 2-AAC LC, 2-AAC SSR, 3-AAC LTP
|
||||
uint8_t sampling_frequency_index; // 0-96000, 1-88200, 2-64000, 3-48000, 4-44100, 5-32000, 6-24000, 7-22050, 8-16000, 9-12000, 10-11025, 11-8000, 12-7350, 13/14-reserved, 15-frequency is written explictly
|
||||
uint8_t channel_configuration; // 0-AOT, 1-1channel,front-center, 2-2channels, front-left/right, 3-3channels: front center/left/right, 4-4channels: front-center/left/right, back-center, 5-5channels: front center/left/right, back-left/right, 6-6channels: front center/left/right, back left/right LFE-channel, 7-8channels
|
||||
|
||||
// uint32_t frequency; // play frequency
|
||||
uint32_t sampling_frequency; // valid only in decode
|
||||
uint8_t channels; // valid only in decode
|
||||
int sbr; // sbr flag, valid only in decode
|
||||
int ps; // ps flag, valid only in decode
|
||||
uint8_t pce[64];
|
||||
int npce; // pce bytes
|
||||
};
|
||||
|
||||
enum mpeg2_aac_profile
|
||||
{
|
||||
MPEG2_AAC_MAIN = 0,
|
||||
MPEG2_AAC_LC,
|
||||
MPEG2_AAC_SSR,
|
||||
};
|
||||
|
||||
// ISO/IEC 14496-3:2009(E) Table 1.3 - Audio Profiles definition (p41)
|
||||
// https://en.wikipedia.org/wiki/MPEG-4_Part_3#Audio_Profiles
|
||||
enum mpeg4_aac_object_type
|
||||
{
|
||||
MPEG4_AAC_MAIN = 1,
|
||||
MPEG4_AAC_LC,
|
||||
MPEG4_AAC_SSR,
|
||||
MPEG4_AAC_LTP,
|
||||
MPEG4_AAC_SBR, // (used with AAC LC in the "High Efficiency AAC Profile" (HE-AAC v1))
|
||||
MPEG4_AAC_SCALABLE,
|
||||
MPEG4_AAC_TWINVQ,
|
||||
MPEG4_AAC_CELP,
|
||||
MPEG4_AAC_HVXC,
|
||||
MPEG4_AAC_TTSI = 12,
|
||||
MPEG4_AAC_MAIN_SYNTHETIC,
|
||||
MPEG4_AAC_WAVETABLE_SYNTHETIC,
|
||||
MPEG4_AAC_GENERAL_MIDI,
|
||||
MPEG4_AAC_ALGORITHMIC_SYNTHESIS, // Algorithmic Synthesis and Audio FX object type
|
||||
MPEG4_AAC_ER_LC, // Error Resilient (ER) AAC Low Complexity (LC) object type
|
||||
MPEG4_AAC_ER_LTP = 19, // Error Resilient (ER) AAC Long Term Predictor (LTP) object type
|
||||
MPEG4_AAC_ER_SCALABLE, // Error Resilient (ER) AAC scalable object type
|
||||
MPEG4_AAC_ER_TWINVQ, // Error Resilient (ER) TwinVQ object type
|
||||
MPEG4_AAC_ER_BSAC, // Error Resilient (ER) BSAC object type
|
||||
MPEG4_AAC_ER_AAC_LD, // Error Resilient (ER) AAC LD object type(used with CELP, ER CELP, HVXC, ER HVXC and TTSI in the "Low Delay Profile")
|
||||
MPEG4_AAC_ER_CELP, // Error Resilient (ER) CELP object type
|
||||
MPEG4_AAC_ER_HVXC, // Error Resilient (ER) HVXC object type
|
||||
MPEG4_AAC_ER_HILN, // Error Resilient (ER) HILN object type
|
||||
MPEG4_AAC_ER_PARAMTRIC, // Error Resilient (ER) Parametric object type
|
||||
MPEG4_AAC_SSC, // SSC Audio object type
|
||||
MPEG4_AAC_PS, // PS object type(used with AAC LC and SBR in the "HE-AAC v2 Profile")
|
||||
MPEG4_AAC_MPEG_SURROUND, // MPEG Surround object type
|
||||
MPEG4_AAC_LAYER_1 = 32, // Layer-1 Audio object type
|
||||
MPEG4_AAC_LAYER_2, // Layer-2 Audio object type
|
||||
MPEG4_AAC_LAYER_3, // Layer-3 Audio object type
|
||||
MPEG4_AAC_DST,
|
||||
MPEG4_AAC_ALS, // ALS Audio object type
|
||||
MPEG4_AAC_SLS, // SLS Audio object type
|
||||
MPEG4_AAC_SLS_NON_CORE, // SLS Non-Core Audio object type
|
||||
MPEG4_AAC_ER_AAC_ELD, // Error Resilient (ER) AAC ELD object type (uses AAC-LD, AAC-ELD and AAC-ELDv2, "Low Delay AAC v2")
|
||||
MPEG4_AAC_SMR_SIMPLE, // SMR Simple object type: MPEG-4 Part 23 standard (ISO/IEC 14496-23:2008)
|
||||
MPEG4_AAC_SMR_MAIN, // SMR Main object type
|
||||
MPEG4_AAC_USAC_NO_SBR, // Unified Speech and Audio Coding (no SBR)
|
||||
MPEG4_AAC_SAOC, // Spatial Audio Object Coding: MPEG-D Part 2 standard (ISO/IEC 23003-2:2010)
|
||||
MPEG4_AAC_LD_MEPG_SURROUND, // MPEG-D Part 2 - ISO/IEC 23003-2
|
||||
MPEG4_AAC_USAC, // MPEG-D Part 3 - ISO/IEC 23003-3
|
||||
};
|
||||
|
||||
enum mpeg4_audio_profile
|
||||
{
|
||||
MPEG4_AAC_PROFILE, // AAC LC
|
||||
MPEG4_HIGH_EFFICIENCY_AAC_PROFILE, // AAC LC, SBR (<=128 kbps)
|
||||
MPEG4_HE_AAC_V2_PROFILE, // AAC LC, SBR, PS (approx. 16 - 48 kbit/s)
|
||||
MPEG4_MAIN_AUDIO_PROFILE, // AAC Main, AAC LC, AAC SSR, AAC LTP, AAC Scalable, TwinVQ, CELP, HVXC, TTSI, Main synthesis
|
||||
MPEG4_SCALABLE_AUDIO_PROFILE, // AAC LC, AAC LTP, AAC Scalable, TwinVQ, CELP, HVXC, TTSI
|
||||
MPEG4_SPEECH_AUDIO_PROFILE, // CELP, HVXC, TTSI
|
||||
MPEG4_SYNTHETIC_AUDIO_PRIFILE, // TTSI, Main synthesis
|
||||
MPEG4_HIGH_QUALITY_AUDIO_PROFILE, // AAC LC, AAC LTP, AAC Scalable, CELP, ER AAC LC, ER AAC LTP, ER AAC Scalable, ER CELP
|
||||
MPEG4_LOW_DELAY_AUDIO_PROFILE, // CELP, HVXC, TTSI, ER AAC LD, ER CELP, ER HVXC
|
||||
MPEG4_NATURAL_AUDIO_PRIFILE, // AAC Main, AAC LC, AAC SSR, AAC LTP, AAC Scalable, TwinVQ, CELP, HVXC, TTSI, ER AAC LC, ER AAC LTP, ER AAC Scalable, ER TwinVQ, ER BSAC, ER AAC LD, ER CELP, ER HVXC, ER HILN, ER Parametric
|
||||
MPEG4_MOBILE_AUDIO_INTERNETWORKING_PROFILE, // ER AAC LC, ER AAC Scalable, ER TwinVQ, ER BSAC, ER AAC LD
|
||||
MPEG4_HD_AAC_PROFILE, // AAC LC, SLS
|
||||
MPEG4_ALS_SIMPLE_PROFILE, // ALS
|
||||
};
|
||||
|
||||
enum mpeg4_aac_frequency
|
||||
{
|
||||
MPEG4_AAC_96000 = 0,
|
||||
MPEG4_AAC_88200, // 0x1
|
||||
MPEG4_AAC_64000, // 0x2
|
||||
MPEG4_AAC_48000, // 0x3
|
||||
MPEG4_AAC_44100, // 0x4
|
||||
MPEG4_AAC_32000, // 0x5
|
||||
MPEG4_AAC_24000, // 0x6
|
||||
MPEG4_AAC_22050, // 0x7
|
||||
MPEG4_AAC_16000, // 0x8
|
||||
MPEG4_AAC_12000, // 0x9
|
||||
MPEG4_AAC_11025, // 0xa
|
||||
MPEG4_AAC_8000, // 0xb
|
||||
MPEG4_AAC_7350, // 0xc
|
||||
// reserved
|
||||
// reserved
|
||||
// escape value
|
||||
|
||||
};
|
||||
|
||||
/// @return >=0-adts header length, <0-error
|
||||
int mpeg4_aac_adts_save(const struct mpeg4_aac_t* aac, size_t payload, uint8_t* data, size_t bytes);
|
||||
/// @return >=0-adts header length, <0-error
|
||||
int mpeg4_aac_adts_load(const uint8_t* data, size_t bytes, struct mpeg4_aac_t* aac);
|
||||
|
||||
/// @return >=0-audio specific config length, <0-error
|
||||
int mpeg4_aac_audio_specific_config_load(const uint8_t* data, size_t bytes, struct mpeg4_aac_t* aac);
|
||||
/// @return >=0-audio specific config length, <0-error
|
||||
int mpeg4_aac_audio_specific_config_save(const struct mpeg4_aac_t* aac, uint8_t* data, size_t bytes);
|
||||
|
||||
/// @return >=0-stream mux config length, <0-error
|
||||
int mpeg4_aac_stream_mux_config_load(const uint8_t* data, size_t bytes, struct mpeg4_aac_t* aac);
|
||||
/// @return >=0-stream mux config length, <0-error
|
||||
int mpeg4_aac_stream_mux_config_save(const struct mpeg4_aac_t* aac, uint8_t* data, size_t bytes);
|
||||
|
||||
/// get AAC profile level indication value
|
||||
int mpeg4_aac_profile_level(const struct mpeg4_aac_t* aac);
|
||||
|
||||
/// MPEG4_AAC_96000 => 96000
|
||||
/// @return -1-error, other-frequency value
|
||||
int mpeg4_aac_audio_frequency_to(enum mpeg4_aac_frequency index);
|
||||
/// 96000 => MPEG4_AAC_96000
|
||||
/// @return -1-error, other-frequency index
|
||||
int mpeg4_aac_audio_frequency_from(int frequency);
|
||||
|
||||
int mpeg4_aac_adts_frame_length(const uint8_t* data, size_t bytes);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
#endif /* !_mpeg4_aac_h_ */
|
68
src/3rdpart/media-server/libflv/include/mpeg4-avc.h
Normal file
68
src/3rdpart/media-server/libflv/include/mpeg4-avc.h
Normal file
@ -0,0 +1,68 @@
|
||||
#ifndef _mpeg4_avc_h_
|
||||
#define _mpeg4_avc_h_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct mpeg4_avc_t
|
||||
{
|
||||
// uint8_t version; // 1-only
|
||||
uint8_t profile;
|
||||
uint8_t compatibility; // constraint_set[0-5]_flag
|
||||
uint8_t level;
|
||||
uint8_t nalu; // NALUnitLength = (lengthSizeMinusOne + 1), default 4(0x03+1)
|
||||
|
||||
uint8_t nb_sps;
|
||||
uint8_t nb_pps;
|
||||
|
||||
struct mpeg4_avc_sps_t
|
||||
{
|
||||
uint16_t bytes;
|
||||
uint8_t* data;
|
||||
} sps[32]; // [0-31]
|
||||
|
||||
struct mpeg4_avc_pps_t
|
||||
{
|
||||
uint16_t bytes;
|
||||
uint8_t* data;
|
||||
} pps[256];
|
||||
|
||||
// extension
|
||||
uint8_t chroma_format_idc;
|
||||
uint8_t bit_depth_luma_minus8;
|
||||
uint8_t bit_depth_chroma_minus8;
|
||||
|
||||
uint8_t data[4 * 1024];
|
||||
int off;
|
||||
};
|
||||
|
||||
int mpeg4_avc_decoder_configuration_record_load(const uint8_t* data, size_t bytes, struct mpeg4_avc_t* avc);
|
||||
|
||||
int mpeg4_avc_decoder_configuration_record_save(const struct mpeg4_avc_t* avc, uint8_t* data, size_t bytes);
|
||||
|
||||
int mpeg4_avc_to_nalu(const struct mpeg4_avc_t* avc, uint8_t* data, size_t bytes);
|
||||
|
||||
int mpeg4_avc_codecs(const struct mpeg4_avc_t* avc, char* codecs, size_t bytes);
|
||||
|
||||
/// @param[out] vcl 0-non VCL, 1-IDR, 2-P/B
|
||||
/// @return <=0-error, >0-output bytes
|
||||
int h264_annexbtomp4(struct mpeg4_avc_t* avc, const void* data, int bytes, void* out, int size, int* vcl, int* update);
|
||||
|
||||
/// @return <=0-error, >0-output bytes
|
||||
int h264_mp4toannexb(const struct mpeg4_avc_t* avc, const void* data, int bytes, void* out, int size);
|
||||
|
||||
/// h264_is_new_access_unit H.264 new access unit(frame)
|
||||
/// @return 1-new access, 0-not a new access
|
||||
int h264_is_new_access_unit(const uint8_t* nalu, size_t bytes);
|
||||
|
||||
/// H.264 nal unit split
|
||||
void mpeg4_h264_annexb_nalu(const void* h264, int bytes, void (*handler)(void* param, const uint8_t* nalu, int bytes), void* param);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
#endif /* !_mpeg4_avc_h_ */
|
169
src/3rdpart/media-server/libflv/include/mpeg4-bits.h
Normal file
169
src/3rdpart/media-server/libflv/include/mpeg4-bits.h
Normal file
@ -0,0 +1,169 @@
|
||||
#ifndef _mpeg4_bits_h_
|
||||
#define _mpeg4_bits_h_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <assert.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct mpeg4_bits_t
|
||||
{
|
||||
uint8_t* data;
|
||||
size_t size;
|
||||
size_t bits; // offset bit
|
||||
int error;
|
||||
};
|
||||
|
||||
#define mpeg4_bits_read_uint8(bits, n) (uint8_t)mpeg4_bits_read_n(bits, n)
|
||||
#define mpeg4_bits_read_uint16(bits, n) (uint16_t)mpeg4_bits_read_n(bits, n)
|
||||
#define mpeg4_bits_read_uint32(bits, n) (uint32_t)mpeg4_bits_read_n(bits, n)
|
||||
#define mpeg4_bits_read_uint64(bits, n) (uint64_t)mpeg4_bits_read_n(bits, n)
|
||||
#define mpeg4_bits_write_uint8(bits, v, n) mpeg4_bits_write_n(bits, (uint64_t)v, n)
|
||||
#define mpeg4_bits_write_uint16(bits, v, n) mpeg4_bits_write_n(bits, (uint64_t)v, n)
|
||||
#define mpeg4_bits_write_uint32(bits, v, n) mpeg4_bits_write_n(bits, (uint64_t)v, n)
|
||||
#define mpeg4_bits_write_uint64(bits, v, n) mpeg4_bits_write_n(bits, (uint64_t)v, n)
|
||||
|
||||
static inline void mpeg4_bits_init(struct mpeg4_bits_t* bits, void* data, size_t size)
|
||||
{
|
||||
bits->data = (uint8_t*)data;
|
||||
bits->size = size;
|
||||
bits->bits = 0;
|
||||
bits->error = 0;
|
||||
}
|
||||
|
||||
/// @return 1-error, 0-no error
|
||||
static inline int mpeg4_bits_error(struct mpeg4_bits_t* bits)
|
||||
{
|
||||
//return bits->bits >= bits->size * 8 ? 1 : 0;
|
||||
return bits->error;
|
||||
}
|
||||
|
||||
static inline void mpeg4_bits_aligment(struct mpeg4_bits_t* bits, int n)
|
||||
{
|
||||
bits->bits = (bits->bits + n - 1) / n * n;
|
||||
}
|
||||
|
||||
static inline size_t mpeg4_bits_remain(struct mpeg4_bits_t* bits)
|
||||
{
|
||||
return bits->error ? 0 : (bits->size * 8 - bits->bits);
|
||||
}
|
||||
|
||||
/// read 1-bit from bit stream(offset position)
|
||||
/// @param[in] bits bit stream
|
||||
/// @return -1-error, 1-value, 0-value
|
||||
static inline int mpeg4_bits_read(struct mpeg4_bits_t* bits)
|
||||
{
|
||||
uint8_t bit;
|
||||
assert(bits && bits->data && bits->size > 0);
|
||||
if (bits->bits >= bits->size * 8)
|
||||
{
|
||||
bits->error = -1;
|
||||
return 0; // throw exception
|
||||
}
|
||||
|
||||
bit = bits->data[bits->bits/8] & (0x80U >> (bits->bits%8));
|
||||
bits->bits += 1; // update offset
|
||||
return bit ? 1 : 0;
|
||||
}
|
||||
|
||||
/// read n-bit(n <= 64) from bit stream(offset position)
|
||||
/// @param[in] bits bit stream
|
||||
/// @return -1-error, other-value
|
||||
static inline uint64_t mpeg4_bits_read_n(struct mpeg4_bits_t* bits, int n)
|
||||
{
|
||||
int m;
|
||||
size_t i;
|
||||
uint64_t v;
|
||||
|
||||
assert(n > 0 && n <= 64);
|
||||
assert(bits && bits->data && bits->size > 0);
|
||||
if (bits->bits + n > bits->size * 8 || n > 64 || n < 0)
|
||||
{
|
||||
bits->error = -1;
|
||||
return 0; // throw exception
|
||||
}
|
||||
|
||||
m = n;
|
||||
v = bits->data[bits->bits / 8] & (0xFFU >> (bits->bits%8)); // remain valid value
|
||||
if (n <= 8 - (int)(bits->bits % 8))
|
||||
{
|
||||
v = v >> (8 - (bits->bits % 8) - n); // shift right value
|
||||
bits->bits += n;
|
||||
return v;
|
||||
}
|
||||
|
||||
n -= 8 - (int)(bits->bits % 8);
|
||||
for (i = 1; n >= 8; i++)
|
||||
{
|
||||
assert(bits->bits / 8 + i < bits->size);
|
||||
v <<= 8;
|
||||
v += bits->data[bits->bits / 8 + i];
|
||||
n -= 8;
|
||||
}
|
||||
|
||||
if (n > 0)
|
||||
{
|
||||
v <<= n;
|
||||
v += bits->data[bits->bits / 8 + i] >> (8 - n);
|
||||
}
|
||||
|
||||
bits->bits += m;
|
||||
return v;
|
||||
}
|
||||
|
||||
/// write 1-bit
|
||||
/// @param[in] v write 0 if v value 0, other, write 1
|
||||
static inline int mpeg4_bits_write(struct mpeg4_bits_t* bits, int v)
|
||||
{
|
||||
assert(bits && bits->data && bits->size > 0);
|
||||
if (bits->bits >= bits->size * 8)
|
||||
{
|
||||
bits->error = -1;
|
||||
return -1; // throw exception
|
||||
}
|
||||
|
||||
if(v)
|
||||
bits->data[bits->bits / 8] |= (0x80U >> (bits->bits % 8));
|
||||
bits->bits += 1; // update offset
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int mpeg4_bits_write_n(struct mpeg4_bits_t* bits, uint64_t v, int n)
|
||||
{
|
||||
int m;
|
||||
size_t i;
|
||||
|
||||
assert(n > 0 && n <= 64);
|
||||
assert(bits && bits->data && bits->size > 0);
|
||||
if (bits->bits + n > bits->size * 8 || n > 64 || n < 0)
|
||||
{
|
||||
bits->error = -1;
|
||||
return -1; // throw exception
|
||||
}
|
||||
|
||||
m = n;
|
||||
v = v << (64 - n); // left shift to first bit
|
||||
|
||||
bits->data[bits->bits / 8] |= v >> (56 + (bits->bits % 8)); // remain valid value
|
||||
v <<= 8 - (bits->bits % 8);
|
||||
n -= 8 - (int)(bits->bits % 8);
|
||||
|
||||
for (i = 1; n > 0; i++)
|
||||
{
|
||||
assert(bits->bits / 8 + i < bits->size);
|
||||
bits->data[bits->bits / 8 + i] = (uint8_t)(v >> 56);
|
||||
v <<= 8;
|
||||
n -= 8;
|
||||
}
|
||||
|
||||
bits->bits += m;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif /* !_mpeg4_bits_h_ */
|
64
src/3rdpart/media-server/libflv/include/mpeg4-hevc.h
Normal file
64
src/3rdpart/media-server/libflv/include/mpeg4-hevc.h
Normal file
@ -0,0 +1,64 @@
|
||||
#ifndef _mpeg4_hevc_h_
|
||||
#define _mpeg4_hevc_h_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct mpeg4_hevc_t
|
||||
{
|
||||
uint8_t configurationVersion; // 1-only
|
||||
uint8_t general_profile_space; // 2bit,[0,3]
|
||||
uint8_t general_tier_flag; // 1bit,[0,1]
|
||||
uint8_t general_profile_idc; // 5bit,[0,31]
|
||||
uint32_t general_profile_compatibility_flags;
|
||||
uint64_t general_constraint_indicator_flags;
|
||||
uint8_t general_level_idc;
|
||||
uint16_t min_spatial_segmentation_idc;
|
||||
uint8_t parallelismType; // 2bit,[0,3]
|
||||
uint8_t chromaFormat; // 2bit,[0,3]
|
||||
uint8_t bitDepthLumaMinus8; // 3bit,[0,7]
|
||||
uint8_t bitDepthChromaMinus8; // 3bit,[0,7]
|
||||
uint16_t avgFrameRate;
|
||||
uint8_t constantFrameRate; // 2bit,[0,3]
|
||||
uint8_t numTemporalLayers; // 3bit,[0,7]
|
||||
uint8_t temporalIdNested; // 1bit,[0,1]
|
||||
uint8_t lengthSizeMinusOne; // 2bit,[0,3]
|
||||
|
||||
uint8_t numOfArrays;
|
||||
struct
|
||||
{
|
||||
uint8_t array_completeness;
|
||||
uint8_t type; // nalu type
|
||||
uint16_t bytes;
|
||||
uint8_t* data;
|
||||
} nalu[64];
|
||||
|
||||
uint8_t array_completeness;
|
||||
uint8_t data[4 * 1024];
|
||||
int off;
|
||||
};
|
||||
|
||||
int mpeg4_hevc_decoder_configuration_record_load(const uint8_t* data, size_t bytes, struct mpeg4_hevc_t* hevc);
|
||||
|
||||
int mpeg4_hevc_decoder_configuration_record_save(const struct mpeg4_hevc_t* hevc, uint8_t* data, size_t bytes);
|
||||
|
||||
int mpeg4_hevc_to_nalu(const struct mpeg4_hevc_t* hevc, uint8_t* data, size_t bytes);
|
||||
|
||||
int mpeg4_hevc_codecs(const struct mpeg4_hevc_t* hevc, char* codecs, size_t bytes);
|
||||
|
||||
int h265_annexbtomp4(struct mpeg4_hevc_t* hevc, const void* data, int bytes, void* out, int size, int *vcl, int* update);
|
||||
|
||||
int h265_mp4toannexb(const struct mpeg4_hevc_t* hevc, const void* data, int bytes, void* out, int size);
|
||||
|
||||
/// h265_is_new_access_unit H.265 new access unit(frame)
|
||||
/// @return 1-new access, 0-not a new access
|
||||
int h265_is_new_access_unit(const uint8_t* nalu, size_t bytes);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
#endif /* !_mpeg4_hevc_h_ */
|
37
src/3rdpart/media-server/libflv/include/opus-head.h
Normal file
37
src/3rdpart/media-server/libflv/include/opus-head.h
Normal file
@ -0,0 +1,37 @@
|
||||
#ifndef _opus_head_h_
|
||||
#define _opus_head_h_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct opus_head_t
|
||||
{
|
||||
uint8_t version;
|
||||
uint8_t channels;
|
||||
uint16_t pre_skip;
|
||||
uint32_t input_sample_rate;
|
||||
int16_t output_gain;
|
||||
uint8_t channel_mapping_family;
|
||||
uint8_t stream_count;
|
||||
uint8_t coupled_count;
|
||||
uint8_t channel_mapping[8];
|
||||
};
|
||||
|
||||
/// @return >0-ok, <=0-error
|
||||
int opus_head_save(const struct opus_head_t* opus, uint8_t* data, size_t bytes);
|
||||
/// @return >0-ok, <=0-error
|
||||
int opus_head_load(const uint8_t* data, size_t bytes, struct opus_head_t* opus);
|
||||
|
||||
static inline int opus_head_channels(const struct opus_head_t* opus)
|
||||
{
|
||||
return 0 == opus->channels ? 2 : opus->channels;
|
||||
}
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
#endif /* !_opus_head_h_ */
|
32
src/3rdpart/media-server/libflv/include/webm-vpx.h
Normal file
32
src/3rdpart/media-server/libflv/include/webm-vpx.h
Normal file
@ -0,0 +1,32 @@
|
||||
#ifndef _webm_vpx_h_
|
||||
#define _webm_vpx_h_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// VP8/VP9/VP10
|
||||
struct webm_vpx_t
|
||||
{
|
||||
uint8_t profile;
|
||||
uint8_t level;
|
||||
uint8_t bit_depth;
|
||||
uint8_t chroma_subsampling; // 0-4:2:0 vertical, 1-4:2:0 colocated with luma (0,0), 2-4:2:2, 3-4:4:4
|
||||
uint8_t video_full_range_flag; // 0 = legal range (e.g. 16-235 for 8 bit sample depth); 1 = full range (e.g. 0-255 for 8-bit sample depth)
|
||||
uint8_t colour_primaries; // ISO/IEC 23001-8:2016
|
||||
uint8_t transfer_characteristics;
|
||||
uint8_t matrix_coefficients;
|
||||
uint16_t codec_intialization_data_size; // must be 0
|
||||
uint8_t codec_intialization_data[1]; // not used for VP8 and VP9
|
||||
};
|
||||
|
||||
int webm_vpx_codec_configuration_record_load(const uint8_t* data, size_t bytes, struct webm_vpx_t* vpx);
|
||||
int webm_vpx_codec_configuration_record_save(const struct webm_vpx_t* vpx, uint8_t* data, size_t bytes);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
#endif /* !_webm_vpx_h_ */
|
177
src/3rdpart/media-server/libflv/libflv.vcxproj
Normal file
177
src/3rdpart/media-server/libflv/libflv.vcxproj
Normal file
@ -0,0 +1,177 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="include\amf0.h" />
|
||||
<ClInclude Include="include\amf3.h" />
|
||||
<ClInclude Include="include\aom-av1.h" />
|
||||
<ClInclude Include="include\flv-demuxer.h" />
|
||||
<ClInclude Include="include\flv-muxer.h" />
|
||||
<ClInclude Include="include\flv-parser.h" />
|
||||
<ClInclude Include="include\flv-proto.h" />
|
||||
<ClInclude Include="include\flv-reader.h" />
|
||||
<ClInclude Include="include\flv-writer.h" />
|
||||
<ClInclude Include="include\mp3-header.h" />
|
||||
<ClInclude Include="include\mpeg4-aac.h" />
|
||||
<ClInclude Include="include\mpeg4-avc.h" />
|
||||
<ClInclude Include="include\mpeg4-bits.h" />
|
||||
<ClInclude Include="include\mpeg4-hevc.h" />
|
||||
<ClInclude Include="include\opus-head.h" />
|
||||
<ClInclude Include="include\webm-vpx.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="source\amf0.c" />
|
||||
<ClCompile Include="source\amf3.c" />
|
||||
<ClCompile Include="source\aom-av1.c" />
|
||||
<ClCompile Include="source\flv-demuxer-script.c" />
|
||||
<ClCompile Include="source\flv-demuxer.c" />
|
||||
<ClCompile Include="source\flv-header.c" />
|
||||
<ClCompile Include="source\flv-muxer.c" />
|
||||
<ClCompile Include="source\flv-parser.c" />
|
||||
<ClCompile Include="source\flv-reader.c" />
|
||||
<ClCompile Include="source\flv-writer.c" />
|
||||
<ClCompile Include="source\hevc-annexbtomp4.c" />
|
||||
<ClCompile Include="source\hevc-mp4toannexb.c" />
|
||||
<ClCompile Include="source\mp3-header.c" />
|
||||
<ClCompile Include="source\mpeg4-aac-asc.c" />
|
||||
<ClCompile Include="source\mpeg4-aac.c" />
|
||||
<ClCompile Include="source\mpeg4-annexbtomp4.c" />
|
||||
<ClCompile Include="source\mpeg4-avc.c" />
|
||||
<ClCompile Include="source\mpeg4-hevc.c" />
|
||||
<ClCompile Include="source\mpeg4-mp4toannexb.c" />
|
||||
<ClCompile Include="source\opus-head.c" />
|
||||
<ClCompile Include="source\webm-vpx.c" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{D5BA0BB6-0D84-48CB-8630-F617CB6DE375}</ProjectGuid>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<RootNamespace>libflv</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup />
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_LIB;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>.;include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>.;include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_LIB;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>.;include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>.;include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
132
src/3rdpart/media-server/libflv/libflv.vcxproj.filters
Normal file
132
src/3rdpart/media-server/libflv/libflv.vcxproj.filters
Normal file
@ -0,0 +1,132 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Resource Files">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="include\flv-demuxer.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\flv-muxer.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\flv-reader.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\flv-writer.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\mpeg4-aac.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\mpeg4-avc.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\amf0.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\amf3.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\flv-proto.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\mp3-header.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\flv-parser.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\mpeg4-hevc.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\mpeg4-bits.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\aom-av1.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\webm-vpx.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\opus-head.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="source\flv-demuxer.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="source\flv-muxer.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="source\flv-reader.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="source\flv-writer.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="source\mpeg4-aac.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="source\mpeg4-avc.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="source\amf0.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="source\amf3.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="source\mpeg4-mp4toannexb.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="source\mpeg4-annexbtomp4.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="source\mp3-header.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="source\flv-parser.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="source\mpeg4-hevc.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="source\hevc-mp4toannexb.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="source\hevc-annexbtomp4.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="source\flv-demuxer-script.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="source\mpeg4-aac-asc.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="source\aom-av1.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="source\flv-header.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="source\webm-vpx.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="source\opus-head.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
378
src/3rdpart/media-server/libflv/libflv.xcodeproj/project.pbxproj
Normal file
378
src/3rdpart/media-server/libflv/libflv.xcodeproj/project.pbxproj
Normal file
@ -0,0 +1,378 @@
|
||||
// !$*UTF8*$!
|
||||
{
|
||||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 50;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
4605125A24D6B4D500B04B70 /* opus-head.c in Sources */ = {isa = PBXBuildFile; fileRef = 4605125924D6B4D500B04B70 /* opus-head.c */; };
|
||||
46733799219B2315009F658F /* mpeg4-aac-asc.c in Sources */ = {isa = PBXBuildFile; fileRef = 46733798219B2315009F658F /* mpeg4-aac-asc.c */; };
|
||||
468B915C23B8ADAA00EA99A3 /* aom-av1.c in Sources */ = {isa = PBXBuildFile; fileRef = 468B915B23B8ADAA00EA99A3 /* aom-av1.c */; };
|
||||
468B916023B8AE3100EA99A3 /* flv-header.c in Sources */ = {isa = PBXBuildFile; fileRef = 468B915F23B8AE3100EA99A3 /* flv-header.c */; };
|
||||
46C5B2DB2183EDA200419E57 /* mpeg4-mp4toannexb.c in Sources */ = {isa = PBXBuildFile; fileRef = 46C5B2CB2183EDA200419E57 /* mpeg4-mp4toannexb.c */; };
|
||||
46C5B2DC2183EDA200419E57 /* mp3-header.c in Sources */ = {isa = PBXBuildFile; fileRef = 46C5B2CC2183EDA200419E57 /* mp3-header.c */; };
|
||||
46C5B2DD2183EDA200419E57 /* flv-writer.c in Sources */ = {isa = PBXBuildFile; fileRef = 46C5B2CD2183EDA200419E57 /* flv-writer.c */; };
|
||||
46C5B2DE2183EDA200419E57 /* amf0.c in Sources */ = {isa = PBXBuildFile; fileRef = 46C5B2CE2183EDA200419E57 /* amf0.c */; };
|
||||
46C5B2DF2183EDA200419E57 /* hevc-annexbtomp4.c in Sources */ = {isa = PBXBuildFile; fileRef = 46C5B2CF2183EDA200419E57 /* hevc-annexbtomp4.c */; };
|
||||
46C5B2E02183EDA200419E57 /* mpeg4-hevc.c in Sources */ = {isa = PBXBuildFile; fileRef = 46C5B2D02183EDA200419E57 /* mpeg4-hevc.c */; };
|
||||
46C5B2E12183EDA200419E57 /* flv-demuxer.c in Sources */ = {isa = PBXBuildFile; fileRef = 46C5B2D12183EDA200419E57 /* flv-demuxer.c */; };
|
||||
46C5B2E22183EDA200419E57 /* amf3.c in Sources */ = {isa = PBXBuildFile; fileRef = 46C5B2D22183EDA200419E57 /* amf3.c */; };
|
||||
46C5B2E32183EDA200419E57 /* mpeg4-aac.c in Sources */ = {isa = PBXBuildFile; fileRef = 46C5B2D32183EDA200419E57 /* mpeg4-aac.c */; };
|
||||
46C5B2E42183EDA200419E57 /* flv-reader.c in Sources */ = {isa = PBXBuildFile; fileRef = 46C5B2D42183EDA200419E57 /* flv-reader.c */; };
|
||||
46C5B2E52183EDA200419E57 /* flv-demuxer-script.c in Sources */ = {isa = PBXBuildFile; fileRef = 46C5B2D52183EDA200419E57 /* flv-demuxer-script.c */; };
|
||||
46C5B2E62183EDA200419E57 /* mpeg4-annexbtomp4.c in Sources */ = {isa = PBXBuildFile; fileRef = 46C5B2D62183EDA200419E57 /* mpeg4-annexbtomp4.c */; };
|
||||
46C5B2E72183EDA200419E57 /* flv-parser.c in Sources */ = {isa = PBXBuildFile; fileRef = 46C5B2D72183EDA200419E57 /* flv-parser.c */; };
|
||||
46C5B2E82183EDA200419E57 /* flv-muxer.c in Sources */ = {isa = PBXBuildFile; fileRef = 46C5B2D82183EDA200419E57 /* flv-muxer.c */; };
|
||||
46C5B2E92183EDA200419E57 /* mpeg4-avc.c in Sources */ = {isa = PBXBuildFile; fileRef = 46C5B2D92183EDA200419E57 /* mpeg4-avc.c */; };
|
||||
46C5B2EA2183EDA200419E57 /* hevc-mp4toannexb.c in Sources */ = {isa = PBXBuildFile; fileRef = 46C5B2DA2183EDA200419E57 /* hevc-mp4toannexb.c */; };
|
||||
46E55E5324694DE000D8BDBA /* webm-vpx.c in Sources */ = {isa = PBXBuildFile; fileRef = 46E55E5224694DE000D8BDBA /* webm-vpx.c */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
4605125924D6B4D500B04B70 /* opus-head.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "opus-head.c"; sourceTree = "<group>"; };
|
||||
46733798219B2315009F658F /* mpeg4-aac-asc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "mpeg4-aac-asc.c"; sourceTree = "<group>"; };
|
||||
468B915B23B8ADAA00EA99A3 /* aom-av1.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "aom-av1.c"; sourceTree = "<group>"; };
|
||||
468B915F23B8AE3100EA99A3 /* flv-header.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "flv-header.c"; sourceTree = "<group>"; };
|
||||
46C5B21C2183EA7400419E57 /* libflv.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libflv.a; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
46C5B2CB2183EDA200419E57 /* mpeg4-mp4toannexb.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "mpeg4-mp4toannexb.c"; sourceTree = "<group>"; };
|
||||
46C5B2CC2183EDA200419E57 /* mp3-header.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "mp3-header.c"; sourceTree = "<group>"; };
|
||||
46C5B2CD2183EDA200419E57 /* flv-writer.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "flv-writer.c"; sourceTree = "<group>"; };
|
||||
46C5B2CE2183EDA200419E57 /* amf0.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = amf0.c; sourceTree = "<group>"; };
|
||||
46C5B2CF2183EDA200419E57 /* hevc-annexbtomp4.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "hevc-annexbtomp4.c"; sourceTree = "<group>"; };
|
||||
46C5B2D02183EDA200419E57 /* mpeg4-hevc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "mpeg4-hevc.c"; sourceTree = "<group>"; };
|
||||
46C5B2D12183EDA200419E57 /* flv-demuxer.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "flv-demuxer.c"; sourceTree = "<group>"; };
|
||||
46C5B2D22183EDA200419E57 /* amf3.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = amf3.c; sourceTree = "<group>"; };
|
||||
46C5B2D32183EDA200419E57 /* mpeg4-aac.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "mpeg4-aac.c"; sourceTree = "<group>"; };
|
||||
46C5B2D42183EDA200419E57 /* flv-reader.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "flv-reader.c"; sourceTree = "<group>"; };
|
||||
46C5B2D52183EDA200419E57 /* flv-demuxer-script.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "flv-demuxer-script.c"; sourceTree = "<group>"; };
|
||||
46C5B2D62183EDA200419E57 /* mpeg4-annexbtomp4.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "mpeg4-annexbtomp4.c"; sourceTree = "<group>"; };
|
||||
46C5B2D72183EDA200419E57 /* flv-parser.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "flv-parser.c"; sourceTree = "<group>"; };
|
||||
46C5B2D82183EDA200419E57 /* flv-muxer.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "flv-muxer.c"; sourceTree = "<group>"; };
|
||||
46C5B2D92183EDA200419E57 /* mpeg4-avc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "mpeg4-avc.c"; sourceTree = "<group>"; };
|
||||
46C5B2DA2183EDA200419E57 /* hevc-mp4toannexb.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "hevc-mp4toannexb.c"; sourceTree = "<group>"; };
|
||||
46C5B2EB2183EDB400419E57 /* include */ = {isa = PBXFileReference; lastKnownFileType = folder; path = include; sourceTree = "<group>"; };
|
||||
46E55E5224694DE000D8BDBA /* webm-vpx.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = "webm-vpx.c"; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
46C5B21A2183EA7400419E57 /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
46C5B2132183EA7300419E57 = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
46C5B2EB2183EDB400419E57 /* include */,
|
||||
46C5B2CA2183EDA200419E57 /* source */,
|
||||
46C5B21D2183EA7400419E57 /* Products */,
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
46C5B21D2183EA7400419E57 /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
46C5B21C2183EA7400419E57 /* libflv.a */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
46C5B2CA2183EDA200419E57 /* source */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
46C5B2CE2183EDA200419E57 /* amf0.c */,
|
||||
46C5B2D22183EDA200419E57 /* amf3.c */,
|
||||
468B915B23B8ADAA00EA99A3 /* aom-av1.c */,
|
||||
46C5B2D52183EDA200419E57 /* flv-demuxer-script.c */,
|
||||
46C5B2D12183EDA200419E57 /* flv-demuxer.c */,
|
||||
468B915F23B8AE3100EA99A3 /* flv-header.c */,
|
||||
46C5B2D82183EDA200419E57 /* flv-muxer.c */,
|
||||
46C5B2D72183EDA200419E57 /* flv-parser.c */,
|
||||
46C5B2D42183EDA200419E57 /* flv-reader.c */,
|
||||
46C5B2CD2183EDA200419E57 /* flv-writer.c */,
|
||||
46C5B2CF2183EDA200419E57 /* hevc-annexbtomp4.c */,
|
||||
46C5B2DA2183EDA200419E57 /* hevc-mp4toannexb.c */,
|
||||
46C5B2CC2183EDA200419E57 /* mp3-header.c */,
|
||||
46733798219B2315009F658F /* mpeg4-aac-asc.c */,
|
||||
46C5B2D32183EDA200419E57 /* mpeg4-aac.c */,
|
||||
46C5B2D62183EDA200419E57 /* mpeg4-annexbtomp4.c */,
|
||||
46C5B2D92183EDA200419E57 /* mpeg4-avc.c */,
|
||||
46C5B2D02183EDA200419E57 /* mpeg4-hevc.c */,
|
||||
46C5B2CB2183EDA200419E57 /* mpeg4-mp4toannexb.c */,
|
||||
4605125924D6B4D500B04B70 /* opus-head.c */,
|
||||
46E55E5224694DE000D8BDBA /* webm-vpx.c */,
|
||||
);
|
||||
path = source;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXHeadersBuildPhase section */
|
||||
46C5B2182183EA7400419E57 /* Headers */ = {
|
||||
isa = PBXHeadersBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXHeadersBuildPhase section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
46C5B21B2183EA7400419E57 /* libflv */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 46C5B2202183EA7400419E57 /* Build configuration list for PBXNativeTarget "libflv" */;
|
||||
buildPhases = (
|
||||
46C5B2182183EA7400419E57 /* Headers */,
|
||||
46C5B2192183EA7400419E57 /* Sources */,
|
||||
46C5B21A2183EA7400419E57 /* Frameworks */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
name = libflv;
|
||||
productName = libflv;
|
||||
productReference = 46C5B21C2183EA7400419E57 /* libflv.a */;
|
||||
productType = "com.apple.product-type.library.static";
|
||||
};
|
||||
/* End PBXNativeTarget section */
|
||||
|
||||
/* Begin PBXProject section */
|
||||
46C5B2142183EA7300419E57 /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastUpgradeCheck = 1000;
|
||||
ORGANIZATIONNAME = ireader;
|
||||
TargetAttributes = {
|
||||
46C5B21B2183EA7400419E57 = {
|
||||
CreatedOnToolsVersion = 10.0;
|
||||
};
|
||||
};
|
||||
};
|
||||
buildConfigurationList = 46C5B2172183EA7300419E57 /* Build configuration list for PBXProject "libflv" */;
|
||||
compatibilityVersion = "Xcode 9.3";
|
||||
developmentRegion = en;
|
||||
hasScannedForEncodings = 0;
|
||||
knownRegions = (
|
||||
en,
|
||||
Base,
|
||||
);
|
||||
mainGroup = 46C5B2132183EA7300419E57;
|
||||
productRefGroup = 46C5B21D2183EA7400419E57 /* Products */;
|
||||
projectDirPath = "";
|
||||
projectRoot = "";
|
||||
targets = (
|
||||
46C5B21B2183EA7400419E57 /* libflv */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
46C5B2192183EA7400419E57 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
46C5B2E12183EDA200419E57 /* flv-demuxer.c in Sources */,
|
||||
46C5B2DB2183EDA200419E57 /* mpeg4-mp4toannexb.c in Sources */,
|
||||
46C5B2E92183EDA200419E57 /* mpeg4-avc.c in Sources */,
|
||||
468B916023B8AE3100EA99A3 /* flv-header.c in Sources */,
|
||||
46C5B2E62183EDA200419E57 /* mpeg4-annexbtomp4.c in Sources */,
|
||||
468B915C23B8ADAA00EA99A3 /* aom-av1.c in Sources */,
|
||||
46C5B2E02183EDA200419E57 /* mpeg4-hevc.c in Sources */,
|
||||
46C5B2DC2183EDA200419E57 /* mp3-header.c in Sources */,
|
||||
46C5B2EA2183EDA200419E57 /* hevc-mp4toannexb.c in Sources */,
|
||||
46C5B2DD2183EDA200419E57 /* flv-writer.c in Sources */,
|
||||
46C5B2E82183EDA200419E57 /* flv-muxer.c in Sources */,
|
||||
46C5B2E42183EDA200419E57 /* flv-reader.c in Sources */,
|
||||
46C5B2E52183EDA200419E57 /* flv-demuxer-script.c in Sources */,
|
||||
46C5B2E72183EDA200419E57 /* flv-parser.c in Sources */,
|
||||
46C5B2DF2183EDA200419E57 /* hevc-annexbtomp4.c in Sources */,
|
||||
46C5B2E22183EDA200419E57 /* amf3.c in Sources */,
|
||||
46733799219B2315009F658F /* mpeg4-aac-asc.c in Sources */,
|
||||
46C5B2DE2183EDA200419E57 /* amf0.c in Sources */,
|
||||
46E55E5324694DE000D8BDBA /* webm-vpx.c in Sources */,
|
||||
4605125A24D6B4D500B04B70 /* opus-head.c in Sources */,
|
||||
46C5B2E32183EDA200419E57 /* mpeg4-aac.c in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXSourcesBuildPhase section */
|
||||
|
||||
/* Begin XCBuildConfiguration section */
|
||||
46C5B21E2183EA7400419E57 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
CODE_SIGN_IDENTITY = "-";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
ENABLE_TESTABILITY = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_OPTIMIZATION_LEVEL = 0;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"DEBUG=1",
|
||||
"$(inherited)",
|
||||
);
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.13;
|
||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||
MTL_FAST_MATH = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
SDKROOT = macosx;
|
||||
USER_HEADER_SEARCH_PATHS = (
|
||||
.,
|
||||
./include,
|
||||
../../sdk/include,
|
||||
);
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
46C5B21F2183EA7400419E57 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
CODE_SIGN_IDENTITY = "-";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.13;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
MTL_FAST_MATH = YES;
|
||||
SDKROOT = macosx;
|
||||
USER_HEADER_SEARCH_PATHS = (
|
||||
.,
|
||||
./include,
|
||||
../../sdk/include,
|
||||
);
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
46C5B2212183EA7400419E57 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
EXECUTABLE_PREFIX = "";
|
||||
GCC_PREPROCESSOR_DEFINITIONS = "$(inherited)";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SKIP_INSTALL = YES;
|
||||
USER_HEADER_SEARCH_PATHS = "$(inherited)";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
46C5B2222183EA7400419E57 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
EXECUTABLE_PREFIX = "";
|
||||
GCC_PREPROCESSOR_DEFINITIONS = "$(inherited)";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SKIP_INSTALL = YES;
|
||||
USER_HEADER_SEARCH_PATHS = "$(inherited)";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
/* End XCBuildConfiguration section */
|
||||
|
||||
/* Begin XCConfigurationList section */
|
||||
46C5B2172183EA7300419E57 /* Build configuration list for PBXProject "libflv" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
46C5B21E2183EA7400419E57 /* Debug */,
|
||||
46C5B21F2183EA7400419E57 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
46C5B2202183EA7400419E57 /* Build configuration list for PBXNativeTarget "libflv" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
46C5B2212183EA7400419E57 /* Debug */,
|
||||
46C5B2222183EA7400419E57 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
/* End XCConfigurationList section */
|
||||
};
|
||||
rootObject = 46C5B2142183EA7300419E57 /* Project object */;
|
||||
}
|
589
src/3rdpart/media-server/libflv/source/amf0.c
Normal file
589
src/3rdpart/media-server/libflv/source/amf0.c
Normal file
@ -0,0 +1,589 @@
|
||||
#include "amf0.h"
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
static double s_double = 1.0; // 3ff0 0000 0000 0000
|
||||
|
||||
static uint8_t* AMFWriteInt16(uint8_t* ptr, const uint8_t* end, uint16_t value)
|
||||
{
|
||||
if (ptr + 2 > end) return NULL;
|
||||
ptr[0] = value >> 8;
|
||||
ptr[1] = value & 0xFF;
|
||||
return ptr + 2;
|
||||
}
|
||||
|
||||
static uint8_t* AMFWriteInt32(uint8_t* ptr, const uint8_t* end, uint32_t value)
|
||||
{
|
||||
if (ptr + 4 > end) return NULL;
|
||||
ptr[0] = (uint8_t)(value >> 24);
|
||||
ptr[1] = (uint8_t)(value >> 16);
|
||||
ptr[2] = (uint8_t)(value >> 8);
|
||||
ptr[3] = (uint8_t)(value & 0xFF);
|
||||
return ptr + 4;
|
||||
}
|
||||
|
||||
static uint8_t* AMFWriteString16(uint8_t* ptr, const uint8_t* end, const char* string, size_t length)
|
||||
{
|
||||
if (ptr + 2 + length > end) return NULL;
|
||||
ptr = AMFWriteInt16(ptr, end, (uint16_t)length);
|
||||
memcpy(ptr, string, length);
|
||||
return ptr + length;
|
||||
}
|
||||
|
||||
static uint8_t* AMFWriteString32(uint8_t* ptr, const uint8_t* end, const char* string, size_t length)
|
||||
{
|
||||
if (ptr + 4 + length > end) return NULL;
|
||||
ptr = AMFWriteInt32(ptr, end, (uint32_t)length);
|
||||
memcpy(ptr, string, length);
|
||||
return ptr + length;
|
||||
}
|
||||
|
||||
uint8_t* AMFWriteNull(uint8_t* ptr, const uint8_t* end)
|
||||
{
|
||||
if (!ptr || ptr + 1 > end) return NULL;
|
||||
|
||||
*ptr++ = AMF_NULL;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
uint8_t* AMFWriteUndefined(uint8_t* ptr, const uint8_t* end)
|
||||
{
|
||||
if (!ptr || ptr + 1 > end) return NULL;
|
||||
|
||||
*ptr++ = AMF_UNDEFINED;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
uint8_t* AMFWriteObject(uint8_t* ptr, const uint8_t* end)
|
||||
{
|
||||
if (!ptr || ptr + 1 > end) return NULL;
|
||||
|
||||
*ptr++ = AMF_OBJECT;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
uint8_t* AMFWriteObjectEnd(uint8_t* ptr, const uint8_t* end)
|
||||
{
|
||||
if (!ptr || ptr + 3 > end) return NULL;
|
||||
|
||||
/* end of object - 0x00 0x00 0x09 */
|
||||
*ptr++ = 0;
|
||||
*ptr++ = 0;
|
||||
*ptr++ = AMF_OBJECT_END;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
uint8_t* AMFWriteTypedObject(uint8_t* ptr, const uint8_t* end)
|
||||
{
|
||||
if (!ptr || ptr + 1 > end) return NULL;
|
||||
|
||||
*ptr++ = AMF_TYPED_OBJECT;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
uint8_t* AMFWriteECMAArarry(uint8_t* ptr, const uint8_t* end)
|
||||
{
|
||||
if (!ptr || ptr + 1 > end) return NULL;
|
||||
|
||||
*ptr++ = AMF_ECMA_ARRAY;
|
||||
return AMFWriteInt32(ptr, end, 0); // U32 associative-count
|
||||
}
|
||||
|
||||
uint8_t* AMFWriteBoolean(uint8_t* ptr, const uint8_t* end, uint8_t value)
|
||||
{
|
||||
if (!ptr || ptr + 2 > end) return NULL;
|
||||
|
||||
ptr[0] = AMF_BOOLEAN;
|
||||
ptr[1] = 0 == value ? 0 : 1;
|
||||
return ptr + 2;
|
||||
}
|
||||
|
||||
uint8_t* AMFWriteDouble(uint8_t* ptr, const uint8_t* end, double value)
|
||||
{
|
||||
if (!ptr || ptr + 9 > end) return NULL;
|
||||
|
||||
assert(8 == sizeof(double));
|
||||
*ptr++ = AMF_NUMBER;
|
||||
|
||||
// Little-Endian
|
||||
if (0x00 == *(char*)&s_double)
|
||||
{
|
||||
*ptr++ = ((uint8_t*)&value)[7];
|
||||
*ptr++ = ((uint8_t*)&value)[6];
|
||||
*ptr++ = ((uint8_t*)&value)[5];
|
||||
*ptr++ = ((uint8_t*)&value)[4];
|
||||
*ptr++ = ((uint8_t*)&value)[3];
|
||||
*ptr++ = ((uint8_t*)&value)[2];
|
||||
*ptr++ = ((uint8_t*)&value)[1];
|
||||
*ptr++ = ((uint8_t*)&value)[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(ptr, &value, 8);
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
uint8_t* AMFWriteString(uint8_t* ptr, const uint8_t* end, const char* string, size_t length)
|
||||
{
|
||||
if (!ptr || ptr + 1 + (length < 65536 ? 2 : 4) + length > end || length > UINT32_MAX)
|
||||
return NULL;
|
||||
|
||||
if (length < 65536)
|
||||
{
|
||||
*ptr++ = AMF_STRING;
|
||||
AMFWriteString16(ptr, end, string, length);
|
||||
ptr += 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
*ptr++ = AMF_LONG_STRING;
|
||||
AMFWriteString32(ptr, end, string, length);
|
||||
ptr += 4;
|
||||
}
|
||||
return ptr + length;
|
||||
}
|
||||
|
||||
uint8_t* AMFWriteDate(uint8_t* ptr, const uint8_t* end, double milliseconds, int16_t timezone)
|
||||
{
|
||||
if (!ptr || ptr + 11 > end)
|
||||
return NULL;
|
||||
|
||||
AMFWriteDouble(ptr, end, milliseconds);
|
||||
*ptr = AMF_DATE; // rewrite to date
|
||||
return AMFWriteInt16(ptr + 8, end, timezone);
|
||||
}
|
||||
|
||||
uint8_t* AMFWriteNamedBoolean(uint8_t* ptr, const uint8_t* end, const char* name, size_t length, uint8_t value)
|
||||
{
|
||||
if (ptr + length + 2 + 2 > end)
|
||||
return NULL;
|
||||
|
||||
ptr = AMFWriteString16(ptr, end, name, length);
|
||||
return ptr ? AMFWriteBoolean(ptr, end, value) : NULL;
|
||||
}
|
||||
|
||||
uint8_t* AMFWriteNamedDouble(uint8_t* ptr, const uint8_t* end, const char* name, size_t length, double value)
|
||||
{
|
||||
if (ptr + length + 2 + 8 + 1 > end)
|
||||
return NULL;
|
||||
|
||||
ptr = AMFWriteString16(ptr, end, name, length);
|
||||
return ptr ? AMFWriteDouble(ptr, end, value) : NULL;
|
||||
}
|
||||
|
||||
uint8_t* AMFWriteNamedString(uint8_t* ptr, const uint8_t* end, const char* name, size_t length, const char* value, size_t length2)
|
||||
{
|
||||
if (ptr + length + 2 + length2 + 3 > end)
|
||||
return NULL;
|
||||
|
||||
ptr = AMFWriteString16(ptr, end, name, length);
|
||||
return ptr ? AMFWriteString(ptr, end, value, length2) : NULL;
|
||||
}
|
||||
|
||||
static const uint8_t* AMFReadInt16(const uint8_t* ptr, const uint8_t* end, uint32_t* value)
|
||||
{
|
||||
if (!ptr || ptr + 2 > end)
|
||||
return NULL;
|
||||
|
||||
if (value)
|
||||
{
|
||||
*value = ((uint32_t)ptr[0] << 8) | ptr[1];
|
||||
}
|
||||
return ptr + 2;
|
||||
}
|
||||
|
||||
static const uint8_t* AMFReadInt32(const uint8_t* ptr, const uint8_t* end, uint32_t* value)
|
||||
{
|
||||
if (!ptr || ptr + 4 > end)
|
||||
return NULL;
|
||||
|
||||
if (value)
|
||||
{
|
||||
*value = ((uint32_t)ptr[0] << 24) | ((uint32_t)ptr[1] << 16) | ((uint32_t)ptr[2] << 8) | ptr[3];
|
||||
}
|
||||
return ptr + 4;
|
||||
}
|
||||
|
||||
const uint8_t* AMFReadNull(const uint8_t* ptr, const uint8_t* end)
|
||||
{
|
||||
(void)end;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
const uint8_t* AMFReadUndefined(const uint8_t* ptr, const uint8_t* end)
|
||||
{
|
||||
(void)end;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
const uint8_t* AMFReadBoolean(const uint8_t* ptr, const uint8_t* end, uint8_t* value)
|
||||
{
|
||||
if (!ptr || ptr + 1 > end)
|
||||
return NULL;
|
||||
|
||||
if (value)
|
||||
{
|
||||
*value = ptr[0];
|
||||
}
|
||||
return ptr + 1;
|
||||
}
|
||||
|
||||
const uint8_t* AMFReadDouble(const uint8_t* ptr, const uint8_t* end, double* value)
|
||||
{
|
||||
uint8_t* p = (uint8_t*)value;
|
||||
if (!ptr || ptr + 8 > end)
|
||||
return NULL;
|
||||
|
||||
if (value)
|
||||
{
|
||||
if (0x00 == *(char*)&s_double)
|
||||
{// Little-Endian
|
||||
*p++ = ptr[7];
|
||||
*p++ = ptr[6];
|
||||
*p++ = ptr[5];
|
||||
*p++ = ptr[4];
|
||||
*p++ = ptr[3];
|
||||
*p++ = ptr[2];
|
||||
*p++ = ptr[1];
|
||||
*p++ = ptr[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(value, ptr, 8);
|
||||
}
|
||||
}
|
||||
return ptr + 8;
|
||||
}
|
||||
|
||||
const uint8_t* AMFReadString(const uint8_t* ptr, const uint8_t* end, int isLongString, char* string, size_t length)
|
||||
{
|
||||
uint32_t len = 0;
|
||||
if (0 == isLongString)
|
||||
ptr = AMFReadInt16(ptr, end, &len);
|
||||
else
|
||||
ptr = AMFReadInt32(ptr, end, &len);
|
||||
|
||||
if (!ptr || ptr + len > end)
|
||||
return NULL;
|
||||
|
||||
if (string && length > len)
|
||||
{
|
||||
memcpy(string, ptr, len);
|
||||
string[len] = 0;
|
||||
}
|
||||
return ptr + len;
|
||||
}
|
||||
|
||||
const uint8_t* AMFReadDate(const uint8_t* ptr, const uint8_t* end, double *milliseconds, int16_t *timezone)
|
||||
{
|
||||
uint32_t v;
|
||||
ptr = AMFReadDouble(ptr, end, milliseconds);
|
||||
if (ptr)
|
||||
{
|
||||
ptr = AMFReadInt16(ptr, end, &v);
|
||||
*timezone = (int16_t)v;
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
static const uint8_t* amf_read_object(const uint8_t* data, const uint8_t* end, struct amf_object_item_t* items, size_t n);
|
||||
static const uint8_t* amf_read_ecma_array(const uint8_t* data, const uint8_t* end, struct amf_object_item_t* items, size_t n);
|
||||
static const uint8_t* amf_read_strict_array(const uint8_t* ptr, const uint8_t* end, struct amf_object_item_t* items, size_t n);
|
||||
|
||||
static const uint8_t* amf_read_item(const uint8_t* data, const uint8_t* end, enum AMFDataType type, struct amf_object_item_t* item)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case AMF_BOOLEAN:
|
||||
return AMFReadBoolean(data, end, (uint8_t*)(item ? item->value : NULL));
|
||||
|
||||
case AMF_NUMBER:
|
||||
return AMFReadDouble(data, end, (double*)(item ? item->value : NULL));
|
||||
|
||||
case AMF_STRING:
|
||||
return AMFReadString(data, end, 0, (char*)(item ? item->value : NULL), item ? item->size : 0);
|
||||
|
||||
case AMF_LONG_STRING:
|
||||
return AMFReadString(data, end, 1, (char*)(item ? item->value : NULL), item ? item->size : 0);
|
||||
|
||||
case AMF_DATE:
|
||||
return AMFReadDate(data, end, (double*)(item ? item->value : NULL), (int16_t*)(item ? (char*)item->value + 8 : NULL));
|
||||
|
||||
case AMF_OBJECT:
|
||||
return amf_read_object(data, end, (struct amf_object_item_t*)(item ? item->value : NULL), item ? item->size : 0);
|
||||
|
||||
case AMF_NULL:
|
||||
return data;
|
||||
|
||||
case AMF_UNDEFINED:
|
||||
return data;
|
||||
|
||||
case AMF_ECMA_ARRAY:
|
||||
return amf_read_ecma_array(data, end, (struct amf_object_item_t*)(item ? item->value : NULL), item ? item->size : 0);
|
||||
|
||||
case AMF_STRICT_ARRAY:
|
||||
return amf_read_strict_array(data, end, (struct amf_object_item_t*)(item ? item->value : NULL), item ? item->size : 0);
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static inline int amf_read_item_type_check(uint8_t type0, uint8_t itemtype)
|
||||
{
|
||||
// decode AMF_ECMA_ARRAY as AMF_OBJECT
|
||||
return (type0 == itemtype || (AMF_OBJECT == itemtype && (AMF_ECMA_ARRAY == type0 || AMF_NULL == type0))) ? 1 : 0;
|
||||
}
|
||||
|
||||
static const uint8_t* amf_read_strict_array(const uint8_t* ptr, const uint8_t* end, struct amf_object_item_t* items, size_t n)
|
||||
{
|
||||
uint8_t type;
|
||||
uint32_t i, count;
|
||||
if (!ptr || ptr + 4 > end)
|
||||
return NULL;
|
||||
|
||||
ptr = AMFReadInt32(ptr, end, &count); // U32 array-count
|
||||
for (i = 0; i < count && ptr && ptr < end; i++)
|
||||
{
|
||||
type = *ptr++;
|
||||
ptr = amf_read_item(ptr, end, type, (i < n && amf_read_item_type_check(type, items[i].type)) ? &items[i] : NULL);
|
||||
}
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
static const uint8_t* amf_read_ecma_array(const uint8_t* ptr, const uint8_t* end, struct amf_object_item_t* items, size_t n)
|
||||
{
|
||||
if (!ptr || ptr + 4 > end)
|
||||
return NULL;
|
||||
ptr += 4; // U32 associative-count
|
||||
return amf_read_object(ptr, end, items, n);
|
||||
}
|
||||
|
||||
static const uint8_t* amf_read_object(const uint8_t* data, const uint8_t* end, struct amf_object_item_t* items, size_t n)
|
||||
{
|
||||
uint8_t type;
|
||||
uint32_t len;
|
||||
size_t i;
|
||||
|
||||
while (data && data + 2 <= end)
|
||||
{
|
||||
len = *data++ << 8;
|
||||
len |= *data++;
|
||||
if (0 == len)
|
||||
break; // last item
|
||||
|
||||
if (data + len + 1 > end)
|
||||
return NULL; // invalid
|
||||
|
||||
for (i = 0; i < n; i++)
|
||||
{
|
||||
if (strlen(items[i].name) == len && 0 == memcmp(items[i].name, data, len) && amf_read_item_type_check(data[len], items[i].type))
|
||||
break;
|
||||
}
|
||||
|
||||
data += len; // skip name string
|
||||
type = *data++; // value type
|
||||
data = amf_read_item(data, end, type, i < n ? &items[i] : NULL);
|
||||
}
|
||||
|
||||
if (data && data < end && AMF_OBJECT_END == *data)
|
||||
return data + 1;
|
||||
return NULL; // invalid object
|
||||
}
|
||||
|
||||
const uint8_t* amf_read_items(const uint8_t* data, const uint8_t* end, struct amf_object_item_t* items, size_t count)
|
||||
{
|
||||
size_t i;
|
||||
uint8_t type;
|
||||
for (i = 0; i < count && data && data < end; i++)
|
||||
{
|
||||
type = *data++;
|
||||
if (!amf_read_item_type_check(type, items[i].type))
|
||||
return NULL;
|
||||
|
||||
data = amf_read_item(data, end, type, &items[i]);
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
#if defined(_DEBUG) || defined(DEBUG)
|
||||
struct rtmp_amf0_command_t
|
||||
{
|
||||
char fmsVer[64];
|
||||
double capabilities;
|
||||
double mode;
|
||||
};
|
||||
struct rtmp_amf0_data_t
|
||||
{
|
||||
char version[64];
|
||||
};
|
||||
struct rtmp_amf0_information_t
|
||||
{
|
||||
char code[64]; // NetStream.Play.Start
|
||||
char level[8]; // warning/status/error
|
||||
char description[256];
|
||||
double clientid;
|
||||
double objectEncoding;
|
||||
struct rtmp_amf0_data_t data;
|
||||
};
|
||||
static void amf0_test_1(void)
|
||||
{
|
||||
const uint8_t amf0[] = {
|
||||
0x02, 0x00, 0x07, 0x5F, 0x72, 0x65, 0x73, 0x75, 0x6C, 0x74,
|
||||
0x00, 0x3F, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
|
||||
0x03,
|
||||
0x00, 0x06, 0x66, 0x6D, 0x73, 0x56, 0x65, 0x72, 0x02, 0x00, 0x0E, 0x46, 0x4D, 0x53, 0x2F, 0x33, 0x2C, 0x35, 0x2C, 0x35, 0x2C, 0x32, 0x30, 0x30, 0x34,
|
||||
0x00, 0x0C, 0x63, 0x61, 0x70,0x61, 0x62, 0x69, 0x6C, 0x69, 0x74, 0x69, 0x65, 0x73, 0x00, 0x40, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x04, 0x6D, 0x6F, 0x64, 0x65, 0x00, 0x3F, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x09,
|
||||
|
||||
0x03,
|
||||
0x00, 0x05, 0x6C, 0x65, 0x76, 0x65, 0x6C, 0x02, 0x00, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73,
|
||||
0x00, 0x04, 0x63, 0x6F, 0x64, 0x65, 0x02, 0x00, 0x1D, 0x4E, 0x65, 0x74, 0x43, 0x6F, 0x6E, 0x6E, 0x65, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x2E, 0x43, 0x6F, 0x6E, 0x6E, 0x65, 0x63, 0x74, 0x2E, 0x53, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73,
|
||||
0x00, 0x0B, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x02, 0x00, 0x15, 0x43, 0x6F, 0x6E, 0x6E, 0x65, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x73, 0x75, 0x63, 0x63, 0x65, 0x65, 0x64, 0x65, 0x64, 0x2E,
|
||||
0x00, 0x04, 0x64, 0x61, 0x74, 0x61,
|
||||
0x08, 0x00, 0x00, 0x00, 0x01,
|
||||
0x00, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x02, 0x00, 0x0A, 0x33, 0x2C, 0x35, 0x2C, 0x35, 0x2C, 0x32, 0x30, 0x30, 0x34,
|
||||
0x00, 0x00, 0x09,
|
||||
0x00, 0x08, 0x63, 0x6C, 0x69, 0x65, 0x6E, 0x74, 0x69, 0x64, 0x00, 0x41, 0xD7, 0x9B, 0x78, 0x7C, 0xC0, 0x00, 0x00,
|
||||
0x00, 0x0E, 0x6F, 0x62, 0x6A, 0x65, 0x63, 0x74, 0x45, 0x6E, 0x63, 0x6F, 0x64, 0x69, 0x6E, 0x67, 0x00, 0x40, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x09,
|
||||
};
|
||||
|
||||
char reply[8];
|
||||
const uint8_t* end;
|
||||
double transactionId;
|
||||
struct rtmp_amf0_command_t fms;
|
||||
struct rtmp_amf0_information_t result;
|
||||
struct amf_object_item_t cmd[3];
|
||||
struct amf_object_item_t data[1];
|
||||
struct amf_object_item_t info[6];
|
||||
struct amf_object_item_t items[4];
|
||||
|
||||
#define AMF_OBJECT_ITEM_VALUE(v, amf_type, amf_name, amf_value, amf_size) { v.type=amf_type; v.name=amf_name; v.value=amf_value; v.size=amf_size; }
|
||||
AMF_OBJECT_ITEM_VALUE(cmd[0], AMF_STRING, "fmsVer", fms.fmsVer, sizeof(fms.fmsVer));
|
||||
AMF_OBJECT_ITEM_VALUE(cmd[1], AMF_NUMBER, "capabilities", &fms.capabilities, sizeof(fms.capabilities));
|
||||
AMF_OBJECT_ITEM_VALUE(cmd[2], AMF_NUMBER, "mode", &fms.mode, sizeof(fms.mode));
|
||||
|
||||
AMF_OBJECT_ITEM_VALUE(data[0], AMF_STRING, "version", result.data.version, sizeof(result.data.version));
|
||||
|
||||
AMF_OBJECT_ITEM_VALUE(info[0], AMF_STRING, "code", result.code, sizeof(result.code));
|
||||
AMF_OBJECT_ITEM_VALUE(info[1], AMF_STRING, "level", result.level, sizeof(result.level));
|
||||
AMF_OBJECT_ITEM_VALUE(info[2], AMF_STRING, "description", result.description, sizeof(result.description));
|
||||
AMF_OBJECT_ITEM_VALUE(info[3], AMF_ECMA_ARRAY, "data", data, sizeof(data)/sizeof(data[0]));
|
||||
AMF_OBJECT_ITEM_VALUE(info[4], AMF_NUMBER, "clientid", &result.clientid, sizeof(result.clientid));
|
||||
AMF_OBJECT_ITEM_VALUE(info[5], AMF_NUMBER, "objectEncoding", &result.objectEncoding, sizeof(result.objectEncoding));
|
||||
|
||||
AMF_OBJECT_ITEM_VALUE(items[0], AMF_STRING, "reply", reply, sizeof(reply)); // Command object
|
||||
AMF_OBJECT_ITEM_VALUE(items[1], AMF_NUMBER, "transaction", &transactionId, sizeof(transactionId)); // Command object
|
||||
AMF_OBJECT_ITEM_VALUE(items[2], AMF_OBJECT, "command", cmd, sizeof(cmd)/sizeof(cmd[0])); // Command object
|
||||
AMF_OBJECT_ITEM_VALUE(items[3], AMF_OBJECT, "information", info, sizeof(info) / sizeof(info[0])); // Information object
|
||||
|
||||
end = amf0 + sizeof(amf0);
|
||||
assert(end == amf_read_items(amf0, end, items, sizeof(items) / sizeof(items[0])));
|
||||
assert(0 == strcmp(fms.fmsVer, "FMS/3,5,5,2004"));
|
||||
assert(fms.capabilities == 31.0);
|
||||
assert(fms.mode == 1.0);
|
||||
assert(0 == strcmp(result.code, "NetConnection.Connect.Success"));
|
||||
assert(0 == strcmp(result.level, "status"));
|
||||
assert(0 == strcmp(result.description, "Connection succeeded."));
|
||||
assert(0 == strcmp(result.data.version, "3,5,5,2004"));
|
||||
assert(1584259571.0 == result.clientid);
|
||||
assert(3.0 == result.objectEncoding);
|
||||
}
|
||||
|
||||
struct rtmp_amf0_connect_t
|
||||
{
|
||||
char app[64]; // Server application name, e.g.: testapp
|
||||
char flashver[32]; // Flash Player version, FMSc/1.0
|
||||
char swfUrl[256]; // URL of the source SWF file
|
||||
char tcUrl[256]; // URL of the Server, rtmp://host:1935/testapp/instance1
|
||||
uint8_t fpad; // boolean: True if proxy is being used.
|
||||
double capabilities; // double default: 15
|
||||
double audioCodecs; // double default: 4071
|
||||
double videoCodecs; // double default: 252
|
||||
double videoFunction; // double default: 1
|
||||
double encoding;
|
||||
char pageUrl[256]; // http://host/sample.html
|
||||
};
|
||||
|
||||
static void amf0_test_2(void)
|
||||
{
|
||||
const uint8_t amf0[] = {
|
||||
0x02, 0x00, 0x07, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x00, 0x3f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x03, 0x00,
|
||||
0x03, 0x61, 0x70,
|
||||
0x70, 0x02, 0x00, 0x06, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x2f, 0x00, 0x05, 0x74, 0x63, 0x55, 0x72,
|
||||
0x6c, 0x02, 0x00, 0x28, 0x72, 0x74, 0x6d, 0x70, 0x3a, 0x2f, 0x2f, 0x70, 0x75, 0x73, 0x68, 0x2d,
|
||||
0x72, 0x74, 0x6d, 0x70, 0x2d, 0x66, 0x35, 0x2d, 0x78, 0x67, 0x2e, 0x69, 0x78, 0x69, 0x67, 0x75,
|
||||
0x61, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x2f, 0x00, 0x04, 0x74, 0x79,
|
||||
0x70, 0x65, 0x02, 0x00, 0x0a, 0x6e, 0x6f, 0x6e, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x00,
|
||||
0x08, 0x66, 0x6c, 0x61, 0x73, 0x68, 0x56, 0x65, 0x72, 0x02, 0x00, 0x1f, 0x46, 0x4d, 0x4c, 0x45,
|
||||
0x2f, 0x33, 0x2e, 0x30, 0x20, 0x28, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x74, 0x69, 0x62, 0x6c,
|
||||
0x65, 0x3b, 0x20, 0x46, 0x4d, 0x53, 0x63, 0x2f, 0x31, 0x2e, 0x30, 0x29, 0x00, 0x06, 0x73, 0x77,
|
||||
0x66, 0x55, 0x72, 0x6c, 0x02, 0x00, 0x28, 0x72, 0x74, 0x6d, 0x70, 0x3a, 0x2f, 0x2f, 0x70, 0x75,
|
||||
0x73, 0x68, 0x2d, 0x72, 0x74, 0x6d, 0x70, 0x2d, 0x66, 0x35, 0x2d, 0x78, 0x67, 0x2e, 0x69, 0x78,
|
||||
0x69, 0x67, 0x75, 0x61, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x2f, 0x00,
|
||||
0x04, 0x66, 0x70, 0x61, 0x64, 0x01, 0x00, 0x00, 0x0c, 0x63, 0x61, 0x70, 0x61, 0x62, 0x69, 0x6c,
|
||||
0x69, 0x74, 0x69, 0x65, 0x73, 0x00, 0x40, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b,
|
||||
0x61, 0x75, 0x64, 0x69, 0x6f, 0x43, 0x6f, 0x64, 0x65, 0x63, 0x73, 0x00, 0x40, 0xa8, 0xee, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x43, 0x6f, 0x64, 0x65,
|
||||
0x63, 0x73, 0x00, 0x40, 0x6f, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x76, 0x69, 0x64,
|
||||
0x65, 0x6f, 0x46, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x3f, 0xf0, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x07, 0x70, 0x61, 0x67, 0x65, 0x55, 0x72, 0x6c, 0x06, 0x00, 0x0e, 0x6f,
|
||||
0x62, 0x6a, 0x65, 0x63, 0x74, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09,
|
||||
};
|
||||
|
||||
char reply[8];
|
||||
const uint8_t* end;
|
||||
double transactionId;
|
||||
struct rtmp_amf0_connect_t connect;
|
||||
struct amf_object_item_t commands[11];
|
||||
struct amf_object_item_t items[3];
|
||||
|
||||
#define AMF_OBJECT_ITEM_VALUE(v, amf_type, amf_name, amf_value, amf_size) { v.type=amf_type; v.name=amf_name; v.value=amf_value; v.size=amf_size; }
|
||||
AMF_OBJECT_ITEM_VALUE(commands[0], AMF_STRING, "app", connect.app, sizeof(connect.app));
|
||||
AMF_OBJECT_ITEM_VALUE(commands[1], AMF_STRING, "flashVer", connect.flashver, sizeof(connect.flashver));
|
||||
AMF_OBJECT_ITEM_VALUE(commands[2], AMF_STRING, "tcUrl", connect.tcUrl, sizeof(connect.tcUrl));
|
||||
AMF_OBJECT_ITEM_VALUE(commands[3], AMF_BOOLEAN, "fpad", &connect.fpad, 1);
|
||||
AMF_OBJECT_ITEM_VALUE(commands[4], AMF_NUMBER, "audioCodecs", &connect.audioCodecs, 8);
|
||||
AMF_OBJECT_ITEM_VALUE(commands[5], AMF_NUMBER, "videoCodecs", &connect.videoCodecs, 8);
|
||||
AMF_OBJECT_ITEM_VALUE(commands[6], AMF_NUMBER, "videoFunction", &connect.videoFunction, 8);
|
||||
AMF_OBJECT_ITEM_VALUE(commands[7], AMF_NUMBER, "objectEncoding", &connect.encoding, 8);
|
||||
AMF_OBJECT_ITEM_VALUE(commands[8], AMF_NUMBER, "capabilities", &connect.capabilities, 8);
|
||||
AMF_OBJECT_ITEM_VALUE(commands[9], AMF_STRING, "pageUrl", &connect.pageUrl, sizeof(connect.pageUrl));
|
||||
AMF_OBJECT_ITEM_VALUE(commands[10], AMF_STRING, "swfUrl", &connect.swfUrl, sizeof(connect.swfUrl));
|
||||
|
||||
AMF_OBJECT_ITEM_VALUE(items[0], AMF_STRING, "reply", reply, sizeof(reply)); // Command object
|
||||
AMF_OBJECT_ITEM_VALUE(items[1], AMF_NUMBER, "transaction", &transactionId, sizeof(transactionId)); // Command object
|
||||
AMF_OBJECT_ITEM_VALUE(items[2], AMF_OBJECT, "command", commands, sizeof(commands) / sizeof(commands[0])); // Command object
|
||||
|
||||
end = amf0 + sizeof(amf0);
|
||||
memset(&connect, 0, sizeof(connect));
|
||||
assert(end == amf_read_items(amf0, end, items, sizeof(items) / sizeof(items[0])));
|
||||
assert(0 == strcmp(connect.app, "media/"));
|
||||
assert(0 == strcmp(connect.tcUrl, "rtmp://push-rtmp-f5-xg.ixigua.com/media/"));
|
||||
assert(0 == strcmp(connect.flashver, "FMLE/3.0 (compatible; FMSc/1.0)"));
|
||||
assert(0 == strcmp(connect.swfUrl, "rtmp://push-rtmp-f5-xg.ixigua.com/media/"));
|
||||
assert(0 == strcmp(connect.pageUrl, "")); // pageUrl undefined
|
||||
assert(connect.fpad == 0);
|
||||
assert(connect.capabilities == 15);
|
||||
assert(connect.audioCodecs == 3191);
|
||||
assert(connect.videoCodecs == 252);
|
||||
assert(connect.videoFunction == 1);
|
||||
assert(connect.encoding == 0);
|
||||
}
|
||||
|
||||
void amf0_test(void)
|
||||
{
|
||||
amf0_test_1();
|
||||
amf0_test_2();
|
||||
}
|
||||
#endif
|
95
src/3rdpart/media-server/libflv/source/amf3.c
Normal file
95
src/3rdpart/media-server/libflv/source/amf3.c
Normal file
@ -0,0 +1,95 @@
|
||||
#include "amf3.h"
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
static double s_double = 1.0; // 3ff0 0000 0000 0000
|
||||
|
||||
const uint8_t* AMF3ReadNull(const uint8_t* ptr, const uint8_t* end)
|
||||
{
|
||||
(void)end;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
const uint8_t* AMF3ReadBoolean(const uint8_t* ptr, const uint8_t* end)
|
||||
{
|
||||
(void)end;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
const uint8_t* AMF3ReadInteger(const uint8_t* ptr, const uint8_t* end, int32_t* value)
|
||||
{
|
||||
int i;
|
||||
int32_t v = 0;
|
||||
|
||||
for (i = 0; i < 3 && ptr + i < end && (0x80 & ptr[i]); i++)
|
||||
{
|
||||
v <<= 7;
|
||||
v |= (ptr[i] & 0x7F);
|
||||
}
|
||||
|
||||
if (ptr + i >= end)
|
||||
return NULL;
|
||||
|
||||
if (3 == i)
|
||||
{
|
||||
v <<= 8;
|
||||
v |= ptr[i];
|
||||
|
||||
if (v >= (1 << 28))
|
||||
v -= (1 << 29);
|
||||
}
|
||||
else
|
||||
{
|
||||
v <<= 7;
|
||||
v |= ptr[i];
|
||||
}
|
||||
|
||||
*value = v;
|
||||
return ptr + i + 1;
|
||||
}
|
||||
|
||||
const uint8_t* AMF3ReadDouble(const uint8_t* ptr, const uint8_t* end, double* value)
|
||||
{
|
||||
uint8_t* p = (uint8_t*)value;
|
||||
if (!ptr || end - ptr < 8)
|
||||
return NULL;
|
||||
|
||||
if (value)
|
||||
{
|
||||
if (0x00 == *(char*)&s_double)
|
||||
{// Little-Endian
|
||||
*p++ = ptr[7];
|
||||
*p++ = ptr[6];
|
||||
*p++ = ptr[5];
|
||||
*p++ = ptr[4];
|
||||
*p++ = ptr[3];
|
||||
*p++ = ptr[2];
|
||||
*p++ = ptr[1];
|
||||
*p++ = ptr[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(&value, ptr, 8);
|
||||
}
|
||||
}
|
||||
return ptr + 8;
|
||||
}
|
||||
|
||||
const uint8_t* AMF3ReadString(const uint8_t* ptr, const uint8_t* end, char* string, uint32_t* length)
|
||||
{
|
||||
uint32_t v;
|
||||
ptr = AMF3ReadInteger(ptr, end, (int32_t*)&v);
|
||||
|
||||
if (v & 0x01)
|
||||
{
|
||||
// reference
|
||||
return ptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
*length = v >> 1;
|
||||
memcpy(string, ptr, *length);
|
||||
string[*length] = 0;
|
||||
return ptr + *length;
|
||||
}
|
||||
}
|
130
src/3rdpart/media-server/libflv/source/aom-av1.c
Normal file
130
src/3rdpart/media-server/libflv/source/aom-av1.c
Normal file
@ -0,0 +1,130 @@
|
||||
#include "aom-av1.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
|
||||
// https://aomediacodec.github.io/av1-isobmff
|
||||
// https://aomediacodec.github.io/av1-avif/
|
||||
|
||||
/*
|
||||
aligned (8) class AV1CodecConfigurationRecord {
|
||||
unsigned int (1) marker = 1;
|
||||
unsigned int (7) version = 1;
|
||||
unsigned int (3) seq_profile;
|
||||
unsigned int (5) seq_level_idx_0;
|
||||
unsigned int (1) seq_tier_0;
|
||||
unsigned int (1) high_bitdepth;
|
||||
unsigned int (1) twelve_bit;
|
||||
unsigned int (1) monochrome;
|
||||
unsigned int (1) chroma_subsampling_x;
|
||||
unsigned int (1) chroma_subsampling_y;
|
||||
unsigned int (2) chroma_sample_position;
|
||||
unsigned int (3) reserved = 0;
|
||||
|
||||
unsigned int (1) initial_presentation_delay_present;
|
||||
if (initial_presentation_delay_present) {
|
||||
unsigned int (4) initial_presentation_delay_minus_one;
|
||||
} else {
|
||||
unsigned int (4) reserved = 0;
|
||||
}
|
||||
|
||||
unsigned int (8)[] configOBUs;
|
||||
}
|
||||
*/
|
||||
|
||||
int aom_av1_codec_configuration_record_load(const uint8_t* data, size_t bytes, struct aom_av1_t* av1)
|
||||
{
|
||||
if (bytes < 4)
|
||||
return -1;
|
||||
|
||||
av1->marker = data[0] >> 7;
|
||||
av1->version = data[0] & 0x7F;
|
||||
av1->seq_profile = data[1] >> 5;
|
||||
av1->seq_level_idx_0 = data[1] & 0x1F;
|
||||
|
||||
av1->seq_tier_0 = data[2] >> 7;
|
||||
av1->high_bitdepth = (data[2] >> 6) & 0x01;
|
||||
av1->twelve_bit = (data[2] >> 5) & 0x01;
|
||||
av1->monochrome = (data[2] >> 4) & 0x01;
|
||||
av1->chroma_subsampling_x = (data[2] >> 3) & 0x01;
|
||||
av1->chroma_subsampling_y = (data[2] >> 2) & 0x01;
|
||||
av1->chroma_sample_position = data[2] & 0x03;
|
||||
|
||||
av1->reserved = data[3] >> 5;
|
||||
av1->initial_presentation_delay_present = (data[3] >> 4) & 0x01;
|
||||
av1->initial_presentation_delay_minus_one = data[3] & 0x0F;
|
||||
|
||||
if (bytes - 4 > sizeof(av1->data))
|
||||
return -1;
|
||||
|
||||
av1->bytes = (uint16_t)(bytes - 4);
|
||||
memcpy(av1->data, data + 4, av1->bytes);
|
||||
return (int)bytes;
|
||||
}
|
||||
|
||||
int aom_av1_codec_configuration_record_save(const struct aom_av1_t* av1, uint8_t* data, size_t bytes)
|
||||
{
|
||||
if (bytes < (size_t)av1->bytes + 4)
|
||||
return 0; // don't have enough memory
|
||||
|
||||
data[0] = (uint8_t)((av1->marker << 7) | av1->version);
|
||||
data[1] = (uint8_t)((av1->seq_profile << 5) | av1->seq_level_idx_0);
|
||||
data[2] = (uint8_t)((av1->seq_tier_0 << 7) | (av1->high_bitdepth << 6) | (av1->twelve_bit << 5) | (av1->monochrome << 4) | (av1->chroma_subsampling_x << 3) | (av1->chroma_subsampling_y << 2) | av1->chroma_sample_position);
|
||||
data[3] = (uint8_t)((av1->initial_presentation_delay_present << 4) | av1->initial_presentation_delay_minus_one);
|
||||
|
||||
memcpy(data + 4, av1->data, av1->bytes);
|
||||
return av1->bytes + 4;
|
||||
}
|
||||
|
||||
//static inline const uint8_t* leb128(const uint8_t* data, size_t bytes, int64_t* v)
|
||||
//{
|
||||
// size_t i;
|
||||
// int64_t b;
|
||||
//
|
||||
// b = 0x80;
|
||||
// for (*v = i = 0; i < 8 && i < bytes && 0 != (b & 0x80); i++)
|
||||
// {
|
||||
// b = data[i];
|
||||
// *v |= (b & 0x7F) << (i * 7);
|
||||
// }
|
||||
// return data + i;
|
||||
//}
|
||||
|
||||
int aom_av1_codecs(const struct aom_av1_t* av1, char* codecs, size_t bytes)
|
||||
{
|
||||
unsigned int bitdepth;
|
||||
|
||||
// AV1 5.5.2.Color config syntax
|
||||
if (2 == av1->seq_profile && av1->high_bitdepth)
|
||||
bitdepth = av1->twelve_bit ? 12 : 10;
|
||||
else
|
||||
bitdepth = av1->high_bitdepth ? 10 : 8;
|
||||
|
||||
// https://aomediacodec.github.io/av1-isobmff/#codecsparam
|
||||
// https://developer.mozilla.org/en-US/docs/Web/Media/Formats/codecs_parameter
|
||||
// <sample entry 4CC>.<profile>.<level><tier>.<bitDepth>.<monochrome>.<chromaSubsampling>.<colorPrimaries>.<transferCharacteristics>.<matrixCoefficients>.<videoFullRangeFlag>
|
||||
return snprintf(codecs, bytes, "av01.%u.%02u%c.%02u", (unsigned int)av1->seq_profile, (unsigned int)av1->seq_level_idx_0, av1->seq_tier_0 ? 'H' : 'M', (unsigned int)bitdepth);
|
||||
}
|
||||
|
||||
#if defined(_DEBUG) || defined(DEBUG)
|
||||
void aom_av1_test(void)
|
||||
{
|
||||
const unsigned char src[] = {
|
||||
0x81, 0x04, 0x0c, 0x00, 0x0a, 0x0b, 0x00, 0x00, 0x00, 0x24, 0xcf, 0x7f, 0x0d, 0xbf, 0xff, 0x30, 0x08
|
||||
};
|
||||
unsigned char data[sizeof(src)];
|
||||
|
||||
struct aom_av1_t av1;
|
||||
assert(sizeof(src) == aom_av1_codec_configuration_record_load(src, sizeof(src), &av1));
|
||||
assert(1 == av1.version && 0 == av1.seq_profile && 4 == av1.seq_level_idx_0);
|
||||
assert(0 == av1.seq_tier_0 && 0 == av1.high_bitdepth && 0 == av1.twelve_bit && 0 == av1.monochrome && 1 == av1.chroma_subsampling_x && 1 == av1.chroma_subsampling_y && 0 == av1.chroma_sample_position);
|
||||
assert(0 == av1.initial_presentation_delay_present && 0 == av1.initial_presentation_delay_minus_one);
|
||||
assert(13 == av1.bytes);
|
||||
assert(sizeof(src) == aom_av1_codec_configuration_record_save(&av1, data, sizeof(data)));
|
||||
assert(0 == memcmp(src, data, sizeof(src)));
|
||||
|
||||
aom_av1_codecs(&av1, (char*)data, sizeof(data));
|
||||
assert(0 == memcmp("av01.0.04M.08", data, 13));
|
||||
}
|
||||
#endif
|
81
src/3rdpart/media-server/libflv/source/flv-demuxer-script.c
Normal file
81
src/3rdpart/media-server/libflv/source/flv-demuxer-script.c
Normal file
@ -0,0 +1,81 @@
|
||||
#include "flv-demuxer.h"
|
||||
#include "amf0.h"
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
// http://www.cnblogs.com/musicfans/archive/2012/11/07/2819291.html
|
||||
// metadata keyframes/filepositions
|
||||
int flv_demuxer_script(struct flv_demuxer_t* flv, const uint8_t* data, size_t bytes)
|
||||
{
|
||||
const uint8_t* end;
|
||||
char buffer[64] = { 0 };
|
||||
double audiocodecid = 0;
|
||||
double audiodatarate = 0; // bitrate / 1024
|
||||
double audiodelay = 0;
|
||||
double audiosamplerate = 0;
|
||||
double audiosamplesize = 0;
|
||||
double videocodecid = 0;
|
||||
double videodatarate = 0; // bitrate / 1024
|
||||
double framerate = 0;
|
||||
double height = 0;
|
||||
double width = 0;
|
||||
double duration = 0;
|
||||
double filesize = 0;
|
||||
int canSeekToEnd = 0;
|
||||
int stereo = 0;
|
||||
struct amf_object_item_t keyframes[2];
|
||||
struct amf_object_item_t prop[16];
|
||||
struct amf_object_item_t items[1];
|
||||
|
||||
#define AMF_OBJECT_ITEM_VALUE(v, amf_type, amf_name, amf_value, amf_size) { v.type=amf_type; v.name=amf_name; v.value=amf_value; v.size=amf_size; }
|
||||
AMF_OBJECT_ITEM_VALUE(keyframes[0], AMF_STRICT_ARRAY, "filepositions", NULL, 0); // ignore keyframes
|
||||
AMF_OBJECT_ITEM_VALUE(keyframes[1], AMF_STRICT_ARRAY, "times", NULL, 0);
|
||||
|
||||
AMF_OBJECT_ITEM_VALUE(prop[0], AMF_NUMBER, "audiocodecid", &audiocodecid, sizeof(audiocodecid));
|
||||
AMF_OBJECT_ITEM_VALUE(prop[1], AMF_NUMBER, "audiodatarate", &audiodatarate, sizeof(audiodatarate));
|
||||
AMF_OBJECT_ITEM_VALUE(prop[2], AMF_NUMBER, "audiodelay", &audiodelay, sizeof(audiodelay));
|
||||
AMF_OBJECT_ITEM_VALUE(prop[3], AMF_NUMBER, "audiosamplerate", &audiosamplerate, sizeof(audiosamplerate));
|
||||
AMF_OBJECT_ITEM_VALUE(prop[4], AMF_NUMBER, "audiosamplesize", &audiosamplesize, sizeof(audiosamplesize));
|
||||
AMF_OBJECT_ITEM_VALUE(prop[5], AMF_BOOLEAN, "stereo", &stereo, sizeof(stereo));
|
||||
|
||||
AMF_OBJECT_ITEM_VALUE(prop[6], AMF_BOOLEAN, "canSeekToEnd", &canSeekToEnd, sizeof(canSeekToEnd));
|
||||
AMF_OBJECT_ITEM_VALUE(prop[7], AMF_STRING, "creationdate", buffer, sizeof(buffer));
|
||||
AMF_OBJECT_ITEM_VALUE(prop[8], AMF_NUMBER, "duration", &duration, sizeof(duration));
|
||||
AMF_OBJECT_ITEM_VALUE(prop[9], AMF_NUMBER, "filesize", &filesize, sizeof(filesize));
|
||||
|
||||
AMF_OBJECT_ITEM_VALUE(prop[10], AMF_NUMBER, "videocodecid", &videocodecid, sizeof(videocodecid));
|
||||
AMF_OBJECT_ITEM_VALUE(prop[11], AMF_NUMBER, "videodatarate", &videodatarate, sizeof(videodatarate));
|
||||
AMF_OBJECT_ITEM_VALUE(prop[12], AMF_NUMBER, "framerate", &framerate, sizeof(framerate));
|
||||
AMF_OBJECT_ITEM_VALUE(prop[13], AMF_NUMBER, "height", &height, sizeof(height));
|
||||
AMF_OBJECT_ITEM_VALUE(prop[14], AMF_NUMBER, "width", &width, sizeof(width));
|
||||
|
||||
AMF_OBJECT_ITEM_VALUE(prop[15], AMF_OBJECT, "keyframes", keyframes, 2); // FLV I-index
|
||||
|
||||
AMF_OBJECT_ITEM_VALUE(items[0], AMF_OBJECT, "onMetaData", prop, sizeof(prop) / sizeof(prop[0]));
|
||||
#undef AMF_OBJECT_ITEM_VALUE
|
||||
|
||||
end = data + bytes;
|
||||
if (AMF_STRING != data[0] || NULL == (data = AMFReadString(data + 1, end, 0, buffer, sizeof(buffer) - 1)))
|
||||
{
|
||||
assert(0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// filter @setDataFrame
|
||||
if (0 == strcmp(buffer, "@setDataFrame"))
|
||||
{
|
||||
if (AMF_STRING != data[0] || NULL == (data = AMFReadString(data + 1, end, 0, buffer, sizeof(buffer) - 1)))
|
||||
{
|
||||
assert(0);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
// onTextData/onCaption/onCaptionInfo/onCuePoint/|RtmpSampleAccess
|
||||
if (0 != strcmp(buffer, "onMetaData"))
|
||||
return 0; // skip
|
||||
|
||||
(void)flv;
|
||||
return amf_read_items(data, end, items, sizeof(items) / sizeof(items[0])) ? 0 : EINVAL;
|
||||
}
|
269
src/3rdpart/media-server/libflv/source/flv-demuxer.c
Normal file
269
src/3rdpart/media-server/libflv/source/flv-demuxer.c
Normal file
@ -0,0 +1,269 @@
|
||||
#include "flv-demuxer.h"
|
||||
#include "flv-header.h"
|
||||
#include "flv-proto.h"
|
||||
#include "mpeg4-aac.h"
|
||||
#include "mpeg4-avc.h"
|
||||
#include "mpeg4-hevc.h"
|
||||
#include "opus-head.h"
|
||||
#include "aom-av1.h"
|
||||
#include "amf0.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
|
||||
struct flv_demuxer_t
|
||||
{
|
||||
union
|
||||
{
|
||||
struct mpeg4_aac_t aac;
|
||||
struct opus_head_t opus;
|
||||
} a;
|
||||
|
||||
union
|
||||
{
|
||||
struct aom_av1_t av1;
|
||||
struct mpeg4_avc_t avc;
|
||||
struct mpeg4_hevc_t hevc;
|
||||
} v;
|
||||
|
||||
flv_demuxer_handler handler;
|
||||
void* param;
|
||||
|
||||
uint8_t* ptr;
|
||||
int capacity;
|
||||
};
|
||||
|
||||
struct flv_demuxer_t* flv_demuxer_create(flv_demuxer_handler handler, void* param)
|
||||
{
|
||||
struct flv_demuxer_t* flv;
|
||||
flv = (struct flv_demuxer_t*)malloc(sizeof(struct flv_demuxer_t));
|
||||
if (NULL == flv)
|
||||
return NULL;
|
||||
|
||||
memset(flv, 0, sizeof(struct flv_demuxer_t));
|
||||
flv->handler = handler;
|
||||
flv->param = param;
|
||||
return flv;
|
||||
}
|
||||
|
||||
void flv_demuxer_destroy(struct flv_demuxer_t* flv)
|
||||
{
|
||||
if (flv->ptr)
|
||||
{
|
||||
assert(flv->capacity > 0);
|
||||
free(flv->ptr);
|
||||
}
|
||||
|
||||
free(flv);
|
||||
}
|
||||
|
||||
static int flv_demuxer_check_and_alloc(struct flv_demuxer_t* flv, int bytes)
|
||||
{
|
||||
if (bytes > flv->capacity)
|
||||
{
|
||||
void* p = realloc(flv->ptr, bytes);
|
||||
if (NULL == p)
|
||||
return -1;
|
||||
flv->ptr = (uint8_t*)p;
|
||||
flv->capacity = bytes;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int flv_demuxer_audio(struct flv_demuxer_t* flv, const uint8_t* data, int bytes, uint32_t timestamp)
|
||||
{
|
||||
int r, n;
|
||||
struct flv_audio_tag_header_t audio;
|
||||
n = flv_audio_tag_header_read(&audio, data, bytes);
|
||||
if (n < 0)
|
||||
return n;
|
||||
|
||||
if (FLV_AUDIO_AAC == audio.codecid)
|
||||
{
|
||||
// Adobe Flash Video File Format Specification Version 10.1 >> E.4.2.1 AUDIODATA (p77)
|
||||
// If the SoundFormat indicates AAC, the SoundType should be 1 (stereo) and the SoundRate should be 3 (44 kHz).
|
||||
// However, this does not mean that AAC audio in FLV is always stereo, 44 kHz data.Instead, the Flash Player ignores
|
||||
// these values and extracts the channel and sample rate data is encoded in the AAC bit stream.
|
||||
//assert(3 == audio.bitrate && 1 == audio.channel);
|
||||
if (FLV_SEQUENCE_HEADER == audio.avpacket)
|
||||
{
|
||||
mpeg4_aac_audio_specific_config_load(data + n, bytes - n, &flv->a.aac);
|
||||
return flv->handler(flv->param, FLV_AUDIO_ASC, data + n, bytes - n, timestamp, timestamp, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (0 != flv_demuxer_check_and_alloc(flv, bytes + 7 + 1 + flv->a.aac.npce))
|
||||
return -ENOMEM;
|
||||
|
||||
// AAC ES stream with ADTS header
|
||||
assert(bytes <= 0x1FFF);
|
||||
assert(bytes > 2 && 0xFFF0 != (((data[2] << 8) | data[3]) & 0xFFF0)); // don't have ADTS
|
||||
r = mpeg4_aac_adts_save(&flv->a.aac, (uint16_t)bytes - n, flv->ptr, 7 + 1 + flv->a.aac.npce); // 13-bits
|
||||
if (r < 7) return -EINVAL; // invalid pce
|
||||
flv->a.aac.npce = 0; // pce write only once
|
||||
memmove(flv->ptr + r, data + n, bytes - n);
|
||||
return flv->handler(flv->param, FLV_AUDIO_AAC, flv->ptr, bytes - n + r, timestamp, timestamp, 0);
|
||||
}
|
||||
}
|
||||
else if (FLV_AUDIO_OPUS == audio.codecid)
|
||||
{
|
||||
if (FLV_SEQUENCE_HEADER == audio.avpacket)
|
||||
{
|
||||
opus_head_load(data + n, bytes - n, &flv->a.opus);
|
||||
return flv->handler(flv->param, FLV_AUDIO_OPUS_HEAD, data + n, bytes - n, timestamp, timestamp, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
return flv->handler(flv->param, audio.codecid, data + n, bytes - n, timestamp, timestamp, 0);
|
||||
}
|
||||
}
|
||||
else if (FLV_AUDIO_MP3 == audio.codecid || FLV_AUDIO_MP3_8K == audio.codecid)
|
||||
{
|
||||
return flv->handler(flv->param, audio.codecid, data + n, bytes - n, timestamp, timestamp, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Audio frame data
|
||||
return flv->handler(flv->param, audio.codecid, data + n, bytes - n, timestamp, timestamp, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static int flv_demuxer_video(struct flv_demuxer_t* flv, const uint8_t* data, int bytes, uint32_t timestamp)
|
||||
{
|
||||
int n;
|
||||
struct flv_video_tag_header_t video;
|
||||
n = flv_video_tag_header_read(&video, data, bytes);
|
||||
if (n < 0)
|
||||
return n;
|
||||
|
||||
if (FLV_VIDEO_H264 == video.codecid)
|
||||
{
|
||||
if (FLV_SEQUENCE_HEADER == video.avpacket)
|
||||
{
|
||||
// AVCDecoderConfigurationRecord
|
||||
assert(bytes > n + 7);
|
||||
mpeg4_avc_decoder_configuration_record_load(data + n, bytes - n, &flv->v.avc);
|
||||
return flv->handler(flv->param, FLV_VIDEO_AVCC, data + n, bytes - n, timestamp + video.cts, timestamp, 0);
|
||||
}
|
||||
else if(FLV_AVPACKET == video.avpacket)
|
||||
{
|
||||
assert(flv->v.avc.nalu > 0); // parse AVCDecoderConfigurationRecord failed
|
||||
if (flv->v.avc.nalu > 0 && bytes > n) // 5 == bytes flv eof
|
||||
{
|
||||
// H.264
|
||||
if (0 != flv_demuxer_check_and_alloc(flv, bytes + 4 * 1024))
|
||||
return -ENOMEM;
|
||||
|
||||
assert(flv->v.avc.nalu <= 4);
|
||||
n = h264_mp4toannexb(&flv->v.avc, data + n, bytes - n, flv->ptr, flv->capacity);
|
||||
if (n <= 0 || n > flv->capacity)
|
||||
{
|
||||
assert(0);
|
||||
return -ENOMEM;
|
||||
}
|
||||
return flv->handler(flv->param, FLV_VIDEO_H264, flv->ptr, n, timestamp + video.cts, timestamp, (FLV_VIDEO_KEY_FRAME == video.keyframe) ? 1 : 0);
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
else if (FLV_END_OF_SEQUENCE == video.avpacket)
|
||||
{
|
||||
return 0; // AVC end of sequence (lower level NALU sequence ender is not required or supported)
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(0);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
else if (FLV_VIDEO_H265 == video.codecid)
|
||||
{
|
||||
if (FLV_SEQUENCE_HEADER == video.avpacket)
|
||||
{
|
||||
// HEVCDecoderConfigurationRecord
|
||||
assert(bytes > n + 7);
|
||||
mpeg4_hevc_decoder_configuration_record_load(data + n, bytes - n, &flv->v.hevc);
|
||||
return flv->handler(flv->param, FLV_VIDEO_HVCC, data + n, bytes - n, timestamp + video.cts, timestamp, 0);
|
||||
}
|
||||
else if (FLV_AVPACKET == video.avpacket)
|
||||
{
|
||||
assert(flv->v.hevc.numOfArrays > 0); // parse HEVCDecoderConfigurationRecord failed
|
||||
if (flv->v.hevc.numOfArrays > 0 && bytes > n) // 5 == bytes flv eof
|
||||
{
|
||||
// H.265
|
||||
if (0 != flv_demuxer_check_and_alloc(flv, bytes + 4 * 1024))
|
||||
return -ENOMEM;
|
||||
|
||||
n = h265_mp4toannexb(&flv->v.hevc, data + n, bytes - n, flv->ptr, flv->capacity);
|
||||
if (n <= 0 || n > flv->capacity)
|
||||
{
|
||||
assert(0);
|
||||
return -ENOMEM;
|
||||
}
|
||||
return flv->handler(flv->param, FLV_VIDEO_H265, flv->ptr, n, timestamp + video.cts, timestamp, (FLV_VIDEO_KEY_FRAME == video.keyframe) ? 1 : 0);
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
else if (FLV_END_OF_SEQUENCE == video.avpacket)
|
||||
{
|
||||
return 0; // AVC end of sequence (lower level NALU sequence ender is not required or supported)
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(0);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
else if (FLV_VIDEO_AV1 == video.codecid)
|
||||
{
|
||||
if (FLV_SEQUENCE_HEADER == video.avpacket)
|
||||
{
|
||||
// HEVCDecoderConfigurationRecord
|
||||
assert(bytes > n + 5);
|
||||
aom_av1_codec_configuration_record_load(data + n, bytes - n, &flv->v.av1);
|
||||
return flv->handler(flv->param, FLV_VIDEO_AV1C, data + n, bytes - n, timestamp + video.cts, timestamp, 0);
|
||||
}
|
||||
else if (FLV_AVPACKET == video.avpacket)
|
||||
{
|
||||
return flv->handler(flv->param, FLV_VIDEO_AV1, data + n, bytes - n, timestamp + video.cts, timestamp, (FLV_VIDEO_KEY_FRAME == video.keyframe) ? 1 : 0);
|
||||
}
|
||||
else if (FLV_END_OF_SEQUENCE == video.avpacket)
|
||||
{
|
||||
return 0; // AV1 end of sequence (lower level NALU sequence ender is not required or supported)
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(0);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Video frame data
|
||||
return flv->handler(flv->param, video.codecid, data + n, bytes - n, timestamp + video.cts, timestamp, (FLV_VIDEO_KEY_FRAME==video.keyframe) ? 1 : 0);
|
||||
}
|
||||
}
|
||||
|
||||
int flv_demuxer_script(struct flv_demuxer_t* flv, const uint8_t* data, size_t bytes);
|
||||
int flv_demuxer_input(struct flv_demuxer_t* flv, int type, const void* data, size_t bytes, uint32_t timestamp)
|
||||
{
|
||||
if (bytes < 1)
|
||||
return 0;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case FLV_TYPE_AUDIO:
|
||||
return flv_demuxer_audio(flv, data, (int)bytes, timestamp);
|
||||
|
||||
case FLV_TYPE_VIDEO:
|
||||
return flv_demuxer_video(flv, data, (int)bytes, timestamp);
|
||||
|
||||
case FLV_TYPE_SCRIPT:
|
||||
//return flv_demuxer_script(flv, data, bytes);
|
||||
return 0;
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
return -1;
|
||||
}
|
||||
}
|
236
src/3rdpart/media-server/libflv/source/flv-header.c
Normal file
236
src/3rdpart/media-server/libflv/source/flv-header.c
Normal file
@ -0,0 +1,236 @@
|
||||
#include "flv-header.h"
|
||||
#include "flv-proto.h"
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
|
||||
#define N_TAG_SIZE 4 // previous tag size
|
||||
#define FLV_HEADER_SIZE 9 // DataOffset included
|
||||
#define FLV_TAG_HEADER_SIZE 11 // StreamID included
|
||||
|
||||
static inline uint32_t be_read_uint32(const uint8_t* ptr)
|
||||
{
|
||||
return (ptr[0] << 24) | (ptr[1] << 16) | (ptr[2] << 8) | ptr[3];
|
||||
}
|
||||
|
||||
static inline void be_write_uint32(uint8_t* ptr, uint32_t val)
|
||||
{
|
||||
ptr[0] = (uint8_t)((val >> 24) & 0xFF);
|
||||
ptr[1] = (uint8_t)((val >> 16) & 0xFF);
|
||||
ptr[2] = (uint8_t)((val >> 8) & 0xFF);
|
||||
ptr[3] = (uint8_t)(val & 0xFF);
|
||||
}
|
||||
|
||||
int flv_header_read(struct flv_header_t* flv, const uint8_t* buf, int len)
|
||||
{
|
||||
if (len < FLV_HEADER_SIZE || 'F' != buf[0] || 'L' != buf[1] || 'V' != buf[2])
|
||||
{
|
||||
assert(0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
flv->FLV[0] = buf[0];
|
||||
flv->FLV[1] = buf[1];
|
||||
flv->FLV[2] = buf[2];
|
||||
flv->version = buf[3];
|
||||
|
||||
assert(0x00 == (buf[4] & 0xF8) && 0x00 == (buf[4] & 0x20));
|
||||
flv->audio = (buf[4] >> 2) & 0x01;
|
||||
flv->video = buf[4] & 0x01;
|
||||
flv->offset = be_read_uint32(buf + 5);
|
||||
|
||||
return FLV_HEADER_SIZE;
|
||||
}
|
||||
|
||||
int flv_tag_header_read(struct flv_tag_header_t* tag, const uint8_t* buf, int len)
|
||||
{
|
||||
if (len < FLV_TAG_HEADER_SIZE)
|
||||
{
|
||||
assert(0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// TagType
|
||||
tag->type = buf[0] & 0x1F;
|
||||
tag->filter = (buf[0] >> 5) & 0x01;
|
||||
assert(FLV_TYPE_VIDEO == tag->type || FLV_TYPE_AUDIO == tag->type || FLV_TYPE_SCRIPT == tag->type);
|
||||
|
||||
// DataSize
|
||||
tag->size = (buf[1] << 16) | (buf[2] << 8) | buf[3];
|
||||
|
||||
// TimestampExtended | Timestamp
|
||||
tag->timestamp = (buf[4] << 16) | (buf[5] << 8) | buf[6] | (buf[7] << 24);
|
||||
|
||||
// StreamID Always 0
|
||||
tag->streamId = (buf[8] << 16) | (buf[9] << 8) | buf[10];
|
||||
//assert(0 == tag->streamId);
|
||||
|
||||
return FLV_TAG_HEADER_SIZE;
|
||||
}
|
||||
|
||||
int flv_audio_tag_header_read(struct flv_audio_tag_header_t* audio, const uint8_t* buf, int len)
|
||||
{
|
||||
assert(len > 0);
|
||||
audio->codecid = (buf[0] & 0xF0) /*>> 4*/;
|
||||
audio->rate = (buf[0] & 0x0C) >> 2;
|
||||
audio->bits = (buf[0] & 0x02) >> 1;
|
||||
audio->channels = buf[0] & 0x01;
|
||||
|
||||
if (FLV_AUDIO_AAC == audio->codecid || FLV_AUDIO_OPUS == audio->codecid)
|
||||
{
|
||||
if (len < 2)
|
||||
{
|
||||
assert(0);
|
||||
return -1;
|
||||
}
|
||||
audio->avpacket = buf[1];
|
||||
assert(FLV_SEQUENCE_HEADER == audio->avpacket || FLV_AVPACKET == audio->avpacket);
|
||||
return 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
int flv_video_tag_header_read(struct flv_video_tag_header_t* video, const uint8_t* buf, int len)
|
||||
{
|
||||
assert(len > 0);
|
||||
video->keyframe = (buf[0] & 0xF0) >> 4;
|
||||
video->codecid = (buf[0] & 0x0F);
|
||||
|
||||
if (FLV_VIDEO_H264 == video->codecid || FLV_VIDEO_H265 == video->codecid || FLV_VIDEO_AV1 == video->codecid)
|
||||
{
|
||||
if (len < 5)
|
||||
return -1;
|
||||
|
||||
video->avpacket = buf[1]; // AVCPacketType
|
||||
video->cts = (buf[2] << 16) | (buf[3] << 8) | buf[4];
|
||||
//if (video->cts >= (1 << 23)) video->cts -= (1 << 24);
|
||||
video->cts = (video->cts + 0xFF800000) ^ 0xFF800000; // signed 24-integer
|
||||
assert(FLV_SEQUENCE_HEADER == video->avpacket || FLV_AVPACKET == video->avpacket || FLV_END_OF_SEQUENCE == video->avpacket);
|
||||
return 5;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
int flv_data_tag_header_read(const uint8_t* buf, int len)
|
||||
{
|
||||
(void)buf;
|
||||
return len;
|
||||
}
|
||||
|
||||
int flv_header_write(int audio, int video, uint8_t* buf, int len)
|
||||
{
|
||||
if (len < FLV_HEADER_SIZE)
|
||||
{
|
||||
assert(0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
buf[0] = 'F'; // FLV signature
|
||||
buf[1] = 'L';
|
||||
buf[2] = 'V';
|
||||
buf[3] = 0x01; // File version
|
||||
buf[4] = ((audio ? 1 : 0) << 2) | (video ? 1 : 0); // Type flags (audio & video)
|
||||
be_write_uint32(buf + 5, FLV_HEADER_SIZE); // Data offset
|
||||
return FLV_HEADER_SIZE;
|
||||
}
|
||||
|
||||
int flv_tag_header_write(const struct flv_tag_header_t* tag, uint8_t* buf, int len)
|
||||
{
|
||||
if (len < FLV_TAG_HEADER_SIZE)
|
||||
{
|
||||
assert(0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// TagType
|
||||
assert(FLV_TYPE_VIDEO == tag->type || FLV_TYPE_AUDIO == tag->type || FLV_TYPE_SCRIPT == tag->type);
|
||||
buf[0] = (tag->type & 0x1F) | ((tag->filter & 0x01) << 5);
|
||||
|
||||
// DataSize
|
||||
buf[1] = (tag->size >> 16) & 0xFF;
|
||||
buf[2] = (tag->size >> 8) & 0xFF;
|
||||
buf[3] = tag->size & 0xFF;
|
||||
|
||||
// Timestamp
|
||||
buf[4] = (tag->timestamp >> 16) & 0xFF;
|
||||
buf[5] = (tag->timestamp >> 8) & 0xFF;
|
||||
buf[6] = (tag->timestamp >> 0) & 0xFF;
|
||||
buf[7] = (tag->timestamp >> 24) & 0xFF; // Timestamp Extended
|
||||
|
||||
// StreamID(Always 0)
|
||||
buf[8] = (tag->streamId >> 16) & 0xFF;
|
||||
buf[9] = (tag->streamId >> 8) & 0xFF;
|
||||
buf[10] = (tag->streamId) & 0xFF;
|
||||
|
||||
return FLV_TAG_HEADER_SIZE;
|
||||
}
|
||||
|
||||
int flv_audio_tag_header_write(const struct flv_audio_tag_header_t* audio, uint8_t* buf, int len)
|
||||
{
|
||||
if (len < 1 + ((FLV_AUDIO_AAC == audio->codecid || FLV_AUDIO_OPUS == audio->codecid)? 1 : 0))
|
||||
return -1;
|
||||
|
||||
if (FLV_AUDIO_AAC == audio->codecid || FLV_AUDIO_OPUS == audio->codecid)
|
||||
{
|
||||
assert(FLV_SEQUENCE_HEADER == audio->avpacket || FLV_AVPACKET == audio->avpacket);
|
||||
buf[0] = (audio->codecid /* <<4 */) /* SoundFormat */ | (3 << 2) /* 44k-SoundRate */ | (1 << 1) /* 16-bit samples */ | 1 /* Stereo sound */;
|
||||
buf[1] = audio->avpacket; // AACPacketType
|
||||
return 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
buf[0] = (audio->codecid /* <<4 */) | ((audio->rate & 0x03) << 2) | ((audio->bits & 0x01) << 1) | (audio->channels & 0x01);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
int flv_video_tag_header_write(const struct flv_video_tag_header_t* video, uint8_t* buf, int len)
|
||||
{
|
||||
if (len < 1)
|
||||
return -1;
|
||||
|
||||
buf[0] = (video->keyframe << 4) /*FrameType*/ | (video->codecid & 0x0F) /*CodecID*/;
|
||||
|
||||
if (FLV_VIDEO_H264 == video->codecid || FLV_VIDEO_H265 == video->codecid || FLV_VIDEO_AV1 == video->codecid)
|
||||
{
|
||||
assert(FLV_SEQUENCE_HEADER == video->avpacket || FLV_AVPACKET == video->avpacket || FLV_END_OF_SEQUENCE == video->avpacket);
|
||||
if (len < 5)
|
||||
return -1;
|
||||
|
||||
buf[1] = video->avpacket; // AVCPacketType
|
||||
buf[2] = (video->cts >> 16) & 0xFF;
|
||||
buf[3] = (video->cts >> 8) & 0xFF;
|
||||
buf[4] = video->cts & 0xFF;
|
||||
return 5;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int flv_data_tag_header_write(uint8_t* buf, int len)
|
||||
{
|
||||
(void)buf;
|
||||
(void)len;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int flv_tag_size_read(const uint8_t* buf, int len, uint32_t* size)
|
||||
{
|
||||
if(len < 4)
|
||||
return -1;
|
||||
*size = be_read_uint32(buf);
|
||||
return 4;
|
||||
}
|
||||
|
||||
int flv_tag_size_write(uint8_t* buf, int len, uint32_t size)
|
||||
{
|
||||
if(len < 4)
|
||||
return -1;
|
||||
be_write_uint32(buf, size);
|
||||
return 4;
|
||||
}
|
370
src/3rdpart/media-server/libflv/source/flv-muxer.c
Normal file
370
src/3rdpart/media-server/libflv/source/flv-muxer.c
Normal file
@ -0,0 +1,370 @@
|
||||
#include "flv-muxer.h"
|
||||
#include "flv-proto.h"
|
||||
#include "flv-header.h"
|
||||
#include "amf0.h"
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include "mpeg4-aac.h"
|
||||
#include "mpeg4-avc.h"
|
||||
#include "mpeg4-hevc.h"
|
||||
#include "mp3-header.h"
|
||||
#include "opus-head.h"
|
||||
|
||||
#define FLV_MUXER "libflv"
|
||||
|
||||
struct flv_muxer_t
|
||||
{
|
||||
flv_muxer_handler handler;
|
||||
void* param;
|
||||
|
||||
uint8_t audio_sequence_header;
|
||||
uint8_t video_sequence_header;
|
||||
|
||||
union
|
||||
{
|
||||
struct mpeg4_aac_t aac;
|
||||
struct opus_head_t opus;
|
||||
} a;
|
||||
|
||||
union
|
||||
{
|
||||
struct mpeg4_avc_t avc;
|
||||
struct mpeg4_hevc_t hevc;
|
||||
} v;
|
||||
int vcl; // 0-non vcl, 1-idr, 2-p/b
|
||||
int update; // avc/hevc sequence header update
|
||||
|
||||
uint8_t* ptr;
|
||||
int bytes;
|
||||
int capacity;
|
||||
};
|
||||
|
||||
struct flv_muxer_t* flv_muxer_create(flv_muxer_handler handler, void* param)
|
||||
{
|
||||
struct flv_muxer_t* flv;
|
||||
flv = (struct flv_muxer_t*)calloc(1, sizeof(struct flv_muxer_t));
|
||||
if (NULL == flv)
|
||||
return NULL;
|
||||
|
||||
flv_muxer_reset(flv);
|
||||
flv->handler = handler;
|
||||
flv->param = param;
|
||||
return flv;
|
||||
}
|
||||
|
||||
void flv_muxer_destroy(struct flv_muxer_t* flv)
|
||||
{
|
||||
if (flv->ptr)
|
||||
{
|
||||
assert(flv->capacity > 0);
|
||||
free(flv->ptr);
|
||||
flv->ptr = NULL;
|
||||
}
|
||||
|
||||
free(flv);
|
||||
}
|
||||
|
||||
int flv_muxer_reset(struct flv_muxer_t* flv)
|
||||
{
|
||||
memset(&flv->v, 0, sizeof(flv->v));
|
||||
flv->audio_sequence_header = 0;
|
||||
flv->video_sequence_header = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int flv_muxer_alloc(struct flv_muxer_t* flv, int bytes)
|
||||
{
|
||||
void* p;
|
||||
p = realloc(flv->ptr, bytes);
|
||||
if (!p)
|
||||
return ENOMEM;
|
||||
|
||||
flv->ptr = (uint8_t*)p;
|
||||
flv->capacity = bytes;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int flv_muxer_mp3(struct flv_muxer_t* flv, const void* data, size_t sz, uint32_t pts, uint32_t dts)
|
||||
{
|
||||
int bytes;
|
||||
struct mp3_header_t mp3;
|
||||
struct flv_audio_tag_header_t audio;
|
||||
(void)pts;
|
||||
|
||||
bytes = (int)sz;
|
||||
if (0 == mp3_header_load(&mp3, data, bytes))
|
||||
{
|
||||
return EINVAL;
|
||||
}
|
||||
else
|
||||
{
|
||||
audio.channels = 3 == mp3.mode ? 0 : 1;
|
||||
switch (mp3_get_frequency(&mp3))
|
||||
{
|
||||
case 5500: audio.rate = 0; break;
|
||||
case 11000: audio.rate = 1; break;
|
||||
case 22000: audio.rate = 2; break;
|
||||
case 44100: audio.rate = 3; break;
|
||||
default: audio.rate = 3;
|
||||
}
|
||||
}
|
||||
|
||||
if (flv->capacity < bytes + 1)
|
||||
{
|
||||
if (0 != flv_muxer_alloc(flv, bytes + 4))
|
||||
return ENOMEM;
|
||||
}
|
||||
|
||||
audio.bits = 1; // 16-bit samples
|
||||
audio.codecid = FLV_AUDIO_MP3;
|
||||
audio.avpacket = FLV_AVPACKET;
|
||||
flv_audio_tag_header_write(&audio, flv->ptr, 1);
|
||||
memcpy(flv->ptr + 1, data, bytes); // MP3
|
||||
return flv->handler(flv->param, FLV_TYPE_AUDIO, flv->ptr, bytes + 1, dts);
|
||||
}
|
||||
|
||||
int flv_muxer_aac(struct flv_muxer_t* flv, const void* data, size_t sz, uint32_t pts, uint32_t dts)
|
||||
{
|
||||
int r, n, m, bytes;
|
||||
struct flv_audio_tag_header_t audio;
|
||||
(void)pts;
|
||||
|
||||
bytes = (int)sz;
|
||||
if (flv->capacity < bytes + 2/*AudioTagHeader*/ + 2/*AudioSpecificConfig*/)
|
||||
{
|
||||
if (0 != flv_muxer_alloc(flv, bytes + 4))
|
||||
return ENOMEM;
|
||||
}
|
||||
|
||||
/* ADTS */
|
||||
n = mpeg4_aac_adts_load(data, bytes, &flv->a.aac);
|
||||
if (n <= 0)
|
||||
return -1; // invalid data
|
||||
|
||||
audio.codecid = FLV_AUDIO_AAC;
|
||||
audio.rate = 3; // 44k-SoundRate
|
||||
audio.bits = 1; // 16-bit samples
|
||||
audio.channels = 1; // Stereo sound
|
||||
if (0 == flv->audio_sequence_header)
|
||||
{
|
||||
flv->audio_sequence_header = 1; // once only
|
||||
audio.avpacket = FLV_SEQUENCE_HEADER;
|
||||
|
||||
// AudioSpecificConfig(AAC sequence header)
|
||||
flv_audio_tag_header_write(&audio, flv->ptr, flv->capacity);
|
||||
m = mpeg4_aac_audio_specific_config_save(&flv->a.aac, flv->ptr + 2, flv->capacity - 2);
|
||||
assert(m + 2 <= (int)flv->capacity);
|
||||
r = flv->handler(flv->param, FLV_TYPE_AUDIO, flv->ptr, m + 2, dts);
|
||||
if (0 != r) return r;
|
||||
}
|
||||
|
||||
audio.avpacket = FLV_AVPACKET;
|
||||
flv_audio_tag_header_write(&audio, flv->ptr, flv->capacity);
|
||||
memcpy(flv->ptr + 2, (uint8_t*)data + n, bytes - n); // AAC exclude ADTS
|
||||
assert(bytes - n + 2 <= (int)flv->capacity);
|
||||
return flv->handler(flv->param, FLV_TYPE_AUDIO, flv->ptr, bytes - n + 2, dts);
|
||||
}
|
||||
|
||||
int flv_muxer_opus(flv_muxer_t* flv, const void* data, size_t sz, uint32_t pts, uint32_t dts)
|
||||
{
|
||||
int r, m, bytes;
|
||||
struct flv_audio_tag_header_t audio;
|
||||
(void)pts;
|
||||
|
||||
bytes = (int)sz;
|
||||
if (flv->capacity < bytes + 2/*AudioTagHeader*/ + 2/*AudioSpecificConfig*/)
|
||||
{
|
||||
if (0 != flv_muxer_alloc(flv, bytes + 4))
|
||||
return ENOMEM;
|
||||
}
|
||||
|
||||
audio.codecid = FLV_AUDIO_OPUS;
|
||||
audio.rate = 3; // 44k-SoundRate
|
||||
audio.bits = 1; // 16-bit samples
|
||||
audio.channels = 1; // Stereo sound
|
||||
|
||||
if (0 == flv->audio_sequence_header)
|
||||
{
|
||||
if (opus_head_load(data, bytes, &flv->a.opus) < 0)
|
||||
return -1;
|
||||
|
||||
flv->audio_sequence_header = 1; // once only
|
||||
audio.avpacket = FLV_SEQUENCE_HEADER;
|
||||
|
||||
// Opus Head
|
||||
m = flv_audio_tag_header_write(&audio, flv->ptr, flv->capacity);
|
||||
assert(m + bytes <= (int)flv->capacity);
|
||||
memcpy(flv->ptr + m, data, bytes);
|
||||
r = flv->handler(flv->param, FLV_TYPE_AUDIO, flv->ptr, m + bytes, dts);
|
||||
return r;
|
||||
}
|
||||
|
||||
audio.avpacket = FLV_AVPACKET;
|
||||
m = flv_audio_tag_header_write(&audio, flv->ptr, flv->capacity);
|
||||
memcpy(flv->ptr + m, (uint8_t*)data, bytes);
|
||||
assert(bytes - m <= (int)flv->capacity);
|
||||
return flv->handler(flv->param, FLV_TYPE_AUDIO, flv->ptr, bytes + m, dts);
|
||||
}
|
||||
|
||||
static int flv_muxer_h264(struct flv_muxer_t* flv, uint32_t pts, uint32_t dts)
|
||||
{
|
||||
int r;
|
||||
int m;
|
||||
struct flv_video_tag_header_t video;
|
||||
|
||||
video.codecid = FLV_VIDEO_H264;
|
||||
if ( /*0 == flv->video_sequence_header &&*/ flv->update && flv->v.avc.nb_sps > 0 && flv->v.avc.nb_pps > 0)
|
||||
{
|
||||
video.cts = 0;
|
||||
video.keyframe = 1; // keyframe
|
||||
video.avpacket = FLV_SEQUENCE_HEADER;
|
||||
flv_video_tag_header_write(&video, flv->ptr + flv->bytes, flv->capacity - flv->bytes);
|
||||
m = mpeg4_avc_decoder_configuration_record_save(&flv->v.avc, flv->ptr + flv->bytes + 5, flv->capacity - flv->bytes - 5);
|
||||
if (m <= 0)
|
||||
return -1; // invalid data
|
||||
|
||||
flv->video_sequence_header = 1; // once only
|
||||
assert(flv->bytes + m + 5 <= (int)flv->capacity);
|
||||
r = flv->handler(flv->param, FLV_TYPE_VIDEO, flv->ptr + flv->bytes, m + 5, dts);
|
||||
if (0 != r) return r;
|
||||
}
|
||||
|
||||
// has video frame
|
||||
if (flv->vcl && flv->video_sequence_header)
|
||||
{
|
||||
video.cts = pts - dts;
|
||||
video.keyframe = 1 == flv->vcl ? 1 : 2;
|
||||
video.avpacket = FLV_AVPACKET;
|
||||
flv_video_tag_header_write(&video, flv->ptr, flv->capacity);
|
||||
assert(flv->bytes <= (int)flv->capacity);
|
||||
return flv->handler(flv->param, FLV_TYPE_VIDEO, flv->ptr, flv->bytes, dts);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int flv_muxer_avc(struct flv_muxer_t* flv, const void* data, size_t bytes, uint32_t pts, uint32_t dts)
|
||||
{
|
||||
if (flv->capacity < (int)bytes + 2048/*AVCDecoderConfigurationRecord*/)
|
||||
{
|
||||
if (0 != flv_muxer_alloc(flv, (int)bytes + 2048))
|
||||
return ENOMEM;
|
||||
}
|
||||
|
||||
flv->bytes = 5;
|
||||
flv->bytes += h264_annexbtomp4(&flv->v.avc, data, (int)bytes, flv->ptr + flv->bytes, flv->capacity - flv->bytes, &flv->vcl, &flv->update);
|
||||
if (flv->bytes <= 5)
|
||||
return ENOMEM;
|
||||
|
||||
return flv_muxer_h264(flv, pts, dts);
|
||||
}
|
||||
|
||||
static int flv_muxer_h265(struct flv_muxer_t* flv, uint32_t pts, uint32_t dts)
|
||||
{
|
||||
int r;
|
||||
int m;
|
||||
struct flv_video_tag_header_t video;
|
||||
|
||||
video.codecid = FLV_VIDEO_H265;
|
||||
if ( /*0 == flv->avc_sequence_header &&*/ flv->update && flv->v.hevc.numOfArrays >= 3) // vps + sps + pps
|
||||
{
|
||||
video.cts = 0;
|
||||
video.keyframe = 1; // keyframe
|
||||
video.avpacket = FLV_SEQUENCE_HEADER;
|
||||
flv_video_tag_header_write(&video, flv->ptr + flv->bytes, flv->capacity - flv->bytes);
|
||||
m = mpeg4_hevc_decoder_configuration_record_save(&flv->v.hevc, flv->ptr + flv->bytes + 5, flv->capacity - flv->bytes - 5);
|
||||
if (m <= 0)
|
||||
return -1; // invalid data
|
||||
|
||||
flv->video_sequence_header = 1; // once only
|
||||
assert(flv->bytes + m + 5 <= (int)flv->capacity);
|
||||
r = flv->handler(flv->param, FLV_TYPE_VIDEO, flv->ptr + flv->bytes, m + 5, dts);
|
||||
if (0 != r) return r;
|
||||
}
|
||||
|
||||
// has video frame
|
||||
if (flv->vcl && flv->video_sequence_header)
|
||||
{
|
||||
video.cts = pts - dts;
|
||||
video.keyframe = 1 == flv->vcl ? 1 : 2;
|
||||
video.avpacket = FLV_AVPACKET;
|
||||
flv_video_tag_header_write(&video, flv->ptr, flv->capacity);
|
||||
assert(flv->bytes <= (int)flv->capacity);
|
||||
return flv->handler(flv->param, FLV_TYPE_VIDEO, flv->ptr, flv->bytes, dts);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int flv_muxer_hevc(struct flv_muxer_t* flv, const void* data, size_t bytes, uint32_t pts, uint32_t dts)
|
||||
{
|
||||
if (flv->capacity < (int)bytes + 2048/*HEVCDecoderConfigurationRecord*/)
|
||||
{
|
||||
if (0 != flv_muxer_alloc(flv, (int)bytes + 2048))
|
||||
return ENOMEM;
|
||||
}
|
||||
|
||||
flv->bytes = 5;
|
||||
flv->bytes += h265_annexbtomp4(&flv->v.hevc, data, (int)bytes, flv->ptr + flv->bytes, flv->capacity - flv->bytes, &flv->vcl, &flv->update);
|
||||
if (flv->bytes <= 5)
|
||||
return ENOMEM;
|
||||
|
||||
return flv_muxer_h265(flv, pts, dts);
|
||||
}
|
||||
|
||||
int flv_muxer_metadata(flv_muxer_t* flv, const struct flv_metadata_t* metadata)
|
||||
{
|
||||
uint8_t* ptr, *end;
|
||||
uint32_t count;
|
||||
|
||||
if (!metadata) return -1;
|
||||
|
||||
count = (metadata->audiocodecid ? 5 : 0) + (metadata->videocodecid ? 5 : 0) + 1;
|
||||
if (flv->capacity < 1024)
|
||||
{
|
||||
if (0 != flv_muxer_alloc(flv, 1024))
|
||||
return ENOMEM;
|
||||
}
|
||||
|
||||
ptr = flv->ptr;
|
||||
end = flv->ptr + flv->capacity;
|
||||
count = (metadata->audiocodecid ? 5 : 0) + (metadata->videocodecid ? 5 : 0) + 1;
|
||||
|
||||
// ScriptTagBody
|
||||
|
||||
// name
|
||||
ptr = AMFWriteString(ptr, end, "onMetaData", 10);
|
||||
|
||||
// value: SCRIPTDATAECMAARRAY
|
||||
ptr[0] = AMF_ECMA_ARRAY;
|
||||
ptr[1] = (uint8_t)((count >> 24) & 0xFF);;
|
||||
ptr[2] = (uint8_t)((count >> 16) & 0xFF);;
|
||||
ptr[3] = (uint8_t)((count >> 8) & 0xFF);
|
||||
ptr[4] = (uint8_t)(count & 0xFF);
|
||||
ptr += 5;
|
||||
|
||||
if (metadata->audiocodecid)
|
||||
{
|
||||
ptr = AMFWriteNamedDouble(ptr, end, "audiocodecid", 12, metadata->audiocodecid);
|
||||
ptr = AMFWriteNamedDouble(ptr, end, "audiodatarate", 13, metadata->audiodatarate);
|
||||
ptr = AMFWriteNamedDouble(ptr, end, "audiosamplerate", 15, metadata->audiosamplerate);
|
||||
ptr = AMFWriteNamedDouble(ptr, end, "audiosamplesize", 15, metadata->audiosamplesize);
|
||||
ptr = AMFWriteNamedBoolean(ptr, end, "stereo", 6, (uint8_t)metadata->stereo);
|
||||
}
|
||||
|
||||
if (metadata->videocodecid)
|
||||
{
|
||||
ptr = AMFWriteNamedDouble(ptr, end, "videocodecid", 12, metadata->videocodecid);
|
||||
ptr = AMFWriteNamedDouble(ptr, end, "videodatarate", 13, metadata->videodatarate);
|
||||
ptr = AMFWriteNamedDouble(ptr, end, "framerate", 9, metadata->framerate);
|
||||
ptr = AMFWriteNamedDouble(ptr, end, "height", 6, metadata->height);
|
||||
ptr = AMFWriteNamedDouble(ptr, end, "width", 5, metadata->width);
|
||||
}
|
||||
|
||||
ptr = AMFWriteNamedString(ptr, end, "encoder", 7, FLV_MUXER, strlen(FLV_MUXER));
|
||||
ptr = AMFWriteObjectEnd(ptr, end);
|
||||
|
||||
return flv->handler(flv->param, FLV_TYPE_SCRIPT, flv->ptr, ptr - flv->ptr, 0);
|
||||
}
|
89
src/3rdpart/media-server/libflv/source/flv-parser.c
Normal file
89
src/3rdpart/media-server/libflv/source/flv-parser.c
Normal file
@ -0,0 +1,89 @@
|
||||
#include "flv-parser.h"
|
||||
#include "flv-header.h"
|
||||
#include "flv-proto.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
|
||||
#define FLV_VIDEO_CODEC_NAME(codecid) (FLV_VIDEO_H264==(codecid) ? FLV_VIDEO_AVCC : (FLV_VIDEO_H265==(codecid) ? FLV_VIDEO_HVCC : FLV_VIDEO_AV1C))
|
||||
|
||||
static int flv_parser_audio(const uint8_t* data, int bytes, uint32_t timestamp, flv_parser_handler handler, void* param)
|
||||
{
|
||||
int n;
|
||||
struct flv_audio_tag_header_t audio;
|
||||
n = flv_audio_tag_header_read(&audio, data, bytes);
|
||||
if (n < 0)
|
||||
return n;
|
||||
if (FLV_SEQUENCE_HEADER == audio.avpacket)
|
||||
return handler(param, FLV_AUDIO_AAC == audio.codecid ? FLV_AUDIO_ASC : FLV_AUDIO_OPUS_HEAD, data + n, bytes - n, timestamp, timestamp, 0);
|
||||
else
|
||||
return handler(param, audio.codecid, data + n, bytes - n, timestamp, timestamp, 0);
|
||||
}
|
||||
|
||||
static int flv_parser_video(const uint8_t* data, int bytes, uint32_t timestamp, flv_parser_handler handler, void* param)
|
||||
{
|
||||
int n;
|
||||
struct flv_video_tag_header_t video;
|
||||
n = flv_video_tag_header_read(&video, data, bytes);
|
||||
if (n < 0)
|
||||
return n;
|
||||
|
||||
if (FLV_VIDEO_H264 == video.codecid || FLV_VIDEO_H265 == video.codecid || FLV_VIDEO_AV1 == video.codecid)
|
||||
{
|
||||
if (FLV_SEQUENCE_HEADER == video.avpacket)
|
||||
{
|
||||
return handler(param, FLV_VIDEO_CODEC_NAME(video.codecid), data + n, bytes - n, timestamp, timestamp, 0);
|
||||
}
|
||||
else if (FLV_AVPACKET == video.avpacket)
|
||||
{
|
||||
return handler(param, video.codecid, data + n, bytes - n, timestamp + video.cts, timestamp, (FLV_VIDEO_KEY_FRAME == video.keyframe) ? 1 : 0);
|
||||
}
|
||||
else if (FLV_END_OF_SEQUENCE == video.avpacket)
|
||||
{
|
||||
return 0; // AVC end of sequence (lower level NALU sequence ender is not required or supported)
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(0);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Video frame data
|
||||
return handler(param, video.codecid, data + n, bytes - n, timestamp, timestamp, (FLV_VIDEO_KEY_FRAME == video.keyframe) ? 1 : 0);
|
||||
}
|
||||
}
|
||||
|
||||
// http://www.cnblogs.com/musicfans/archive/2012/11/07/2819291.html
|
||||
// metadata keyframes/filepositions
|
||||
static int flv_parser_script(const uint8_t* data, int bytes, uint32_t timestamp, flv_parser_handler handler, void* param)
|
||||
{
|
||||
int n;
|
||||
n = flv_data_tag_header_read(data, bytes);
|
||||
if (n < 0)
|
||||
return n;
|
||||
return handler(param, 0, data + n, bytes - n, timestamp, timestamp, 0);
|
||||
}
|
||||
|
||||
int flv_parser_input(int type, const void* data, size_t bytes, uint32_t timestamp, flv_parser_handler handler, void* param)
|
||||
{
|
||||
if (bytes < 1) return -EINVAL;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case FLV_TYPE_AUDIO:
|
||||
return flv_parser_audio(data, (int)bytes, timestamp, handler, param);
|
||||
|
||||
case FLV_TYPE_VIDEO:
|
||||
return flv_parser_video(data, (int)bytes, timestamp, handler, param);
|
||||
|
||||
case FLV_TYPE_SCRIPT:
|
||||
return flv_parser_script(data, (int)bytes, timestamp, handler, param);
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
return -1;
|
||||
}
|
||||
}
|
135
src/3rdpart/media-server/libflv/source/flv-reader.c
Normal file
135
src/3rdpart/media-server/libflv/source/flv-reader.c
Normal file
@ -0,0 +1,135 @@
|
||||
#include "flv-reader.h"
|
||||
#include "flv-header.h"
|
||||
#include "flv-proto.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define FLV_HEADER_SIZE 9 // DataOffset included
|
||||
#define FLV_TAG_HEADER_SIZE 11 // StreamID included
|
||||
|
||||
struct flv_reader_t
|
||||
{
|
||||
FILE* fp;
|
||||
int (*read)(void* param, void* buf, int len);
|
||||
void* param;
|
||||
};
|
||||
|
||||
static int flv_read_header(struct flv_reader_t* flv)
|
||||
{
|
||||
uint32_t sz;
|
||||
uint8_t data[FLV_HEADER_SIZE];
|
||||
struct flv_header_t h;
|
||||
int n;
|
||||
|
||||
if (FLV_HEADER_SIZE != flv->read(flv->param, data, FLV_HEADER_SIZE))
|
||||
return -1;
|
||||
|
||||
if(FLV_HEADER_SIZE != flv_header_read(&h, data, FLV_HEADER_SIZE))
|
||||
return -1;
|
||||
|
||||
assert(h.offset >= FLV_HEADER_SIZE && h.offset < FLV_HEADER_SIZE + 4096);
|
||||
for(n = (int)(h.offset - FLV_HEADER_SIZE); n > 0 && n < 4096; n -= sizeof(data))
|
||||
flv->read(flv->param, data, n >= sizeof(data) ? sizeof(data) : n); // skip
|
||||
|
||||
// PreviousTagSize0
|
||||
if (4 != flv->read(flv->param, data, 4))
|
||||
return -1;
|
||||
|
||||
flv_tag_size_read(data, 4, &sz);
|
||||
assert(0 == sz);
|
||||
return 0 == sz ? 0 : -1;
|
||||
}
|
||||
|
||||
static int file_read(void* param, void* buf, int len)
|
||||
{
|
||||
return (int)fread(buf, 1, len, (FILE*)param);
|
||||
}
|
||||
|
||||
void* flv_reader_create(const char* file)
|
||||
{
|
||||
FILE* fp;
|
||||
struct flv_reader_t* flv;
|
||||
fp = fopen(file, "rb");
|
||||
if (!fp)
|
||||
return NULL;
|
||||
|
||||
flv = flv_reader_create2(file_read, fp);
|
||||
if (!flv)
|
||||
{
|
||||
fclose(fp);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
flv->fp = fp;
|
||||
return flv;
|
||||
}
|
||||
|
||||
void* flv_reader_create2(int (*read)(void* param, void* buf, int len), void* param)
|
||||
{
|
||||
struct flv_reader_t* flv;
|
||||
flv = (struct flv_reader_t*)calloc(1, sizeof(*flv));
|
||||
if (!flv)
|
||||
return NULL;
|
||||
|
||||
flv->read = read;
|
||||
flv->param = param;
|
||||
if (0 != flv_read_header(flv))
|
||||
{
|
||||
flv_reader_destroy(flv);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return flv;
|
||||
}
|
||||
|
||||
void flv_reader_destroy(void* p)
|
||||
{
|
||||
struct flv_reader_t* flv;
|
||||
flv = (struct flv_reader_t*)p;
|
||||
if (NULL != flv)
|
||||
{
|
||||
if (flv->fp)
|
||||
fclose(flv->fp);
|
||||
free(flv);
|
||||
}
|
||||
}
|
||||
|
||||
int flv_reader_read(void* p, int* tagtype, uint32_t* timestamp, size_t* taglen, void* buffer, size_t bytes)
|
||||
{
|
||||
int r;
|
||||
uint32_t sz;
|
||||
uint8_t header[FLV_TAG_HEADER_SIZE];
|
||||
struct flv_tag_header_t tag;
|
||||
struct flv_reader_t* flv;
|
||||
flv = (struct flv_reader_t*)p;
|
||||
|
||||
r = flv->read(flv->param, &header, FLV_TAG_HEADER_SIZE);
|
||||
if (r != FLV_TAG_HEADER_SIZE)
|
||||
return r < 0 ? r : 0; // 0-EOF
|
||||
|
||||
if (FLV_TAG_HEADER_SIZE != flv_tag_header_read(&tag, header, FLV_TAG_HEADER_SIZE))
|
||||
return -1;
|
||||
|
||||
if (bytes < tag.size)
|
||||
return -1;
|
||||
|
||||
// FLV stream
|
||||
r = flv->read(flv->param, buffer, tag.size);
|
||||
if(tag.size != (uint32_t)r)
|
||||
return r < 0 ? r : 0; // 0-EOF
|
||||
|
||||
// PreviousTagSizeN
|
||||
r = flv->read(flv->param, header, 4);
|
||||
if (4 != r)
|
||||
return r < 0 ? r : 0; // 0-EOF
|
||||
|
||||
*taglen = tag.size;
|
||||
*tagtype = tag.type;
|
||||
*timestamp = tag.timestamp;
|
||||
flv_tag_size_read(header, 4, &sz);
|
||||
assert(0 == tag.streamId); // StreamID Always 0
|
||||
assert(sz == tag.size + FLV_TAG_HEADER_SIZE);
|
||||
return (sz == tag.size + FLV_TAG_HEADER_SIZE) ? 1 : -1;
|
||||
}
|
117
src/3rdpart/media-server/libflv/source/flv-writer.c
Normal file
117
src/3rdpart/media-server/libflv/source/flv-writer.c
Normal file
@ -0,0 +1,117 @@
|
||||
#include "flv-writer.h"
|
||||
#include "flv-header.h"
|
||||
#include "flv-proto.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define FLV_HEADER_SIZE 9 // DataOffset included
|
||||
#define FLV_TAG_HEADER_SIZE 11 // StreamID included
|
||||
|
||||
struct flv_writer_t
|
||||
{
|
||||
FILE* fp;
|
||||
int (*write)(void* param, const void* buf, int len);
|
||||
void* param;
|
||||
};
|
||||
|
||||
static int flv_write_header(struct flv_writer_t* flv)
|
||||
{
|
||||
uint8_t header[FLV_HEADER_SIZE + 4];
|
||||
flv_header_write(1, 1, header, FLV_HEADER_SIZE);
|
||||
flv_tag_size_write(header + FLV_HEADER_SIZE, 4, 0); // PreviousTagSize0(Always 0)
|
||||
return sizeof(header) == flv->write(flv->param, header, sizeof(header)) ? 0 : -1;
|
||||
}
|
||||
|
||||
static int flv_write_eos(struct flv_writer_t* flv)
|
||||
{
|
||||
int n;
|
||||
uint8_t header[16];
|
||||
struct flv_video_tag_header_t video;
|
||||
memset(&video, 0, sizeof(video));
|
||||
video.codecid = FLV_VIDEO_H264;
|
||||
video.keyframe = 1;
|
||||
video.avpacket = FLV_END_OF_SEQUENCE;
|
||||
video.cts = 0;
|
||||
|
||||
n = flv_video_tag_header_write(&video, header, sizeof(header));
|
||||
return n > 0 ? flv_writer_input(flv, FLV_TYPE_VIDEO, header, n, 0) : -1;
|
||||
}
|
||||
|
||||
static int file_write(void* param, const void* buf, int len)
|
||||
{
|
||||
return (int)fwrite(buf, 1, len, (FILE*)param);
|
||||
}
|
||||
|
||||
void* flv_writer_create(const char* file)
|
||||
{
|
||||
FILE* fp;
|
||||
struct flv_writer_t* flv;
|
||||
fp = fopen(file, "wb");
|
||||
if (!fp)
|
||||
return NULL;
|
||||
|
||||
flv = flv_writer_create2(file_write, fp);
|
||||
if (!flv)
|
||||
{
|
||||
fclose(fp);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
flv->fp = fp;
|
||||
return flv;
|
||||
}
|
||||
|
||||
void* flv_writer_create2(int (*write)(void* param, const void* buf, int len), void* param)
|
||||
{
|
||||
struct flv_writer_t* flv;
|
||||
flv = (struct flv_writer_t*)calloc(1, sizeof(*flv));
|
||||
if (!flv)
|
||||
return NULL;
|
||||
|
||||
flv->write = write;
|
||||
flv->param = param;
|
||||
if (0 != flv_write_header(flv))
|
||||
{
|
||||
flv_writer_destroy(flv);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return flv;
|
||||
}
|
||||
|
||||
void flv_writer_destroy(void* p)
|
||||
{
|
||||
struct flv_writer_t* flv;
|
||||
flv = (struct flv_writer_t*)p;
|
||||
|
||||
if (NULL != flv)
|
||||
{
|
||||
flv_write_eos(flv);
|
||||
if (flv->fp)
|
||||
fclose(flv->fp);
|
||||
free(flv);
|
||||
}
|
||||
}
|
||||
|
||||
int flv_writer_input(void* p, int type, const void* data, size_t bytes, uint32_t timestamp)
|
||||
{
|
||||
uint8_t buf[FLV_TAG_HEADER_SIZE + 4];
|
||||
struct flv_writer_t* flv;
|
||||
struct flv_tag_header_t tag;
|
||||
flv = (struct flv_writer_t*)p;
|
||||
|
||||
memset(&tag, 0, sizeof(tag));
|
||||
tag.size = (int)bytes;
|
||||
tag.type = (uint8_t)type;
|
||||
tag.timestamp = timestamp;
|
||||
flv_tag_header_write(&tag, buf, FLV_TAG_HEADER_SIZE);
|
||||
flv_tag_size_write(buf + FLV_TAG_HEADER_SIZE, 4, (uint32_t)bytes + FLV_TAG_HEADER_SIZE);
|
||||
|
||||
if(FLV_TAG_HEADER_SIZE != flv->write(flv->param, buf, FLV_TAG_HEADER_SIZE) // FLV Tag Header
|
||||
|| bytes != (size_t)flv->write(flv->param, data, (int)bytes)
|
||||
|| 4 != flv->write(flv->param, buf + FLV_TAG_HEADER_SIZE, 4)) // TAG size
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
466
src/3rdpart/media-server/libflv/source/hevc-annexbtomp4.c
Normal file
466
src/3rdpart/media-server/libflv/source/hevc-annexbtomp4.c
Normal file
@ -0,0 +1,466 @@
|
||||
#include "mpeg4-hevc.h"
|
||||
#include "mpeg4-avc.h"
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#define H265_NAL_VPS 32
|
||||
#define H265_NAL_SPS 33
|
||||
#define H265_NAL_PPS 34
|
||||
#define H265_NAL_AUD 35
|
||||
#define H265_NAL_SEI_PREFIX 39
|
||||
#define H265_NAL_SEI_SUFFIX 40
|
||||
|
||||
#define MAX(x, y) ((x) > (y) ? (x) : (y))
|
||||
|
||||
#define BIT(ptr, off) (((ptr)[(off) / 8] >> (7 - ((off) % 8))) & 0x01)
|
||||
|
||||
struct h265_annexbtomp4_handle_t
|
||||
{
|
||||
struct mpeg4_hevc_t* hevc;
|
||||
int errcode;
|
||||
int* update; // avc sps/pps update flags
|
||||
int* vcl;
|
||||
|
||||
uint8_t* out;
|
||||
int bytes;
|
||||
int capacity;
|
||||
};
|
||||
|
||||
uint8_t mpeg4_h264_read_ue(const uint8_t* data, int bytes, int* offset);
|
||||
|
||||
static int hevc_rbsp_decode(const uint8_t* nalu, int bytes, uint8_t* sodb)
|
||||
{
|
||||
int i, j;
|
||||
for (j = i = 0; i < bytes; i++)
|
||||
{
|
||||
if (i + 2 < bytes && 0 == nalu[i] && 0 == nalu[i + 1] && 0x03 == nalu[i + 2])
|
||||
{
|
||||
sodb[j++] = nalu[i];
|
||||
sodb[j++] = nalu[i + 1];
|
||||
i += 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
sodb[j++] = nalu[i];
|
||||
}
|
||||
}
|
||||
return j;
|
||||
}
|
||||
|
||||
static int hevc_profile_tier_level(const uint8_t* nalu, int bytes, uint8_t maxNumSubLayersMinus1, struct mpeg4_hevc_t* hevc)
|
||||
{
|
||||
int n;
|
||||
uint8_t i;
|
||||
uint8_t sub_layer_profile_present_flag[8];
|
||||
uint8_t sub_layer_level_present_flag[8];
|
||||
|
||||
if (bytes < 12)
|
||||
return -1;
|
||||
|
||||
hevc->general_profile_space = (nalu[0] >> 6) & 0x03;
|
||||
hevc->general_tier_flag = (nalu[0] >> 5) & 0x01;
|
||||
hevc->general_profile_idc = nalu[0] & 0x1f;
|
||||
|
||||
hevc->general_profile_compatibility_flags = 0;
|
||||
hevc->general_profile_compatibility_flags |= nalu[1] << 24;
|
||||
hevc->general_profile_compatibility_flags |= nalu[2] << 16;
|
||||
hevc->general_profile_compatibility_flags |= nalu[3] << 8;
|
||||
hevc->general_profile_compatibility_flags |= nalu[4];
|
||||
|
||||
hevc->general_constraint_indicator_flags = 0;
|
||||
hevc->general_constraint_indicator_flags |= ((uint64_t)nalu[5]) << 40;
|
||||
hevc->general_constraint_indicator_flags |= ((uint64_t)nalu[6]) << 32;
|
||||
hevc->general_constraint_indicator_flags |= ((uint64_t)nalu[7]) << 24;
|
||||
hevc->general_constraint_indicator_flags |= ((uint64_t)nalu[8]) << 16;
|
||||
hevc->general_constraint_indicator_flags |= ((uint64_t)nalu[9]) << 8;
|
||||
hevc->general_constraint_indicator_flags |= nalu[10];
|
||||
|
||||
hevc->general_level_idc = nalu[11];
|
||||
if (maxNumSubLayersMinus1 < 1)
|
||||
return 12;
|
||||
|
||||
if (bytes < 14)
|
||||
return -1; // error
|
||||
|
||||
for (i = 0; i < maxNumSubLayersMinus1; i++)
|
||||
{
|
||||
sub_layer_profile_present_flag[i] = BIT(nalu, 12 * 8 + i * 2);
|
||||
sub_layer_level_present_flag[i] = BIT(nalu, 12 * 8 + i * 2 + 1);
|
||||
}
|
||||
|
||||
n = 12 + 2;
|
||||
for (i = 0; i < maxNumSubLayersMinus1; i++)
|
||||
{
|
||||
if(sub_layer_profile_present_flag[i])
|
||||
n += 11;
|
||||
if (sub_layer_level_present_flag[i])
|
||||
n += 1;
|
||||
}
|
||||
|
||||
return bytes < n ? n : -1;
|
||||
}
|
||||
|
||||
static uint8_t hevc_vps_id(const uint8_t* rbsp, int bytes, struct mpeg4_hevc_t* hevc, uint8_t* ptr)
|
||||
{
|
||||
int sodb;
|
||||
uint8_t vps;
|
||||
uint8_t vps_max_sub_layers_minus1;
|
||||
uint8_t vps_temporal_id_nesting_flag;
|
||||
|
||||
sodb = hevc_rbsp_decode(rbsp, bytes, ptr);
|
||||
if (sodb < 16 + 2)
|
||||
return 0xFF;
|
||||
|
||||
vps = ptr[2] >> 4; // 2-nalu type
|
||||
vps_max_sub_layers_minus1 = (ptr[3] >> 1) & 0x07;
|
||||
vps_temporal_id_nesting_flag = ptr[3] & 0x01;
|
||||
hevc->numTemporalLayers = MAX(hevc->numTemporalLayers, vps_max_sub_layers_minus1 + 1);
|
||||
hevc->temporalIdNested = (hevc->temporalIdNested || vps_temporal_id_nesting_flag) ? 1 : 0;
|
||||
hevc_profile_tier_level(ptr + 6, sodb - 6, vps_max_sub_layers_minus1, hevc);
|
||||
|
||||
return vps;
|
||||
}
|
||||
|
||||
static uint8_t hevc_sps_id(const uint8_t* rbsp, int bytes, struct mpeg4_hevc_t* hevc, uint8_t* ptr, uint8_t* vps)
|
||||
{
|
||||
int n;
|
||||
int sodb;
|
||||
uint8_t sps;
|
||||
uint8_t sps_max_sub_layers_minus1;
|
||||
uint8_t sps_temporal_id_nesting_flag;
|
||||
uint8_t conformance_window_flag;
|
||||
|
||||
sodb = hevc_rbsp_decode(rbsp, bytes, ptr);
|
||||
if (sodb < 12+3)
|
||||
return 0xFF;
|
||||
|
||||
*vps = ptr[2] >> 4; // 2-nalu type
|
||||
sps_max_sub_layers_minus1 = (ptr[2] >> 1) & 0x07;
|
||||
sps_temporal_id_nesting_flag = ptr[2] & 0x01;
|
||||
n = hevc_profile_tier_level(ptr + 3, sodb - 3, sps_max_sub_layers_minus1, hevc);
|
||||
if (n <= 0)
|
||||
return 0xFF;
|
||||
|
||||
n = (n + 3) * 8;
|
||||
sps = mpeg4_h264_read_ue(ptr, sodb, &n);
|
||||
hevc->chromaFormat = mpeg4_h264_read_ue(ptr, sodb, &n);
|
||||
if (3 == hevc->chromaFormat)
|
||||
n++;
|
||||
mpeg4_h264_read_ue(ptr, sodb, &n); // pic_width_in_luma_samples
|
||||
mpeg4_h264_read_ue(ptr, sodb, &n); // pic_height_in_luma_samples
|
||||
conformance_window_flag = BIT(ptr, n); n++; // conformance_window_flag
|
||||
if (conformance_window_flag)
|
||||
{
|
||||
mpeg4_h264_read_ue(ptr, sodb, &n); // conf_win_left_offset
|
||||
mpeg4_h264_read_ue(ptr, sodb, &n); // conf_win_right_offset
|
||||
mpeg4_h264_read_ue(ptr, sodb, &n); // conf_win_top_offset
|
||||
mpeg4_h264_read_ue(ptr, sodb, &n); // conf_win_bottom_offset
|
||||
}
|
||||
hevc->bitDepthLumaMinus8 = mpeg4_h264_read_ue(ptr, sodb, &n);
|
||||
hevc->bitDepthChromaMinus8 = mpeg4_h264_read_ue(ptr, sodb, &n);
|
||||
|
||||
// TODO: vui_parameters
|
||||
//mp4->hevc->min_spatial_segmentation_idc; // min_spatial_segmentation_idc
|
||||
return sps;
|
||||
}
|
||||
|
||||
static uint8_t hevc_pps_id(const uint8_t* rbsp, int bytes, struct mpeg4_hevc_t* hevc, uint8_t* ptr, uint8_t* sps)
|
||||
{
|
||||
// TODO:
|
||||
//hevc->parallelismType; // entropy_coding_sync_enabled_flag
|
||||
(void)hevc;
|
||||
|
||||
int sodb;
|
||||
int offset = 2 * 8; // 2-nalu type
|
||||
sodb = hevc_rbsp_decode(rbsp, bytes, ptr);
|
||||
if (sodb < 3)
|
||||
return 0xFF;
|
||||
*sps = mpeg4_h264_read_ue(ptr, sodb, &offset);
|
||||
return mpeg4_h264_read_ue(ptr, sodb, &offset);
|
||||
}
|
||||
|
||||
static void mpeg4_hevc_remove(struct mpeg4_hevc_t* hevc, uint8_t* ptr, int bytes, const uint8_t* end)
|
||||
{
|
||||
uint8_t i;
|
||||
assert(ptr >= hevc->data && ptr + bytes <= end && end <= hevc->data + sizeof(hevc->data));
|
||||
memmove(ptr, ptr + bytes, end - ptr - bytes);
|
||||
|
||||
for (i = 0; i < hevc->numOfArrays; i++)
|
||||
{
|
||||
if (hevc->nalu[i].data > ptr)
|
||||
hevc->nalu[i].data -= bytes;
|
||||
}
|
||||
}
|
||||
|
||||
static int mpeg4_hevc_update2(struct mpeg4_hevc_t* hevc, int i, const uint8_t* nalu, int bytes)
|
||||
{
|
||||
if (bytes == hevc->nalu[i].bytes && 0 == memcmp(nalu, hevc->nalu[i].data, bytes))
|
||||
return 0; // do nothing
|
||||
|
||||
if (bytes > hevc->nalu[i].bytes && hevc->off + (bytes - hevc->nalu[i].bytes) > sizeof(hevc->data))
|
||||
{
|
||||
assert(0);
|
||||
return -1; // too big
|
||||
}
|
||||
|
||||
mpeg4_hevc_remove(hevc, hevc->nalu[i].data, hevc->nalu[i].bytes, hevc->data + hevc->off);
|
||||
hevc->off -= hevc->nalu[i].bytes;
|
||||
|
||||
hevc->nalu[i].data = hevc->data + hevc->off;
|
||||
hevc->nalu[i].bytes = (uint16_t)bytes;
|
||||
memcpy(hevc->nalu[i].data, nalu, bytes);
|
||||
hevc->off += bytes;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int mpeg4_hevc_add(struct mpeg4_hevc_t* hevc, uint8_t type, const uint8_t* nalu, int bytes)
|
||||
{
|
||||
// copy new
|
||||
assert(hevc->numOfArrays < sizeof(hevc->nalu) / sizeof(hevc->nalu[0]));
|
||||
if (hevc->numOfArrays >= sizeof(hevc->nalu) / sizeof(hevc->nalu[0])
|
||||
|| hevc->off + bytes > sizeof(hevc->data))
|
||||
{
|
||||
assert(0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
hevc->nalu[hevc->numOfArrays].type = type;
|
||||
hevc->nalu[hevc->numOfArrays].bytes = (uint16_t)bytes;
|
||||
hevc->nalu[hevc->numOfArrays].array_completeness = 1;
|
||||
hevc->nalu[hevc->numOfArrays].data = hevc->data + hevc->off;
|
||||
memcpy(hevc->nalu[hevc->numOfArrays].data, nalu, bytes);
|
||||
hevc->off += bytes;
|
||||
++hevc->numOfArrays;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int h265_vps_copy(struct mpeg4_hevc_t* hevc, const uint8_t* nalu, int bytes)
|
||||
{
|
||||
int i;
|
||||
uint8_t vpsid;
|
||||
|
||||
if (bytes < 3)
|
||||
{
|
||||
assert(0);
|
||||
return -1; // invalid length
|
||||
}
|
||||
|
||||
vpsid = hevc_vps_id(nalu, bytes, hevc, hevc->data + hevc->off);
|
||||
for (i = 0; i < hevc->numOfArrays; i++)
|
||||
{
|
||||
if (H265_NAL_VPS == hevc->nalu[i].type && vpsid == hevc_vps_id(hevc->nalu[i].data, hevc->nalu[i].bytes, hevc, hevc->data + hevc->off))
|
||||
return mpeg4_hevc_update2(hevc, i, nalu, bytes);
|
||||
}
|
||||
|
||||
return mpeg4_hevc_add(hevc, H265_NAL_VPS, nalu, bytes);
|
||||
}
|
||||
|
||||
static int h265_sps_copy(struct mpeg4_hevc_t* hevc, const uint8_t* nalu, int bytes)
|
||||
{
|
||||
int i;
|
||||
uint8_t spsid;
|
||||
uint8_t vpsid, vpsid2;
|
||||
|
||||
if (bytes < 13 + 2)
|
||||
{
|
||||
assert(0);
|
||||
return -1; // invalid length
|
||||
}
|
||||
|
||||
spsid = hevc_sps_id(nalu, bytes, hevc, hevc->data + hevc->off, &vpsid);
|
||||
for (i = 0; i < hevc->numOfArrays; i++)
|
||||
{
|
||||
if (H265_NAL_SPS == hevc->nalu[i].type && spsid == hevc_sps_id(hevc->nalu[i].data, hevc->nalu[i].bytes, hevc, hevc->data + hevc->off, &vpsid2) && vpsid == vpsid2)
|
||||
return mpeg4_hevc_update2(hevc, i, nalu, bytes);
|
||||
}
|
||||
|
||||
return mpeg4_hevc_add(hevc, H265_NAL_SPS, nalu, bytes);
|
||||
}
|
||||
|
||||
static int h265_pps_copy(struct mpeg4_hevc_t* hevc, const uint8_t* nalu, int bytes)
|
||||
{
|
||||
int i;
|
||||
uint8_t ppsid;
|
||||
uint8_t spsid, spsid2;
|
||||
|
||||
if (bytes < 1 + 2)
|
||||
{
|
||||
assert(0);
|
||||
return -1; // invalid length
|
||||
}
|
||||
|
||||
ppsid = hevc_pps_id(nalu, bytes, hevc, hevc->data + hevc->off, &spsid);
|
||||
for (i = 0; i < hevc->numOfArrays; i++)
|
||||
{
|
||||
if (H265_NAL_PPS == hevc->nalu[i].type && ppsid == hevc_pps_id(hevc->nalu[i].data, hevc->nalu[i].bytes, hevc, hevc->data + hevc->off, &spsid2) && spsid == spsid2)
|
||||
return mpeg4_hevc_update2(hevc, i, nalu, bytes);
|
||||
}
|
||||
|
||||
return mpeg4_hevc_add(hevc, H265_NAL_PPS, nalu, bytes);
|
||||
}
|
||||
|
||||
static int h265_sei_clear(struct mpeg4_hevc_t* hevc)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < hevc->numOfArrays; i++)
|
||||
{
|
||||
if (H265_NAL_SEI_PREFIX == hevc->nalu[i].type || H265_NAL_SEI_SUFFIX == hevc->nalu[i].type)
|
||||
{
|
||||
mpeg4_hevc_remove(hevc, hevc->nalu[i].data, hevc->nalu[i].bytes, hevc->data + hevc->off);
|
||||
hevc->off -= hevc->nalu[i].bytes;
|
||||
if(i + 1 < hevc->numOfArrays)
|
||||
memmove(hevc->nalu + i, hevc->nalu + i + 1, sizeof(hevc->nalu[0]) * (hevc->numOfArrays - i - 1));
|
||||
--hevc->numOfArrays;
|
||||
--i;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mpeg4_hevc_update(struct mpeg4_hevc_t* hevc, const uint8_t* nalu, int bytes)
|
||||
{
|
||||
int r;
|
||||
|
||||
switch ((nalu[0] >> 1) & 0x3f)
|
||||
{
|
||||
case H265_NAL_VPS:
|
||||
h265_sei_clear(hevc); // remove all prefix/suffix sei
|
||||
r = h265_vps_copy(hevc, nalu, bytes);
|
||||
break;
|
||||
|
||||
case H265_NAL_SPS:
|
||||
r = h265_sps_copy(hevc, nalu, bytes);
|
||||
break;
|
||||
|
||||
case H265_NAL_PPS:
|
||||
r = h265_pps_copy(hevc, nalu, bytes);
|
||||
break;
|
||||
|
||||
#if defined(H265_FILTER_SEI)
|
||||
case H265_NAL_SEI_PREFIX:
|
||||
r = mpeg4_hevc_add(hevc, H265_NAL_SEI_PREFIX, nalu, bytes);
|
||||
break;
|
||||
|
||||
case H265_NAL_SEI_SUFFIX:
|
||||
r = mpeg4_hevc_add(hevc, H265_NAL_SEI_SUFFIX, nalu, bytes);
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
r = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static void hevc_handler(void* param, const uint8_t* nalu, int bytes)
|
||||
{
|
||||
int r;
|
||||
uint8_t nalutype;
|
||||
struct h265_annexbtomp4_handle_t* mp4;
|
||||
mp4 = (struct h265_annexbtomp4_handle_t*)param;
|
||||
|
||||
nalutype = (nalu[0] >> 1) & 0x3f;
|
||||
#if defined(H2645_FILTER_AUD)
|
||||
if(H265_NAL_AUD == nalutype)
|
||||
return; // ignore AUD
|
||||
#endif
|
||||
|
||||
r = mpeg4_hevc_update(mp4->hevc, nalu, bytes);
|
||||
if (1 == r && mp4->update)
|
||||
*mp4->update = 1;
|
||||
else if (r < 0)
|
||||
mp4->errcode = r;
|
||||
|
||||
// IRAP-1, B/P-2, other-0
|
||||
if (mp4->vcl && nalutype < H265_NAL_VPS)
|
||||
*mp4->vcl = 16<=nalutype && nalutype<=23 ? 1 : 2;
|
||||
|
||||
if (mp4->capacity >= mp4->bytes + bytes + 4)
|
||||
{
|
||||
mp4->out[mp4->bytes + 0] = (uint8_t)((bytes >> 24) & 0xFF);
|
||||
mp4->out[mp4->bytes + 1] = (uint8_t)((bytes >> 16) & 0xFF);
|
||||
mp4->out[mp4->bytes + 2] = (uint8_t)((bytes >> 8) & 0xFF);
|
||||
mp4->out[mp4->bytes + 3] = (uint8_t)((bytes >> 0) & 0xFF);
|
||||
memcpy(mp4->out + mp4->bytes + 4, nalu, bytes);
|
||||
mp4->bytes += bytes + 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
mp4->errcode = -1;
|
||||
}
|
||||
}
|
||||
|
||||
int h265_annexbtomp4(struct mpeg4_hevc_t* hevc, const void* data, int bytes, void* out, int size, int *vcl, int* update)
|
||||
{
|
||||
struct h265_annexbtomp4_handle_t h;
|
||||
memset(&h, 0, sizeof(h));
|
||||
h.hevc = hevc;
|
||||
h.vcl = vcl;
|
||||
h.update = update;
|
||||
h.out = (uint8_t*)out;
|
||||
h.capacity = size;
|
||||
if (vcl) *vcl = 0;
|
||||
if (update) *update = 0;
|
||||
|
||||
// hevc->numTemporalLayers = 0;
|
||||
// hevc->temporalIdNested = 0;
|
||||
// hevc->min_spatial_segmentation_idc = 0;
|
||||
// hevc->general_profile_compatibility_flags = 0xffffffff;
|
||||
// hevc->general_constraint_indicator_flags = 0xffffffffffULL;
|
||||
// hevc->chromaFormat = 1; // 4:2:0
|
||||
|
||||
mpeg4_h264_annexb_nalu((const uint8_t*)data, bytes, hevc_handler, &h);
|
||||
hevc->configurationVersion = 1;
|
||||
hevc->lengthSizeMinusOne = 3; // 4 bytes
|
||||
return 0 == h.errcode ? h.bytes : 0;
|
||||
}
|
||||
|
||||
int h265_is_new_access_unit(const uint8_t* nalu, size_t bytes)
|
||||
{
|
||||
enum { NAL_VPS = 32, NAL_SPS = 33, NAL_PPS = 34, NAL_AUD = 35, NAL_PREFIX_SEI = 39, };
|
||||
|
||||
uint8_t nal_type;
|
||||
uint8_t nuh_layer_id;
|
||||
|
||||
if(bytes < 3)
|
||||
return 0;
|
||||
|
||||
nal_type = (nalu[0] >> 1) & 0x3f;
|
||||
nuh_layer_id = ((nalu[0] & 0x01) << 5) | ((nalu[1] >> 3) &0x1F);
|
||||
|
||||
// 7.4.2.4.4 Order of NAL units and coded pictures and their association to access units
|
||||
if(NAL_VPS == nal_type || NAL_SPS == nal_type || NAL_PPS == nal_type ||
|
||||
(nuh_layer_id == 0 && (NAL_AUD == nal_type || NAL_PREFIX_SEI == nal_type || (41 <= nal_type && nal_type <= 44) || (48 <= nal_type && nal_type <= 55))))
|
||||
return 1;
|
||||
|
||||
// 7.4.2.4.5 Order of VCL NAL units and association to coded pictures
|
||||
if (nal_type <= 31)
|
||||
{
|
||||
//first_slice_segment_in_pic_flag 0x80
|
||||
return (nalu[2] & 0x80) ? 1 : 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(_DEBUG) || defined(DEBUG)
|
||||
void hevc_annexbtomp4_test(void)
|
||||
{
|
||||
const uint8_t vps[] = { 0x40, 0x01, 0x0c, 0x01, 0xff, 0xff, 0x01, 0x60, 0x00, 0x00, 0x03, 0x00, 0x80, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x78, 0x9d, 0xc0, 0x90 };
|
||||
const uint8_t sps[] = { 0x42, 0x01, 0x01, 0x01, 0x60, 0x00, 0x00, 0x03, 0x00, 0x80, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x78, 0xa0, 0x03, 0xc0, 0x80, 0x32, 0x16, 0x59, 0xde, 0x49, 0x1b, 0x6b, 0x80, 0x40, 0x00, 0x00, 0xfa, 0x00, 0x00, 0x17, 0x70, 0x02 };
|
||||
const uint8_t pps[] = { 0x44, 0x01, 0xc1, 0x73, 0xd1, 0x89 };
|
||||
const uint8_t annexb[] = { 0x00, 0x00, 0x00, 0x01, 0x4e, 0x01, 0x06, 0x01, 0xd0, 0x80, 0x00, 0x00, 0x00, 0x01, 0x40, 0x01, 0x0c, 0x01, 0xff, 0xff, 0x01, 0x60, 0x00, 0x00, 0x03, 0x00, 0x80, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x78, 0x9d, 0xc0, 0x90, 0x00, 0x00, 0x00, 0x01, 0x42, 0x01, 0x01, 0x01, 0x60, 0x00, 0x00, 0x03, 0x00, 0x80, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x78, 0xa0, 0x03, 0xc0, 0x80, 0x32, 0x16, 0x59, 0xde, 0x49, 0x1b, 0x6b, 0x80, 0x40, 0x00, 0x00, 0xfa, 0x00, 0x00, 0x17, 0x70, 0x02, 0x00, 0x00, 0x00, 0x01, 0x44, 0x01, 0xc1, 0x73, 0xd1, 0x89 };
|
||||
uint8_t output[512];
|
||||
int vcl, update;
|
||||
|
||||
struct mpeg4_hevc_t hevc;
|
||||
memset(&hevc, 0, sizeof(hevc));
|
||||
assert(h265_annexbtomp4(&hevc, annexb, sizeof(annexb), output, sizeof(output), &vcl, &update) > 0);
|
||||
assert(3 == hevc.numOfArrays && vcl == 0 && update == 1);
|
||||
assert(hevc.nalu[0].bytes == sizeof(vps) && 0 == memcmp(hevc.nalu[0].data, vps, sizeof(vps)));
|
||||
assert(hevc.nalu[1].bytes == sizeof(sps) && 0 == memcmp(hevc.nalu[1].data, sps, sizeof(sps)));
|
||||
assert(hevc.nalu[2].bytes == sizeof(pps) && 0 == memcmp(hevc.nalu[2].data, pps, sizeof(pps)));
|
||||
}
|
||||
#endif
|
59
src/3rdpart/media-server/libflv/source/hevc-mp4toannexb.c
Normal file
59
src/3rdpart/media-server/libflv/source/hevc-mp4toannexb.c
Normal file
@ -0,0 +1,59 @@
|
||||
#include "mpeg4-hevc.h"
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#define H265_NAL_AUD 35 // Access unit delimiter
|
||||
|
||||
int h265_mp4toannexb(const struct mpeg4_hevc_t* hevc, const void* data, int bytes, void* out, int size)
|
||||
{
|
||||
int r;
|
||||
uint8_t i;
|
||||
uint8_t* dst, *dstend;
|
||||
const uint8_t* src, *srcend;
|
||||
const uint8_t startcode[] = { 0, 0, 0, 1 };
|
||||
uint8_t irap, nalu_type;
|
||||
uint32_t nalu_size;
|
||||
uint8_t vps_sps_pps_flag;
|
||||
|
||||
srcend = (uint8_t*)data + bytes;
|
||||
dst = (uint8_t*)out;
|
||||
dstend = dst + size;
|
||||
vps_sps_pps_flag = 0;
|
||||
|
||||
for(src = (uint8_t*)data; src + hevc->lengthSizeMinusOne + 1 < srcend; src += nalu_size)
|
||||
{
|
||||
nalu_size = 0;
|
||||
for (i = 0; i < hevc->lengthSizeMinusOne + 1; i++)
|
||||
nalu_size = (nalu_size << 8) | src[i];
|
||||
src += hevc->lengthSizeMinusOne + 1;
|
||||
if (nalu_size < 1 || src + nalu_size > srcend)
|
||||
{
|
||||
assert(0);
|
||||
return 0; // invalid
|
||||
}
|
||||
|
||||
nalu_type = (src[0] >> 1) & 0x3F;
|
||||
#if defined(H2645_FILTER_AUD)
|
||||
if (H265_NAL_AUD == nalu_type)
|
||||
continue; // ignore AUD
|
||||
#endif
|
||||
irap = 16 <= nalu_type && nalu_type <= 23;
|
||||
if (irap && 0 == vps_sps_pps_flag)
|
||||
{
|
||||
r = mpeg4_hevc_to_nalu(hevc, dst, dstend - dst);
|
||||
if (r <= 0)
|
||||
return 0; // don't have enough memory
|
||||
|
||||
dst += r;
|
||||
vps_sps_pps_flag = 1;
|
||||
}
|
||||
|
||||
if (dst + nalu_size + 4 > dstend)
|
||||
return 0; // don't have enough memory
|
||||
memcpy(dst, startcode, 4);
|
||||
memcpy(dst + 4, src, nalu_size);
|
||||
dst += 4 + nalu_size;
|
||||
}
|
||||
|
||||
return (int)(dst - (uint8_t*)out);
|
||||
}
|
233
src/3rdpart/media-server/libflv/source/mp3-header.c
Normal file
233
src/3rdpart/media-server/libflv/source/mp3-header.c
Normal file
@ -0,0 +1,233 @@
|
||||
#include "mp3-header.h"
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
// layer-1, layer-2, layer-3
|
||||
static int s_bitrate_mpeg1[3][16] = {
|
||||
{ 0/*free*/, 32000, 64000, 96000, 128000, 160000, 192000, 224000, 256000, 288000, 320000, 352000, 384000, 416000, 448000, -1 },
|
||||
{ 0/*free*/, 32000, 48000, 56000, 64000, 80000, 96000, 112000, 128000, 160000, 192000, 224000, 256000, 320000, 384000, -1 },
|
||||
{ 0/*free*/, 32000, 40000, 48000, 56000, 64000, 80000, 96000, 112000, 128000, 160000, 192000, 224000, 256000, 320000, -1 },
|
||||
};
|
||||
|
||||
// layer-1, layer-2, layer-3
|
||||
static int s_bitrate_mpeg2[3][16] = {
|
||||
{ 0/*free*/, 32000, 48000, 56000, 64000, 80000, 96000, 112000, 128000, 144000, 160000, 176000, 192000, 224000, 256000, -1 },
|
||||
{ 0/*free*/, 8000, 16000, 24000, 32000, 40000, 48000, 56000, 64000, 80000, 96000, 112000, 128000, 144000, 160000, -1 },
|
||||
{ 0/*free*/, 8000, 16000, 24000, 32000, 40000, 48000, 56000, 64000, 80000, 96000, 112000, 128000, 144000, 160000, -1 },
|
||||
};
|
||||
|
||||
// layer-1, layer-2, layer-3
|
||||
static int s_frequency_mpeg1[4] = { 44100, 48000, 32000, -1 };
|
||||
static int s_frequency_mpeg2[4] = { 22050, 24000, 16000, -1 };
|
||||
static int s_frequency_mpeg25[4] = { 11025, 12000, 8000, -1 };
|
||||
|
||||
// layer-1, layer-2, layer-3
|
||||
//static int s_frames_mpeg1[3] = { 384, 1152, 1152 };
|
||||
//static int s_frames_mpeg2[3] = { 384, 1152, 576 };
|
||||
//static int s_frames_mpeg25[3] = { 384, 1152, 576 };
|
||||
|
||||
// layer-1 bytes = ((frames / 8 * bitrate) / frequency + padding * 4
|
||||
// layer-2/3 bytes = ((frames / 8 * bitrate) / frequency + padding
|
||||
|
||||
int mp3_header_load(struct mp3_header_t* mp3, const void* data, int bytes)
|
||||
{
|
||||
const uint8_t* p;
|
||||
if (bytes < 4)
|
||||
return 0;
|
||||
|
||||
p = data;
|
||||
if (0 == memcmp("TAG", p, 3))
|
||||
{
|
||||
if (bytes < 128/*ID3v1*/ + 4)
|
||||
return 0;
|
||||
p += 128;
|
||||
}
|
||||
else if (0 == memcmp("ID3", p, 3))
|
||||
{
|
||||
uint32_t n;
|
||||
if (3 != p[3]/*version*/ || bytes < 10)
|
||||
return 0;
|
||||
n = (((uint32_t)p[6] & 0x7F) << 21) | (((uint32_t)p[7] & 0x7F) << 14) | (((uint32_t)p[8] & 0x7F) << 7) | (p[9] & 0x7F);
|
||||
if (bytes < (int)n + 10)
|
||||
return 0;
|
||||
p += n + 10;
|
||||
}
|
||||
|
||||
//sync: 1111 1111 111
|
||||
if (0xFF != p[0] || 0xE0 != (p[1] & 0xE0))
|
||||
{
|
||||
assert(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
mp3->version = (p[1] >> 3) & 0x03;
|
||||
mp3->layer = (p[1] >> 1) & 0x03;
|
||||
mp3->protection = p[1] & 0x01;
|
||||
mp3->bitrate_index = (p[2] >> 4) & 0x0F;
|
||||
mp3->sampling_frequency = (p[2] >> 2) & 0x03;
|
||||
mp3->priviate = p[2] & 0x01;
|
||||
mp3->mode = (p[3] >> 6) & 0x03;
|
||||
mp3->mode_extension = (p[3] >> 4) & 0x03;
|
||||
mp3->copyright = (p[3] >> 3) & 0x01;
|
||||
mp3->original = (p[3] >> 2) & 0x01;
|
||||
mp3->emphasis = p[3] & 0x03;
|
||||
|
||||
return (int)(p - (uint8_t*)data) + 4;
|
||||
}
|
||||
|
||||
int mp3_header_save(const struct mp3_header_t* mp3, void* data, int bytes)
|
||||
{
|
||||
uint8_t* p;
|
||||
if (bytes < 4)
|
||||
return 0;
|
||||
|
||||
p = data;
|
||||
p[0] = 0xFF;
|
||||
p[1] = (uint8_t)(0xE0 | (mp3->version << 3) | (mp3->layer << 1) | mp3->protection);
|
||||
p[2] = (uint8_t)((mp3->bitrate_index << 4) | (mp3->sampling_frequency << 2) | 0x00 /*padding*/ | mp3->priviate);
|
||||
p[3] = (uint8_t)((mp3->mode << 6) | (mp3->mode_extension << 4) | (mp3->copyright << 3) | (mp3->original << 2) | mp3->emphasis);
|
||||
return 4;
|
||||
}
|
||||
|
||||
int mp3_get_channel(const struct mp3_header_t* mp3)
|
||||
{
|
||||
return 0x03 == mp3->mode ? 1 : 2;
|
||||
}
|
||||
|
||||
int mp3_get_bitrate(const struct mp3_header_t* mp3)
|
||||
{
|
||||
if (mp3->layer < 1 || mp3->layer > 3)
|
||||
{
|
||||
assert(0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch (mp3->version)
|
||||
{
|
||||
case MP3_MPEG1:
|
||||
return s_bitrate_mpeg1[3 - mp3->layer][mp3->bitrate_index];
|
||||
|
||||
case MP3_MPEG2:
|
||||
case MP3_MPEG2_5:
|
||||
return s_bitrate_mpeg2[3 - mp3->layer][mp3->bitrate_index];
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static int mp3_find_bitrate(const int* arr, int bitrate)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < 16; i++)
|
||||
{
|
||||
if (bitrate == arr[i])
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int mp3_set_bitrate(struct mp3_header_t* mp3, int bitrate)
|
||||
{
|
||||
int r;
|
||||
if (mp3->layer < 1 || mp3->layer > 3)
|
||||
{
|
||||
assert(0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch (mp3->version)
|
||||
{
|
||||
case MP3_MPEG1:
|
||||
r = mp3_find_bitrate(s_bitrate_mpeg1[3 - mp3->layer], bitrate);
|
||||
break;
|
||||
|
||||
case MP3_MPEG2:
|
||||
case MP3_MPEG2_5:
|
||||
r = mp3_find_bitrate(s_bitrate_mpeg2[3 - mp3->layer], bitrate);
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
r = -1;
|
||||
}
|
||||
|
||||
if (-1 == r)
|
||||
return -1;
|
||||
|
||||
mp3->bitrate_index = (unsigned int)r;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mp3_get_frequency(const struct mp3_header_t* mp3)
|
||||
{
|
||||
if (mp3->sampling_frequency < 0 || mp3->sampling_frequency > 3)
|
||||
return -1;
|
||||
|
||||
switch (mp3->version)
|
||||
{
|
||||
case MP3_MPEG1: return s_frequency_mpeg1[mp3->sampling_frequency];
|
||||
case MP3_MPEG2: return s_frequency_mpeg2[mp3->sampling_frequency];
|
||||
case MP3_MPEG2_5: return s_frequency_mpeg25[mp3->sampling_frequency];
|
||||
default: assert(0); return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static int mp3_find_frequency(const int* arr, int frequency)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
if (frequency == arr[i])
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int mp3_set_frequency(struct mp3_header_t* mp3, int frequency)
|
||||
{
|
||||
int r;
|
||||
switch (mp3->version)
|
||||
{
|
||||
case MP3_MPEG1:
|
||||
r = mp3_find_frequency(s_frequency_mpeg1, frequency);
|
||||
break;
|
||||
|
||||
case MP3_MPEG2:
|
||||
r = mp3_find_frequency(s_frequency_mpeg2, frequency);
|
||||
break;
|
||||
|
||||
case MP3_MPEG2_5:
|
||||
r = mp3_find_frequency(s_frequency_mpeg25, frequency);
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
r = -1;
|
||||
}
|
||||
|
||||
if (-1 == r)
|
||||
return -1;
|
||||
|
||||
mp3->sampling_frequency = (unsigned int)r;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(DEBUG) || defined(_DEBUG)
|
||||
void mp3_header_test(void)
|
||||
{
|
||||
uint8_t v[4] = { 0xff, 0xfb, 0xe0, 0x64 };
|
||||
uint8_t v2[4];
|
||||
struct mp3_header_t mp3;
|
||||
|
||||
assert(4 == mp3_header_load(&mp3, v, 4));
|
||||
assert(MP3_MPEG1 == mp3.version && MP3_LAYER3 == mp3.layer);
|
||||
assert(14 == mp3.bitrate_index && 320000 == mp3_get_bitrate(&mp3));
|
||||
assert(0 == mp3.sampling_frequency && 44100 == mp3_get_frequency(&mp3));
|
||||
assert(1 == mp3.mode && 1 == mp3.protection);
|
||||
assert(4 == mp3_header_save(&mp3, v2, 4));
|
||||
assert(0 == memcmp(v, v2, 4));
|
||||
}
|
||||
#endif
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user