mirror of
https://github.com/ZLMediaKit/ZLMediaKit.git
synced 2024-11-22 19:00:01 +08:00
mp4录制全部替换mp4v2为media-server
This commit is contained in:
parent
7e92a0b738
commit
124cce34b6
@ -1 +1 @@
|
|||||||
Subproject commit e399b93802610dcf574ff64bcb7677572cd028c1
|
Subproject commit a32fe104c0290bc01a7ee73d50b568e8d9ded931
|
@ -2,6 +2,14 @@
|
|||||||
cmake_minimum_required(VERSION 3.1.3)
|
cmake_minimum_required(VERSION 3.1.3)
|
||||||
#使能c++11
|
#使能c++11
|
||||||
set(CMAKE_CXX_STANDARD 11)
|
set(CMAKE_CXX_STANDARD 11)
|
||||||
|
SET(CMAKE_C_COMPILER aarch64-himix100-linux-gcc)
|
||||||
|
SET(CMAKE_CXX_COMPILER aarch64-himix100-linux-g++)
|
||||||
|
#SET(CMAKE_LINKER aarch64-himix100-linux-ld)
|
||||||
|
SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
|
||||||
|
SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
|
||||||
|
SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#加载自定义模块
|
#加载自定义模块
|
||||||
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${PROJECT_SOURCE_DIR}/cmake")
|
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${PROJECT_SOURCE_DIR}/cmake")
|
||||||
@ -14,6 +22,7 @@ set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
|
|||||||
set(ToolKit_Root ${CMAKE_SOURCE_DIR}/3rdpart/ZLToolKit/src)
|
set(ToolKit_Root ${CMAKE_SOURCE_DIR}/3rdpart/ZLToolKit/src)
|
||||||
set(MediaKit_Root ${CMAKE_SOURCE_DIR}/src)
|
set(MediaKit_Root ${CMAKE_SOURCE_DIR}/src)
|
||||||
|
|
||||||
|
|
||||||
#设置头文件目录
|
#设置头文件目录
|
||||||
INCLUDE_DIRECTORIES(${ToolKit_Root})
|
INCLUDE_DIRECTORIES(${ToolKit_Root})
|
||||||
INCLUDE_DIRECTORIES(${MediaKit_Root})
|
INCLUDE_DIRECTORIES(${MediaKit_Root})
|
||||||
@ -32,11 +41,14 @@ endif ()
|
|||||||
|
|
||||||
set(ENABLE_HLS true)
|
set(ENABLE_HLS true)
|
||||||
set(ENABLE_OPENSSL true)
|
set(ENABLE_OPENSSL true)
|
||||||
set(ENABLE_MYSQL true)
|
set(ENABLE_MYSQL false)
|
||||||
set(ENABLE_MP4V2 true)
|
set(ENABLE_MP4V2 true)
|
||||||
set(ENABLE_FAAC true)
|
set(ENABLE_FAAC false)
|
||||||
set(ENABLE_X264 true)
|
set(ENABLE_X264 false)
|
||||||
set(MP4_H265RECORD true)
|
set(ENABLE_MP4RECORD true)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#添加两个静态库
|
#添加两个静态库
|
||||||
if(ENABLE_HLS)
|
if(ENABLE_HLS)
|
||||||
@ -48,19 +60,28 @@ else()
|
|||||||
set(LINK_LIB_LIST zlmediakit zltoolkit)
|
set(LINK_LIB_LIST zlmediakit zltoolkit)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(MP4_H265RECORD)
|
if(ENABLE_MP4RECORD)
|
||||||
message(STATUS "MP4_H265RECORD defined")
|
message(STATUS "ENABLE_MP4RECORD defined")
|
||||||
add_definitions(-DMP4_H265RECORD)
|
add_definitions(-DENABLE_MP4RECORD)
|
||||||
set(MediaServer_Root ${CMAKE_SOURCE_DIR}/3rdpart/media-server)
|
set(MediaServer_Root ${CMAKE_SOURCE_DIR}/3rdpart/media-server)
|
||||||
list(APPEND LINK_LIB_LIST mov flv)
|
list(APPEND LINK_LIB_LIST mov flv)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
set(OPENSSL_INCLUDE_DIR /nand/hi3559/openssl/include/)
|
||||||
|
set(OPENSSL_LIBRARIES /nand/hi3559/openssl/lib/)
|
||||||
|
#set(OPENSSL_CRYPTO_LIBRARIES /nand/hi3559/openssl/lib/libcrypto.so)
|
||||||
|
|
||||||
|
set(MP4V2_INCLUDE_DIR /nand/hi3559/mp4v2/include/)
|
||||||
|
#set(MP4V2_LIBRARY /nand/hi3559/mp4v2/lib/libmp4v2.a)
|
||||||
|
set(MP4V2_LIBRARY /nand/hi3559/mp4v2/lib/libmp4v2.so)
|
||||||
|
|
||||||
#查找openssl是否安装
|
#查找openssl是否安装
|
||||||
find_package(OpenSSL QUIET)
|
find_package(OpenSSL QUIET)
|
||||||
if (OPENSSL_FOUND AND ENABLE_OPENSSL)
|
if (1)
|
||||||
message(STATUS "found library:${OPENSSL_LIBRARIES},ENABLE_OPENSSL defined")
|
message(STATUS "found library:${OPENSSL_LIBRARIES},ENABLE_OPENSSL defined")
|
||||||
include_directories(${OPENSSL_INCLUDE_DIR})
|
include_directories(/nand/hi3559/openssl/include/)
|
||||||
add_definitions(-DENABLE_OPENSSL)
|
add_definitions(-DENABLE_OPENSSL)
|
||||||
list(APPEND LINK_LIB_LIST ${OPENSSL_LIBRARIES})
|
list(APPEND LINK_LIB_LIST /nand/hi3559/openssl/lib/libssl.so /nand/hi3559/openssl/lib/libcrypto.so)
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
#查找mysql是否安装
|
#查找mysql是否安装
|
||||||
@ -118,7 +139,7 @@ if(ENABLE_HLS)
|
|||||||
endif(WIN32)
|
endif(WIN32)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(MP4_H265RECORD)
|
if(ENABLE_MP4RECORD)
|
||||||
aux_source_directory(${MediaServer_Root}/libmov/include src_mov)
|
aux_source_directory(${MediaServer_Root}/libmov/include src_mov)
|
||||||
aux_source_directory(${MediaServer_Root}/libmov/source src_mov)
|
aux_source_directory(${MediaServer_Root}/libmov/source src_mov)
|
||||||
include_directories(${MediaServer_Root}/libmov/include)
|
include_directories(${MediaServer_Root}/libmov/include)
|
||||||
|
@ -24,7 +24,7 @@
|
|||||||
* SOFTWARE.
|
* SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifdef ENABLE_MP4V2
|
#ifdef ENABLE_MP4RECORD
|
||||||
#include <ctime>
|
#include <ctime>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include "Common/config.h"
|
#include "Common/config.h"
|
||||||
@ -40,10 +40,15 @@
|
|||||||
#include "Thread/WorkThreadPool.h"
|
#include "Thread/WorkThreadPool.h"
|
||||||
|
|
||||||
|
|
||||||
#ifdef MP4_H265RECORD
|
|
||||||
#include "mov-buffer.h"
|
#include "mov-buffer.h"
|
||||||
#include "mov-format.h"
|
#include "mov-format.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
using namespace toolkit;
|
||||||
|
|
||||||
|
namespace mediakit {
|
||||||
|
|
||||||
#if defined(_WIN32) || defined(_WIN64)
|
#if defined(_WIN32) || defined(_WIN64)
|
||||||
#define fseek64 _fseeki64
|
#define fseek64 _fseeki64
|
||||||
#define ftell64 _ftelli64
|
#define ftell64 _ftelli64
|
||||||
@ -52,43 +57,39 @@
|
|||||||
#define ftell64 ftell
|
#define ftell64 ftell
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static int mov_file_read(void* fp, void* data, uint64_t bytes)
|
static int movfileRead(void* fp, void* data, uint64_t bytes)
|
||||||
{
|
{
|
||||||
if (bytes == fread(data, 1, bytes, (FILE*)fp))
|
if (bytes == fread(data, 1, bytes, (FILE*)fp))
|
||||||
return 0;
|
return 0;
|
||||||
return 0 != ferror((FILE*)fp) ? ferror((FILE*)fp) : -1 /*EOF*/;
|
return 0 != ferror((FILE*)fp) ? ferror((FILE*)fp) : -1 /*EOF*/;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int mov_file_write(void* fp, const void* data, uint64_t bytes)
|
static int movfileWrite(void* fp, const void* data, uint64_t bytes)
|
||||||
{
|
{
|
||||||
return bytes == fwrite(data, 1, bytes, (FILE*)fp) ? 0 : ferror((FILE*)fp);
|
return bytes == fwrite(data, 1, bytes, (FILE*)fp) ? 0 : ferror((FILE*)fp);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int mov_file_seek(void* fp, uint64_t offset)
|
static int movfileSeek(void* fp, uint64_t offset)
|
||||||
{
|
{
|
||||||
return fseek64((FILE*)fp, offset, SEEK_SET);
|
return fseek64((FILE*)fp, offset, SEEK_SET);
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint64_t mov_file_tell(void* fp)
|
static uint64_t movfileTell(void* fp)
|
||||||
{
|
{
|
||||||
return ftell64((FILE*)fp);
|
return ftell64((FILE*)fp);
|
||||||
}
|
}
|
||||||
|
|
||||||
const struct mov_buffer_t* mov_file_buffer(void)
|
const struct mov_buffer_t* movfileBuffer(void)
|
||||||
{
|
{
|
||||||
static struct mov_buffer_t s_io = {
|
static struct mov_buffer_t s_io = {
|
||||||
mov_file_read,
|
movfileRead,
|
||||||
mov_file_write,
|
movfileWrite,
|
||||||
mov_file_seek,
|
movfileSeek,
|
||||||
mov_file_tell,
|
movfileTell,
|
||||||
};
|
};
|
||||||
return &s_io;
|
return &s_io;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
using namespace toolkit;
|
|
||||||
|
|
||||||
namespace mediakit {
|
|
||||||
|
|
||||||
string timeStr(const char *fmt) {
|
string timeStr(const char *fmt) {
|
||||||
std::tm tm_snapshot;
|
std::tm tm_snapshot;
|
||||||
@ -118,6 +119,11 @@ Mp4Maker::Mp4Maker(const string& strPath,
|
|||||||
_info.strStreamId = strStreamId;
|
_info.strStreamId = strStreamId;
|
||||||
_info.strVhost = strVhost;
|
_info.strVhost = strVhost;
|
||||||
_info.strFolder = strPath;
|
_info.strFolder = strPath;
|
||||||
|
|
||||||
|
memset(&_movH265info, 0, sizeof(_movH265info));
|
||||||
|
_movH265info.videoTrack = -1;
|
||||||
|
_movH265info.audioTrack = -1;
|
||||||
|
|
||||||
//----record 业务逻辑----//
|
//----record 业务逻辑----//
|
||||||
}
|
}
|
||||||
Mp4Maker::~Mp4Maker() {
|
Mp4Maker::~Mp4Maker() {
|
||||||
@ -125,105 +131,140 @@ Mp4Maker::~Mp4Maker() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Mp4Maker::inputH264(void *pData, uint32_t ui32Length, uint32_t ui32TimeStamp){
|
void Mp4Maker::inputH264(void *pData, uint32_t ui32Length, uint32_t ui32TimeStamp){
|
||||||
auto iType = H264_TYPE(((uint8_t*)pData)[0]);
|
auto iType = H264_TYPE(((uint8_t*)pData)[4]);
|
||||||
switch (iType) {
|
|
||||||
case H264Frame::NAL_B_P: //P
|
if (H264Frame::NAL_B_P <= iType && iType <= H264Frame::NAL_IDR){
|
||||||
case H264Frame::NAL_IDR: { //IDR
|
|
||||||
if (_strLastVideo.size()) {
|
int64_t iTimeInc = (int64_t)ui32TimeStamp - (int64_t)_ui32LastVideoTime;
|
||||||
int64_t iTimeInc = (int64_t)ui32TimeStamp - (int64_t)_ui32LastVideoTime;
|
iTimeInc = MAX(0,MIN(iTimeInc,500));
|
||||||
iTimeInc = MAX(0,MIN(iTimeInc,500));
|
if( (iTimeInc == 0 || iTimeInc == 500) && H264Frame::NAL_IDR != iType){
|
||||||
if(iTimeInc == 0 || iTimeInc == 500){
|
WarnL << "abnormal time stamp increment:" << ui32TimeStamp << " " << _ui32LastVideoTime;
|
||||||
WarnL << "abnormal time stamp increment:" << ui32TimeStamp << " " << _ui32LastVideoTime;
|
|
||||||
}
|
|
||||||
inputH264_l((char *) _strLastVideo.data(), _strLastVideo.size(), iTimeInc);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t prefixe = htonl(ui32Length);
|
if ( _strLastVideo.size() ){
|
||||||
_strLastVideo.assign((char *) &prefixe, 4);
|
//如果出现SPS PPS黏连的帧,那么在这里先处理
|
||||||
_strLastVideo.append((char *)pData,ui32Length);
|
inputH264_l((char *) _strLastVideo.data(), _strLastVideo.size(), _ui32LastVideoTime);
|
||||||
|
_strLastVideo = "";
|
||||||
|
}
|
||||||
|
inputH264_l((char *) pData, ui32Length, ui32TimeStamp);
|
||||||
|
_ui32LastVideoTime = ui32TimeStamp;
|
||||||
|
}else{
|
||||||
|
//SPS PPS 进入等待组合为一帧
|
||||||
|
_strLastVideo.append((char *)pData,ui32Length);
|
||||||
_ui32LastVideoTime = ui32TimeStamp;
|
_ui32LastVideoTime = ui32TimeStamp;
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Mp4Maker::inputH265(void *pData, uint32_t ui32Length, uint32_t ui32TimeStamp){
|
void Mp4Maker::inputH265(void *pData, uint32_t ui32Length, uint32_t ui32TimeStamp){
|
||||||
#ifdef MP4_H265RECORD
|
|
||||||
auto iType = H265_TYPE(((uint8_t*)pData)[4]);
|
auto iType = H265_TYPE(((uint8_t*)pData)[4]);
|
||||||
if (iType <= 19 ){
|
if (iType <= H265Frame::NAL_IDR_W_RADL ){
|
||||||
if (_strLastVideo.size() && iType == 19){
|
|
||||||
_strLastVideo.append((char *)pData,ui32Length);
|
int64_t iTimeInc = (int64_t)ui32TimeStamp - (int64_t)_ui32LastVideoTime;
|
||||||
inputH265_l((char *) _strLastVideo.data(), _strLastVideo.size(), ui32TimeStamp);
|
iTimeInc = MAX(0,MIN(iTimeInc,500));
|
||||||
|
if((iTimeInc == 0 || iTimeInc == 500) && H265Frame::NAL_IDR_W_RADL != iType){
|
||||||
|
WarnL << "abnormal time stamp increment:" << ui32TimeStamp << " " << _ui32LastVideoTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( _strLastVideo.size() ){
|
||||||
|
//如果出现SPS PPS VPS黏连的帧,那么在这里先处理
|
||||||
|
inputH265_l((char *) _strLastVideo.data(), _strLastVideo.size(), _ui32LastVideoTime);
|
||||||
_strLastVideo = "";
|
_strLastVideo = "";
|
||||||
_ui32LastVideoTime = ui32TimeStamp;
|
}
|
||||||
}else
|
inputH265_l((char *) pData, ui32Length, ui32TimeStamp);
|
||||||
inputH265_l((char *) pData, ui32Length, ui32TimeStamp);
|
_ui32LastVideoTime = ui32TimeStamp;
|
||||||
}else{
|
}else{
|
||||||
_strLastVideo.append((char *)pData,ui32Length);
|
_strLastVideo.append((char *)pData,ui32Length);
|
||||||
_ui32LastVideoTime = ui32TimeStamp;
|
_ui32LastVideoTime = ui32TimeStamp;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Mp4Maker::inputAAC(void *pData, uint32_t ui32Length, uint32_t ui32TimeStamp){
|
void Mp4Maker::inputAAC(void *pData, uint32_t ui32Length, uint32_t ui32TimeStamp){
|
||||||
#ifdef MP4_H265RECORD
|
int64_t iTimeInc = (int64_t)ui32TimeStamp - (int64_t)_ui32LastAudioTime;
|
||||||
if (_h265Record){
|
iTimeInc = MAX(0,MIN(iTimeInc,500));
|
||||||
inputAAC_l((char *) pData, ui32Length, ui32TimeStamp);
|
if(iTimeInc == 0 || iTimeInc == 500){
|
||||||
}else
|
WarnL << "abnormal time stamp increment:" << ui32TimeStamp << " " << _ui32LastAudioTime;
|
||||||
#endif
|
|
||||||
{
|
|
||||||
if (_strLastAudio.size()) {
|
|
||||||
int64_t iTimeInc = (int64_t)ui32TimeStamp - (int64_t)_ui32LastAudioTime;
|
|
||||||
iTimeInc = MAX(0,MIN(iTimeInc,500));
|
|
||||||
if(iTimeInc == 0 || iTimeInc == 500){
|
|
||||||
WarnL << "abnormal time stamp increment:" << ui32TimeStamp << " " << _ui32LastAudioTime;
|
|
||||||
}
|
|
||||||
inputAAC_l((char *) _strLastAudio.data(), _strLastAudio.size(), iTimeInc);
|
|
||||||
}
|
|
||||||
_strLastAudio.assign((char *)pData, ui32Length);
|
|
||||||
_ui32LastAudioTime = ui32TimeStamp;
|
|
||||||
}
|
}
|
||||||
|
inputAAC_l((char *) pData, ui32Length, ui32TimeStamp);
|
||||||
|
_ui32LastAudioTime = ui32TimeStamp;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Mp4Maker::inputH264_l(void *pData, uint32_t ui32Length, uint32_t ui32Duration) {
|
void Mp4Maker::inputH264_l(void *pData, uint32_t ui32Length, uint32_t ui32TimeStamp) {
|
||||||
GET_CONFIG(uint32_t,recordSec,Record::kFileSecond);
|
GET_CONFIG(uint32_t,recordSec,Record::kFileSecond);
|
||||||
auto iType = H264_TYPE(((uint8_t*)pData)[4]);
|
auto iType = H264_TYPE(((uint8_t*)pData)[4]);
|
||||||
if(iType == H264Frame::NAL_IDR && (_hMp4 == MP4_INVALID_FILE_HANDLE || _ticker.elapsedTime() > recordSec * 1000)){
|
int32_t compositionTime;
|
||||||
|
if( iType >= H264Frame::NAL_IDR && (_movH265info.pMov == NULL || _ticker.elapsedTime() > recordSec * 1000)){
|
||||||
//在I帧率处新建MP4文件
|
//在I帧率处新建MP4文件
|
||||||
//如果文件未创建或者文件超过10分钟则创建新文件
|
//如果文件未创建或者文件超过10分钟则创建新文件
|
||||||
|
//每一个录制的MP4文件时间戳都要从0开始
|
||||||
|
_startPts = ui32TimeStamp;
|
||||||
createFile();
|
createFile();
|
||||||
}
|
}
|
||||||
if (_hVideo != MP4_INVALID_TRACK_ID) {
|
|
||||||
MP4WriteSample(_hMp4, _hVideo, (uint8_t *) pData, ui32Length,ui32Duration * 90,0,iType == 5);
|
char *pNualData = (char *)pData;
|
||||||
|
if (_movH265info.pMov!=NULL){
|
||||||
|
int vcl;
|
||||||
|
if (_movH265info.videoTrack < 0){
|
||||||
|
//解析解析SPS PPS,未添加track的时候执行
|
||||||
|
int n = h264_annexbtomp4(&_movH265info.avc, pData, ui32Length, _sBbuffer, sizeof(_sBbuffer), &vcl);
|
||||||
|
if (_movH265info.avc.nb_sps < 1 || _movH265info.avc.nb_pps < 1){
|
||||||
|
return; // waiting for sps/pps
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t sExtraData[64 * 1024];
|
||||||
|
int extraDataSize = mpeg4_avc_decoder_configuration_record_save(&_movH265info.avc, sExtraData, sizeof(sExtraData));
|
||||||
|
if (extraDataSize <= 0){
|
||||||
|
// invalid HVCC
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: waiting for key frame ???
|
||||||
|
_movH265info.videoTrack = mov_writer_add_video(_movH265info.pMov,
|
||||||
|
MOV_OBJECT_H264,
|
||||||
|
_movH265info.width,
|
||||||
|
_movH265info.height,
|
||||||
|
sExtraData,
|
||||||
|
extraDataSize);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if ( iType <= H264Frame::NAL_IDR ){
|
||||||
|
uint8_t *ptr = (uint8_t*)pData;
|
||||||
|
ptr[0] = (uint8_t)((ui32Length-4 >> 24) & 0xFF);
|
||||||
|
ptr[1] = (uint8_t)((ui32Length-4 >> 16) & 0xFF);
|
||||||
|
ptr[2] = (uint8_t)((ui32Length-4 >> 8) & 0xFF);
|
||||||
|
ptr[3] = (uint8_t)((ui32Length-4 >> 0) & 0xFF);
|
||||||
|
uint32_t ui32Pts = ui32TimeStamp < _movH265info.startPts ? 0 : ui32TimeStamp-_movH265info.startPts;
|
||||||
|
mov_writer_write(_movH265info.pMov,
|
||||||
|
_movH265info.videoTrack, pData, ui32Length,
|
||||||
|
ui32Pts,
|
||||||
|
ui32Pts,
|
||||||
|
iType == H264Frame::NAL_IDR ? MOV_AV_FLAG_KEYFREAME : 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Mp4Maker::inputH265_l(void *pData, uint32_t ui32Length, uint32_t ui32TimeStamp) {
|
void Mp4Maker::inputH265_l(void *pData, uint32_t ui32Length, uint32_t ui32TimeStamp) {
|
||||||
GET_CONFIG(uint32_t,recordSec,Record::kFileSecond);
|
GET_CONFIG(uint32_t,recordSec,Record::kFileSecond);
|
||||||
|
|
||||||
#ifdef MP4_H265RECORD
|
|
||||||
int32_t compositionTime;
|
int32_t compositionTime;
|
||||||
auto iType = H265_TYPE(((uint8_t*)pData)[4]);
|
auto iType = H265_TYPE(((uint8_t*)pData)[4]);
|
||||||
if( iType >= H265Frame::NAL_IDR_W_RADL && (_movH265info.pMov == NULL || _ticker.elapsedTime() > recordSec * 1000)){
|
if( iType >= H265Frame::NAL_IDR_W_RADL && (_movH265info.pMov == NULL || _ticker.elapsedTime() > recordSec * 1000)){
|
||||||
//在I帧率处新建MP4文件
|
|
||||||
//如果文件未创建或者文件超过10分钟则创建新文件
|
|
||||||
_h265Record = 1;
|
_h265Record = 1;
|
||||||
|
//每一个录制的MP4文件时间戳都要从0开始
|
||||||
|
_startPts = ui32TimeStamp;
|
||||||
|
|
||||||
|
//在I帧率处新建MP4文件
|
||||||
|
//如果文件未创建或者文件超过最长时间则创建新文件
|
||||||
createFile();
|
createFile();
|
||||||
}
|
}
|
||||||
|
|
||||||
char *pNualData = (char *)pData;
|
char *pNualData = (char *)pData;
|
||||||
if (/*iType <= 31 && */_movH265info.pMov!=NULL){
|
if (_movH265info.pMov!=NULL){
|
||||||
int vcl;
|
int vcl;
|
||||||
//media-server新版的api使用h265_annexbtomp4
|
|
||||||
//int n = h265_annexbtomp4(&_movH265info.hevc, pData, ui32Length, _sBbuffer, sizeof(_sBbuffer), &vcl);
|
|
||||||
int n = hevc_annexbtomp4(&_movH265info.hevc, pData, ui32Length, _sBbuffer, sizeof(_sBbuffer));
|
|
||||||
if (_movH265info.videoTrack < 0){
|
if (_movH265info.videoTrack < 0){
|
||||||
|
//解析解析VPS SPS PPS,未添加track的时候执行
|
||||||
|
int n = h265_annexbtomp4(&_movH265info.hevc, pData, ui32Length, _sBbuffer, sizeof(_sBbuffer), &vcl);
|
||||||
if (_movH265info.hevc.numOfArrays < 1){
|
if (_movH265info.hevc.numOfArrays < 1){
|
||||||
return; // waiting for vps/sps/pps
|
return; // waiting for vps/sps/pps
|
||||||
}
|
}
|
||||||
@ -234,55 +275,49 @@ void Mp4Maker::inputH265_l(void *pData, uint32_t ui32Length, uint32_t ui32TimeSt
|
|||||||
// invalid HVCC
|
// invalid HVCC
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: waiting for key frame ???
|
// TODO: waiting for key frame ???
|
||||||
_movH265info.videoTrack = mov_writer_add_video(_movH265info.pMov, MOV_OBJECT_HEVC, _movH265info.width, _movH265info.height, sExtraData, extraDataSize);
|
_movH265info.videoTrack = mov_writer_add_video(_movH265info.pMov, MOV_OBJECT_HEVC, _movH265info.width, _movH265info.height, sExtraData, extraDataSize);
|
||||||
if (_movH265info.videoTrack < 0)
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
mov_writer_write(_movH265info.pMov,
|
if ( iType <= H265Frame::NAL_IDR_W_RADL )
|
||||||
|
{
|
||||||
|
uint8_t *ptr = (uint8_t*)pData;
|
||||||
|
ptr[0] = (uint8_t)((ui32Length-4 >> 24) & 0xFF);
|
||||||
|
ptr[1] = (uint8_t)((ui32Length-4 >> 16) & 0xFF);
|
||||||
|
ptr[2] = (uint8_t)((ui32Length-4 >> 8) & 0xFF);
|
||||||
|
ptr[3] = (uint8_t)((ui32Length-4 >> 0) & 0xFF);
|
||||||
|
|
||||||
|
uint32_t ui32Pts = ui32TimeStamp < _movH265info.startPts ? 0 : ui32TimeStamp-_movH265info.startPts;
|
||||||
|
mov_writer_write(_movH265info.pMov,
|
||||||
_movH265info.videoTrack,
|
_movH265info.videoTrack,
|
||||||
_sBbuffer,
|
pData,
|
||||||
n,
|
ui32Length,
|
||||||
ui32TimeStamp,
|
ui32Pts,
|
||||||
ui32TimeStamp,
|
ui32Pts,
|
||||||
(iType >= 16 && iType <= 23) ? MOV_AV_FLAG_KEYFREAME : 0 );
|
iType == H265Frame::NAL_IDR_W_RADL ? MOV_AV_FLAG_KEYFREAME : 0);
|
||||||
// mov_writer_write(_movH265info.pMov, _movH265info.videoTrack, _sBbuffer, n, ui32TimeStamp, ui32TimeStamp, 1 == vcl ? MOV_AV_FLAG_KEYFREAME : 0);
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Mp4Maker::inputAAC_l(void *pData, uint32_t ui32Length, uint32_t ui32Duration) {
|
void Mp4Maker::inputAAC_l(void *pData, uint32_t ui32Length, uint32_t ui32TimeStamp) {
|
||||||
GET_CONFIG(uint32_t,recordSec,Record::kFileSecond);
|
GET_CONFIG(uint32_t,recordSec,Record::kFileSecond);
|
||||||
#ifdef MP4_H265RECORD
|
if (!_haveVideo && (_movH265info.pMov == NULL || _ticker.elapsedTime() > recordSec * 1000)) {
|
||||||
if ( _h265Record )
|
_startPts = ui32TimeStamp;
|
||||||
{
|
createFile();
|
||||||
if (!_haveVideo && (_movH265info.pMov == NULL || _ticker.elapsedTime() > recordSec * 1000)) {
|
|
||||||
createFile();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (-1 != _movH265info.audioTrack && _movH265info.pMov != NULL){
|
|
||||||
mov_writer_write(_movH265info.pMov, _movH265info.audioTrack, (uint8_t*)pData, ui32Length, ui32Duration, ui32Duration, 0);
|
|
||||||
}
|
|
||||||
}else
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
if (!_haveVideo && (_hMp4 == MP4_INVALID_FILE_HANDLE || _ticker.elapsedTime() > recordSec * 1000)) {
|
|
||||||
//在I帧率处新建MP4文件
|
|
||||||
//如果文件未创建或者文件超过10分钟则创建新文件
|
|
||||||
createFile();
|
|
||||||
}
|
|
||||||
if (_hAudio != MP4_INVALID_TRACK_ID) {
|
|
||||||
auto duration = ui32Duration * _audioSampleRate /1000.0;
|
|
||||||
MP4WriteSample(_hMp4, _hAudio, (uint8_t*)pData, ui32Length,duration,0,false);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (-1 != _movH265info.audioTrack && _movH265info.pMov != NULL){
|
||||||
|
|
||||||
|
uint32_t ui32Pts = ui32TimeStamp < _movH265info.startPts ? 0 : ui32TimeStamp-_movH265info.startPts;
|
||||||
|
mov_writer_write(_movH265info.pMov, _movH265info.audioTrack, (uint8_t*)pData, ui32Length, ui32Pts, ui32Pts, 0);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Mp4Maker::createFile() {
|
void Mp4Maker::createFile() {
|
||||||
closeFile();
|
closeFile();
|
||||||
|
|
||||||
auto strDate = timeStr("%Y-%m-%d");
|
auto strDate = timeStr("%Y-%m-%d");
|
||||||
auto strTime = timeStr("%H-%M-%S");
|
auto strTime = timeStr("%H-%M-%S");
|
||||||
auto strFileTmp = _strPath + strDate + "/." + strTime + ".mp4";
|
auto strFileTmp = _strPath + strDate + "/." + strTime + ".mp4";
|
||||||
@ -309,119 +344,65 @@ void Mp4Maker::createFile() {
|
|||||||
File::createfile_path(strFileTmp.data(), 0);
|
File::createfile_path(strFileTmp.data(), 0);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef MP4_H265RECORD
|
memset(&_movH265info, 0, sizeof(_movH265info));
|
||||||
if ( _h265Record ){
|
_movH265info.videoTrack = -1;
|
||||||
memset(&_movH265info, 0, sizeof(_movH265info));
|
_movH265info.audioTrack = -1;
|
||||||
_movH265info.videoTrack = -1;
|
_movH265info.width = 0;
|
||||||
_movH265info.audioTrack = -1;
|
_movH265info.height = 0;
|
||||||
_movH265info.width = 0;
|
_movH265info.pFile = fopen(strFileTmp.data(), "wb+");
|
||||||
_movH265info.height = 0;
|
_movH265info.startPts = _startPts;
|
||||||
_movH265info.ptr = NULL;
|
_movH265info.pMov = mov_writer_create(movfileBuffer(), _movH265info.pFile, 0/*MOV_FLAG_FASTSTART*/);
|
||||||
_movH265info.pFile = fopen(strFileTmp.data(), "wb+");
|
|
||||||
_movH265info.pMov = mov_writer_create(mov_file_buffer(), _movH265info.pFile, 0/*MOV_FLAG_FASTSTART*/);
|
|
||||||
}else
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
_hMp4 = MP4Create(strFileTmp.data(),MP4_CREATE_64BIT_DATA);
|
|
||||||
if (_hMp4 == MP4_INVALID_FILE_HANDLE) {
|
|
||||||
WarnL << "创建MP4文件失败:" << strFileTmp;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//MP4SetTimeScale(_hMp4, 90000);
|
|
||||||
_strFileTmp = strFileTmp;
|
_strFileTmp = strFileTmp;
|
||||||
_strFile = strFile;
|
_strFile = strFile;
|
||||||
_ticker.resetTime();
|
_ticker.resetTime();
|
||||||
|
|
||||||
if ( _h265Record ){
|
if ( _h265Record ){
|
||||||
auto videoTrack = dynamic_pointer_cast<H265Track>(getTrack(TrackVideo));
|
auto videoTrack = dynamic_pointer_cast<H265Track>(getTrack(TrackVideo));
|
||||||
#ifdef MP4_H265RECORD
|
|
||||||
if(videoTrack){
|
if(videoTrack){
|
||||||
_movH265info.width = videoTrack->getVideoWidth();
|
_movH265info.width = videoTrack->getVideoWidth();
|
||||||
_movH265info.height = videoTrack->getVideoHeight();
|
_movH265info.height = videoTrack->getVideoHeight();
|
||||||
}
|
}
|
||||||
#endif
|
}else{
|
||||||
|
|
||||||
}else {
|
|
||||||
auto videoTrack = dynamic_pointer_cast<H264Track>(getTrack(TrackVideo));
|
auto videoTrack = dynamic_pointer_cast<H264Track>(getTrack(TrackVideo));
|
||||||
if(videoTrack){
|
if(videoTrack){
|
||||||
auto &sps = videoTrack->getSps();
|
// auto &sps = videoTrack->getSps();
|
||||||
auto &pps = videoTrack->getPps();
|
// auto &pps = videoTrack->getPps();
|
||||||
|
_movH265info.width = videoTrack->getVideoWidth();
|
||||||
|
_movH265info.height = videoTrack->getVideoHeight();
|
||||||
_hVideo = MP4AddH264VideoTrack(_hMp4,
|
|
||||||
90000,
|
|
||||||
MP4_INVALID_DURATION,
|
|
||||||
videoTrack->getVideoWidth(),
|
|
||||||
videoTrack->getVideoHeight(),
|
|
||||||
sps[1],
|
|
||||||
sps[2],
|
|
||||||
sps[3],
|
|
||||||
3);
|
|
||||||
if(_hVideo != MP4_INVALID_TRACK_ID){
|
|
||||||
MP4AddH264SequenceParameterSet(_hMp4, _hVideo, (uint8_t *)sps.data(), sps.size());
|
|
||||||
MP4AddH264PictureParameterSet(_hMp4, _hVideo, (uint8_t *)pps.data(), pps.size());
|
|
||||||
}else{
|
|
||||||
WarnL << "添加视频通道失败:" << strFileTmp;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
if ( _movH265info.width <=0 || _movH265info.height <= 0 )
|
||||||
|
WarnL << "分辨率获取失败,MP4录制异常";
|
||||||
|
|
||||||
auto audioTrack = dynamic_pointer_cast<AACTrack>(getTrack(TrackAudio));
|
auto audioTrack = dynamic_pointer_cast<AACTrack>(getTrack(TrackAudio));
|
||||||
if(audioTrack){
|
if(audioTrack){
|
||||||
_audioSampleRate = audioTrack->getAudioSampleRate();
|
_audioSampleRate = audioTrack->getAudioSampleRate();
|
||||||
_audioChannel = audioTrack->getAudioChannel();
|
_audioChannel = audioTrack->getAudioChannel();
|
||||||
#ifdef MP4_H265RECORD
|
|
||||||
uint8_t extra_data[64 * 1024];
|
uint8_t extra_data[64 * 1024];
|
||||||
if ( _h265Record ){
|
_movH265info.audioTrack = mov_writer_add_audio(_movH265info.pMov, MOV_OBJECT_AAC, _audioChannel, 16, _audioSampleRate, audioTrack->getAacCfg().data(), 2);
|
||||||
_movH265info.audioTrack = mov_writer_add_audio(_movH265info.pMov, MOV_OBJECT_AAC, _audioChannel, 16, _audioSampleRate, audioTrack->getAacCfg().data(), 2);
|
if (-1 == _movH265info.audioTrack)
|
||||||
if (-1 == _movH265info.audioTrack)
|
WarnL << "添加音频通道失败:" << strFileTmp;
|
||||||
WarnL << "添加音频通道失败:" << strFileTmp;
|
|
||||||
}else
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
_hAudio = MP4AddAudioTrack(_hMp4, _audioSampleRate, MP4_INVALID_DURATION, MP4_MPEG4_AUDIO_TYPE);
|
|
||||||
if (_hAudio != MP4_INVALID_TRACK_ID) {
|
|
||||||
auto &cfg = audioTrack->getAacCfg();
|
|
||||||
MP4SetTrackESConfiguration(_hMp4, _hAudio,(uint8_t *)cfg.data(), cfg.size());
|
|
||||||
}else{
|
|
||||||
WarnL << "添加音频通道失败:" << strFileTmp;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Mp4Maker::asyncClose() {
|
void Mp4Maker::asyncClose() {
|
||||||
|
|
||||||
// auto hMp4 = (_h265Record==0)?_hMp4:_movH265info.pMov;
|
|
||||||
auto strFileTmp = _strFileTmp;
|
auto strFileTmp = _strFileTmp;
|
||||||
auto strFile = _strFile;
|
auto strFile = _strFile;
|
||||||
auto info = _info;
|
auto info = _info;
|
||||||
|
|
||||||
int h265Record = _h265Record;
|
FILE *pFile = _movH265info.pFile;
|
||||||
#ifdef MP4_H265RECORD
|
mov_writer_t* hMp4 = _movH265info.pMov;
|
||||||
FILE *pFile = (_h265Record)?_movH265info.pFile:NULL;
|
WorkThreadPool::Instance().getExecutor()->async([hMp4,strFileTmp,strFile,info,pFile]() {
|
||||||
void * hMp4 = (_h265Record)?(void*)_movH265info.pMov:(void*)_hMp4;
|
|
||||||
#else
|
|
||||||
auto hMp4 = _hMp4;
|
|
||||||
FILE *pFile = NULL;
|
|
||||||
#endif
|
|
||||||
WorkThreadPool::Instance().getExecutor()->async([hMp4,strFileTmp,strFile,info,pFile,h265Record]() {
|
|
||||||
//获取文件录制时间,放在MP4Close之前是为了忽略MP4Close执行时间
|
//获取文件录制时间,放在MP4Close之前是为了忽略MP4Close执行时间
|
||||||
const_cast<Mp4Info&>(info).ui64TimeLen = ::time(NULL) - info.ui64StartedTime;
|
const_cast<Mp4Info&>(info).ui64TimeLen = ::time(NULL) - info.ui64StartedTime;
|
||||||
//MP4Close非常耗时,所以要放在后台线程执行
|
//MP4Close非常耗时,所以要放在后台线程执行
|
||||||
|
if (hMp4 != NULL ){
|
||||||
#ifdef MP4_H265RECORD
|
mov_writer_destroy(hMp4);
|
||||||
if (h265Record){
|
|
||||||
mov_writer_destroy((mov_writer_t*)hMp4);
|
|
||||||
fclose(pFile);
|
fclose(pFile);
|
||||||
}else
|
DebugL << "fclose end";
|
||||||
#endif
|
|
||||||
{
|
|
||||||
MP4Close(hMp4,MP4_CLOSE_DO_NOT_COMPUTE_BITRATE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//临时文件名改成正式文件名,防止mp4未完成时被访问
|
//临时文件名改成正式文件名,防止mp4未完成时被访问
|
||||||
rename(strFileTmp.data(),strFile.data());
|
rename(strFileTmp.data(),strFile.data());
|
||||||
//获取文件大小
|
//获取文件大小
|
||||||
@ -434,35 +415,30 @@ void Mp4Maker::asyncClose() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Mp4Maker::closeFile() {
|
void Mp4Maker::closeFile() {
|
||||||
#ifdef MP4_H265RECORD
|
if (_movH265info.pMov != NULL) {
|
||||||
if (_h265Record){
|
asyncClose();
|
||||||
if (_movH265info.pMov != NULL) {
|
memset(&_movH265info, 0, sizeof(_movH265info));
|
||||||
asyncClose();
|
_movH265info.pMov = NULL;
|
||||||
}
|
_movH265info.videoTrack = -1;
|
||||||
}else
|
_movH265info.audioTrack = -1;
|
||||||
#endif
|
|
||||||
{
|
|
||||||
if (_hMp4 != MP4_INVALID_FILE_HANDLE) {
|
|
||||||
asyncClose();
|
|
||||||
_hMp4 = MP4_INVALID_FILE_HANDLE;
|
|
||||||
_hVideo = MP4_INVALID_TRACK_ID;
|
|
||||||
_hAudio = MP4_INVALID_TRACK_ID;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Mp4Maker::onTrackFrame(const Frame::Ptr &frame) {
|
void Mp4Maker::onTrackFrame(const Frame::Ptr &frame) {
|
||||||
switch (frame->getCodecId()){
|
switch (frame->getCodecId()){
|
||||||
case CodecH264:{
|
case CodecH264:{
|
||||||
inputH264(frame->data() + frame->prefixSize(), frame->size() - frame->prefixSize(),frame->stamp());
|
//需要带00 00 00 01,方便在mov_writer_write的时候字节修改这4Byte为长度信息
|
||||||
|
inputH264(frame->data() , frame->size(),frame->pts());
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case CodecAAC:{
|
case CodecAAC:{
|
||||||
inputAAC(frame->data() + frame->prefixSize(), frame->size() - frame->prefixSize(),frame->stamp());
|
//不需要ADTS头
|
||||||
|
inputAAC(frame->data() + frame->prefixSize(), frame->size() - frame->prefixSize(),frame->pts());
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case CodecH265:{
|
case CodecH265:{
|
||||||
inputH265(frame->data() , frame->size(),frame->stamp());
|
//需要带00 00 00 01,方便在mov_writer_write的时候字节修改这4Byte为长度信息
|
||||||
|
inputH265(frame->data() , frame->size(),frame->pts());
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -477,4 +453,4 @@ void Mp4Maker::onAllTrackReady() {
|
|||||||
} /* namespace mediakit */
|
} /* namespace mediakit */
|
||||||
|
|
||||||
|
|
||||||
#endif //ENABLE_MP4V2
|
#endif //ENABLE_MP4RECORD
|
@ -27,11 +27,10 @@
|
|||||||
#ifndef MP4MAKER_H_
|
#ifndef MP4MAKER_H_
|
||||||
#define MP4MAKER_H_
|
#define MP4MAKER_H_
|
||||||
|
|
||||||
#ifdef ENABLE_MP4V2
|
#ifdef ENABLE_MP4RECORD
|
||||||
|
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <mp4v2/mp4v2.h>
|
|
||||||
#include "Player/PlayerBase.h"
|
#include "Player/PlayerBase.h"
|
||||||
#include "Util/util.h"
|
#include "Util/util.h"
|
||||||
#include "Util/logger.h"
|
#include "Util/logger.h"
|
||||||
@ -41,10 +40,10 @@
|
|||||||
#include "Extension/Track.h"
|
#include "Extension/Track.h"
|
||||||
|
|
||||||
|
|
||||||
#ifdef MP4_H265RECORD
|
|
||||||
#include "mov-writer.h"
|
#include "mov-writer.h"
|
||||||
#include "mpeg4-hevc.h"
|
#include "mpeg4-hevc.h"
|
||||||
#endif
|
#include "mpeg4-avc.h"
|
||||||
|
|
||||||
|
|
||||||
using namespace toolkit;
|
using namespace toolkit;
|
||||||
|
|
||||||
@ -66,17 +65,15 @@ public:
|
|||||||
|
|
||||||
class MovH265Info {
|
class MovH265Info {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
#ifdef MP4_H265RECORD
|
|
||||||
mov_writer_t* pMov;
|
mov_writer_t* pMov;
|
||||||
struct mpeg4_hevc_t hevc;
|
struct mpeg4_hevc_t hevc;
|
||||||
|
struct mpeg4_avc_t avc;
|
||||||
int videoTrack;
|
int videoTrack;
|
||||||
int audioTrack;
|
int audioTrack;
|
||||||
int width;
|
int width;
|
||||||
int height;
|
int height;
|
||||||
const uint8_t* ptr;
|
uint32_t startPts;
|
||||||
FILE * pFile;
|
FILE * pFile;
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class Mp4Maker : public MediaSink{
|
class Mp4Maker : public MediaSink{
|
||||||
@ -109,19 +106,16 @@ private:
|
|||||||
//时间戳:参考频率1000
|
//时间戳:参考频率1000
|
||||||
void inputAAC(void *pData, uint32_t ui32Length, uint32_t ui32TimeStamp);
|
void inputAAC(void *pData, uint32_t ui32Length, uint32_t ui32TimeStamp);
|
||||||
|
|
||||||
void inputH264_l(void *pData, uint32_t ui32Length, uint32_t ui64Duration);
|
void inputH264_l(void *pData, uint32_t ui32Length, uint32_t ui32TimeStamp);
|
||||||
void inputH265_l(void *pData, uint32_t ui32Length, uint32_t ui32TimeStamp);
|
void inputH265_l(void *pData, uint32_t ui32Length, uint32_t ui32TimeStamp);
|
||||||
void inputAAC_l(void *pData, uint32_t ui32Length, uint32_t ui64Duration);
|
void inputAAC_l(void *pData, uint32_t ui32Length, uint32_t ui32TimeStamp);
|
||||||
private:
|
private:
|
||||||
|
|
||||||
MovH265Info _movH265info;
|
MovH265Info _movH265info;
|
||||||
int _h265Record = 0;
|
int _h265Record = 0;
|
||||||
|
uint32_t _startPts;
|
||||||
|
|
||||||
uint8_t _sBbuffer[2 * 1024 * 1024];
|
uint8_t _sBbuffer[2 * 1024 * 1024];
|
||||||
MP4FileHandle _hMp4 = MP4_INVALID_FILE_HANDLE;
|
|
||||||
|
|
||||||
MP4TrackId _hVideo = MP4_INVALID_TRACK_ID;
|
|
||||||
MP4TrackId _hAudio = MP4_INVALID_TRACK_ID;
|
|
||||||
string _strPath;
|
string _strPath;
|
||||||
string _strFile;
|
string _strFile;
|
||||||
string _strFileTmp;
|
string _strFileTmp;
|
||||||
@ -141,6 +135,6 @@ private:
|
|||||||
|
|
||||||
} /* namespace mediakit */
|
} /* namespace mediakit */
|
||||||
|
|
||||||
#endif ///ENABLE_MP4V2
|
#endif ///ENABLE_MP4RECORD
|
||||||
|
|
||||||
#endif /* MP4MAKER_H_ */
|
#endif /* MP4MAKER_H_ */
|
||||||
|
Loading…
Reference in New Issue
Block a user