Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
Z
ZLMediaKit
概览
Overview
Details
Activity
Cycle Analytics
版本库
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
问题
0
Issues
0
列表
Board
标记
里程碑
合并请求
0
Merge Requests
0
CI / CD
CI / CD
流水线
作业
日程表
图表
维基
Wiki
代码片段
Snippets
成员
Collapse sidebar
Close sidebar
活动
图像
聊天
创建新问题
作业
提交
Issue Boards
Open sidebar
张翔宇
ZLMediaKit
Commits
89870190
Commit
89870190
authored
Dec 28, 2021
by
ziyue
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
MPEG: 整合复用ts/ps生成代码
parent
dce6b27f
隐藏空白字符变更
内嵌
并排
正在显示
11 个修改的文件
包含
356 行增加
和
413 行删除
+356
-413
CMakeLists.txt
+7
-6
server/main.cpp
+1
-0
src/Extension/Frame.cpp
+3
-3
src/Extension/Frame.h
+11
-11
src/Record/HlsRecorder.h
+11
-9
src/Record/MPEG.cpp
+257
-0
src/Record/MPEG.h
+44
-27
src/Record/TsMuxer.cpp
+0
-160
src/Rtp/PSEncoder.cpp
+9
-139
src/Rtp/PSEncoder.h
+7
-52
src/TS/TSMediaSourceMuxer.h
+6
-6
没有找到文件。
CMakeLists.txt
查看文件 @
89870190
...
...
@@ -187,10 +187,7 @@ endif ()
set
(
VS_FALGS
"/wd4819"
)
#添加mpeg用于支持ts生成
if
(
ENABLE_HLS
)
message
(
STATUS
"ENABLE_HLS defined"
)
add_definitions
(
-DENABLE_HLS
)
if
(
ENABLE_RTPPROXY OR ENABLE_HLS
)
include_directories
(
${
MediaServer_Root
}
/libmpeg/include
)
aux_source_directory
(
${
MediaServer_Root
}
/libmpeg/include src_mpeg
)
aux_source_directory
(
${
MediaServer_Root
}
/libmpeg/source src_mpeg
)
...
...
@@ -228,12 +225,16 @@ if (ENABLE_MP4)
endif
()
endif
()
#添加rtp库用于rtp转ps/ts
if
(
ENABLE_RTPPROXY AND ENABLE_HLS
)
if
(
ENABLE_RTPPROXY
)
message
(
STATUS
"ENABLE_RTPPROXY defined"
)
add_definitions
(
-DENABLE_RTPPROXY
)
endif
()
if
(
ENABLE_HLS
)
message
(
STATUS
"ENABLE_HLS defined"
)
add_definitions
(
-DENABLE_HLS
)
endif
()
#收集源代码
file
(
GLOB ToolKit_src_list
${
ToolKit_Root
}
/*/*.cpp
${
ToolKit_Root
}
/*/*.h
${
ToolKit_Root
}
/*/*.c
)
if
(
IOS
)
...
...
server/main.cpp
查看文件 @
89870190
...
...
@@ -16,6 +16,7 @@
#include "Util/onceToken.h"
#include "Util/CMD.h"
#include "Network/TcpServer.h"
#include "Network/UdpServer.h"
#include "Poller/EventPoller.h"
#include "Common/config.h"
#include "Rtsp/RtspSession.h"
...
...
src/Extension/Frame.cpp
查看文件 @
89870190
...
...
@@ -92,7 +92,7 @@ Frame::Ptr Frame::getCacheAbleFrame(const Frame::Ptr &frame){
TrackType
getTrackType
(
CodecId
codecId
)
{
switch
(
codecId
)
{
#define XX(name, type, value, str) case name : return type;
#define XX(name, type, value, str
, mpeg_id
) case name : return type;
CODEC_MAP
(
XX
)
#undef XX
default
:
return
TrackInvalid
;
...
...
@@ -101,14 +101,14 @@ TrackType getTrackType(CodecId codecId) {
const
char
*
getCodecName
(
CodecId
codec
)
{
switch
(
codec
)
{
#define XX(name, type, value, str) case name : return str;
#define XX(name, type, value, str
, mpeg_id
) case name : return str;
CODEC_MAP
(
XX
)
#undef XX
default
:
return
"invalid"
;
}
}
#define XX(name, type, value, str) {str, name},
#define XX(name, type, value, str
, mpeg_id
) {str, name},
static
map
<
string
,
CodecId
,
StrCaseCompare
>
codec_map
=
{
CODEC_MAP
(
XX
)};
#undef XX
...
...
src/Extension/Frame.h
查看文件 @
89870190
...
...
@@ -31,20 +31,20 @@ typedef enum {
}
TrackType
;
#define CODEC_MAP(XX) \
XX(CodecH264, TrackVideo, 0, "H264") \
XX(CodecH265, TrackVideo, 1, "H265") \
XX(CodecAAC, TrackAudio, 2, "mpeg4-generic"
)
\
XX(CodecG711A, TrackAudio, 3, "PCMA"
)
\
XX(CodecG711U, TrackAudio, 4, "PCMU"
)
\
XX(CodecOpus, TrackAudio, 5, "opus"
)
\
XX(CodecL16, TrackAudio, 6, "L16"
)
\
XX(CodecVP8, TrackVideo, 7, "VP8"
)
\
XX(CodecVP9, TrackVideo, 8, "VP9"
)
\
XX(CodecAV1, TrackVideo, 9, "AV1X")
XX(CodecH264, TrackVideo, 0, "H264"
, PSI_STREAM_H264
) \
XX(CodecH265, TrackVideo, 1, "H265"
, PSI_STREAM_H265
) \
XX(CodecAAC, TrackAudio, 2, "mpeg4-generic"
, PSI_STREAM_AAC)
\
XX(CodecG711A, TrackAudio, 3, "PCMA"
, PSI_STREAM_AUDIO_G711A)
\
XX(CodecG711U, TrackAudio, 4, "PCMU"
, PSI_STREAM_AUDIO_G711U)
\
XX(CodecOpus, TrackAudio, 5, "opus"
, PSI_STREAM_AUDIO_OPUS)
\
XX(CodecL16, TrackAudio, 6, "L16"
, PSI_STREAM_RESERVED)
\
XX(CodecVP8, TrackVideo, 7, "VP8"
, PSI_STREAM_VP8)
\
XX(CodecVP9, TrackVideo, 8, "VP9"
, PSI_STREAM_VP9)
\
XX(CodecAV1, TrackVideo, 9, "AV1X"
, PSI_STREAM_AV1
)
typedef
enum
{
CodecInvalid
=
-
1
,
#define XX(name, type, value, str) name = value,
#define XX(name, type, value, str
, mpeg_id
) name = value,
CODEC_MAP
(
XX
)
#undef XX
CodecMax
...
...
src/Record/HlsRecorder.h
查看文件 @
89870190
...
...
@@ -12,13 +12,15 @@
#define HLSRECORDER_H
#include "HlsMakerImp.h"
#include "TsMuxer.h"
#include "MPEG.h"
namespace
mediakit
{
class
HlsRecorder
:
public
MediaSourceEventInterceptor
,
public
Ts
Muxer
,
public
std
::
enable_shared_from_this
<
HlsRecorder
>
{
class
HlsRecorder
:
public
MediaSourceEventInterceptor
,
public
Mpeg
Muxer
,
public
std
::
enable_shared_from_this
<
HlsRecorder
>
{
public
:
typedef
std
::
shared_ptr
<
HlsRecorder
>
Ptr
;
HlsRecorder
(
const
string
&
m3u8_file
,
const
string
&
params
){
using
Ptr
=
std
::
shared_ptr
<
HlsRecorder
>
;
HlsRecorder
(
const
string
&
m3u8_file
,
const
string
&
params
)
:
MpegMuxer
(
false
)
{
GET_CONFIG
(
uint32_t
,
hlsNum
,
Hls
::
kSegmentNum
);
GET_CONFIG
(
uint32_t
,
hlsBufSize
,
Hls
::
kFileBufSize
);
GET_CONFIG
(
float
,
hlsDuration
,
Hls
::
kSegmentDuration
);
...
...
@@ -27,7 +29,7 @@ public:
_hls
->
clearCache
();
}
~
HlsRecorder
()
{}
~
HlsRecorder
()
=
default
;
void
setMediaSource
(
const
string
&
vhost
,
const
string
&
app
,
const
string
&
stream_id
)
{
_hls
->
setMediaSource
(
vhost
,
app
,
stream_id
);
...
...
@@ -68,17 +70,17 @@ public:
_hls
->
clearCache
();
}
if
(
_enabled
||
!
hls_demand
)
{
return
Ts
Muxer
::
inputFrame
(
frame
);
return
Mpeg
Muxer
::
inputFrame
(
frame
);
}
return
false
;
}
private
:
void
on
Ts
(
std
::
shared_ptr
<
Buffer
>
buffer
,
uint32_t
timestamp
,
bool
is_idr_fast_packet
)
override
{
void
on
Write
(
std
::
shared_ptr
<
Buffer
>
buffer
,
uint32_t
timestamp
,
bool
key_pos
)
override
{
if
(
!
buffer
)
{
_hls
->
inputData
(
nullptr
,
0
,
timestamp
,
is_idr_fast_packet
);
_hls
->
inputData
(
nullptr
,
0
,
timestamp
,
key_pos
);
}
else
{
_hls
->
inputData
(
buffer
->
data
(),
buffer
->
size
(),
timestamp
,
is_idr_fast_packet
);
_hls
->
inputData
(
buffer
->
data
(),
buffer
->
size
(),
timestamp
,
key_pos
);
}
}
...
...
src/Record/MPEG.cpp
0 → 100644
查看文件 @
89870190
/*
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
*
* This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit).
*
* Use of this source code is governed by MIT license that can be found in the
* LICENSE file in the root of the source tree. All contributing project authors
* may be found in the AUTHORS file in the root of the source tree.
*/
#include <cstdlib>
#include <assert.h>
#include "MPEG.h"
#if defined(ENABLE_HLS) || defined(ENABLE_RTPPROXY)
#include "mpeg-ps.h"
#include "mpeg-ts.h"
#include "mpeg-ts-proto.h"
namespace
mediakit
{
struct
mpeg_muxer_t
{
int
is_ps
;
union
{
struct
{
void
*
ctx
;
void
*
param
;
mpeg_muxer_func_t
func
;
}
ts
;
ps_muxer_t
*
ps
;
}
u
;
};
static
void
*
on_mpeg_ts_alloc
(
void
*
param
,
size_t
bytes
)
{
mpeg_muxer_t
*
mpeg
=
(
mpeg_muxer_t
*
)
param
;
return
mpeg
->
u
.
ts
.
func
.
alloc
(
mpeg
->
u
.
ts
.
param
,
bytes
);
}
static
void
on_mpeg_ts_free
(
void
*
param
,
void
*
packet
)
{
mpeg_muxer_t
*
mpeg
=
(
mpeg_muxer_t
*
)
param
;
mpeg
->
u
.
ts
.
func
.
free
(
mpeg
->
u
.
ts
.
param
,
packet
);
}
static
int
on_mpeg_ts_write
(
void
*
param
,
const
void
*
packet
,
size_t
bytes
)
{
mpeg_muxer_t
*
mpeg
=
(
mpeg_muxer_t
*
)
param
;
return
mpeg
->
u
.
ts
.
func
.
write
(
mpeg
->
u
.
ts
.
param
,
0
,
(
void
*
)
packet
,
bytes
);
}
mpeg_muxer_t
*
mpeg_muxer_create
(
int
is_ps
,
const
mpeg_muxer_func_t
*
func
,
void
*
param
)
{
mpeg_muxer_t
*
mpeg
=
(
mpeg_muxer_t
*
)
malloc
(
sizeof
(
mpeg_muxer_t
));
assert
(
mpeg
);
mpeg
->
is_ps
=
is_ps
;
if
(
is_ps
)
{
mpeg
->
u
.
ps
=
ps_muxer_create
(
func
,
param
);
}
else
{
struct
mpeg_ts_func_t
ts_func
{
on_mpeg_ts_alloc
,
on_mpeg_ts_free
,
on_mpeg_ts_write
};
mpeg
->
u
.
ts
.
func
=
*
func
;
mpeg
->
u
.
ts
.
param
=
param
;
mpeg
->
u
.
ts
.
ctx
=
mpeg_ts_create
(
&
ts_func
,
mpeg
);
}
return
mpeg
;
}
int
mpeg_muxer_destroy
(
mpeg_muxer_t
*
muxer
)
{
assert
(
muxer
);
int
ret
=
-
1
;
if
(
muxer
->
is_ps
)
{
ret
=
ps_muxer_destroy
(
muxer
->
u
.
ps
);
}
else
{
ret
=
mpeg_ts_destroy
(
muxer
->
u
.
ts
.
ctx
);
}
free
(
muxer
);
return
ret
;
}
int
mpeg_muxer_add_stream
(
mpeg_muxer_t
*
muxer
,
int
codecid
,
const
void
*
extradata
,
size_t
extradata_size
)
{
assert
(
muxer
);
if
(
muxer
->
is_ps
)
{
return
ps_muxer_add_stream
(
muxer
->
u
.
ps
,
codecid
,
extradata
,
extradata_size
);
}
return
mpeg_ts_add_stream
(
muxer
->
u
.
ts
.
ctx
,
codecid
,
extradata
,
extradata_size
);
}
int
mpeg_muxer_input
(
mpeg_muxer_t
*
muxer
,
int
stream
,
int
flags
,
int64_t
pts
,
int64_t
dts
,
const
void
*
data
,
size_t
bytes
)
{
assert
(
muxer
);
if
(
muxer
->
is_ps
)
{
return
ps_muxer_input
(
muxer
->
u
.
ps
,
stream
,
flags
,
pts
,
dts
,
data
,
bytes
);
}
return
mpeg_ts_write
(
muxer
->
u
.
ts
.
ctx
,
stream
,
flags
,
pts
,
dts
,
data
,
bytes
);
}
int
mpeg_muxer_reset
(
mpeg_muxer_t
*
muxer
)
{
assert
(
muxer
);
if
(
muxer
->
is_ps
)
{
return
-
1
;
}
return
mpeg_ts_reset
(
muxer
->
u
.
ts
.
ctx
);
}
int
mpeg_muxer_add_program
(
mpeg_muxer_t
*
muxer
,
uint16_t
pn
,
const
void
*
info
,
int
bytes
)
{
assert
(
muxer
);
if
(
muxer
->
is_ps
)
{
return
-
1
;
}
return
mpeg_ts_add_program
(
muxer
->
u
.
ts
.
ctx
,
pn
,
info
,
bytes
);
}
int
mpeg_muxer_remove_program
(
mpeg_muxer_t
*
muxer
,
uint16_t
pn
)
{
assert
(
muxer
);
if
(
muxer
->
is_ps
)
{
return
-
1
;
}
return
mpeg_ts_remove_program
(
muxer
->
u
.
ts
.
ctx
,
pn
);
}
int
peg_muxer_add_program_stream
(
mpeg_muxer_t
*
muxer
,
uint16_t
pn
,
int
codecid
,
const
void
*
extra_data
,
size_t
extra_data_size
)
{
assert
(
muxer
);
if
(
muxer
->
is_ps
)
{
return
-
1
;
}
return
mpeg_ts_add_program_stream
(
muxer
->
u
.
ts
.
ctx
,
pn
,
codecid
,
extra_data
,
extra_data_size
);
}
//////////////////////////////////////////////////////////////////////////////////////////
MpegMuxer
::
MpegMuxer
(
bool
is_ps
)
{
_is_ps
=
is_ps
;
_buffer
=
BufferRaw
::
create
();
createContext
();
}
MpegMuxer
::~
MpegMuxer
()
{
releaseContext
();
}
#define XX(name, type, value, str, mpeg_id) \
case name : { \
if (mpeg_id == PSI_STREAM_RESERVED) { \
break; \
} \
_codec_to_trackid[track->getCodecId()] = mpeg_muxer_add_stream(_context, mpeg_id, nullptr, 0); \
return true; \
}
bool
MpegMuxer
::
addTrack
(
const
Track
::
Ptr
&
track
)
{
if
(
track
->
getTrackType
()
==
TrackVideo
)
{
_have_video
=
true
;
}
switch
(
track
->
getCodecId
())
{
CODEC_MAP
(
XX
)
default
:
break
;
}
WarnL
<<
"不支持该编码格式,已忽略:"
<<
track
->
getCodecName
();
return
false
;
}
#undef XX
bool
MpegMuxer
::
inputFrame
(
const
Frame
::
Ptr
&
frame
)
{
auto
it
=
_codec_to_trackid
.
find
(
frame
->
getCodecId
());
if
(
it
==
_codec_to_trackid
.
end
())
{
return
false
;
}
auto
track_id
=
it
->
second
;
_key_pos
=
!
_have_video
;
switch
(
frame
->
getCodecId
())
{
case
CodecH264
:
case
CodecH265
:
{
//这里的代码逻辑是让SPS、PPS、IDR这些时间戳相同的帧打包到一起当做一个帧处理,
return
_frame_merger
.
inputFrame
(
frame
,[
&
](
uint32_t
dts
,
uint32_t
pts
,
const
Buffer
::
Ptr
&
buffer
,
bool
have_idr
)
{
_key_pos
=
have_idr
;
//取视频时间戳为TS的时间戳
_timestamp
=
(
uint32_t
)
dts
;
mpeg_muxer_input
(
_context
,
track_id
,
have_idr
?
0x0001
:
0
,
pts
*
90LL
,
dts
*
90LL
,
buffer
->
data
(),
buffer
->
size
());
flushCache
();
});
}
case
CodecAAC
:
{
if
(
frame
->
prefixSize
()
==
0
)
{
WarnL
<<
"必须提供adts头才能mpeg-ts打包"
;
return
false
;
}
}
default
:
{
if
(
!
_have_video
)
{
//没有视频时,才以音频时间戳为TS的时间戳
_timestamp
=
(
uint32_t
)
frame
->
dts
();
}
mpeg_muxer_input
(
_context
,
track_id
,
frame
->
keyFrame
()
?
0x0001
:
0
,
frame
->
pts
()
*
90LL
,
frame
->
dts
()
*
90LL
,
frame
->
data
(),
frame
->
size
());
flushCache
();
return
true
;
}
}
}
void
MpegMuxer
::
resetTracks
()
{
_have_video
=
false
;
//通知片段中断
onWrite
(
nullptr
,
_timestamp
,
false
);
releaseContext
();
createContext
();
}
void
MpegMuxer
::
createContext
()
{
static
mpeg_muxer_func_t
func
=
{
/*alloc*/
[](
void
*
param
,
size_t
bytes
)
{
MpegMuxer
*
thiz
=
(
MpegMuxer
*
)
param
;
thiz
->
_buffer
->
setCapacity
(
bytes
+
1
);
return
(
void
*
)
thiz
->
_buffer
->
data
();
},
/*free*/
[](
void
*
param
,
void
*
packet
)
{
//什么也不做
},
/*wtite*/
[](
void
*
param
,
int
stream
,
void
*
packet
,
size_t
bytes
)
{
MpegMuxer
*
thiz
=
(
MpegMuxer
*
)
param
;
thiz
->
onWrite_l
(
packet
,
bytes
);
return
0
;
}
};
if
(
_context
==
nullptr
)
{
_context
=
mpeg_muxer_create
(
_is_ps
,
&
func
,
this
);
}
}
void
MpegMuxer
::
onWrite_l
(
const
void
*
packet
,
size_t
bytes
)
{
if
(
!
_cache
)
{
_cache
=
std
::
make_shared
<
BufferLikeString
>
();
}
_cache
->
append
((
char
*
)
packet
,
bytes
);
}
void
MpegMuxer
::
flushCache
()
{
if
(
!
_cache
||
_cache
->
empty
())
{
return
;
}
onWrite
(
std
::
move
(
_cache
),
_timestamp
,
_key_pos
);
_key_pos
=
false
;
}
void
MpegMuxer
::
releaseContext
()
{
if
(
_context
)
{
mpeg_muxer_destroy
(
_context
);
_context
=
nullptr
;
}
_codec_to_trackid
.
clear
();
_frame_merger
.
clear
();
}
}
//mediakit
#endif
\ No newline at end of file
src/Record/
TsMuxer
.h
→
src/Record/
MPEG
.h
查看文件 @
89870190
...
...
@@ -8,27 +8,42 @@
* may be found in the AUTHORS file in the root of the source tree.
*/
#ifndef
TSMUXER
_H
#define
TSMUXER
_H
#ifndef
ZLMEDIAKIT_MPEG
_H
#define
ZLMEDIAKIT_MPEG
_H
#if defined(ENABLE_HLS)
#if defined(ENABLE_HLS)
|| defined(ENABLE_RTPPROXY)
#include <cstdio>
#include <cstdint>
#include <unordered_map>
#include "mpeg-ps.h"
#include "Extension/Frame.h"
#include "Extension/Track.h"
#include "Util/File.h"
#include "Common/MediaSink.h"
#include "Common/Stamp.h"
using
namespace
toolkit
;
namespace
mediakit
{
//该类用于产生MPEG-TS
class
TsMuxer
:
public
MediaSinkInterface
{
typedef
struct
mpeg_muxer_t
mpeg_muxer_t
;
typedef
struct
ps_muxer_func_t
mpeg_muxer_func_t
;
mpeg_muxer_t
*
mpeg_muxer_create
(
int
is_ps
,
const
mpeg_muxer_func_t
*
func
,
void
*
param
);
int
mpeg_muxer_destroy
(
mpeg_muxer_t
*
muxer
);
int
mpeg_muxer_add_stream
(
mpeg_muxer_t
*
muxer
,
int
codecid
,
const
void
*
extradata
,
size_t
extradata_size
);
int
mpeg_muxer_input
(
mpeg_muxer_t
*
muxer
,
int
stream
,
int
flags
,
int64_t
pts
,
int64_t
dts
,
const
void
*
data
,
size_t
bytes
);
int
mpeg_muxer_reset
(
mpeg_muxer_t
*
muxer
);
int
mpeg_muxer_add_program
(
mpeg_muxer_t
*
muxer
,
uint16_t
pn
,
const
void
*
info
,
int
bytes
);
int
mpeg_muxer_remove_program
(
mpeg_muxer_t
*
muxer
,
uint16_t
pn
);
int
peg_muxer_add_program_stream
(
mpeg_muxer_t
*
muxer
,
uint16_t
pn
,
int
codecid
,
const
void
*
extra_data
,
size_t
extra_data_size
);
///////////////////////////////////////////////////////////////
//该类用于产生MPEG-TS/MPEG-PS
class
MpegMuxer
:
public
MediaSinkInterface
{
public
:
TsMuxer
(
);
virtual
~
TsMuxer
()
;
MpegMuxer
(
bool
is_ps
);
~
MpegMuxer
()
override
;
/**
* 添加音视频轨道
...
...
@@ -47,50 +62,53 @@ public:
protected
:
/**
* 输出
mpegt
s数据回调
* @param buffer
mpegt
s数据包
* 输出
ts/p
s数据回调
* @param buffer
ts/p
s数据包
* @param timestamp 时间戳,单位毫秒
* @param
is_idr_fast_packet 是否为关键帧的第一个TS
包,用于确保ts切片第一帧为关键帧
* @param
key_pos 是否为关键帧的第一个ts/ps
包,用于确保ts切片第一帧为关键帧
*/
virtual
void
on
Ts
(
std
::
shared_ptr
<
Buffer
>
buffer
,
uint32_t
timestamp
,
bool
is_idr_fast_packet
)
=
0
;
virtual
void
on
Write
(
std
::
shared_ptr
<
Buffer
>
buffer
,
uint32_t
timestamp
,
bool
key_pos
)
=
0
;
private
:
void
ini
t
();
void
unini
t
();
void
createContex
t
();
void
releaseContex
t
();
void
flushCache
();
void
on
Ts
_l
(
const
void
*
packet
,
size_t
bytes
);
void
on
Write
_l
(
const
void
*
packet
,
size_t
bytes
);
private
:
bool
_is_ps
=
false
;
bool
_have_video
=
false
;
bool
_is_idr_fast_packet
=
false
;
void
*
_context
=
nullptr
;
char
_tsbuf
[
188
];
bool
_key_pos
=
false
;
uint32_t
_timestamp
=
0
;
mpeg_muxer_t
*
_context
=
nullptr
;
BufferRaw
::
Ptr
_buffer
;
unordered_map
<
int
,
int
/*track_id*/
>
_codec_to_trackid
;
FrameMerger
_frame_merger
{
FrameMerger
::
h264_prefix
};
std
::
shared_ptr
<
BufferLikeString
>
_cache
;
};
}
//
namespace
mediakit
}
//mediakit
#else
#include "Common/MediaSink.h"
namespace
mediakit
{
class
TsMuxer
:
public
MediaSinkInterface
{
class
MpegMuxer
:
public
MediaSinkInterface
{
public
:
TsMuxer
()
{}
~
TsMuxer
()
override
{}
MpegMuxer
(
bool
is_ps
)
{};
~
MpegMuxer
()
override
=
default
;
bool
addTrack
(
const
Track
::
Ptr
&
track
)
override
{
return
false
;
}
void
resetTracks
()
override
{}
bool
inputFrame
(
const
Frame
::
Ptr
&
frame
)
override
{
return
false
;
}
protected
:
virtual
void
on
Ts
(
std
::
shared_ptr
<
Buffer
>
buffer
,
uint32_t
timestamp
,
bool
is_idr_fast_packet
)
=
0
;
virtual
void
on
Write
(
std
::
shared_ptr
<
Buffer
>
buffer
,
uint32_t
timestamp
,
bool
key_pos
)
=
0
;
};
}
//namespace mediakit
#endif
// defined(ENABLE_HLS)
#endif
#endif //TSMUXER_H
\ No newline at end of file
#endif //ZLMEDIAKIT_MPEG_H
src/Record/TsMuxer.cpp
deleted
100644 → 0
查看文件 @
dce6b27f
/*
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
*
* This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit).
*
* Use of this source code is governed by MIT license that can be found in the
* LICENSE file in the root of the source tree. All contributing project authors
* may be found in the AUTHORS file in the root of the source tree.
*/
#if defined(ENABLE_HLS)
#include "TsMuxer.h"
#include "mpeg-ts-proto.h"
#include "mpeg-ts.h"
#include "Extension/H264.h"
namespace
mediakit
{
TsMuxer
::
TsMuxer
()
{
init
();
}
TsMuxer
::~
TsMuxer
()
{
uninit
();
}
bool
TsMuxer
::
addTrack
(
const
Track
::
Ptr
&
track
)
{
switch
(
track
->
getCodecId
())
{
case
CodecH264
:
{
_have_video
=
true
;
_codec_to_trackid
[
track
->
getCodecId
()]
=
mpeg_ts_add_stream
(
_context
,
PSI_STREAM_H264
,
nullptr
,
0
);
break
;
}
case
CodecH265
:
{
_have_video
=
true
;
_codec_to_trackid
[
track
->
getCodecId
()]
=
mpeg_ts_add_stream
(
_context
,
PSI_STREAM_H265
,
nullptr
,
0
);
break
;
}
case
CodecAAC
:
{
_codec_to_trackid
[
track
->
getCodecId
()]
=
mpeg_ts_add_stream
(
_context
,
PSI_STREAM_AAC
,
nullptr
,
0
);
break
;
}
case
CodecG711A
:
{
_codec_to_trackid
[
track
->
getCodecId
()]
=
mpeg_ts_add_stream
(
_context
,
PSI_STREAM_AUDIO_G711A
,
nullptr
,
0
);
break
;
}
case
CodecG711U
:
{
_codec_to_trackid
[
track
->
getCodecId
()]
=
mpeg_ts_add_stream
(
_context
,
PSI_STREAM_AUDIO_G711U
,
nullptr
,
0
);
break
;
}
case
CodecOpus
:
{
_codec_to_trackid
[
track
->
getCodecId
()]
=
mpeg_ts_add_stream
(
_context
,
PSI_STREAM_AUDIO_OPUS
,
nullptr
,
0
);
break
;
}
default
:
WarnL
<<
"mpeg-ts 不支持该编码格式,已忽略:"
<<
track
->
getCodecName
();
return
false
;
}
return
true
;
}
bool
TsMuxer
::
inputFrame
(
const
Frame
::
Ptr
&
frame
)
{
auto
it
=
_codec_to_trackid
.
find
(
frame
->
getCodecId
());
if
(
it
==
_codec_to_trackid
.
end
())
{
return
false
;
}
auto
track_id
=
it
->
second
;
_is_idr_fast_packet
=
!
_have_video
;
switch
(
frame
->
getCodecId
())
{
case
CodecH264
:
case
CodecH265
:
{
//这里的代码逻辑是让SPS、PPS、IDR这些时间戳相同的帧打包到一起当做一个帧处理,
return
_frame_merger
.
inputFrame
(
frame
,[
&
](
uint32_t
dts
,
uint32_t
pts
,
const
Buffer
::
Ptr
&
buffer
,
bool
have_idr
)
{
//取视频时间戳为TS的时间戳
_timestamp
=
(
uint32_t
)
dts
;
_is_idr_fast_packet
=
have_idr
;
mpeg_ts_write
(
_context
,
track_id
,
have_idr
?
0x0001
:
0
,
pts
*
90LL
,
dts
*
90LL
,
buffer
->
data
(),
buffer
->
size
());
flushCache
();
});
}
case
CodecAAC
:
{
if
(
frame
->
prefixSize
()
==
0
)
{
WarnL
<<
"必须提供adts头才能mpeg-ts打包"
;
return
false
;
}
}
default
:
{
if
(
!
_have_video
)
{
//没有视频时,才以音频时间戳为TS的时间戳
_timestamp
=
(
uint32_t
)
frame
->
dts
();
}
mpeg_ts_write
(
_context
,
track_id
,
frame
->
keyFrame
()
?
0x0001
:
0
,
frame
->
pts
()
*
90LL
,
frame
->
dts
()
*
90LL
,
frame
->
data
(),
frame
->
size
());
flushCache
();
return
true
;
}
}
}
void
TsMuxer
::
resetTracks
()
{
_have_video
=
false
;
//通知片段中断
onTs
(
nullptr
,
_timestamp
,
0
);
uninit
();
init
();
}
void
TsMuxer
::
init
()
{
static
mpeg_ts_func_t
s_func
=
{
[](
void
*
param
,
size_t
bytes
)
{
TsMuxer
*
muxer
=
(
TsMuxer
*
)
param
;
assert
(
sizeof
(
muxer
->
_tsbuf
)
>=
bytes
);
return
(
void
*
)
muxer
->
_tsbuf
;
},
[](
void
*
param
,
void
*
packet
)
{
//do nothing
},
[](
void
*
param
,
const
void
*
packet
,
size_t
bytes
)
{
TsMuxer
*
muxer
=
(
TsMuxer
*
)
param
;
muxer
->
onTs_l
(
packet
,
bytes
);
return
0
;
}
};
if
(
_context
==
nullptr
)
{
_context
=
mpeg_ts_create
(
&
s_func
,
this
);
}
}
void
TsMuxer
::
onTs_l
(
const
void
*
packet
,
size_t
bytes
)
{
if
(
!
_cache
)
{
_cache
=
std
::
make_shared
<
BufferLikeString
>
();
}
_cache
->
append
((
char
*
)
packet
,
bytes
);
}
void
TsMuxer
::
flushCache
()
{
onTs
(
std
::
move
(
_cache
),
_timestamp
,
_is_idr_fast_packet
);
_is_idr_fast_packet
=
false
;
}
void
TsMuxer
::
uninit
()
{
if
(
_context
)
{
mpeg_ts_destroy
(
_context
);
_context
=
nullptr
;
}
_codec_to_trackid
.
clear
();
_frame_merger
.
clear
();
}
}
//namespace mediakit
#endif// defined(ENABLE_HLS)
\ No newline at end of file
src/Rtp/PSEncoder.cpp
查看文件 @
89870190
...
...
@@ -9,148 +9,14 @@
*/
#if defined(ENABLE_RTPPROXY)
#include "PSEncoder.h"
#include "Extension/H264.h"
#include "Rtsp/RtspMuxer.h"
namespace
mediakit
{
PSEncoder
::
PSEncoder
()
{
_buffer
=
BufferRaw
::
create
();
init
();
}
PSEncoder
::~
PSEncoder
()
{
}
void
PSEncoder
::
init
()
{
static
struct
ps_muxer_func_t
func
=
{
/*alloc*/
[](
void
*
param
,
size_t
bytes
)
{
PSEncoder
*
thiz
=
(
PSEncoder
*
)
param
;
thiz
->
_buffer
->
setCapacity
(
bytes
+
1
);
return
(
void
*
)
thiz
->
_buffer
->
data
();
},
/*free*/
[](
void
*
param
,
void
*
packet
)
{
//什么也不做
},
/*wtite*/
[](
void
*
param
,
int
stream
,
void
*
packet
,
size_t
bytes
)
{
PSEncoder
*
thiz
=
(
PSEncoder
*
)
param
;
thiz
->
onPS
(
thiz
->
_timestamp
,
packet
,
bytes
);
return
0
;
}
};
_muxer
.
reset
(
ps_muxer_create
(
&
func
,
this
),
[](
struct
ps_muxer_t
*
ptr
)
{
ps_muxer_destroy
(
ptr
);
});
}
bool
PSEncoder
::
addTrack
(
const
Track
::
Ptr
&
track
)
{
switch
(
track
->
getCodecId
())
{
case
CodecH264
:
{
_codec_to_trackid
[
track
->
getCodecId
()].
track_id
=
ps_muxer_add_stream
(
_muxer
.
get
(),
STREAM_VIDEO_H264
,
nullptr
,
0
);
break
;
}
case
CodecH265
:
{
_codec_to_trackid
[
track
->
getCodecId
()].
track_id
=
ps_muxer_add_stream
(
_muxer
.
get
(),
STREAM_VIDEO_H265
,
nullptr
,
0
);
break
;
}
case
CodecAAC
:
{
_codec_to_trackid
[
track
->
getCodecId
()].
track_id
=
ps_muxer_add_stream
(
_muxer
.
get
(),
STREAM_AUDIO_AAC
,
nullptr
,
0
);
break
;
}
case
CodecG711A
:
{
_codec_to_trackid
[
track
->
getCodecId
()].
track_id
=
ps_muxer_add_stream
(
_muxer
.
get
(),
STREAM_AUDIO_G711A
,
nullptr
,
0
);
break
;
}
case
CodecG711U
:
{
_codec_to_trackid
[
track
->
getCodecId
()].
track_id
=
ps_muxer_add_stream
(
_muxer
.
get
(),
STREAM_AUDIO_G711U
,
nullptr
,
0
);
break
;
}
case
CodecOpus
:
{
_codec_to_trackid
[
track
->
getCodecId
()].
track_id
=
ps_muxer_add_stream
(
_muxer
.
get
(),
STREAM_AUDIO_OPUS
,
nullptr
,
0
);
break
;
}
default
:
WarnL
<<
"mpeg-ps 不支持该编码格式,已忽略:"
<<
track
->
getCodecName
();
return
false
;
}
//尝试音视频同步
stampSync
();
return
true
;
}
void
PSEncoder
::
stampSync
(){
if
(
_codec_to_trackid
.
size
()
<
2
){
return
;
}
Stamp
*
audio
=
nullptr
,
*
video
=
nullptr
;
for
(
auto
&
pr
:
_codec_to_trackid
){
switch
(
getTrackType
((
CodecId
)
pr
.
first
)){
case
TrackAudio
:
audio
=
&
pr
.
second
.
stamp
;
break
;
case
TrackVideo
:
video
=
&
pr
.
second
.
stamp
;
break
;
default
:
break
;
}
}
if
(
audio
&&
video
){
//音频时间戳同步于视频,因为音频时间戳被修改后不影响播放
audio
->
syncTo
(
*
video
);
}
}
void
PSEncoder
::
resetTracks
()
{
init
();
}
bool
PSEncoder
::
inputFrame
(
const
Frame
::
Ptr
&
frame
)
{
auto
it
=
_codec_to_trackid
.
find
(
frame
->
getCodecId
());
if
(
it
==
_codec_to_trackid
.
end
())
{
return
false
;
}
auto
&
track_info
=
it
->
second
;
int64_t
dts_out
,
pts_out
;
switch
(
frame
->
getCodecId
())
{
case
CodecH264
:
case
CodecH265
:
{
//这里的代码逻辑是让SPS、PPS、IDR这些时间戳相同的帧打包到一起当做一个帧处理,
return
_frame_merger
.
inputFrame
(
frame
,
[
&
](
uint32_t
dts
,
uint32_t
pts
,
const
Buffer
::
Ptr
&
buffer
,
bool
have_idr
)
{
track_info
.
stamp
.
revise
(
dts
,
pts
,
dts_out
,
pts_out
);
//取视频时间戳为TS的时间戳
_timestamp
=
(
uint32_t
)
pts_out
;
ps_muxer_input
(
_muxer
.
get
(),
track_info
.
track_id
,
have_idr
?
0x0001
:
0
,
pts_out
*
90LL
,
dts_out
*
90LL
,
buffer
->
data
(),
buffer
->
size
());
});
}
case
CodecAAC
:
{
if
(
frame
->
prefixSize
()
==
0
)
{
WarnL
<<
"必须提供adts头才能mpeg-ps打包"
;
return
false
;
}
}
default
:
{
track_info
.
stamp
.
revise
(
frame
->
dts
(),
frame
->
pts
(),
dts_out
,
pts_out
);
_timestamp
=
(
uint32_t
)
dts_out
;
ps_muxer_input
(
_muxer
.
get
(),
track_info
.
track_id
,
frame
->
keyFrame
()
?
0x0001
:
0
,
pts_out
*
90LL
,
dts_out
*
90LL
,
frame
->
data
(),
frame
->
size
());
return
true
;
}
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
namespace
mediakit
{
PSEncoderImp
::
PSEncoderImp
(
uint32_t
ssrc
,
uint8_t
payload_type
)
{
PSEncoderImp
::
PSEncoderImp
(
uint32_t
ssrc
,
uint8_t
payload_type
)
:
MpegMuxer
(
true
)
{
GET_CONFIG
(
uint32_t
,
video_mtu
,
Rtp
::
kVideoMtuSize
);
_rtp_encoder
=
std
::
make_shared
<
CommonRtpEncoder
>
(
CodecInvalid
,
ssrc
,
video_mtu
,
90000
,
payload_type
,
0
);
_rtp_encoder
->
setRtpRing
(
std
::
make_shared
<
RtpRing
::
RingType
>
());
...
...
@@ -164,9 +30,13 @@ PSEncoderImp::~PSEncoderImp() {
InfoL
<<
this
<<
" "
<<
printSSRC
(
_rtp_encoder
->
getSsrc
());
}
void
PSEncoderImp
::
onPS
(
uint32_t
stamp
,
void
*
packet
,
size_t
bytes
)
{
_rtp_encoder
->
inputFrame
(
std
::
make_shared
<
FrameFromPtr
>
((
char
*
)
packet
,
bytes
,
stamp
,
stamp
));
void
PSEncoderImp
::
onWrite
(
std
::
shared_ptr
<
Buffer
>
buffer
,
uint32_t
stamp
,
bool
key_pos
)
{
if
(
!
buffer
)
{
return
;
}
_rtp_encoder
->
inputFrame
(
std
::
make_shared
<
FrameFromPtr
>
(
buffer
->
data
(),
buffer
->
size
(),
stamp
,
stamp
));
}
}
//namespace mediakit
#endif//defined(ENABLE_RTPPROXY)
src/Rtp/PSEncoder.h
查看文件 @
89870190
...
...
@@ -10,63 +10,17 @@
#ifndef ZLMEDIAKIT_PSENCODER_H
#define ZLMEDIAKIT_PSENCODER_H
#if defined(ENABLE_RTPPROXY)
#include "mpeg-ps.h"
#include "Record/MPEG.h"
#include "Common/MediaSink.h"
#include "Common/Stamp.h"
#include "Extension/CommonRtp.h"
namespace
mediakit
{
//该类实现mpeg-ps容器格式的打包
class
PSEncoder
:
public
MediaSinkInterface
{
public
:
PSEncoder
();
~
PSEncoder
()
override
;
/**
* 添加音视频轨道
*/
bool
addTrack
(
const
Track
::
Ptr
&
track
)
override
;
/**
* 重置音视频轨道
*/
void
resetTracks
()
override
;
/**
* 输入帧数据
*/
bool
inputFrame
(
const
Frame
::
Ptr
&
frame
)
override
;
protected
:
/**
* 输出mpeg-ps的回调函数
* @param stamp 时间戳,毫秒
* @param packet 数据指针
* @param bytes 数据长度
*/
virtual
void
onPS
(
uint32_t
stamp
,
void
*
packet
,
size_t
bytes
)
=
0
;
private
:
void
init
();
//音视频时间戳同步用
void
stampSync
();
private
:
struct
track_info
{
int
track_id
=
-
1
;
Stamp
stamp
;
};
private
:
uint32_t
_timestamp
=
0
;
BufferRaw
::
Ptr
_buffer
;
std
::
shared_ptr
<
struct
ps_muxer_t
>
_muxer
;
unordered_map
<
int
,
track_info
>
_codec_to_trackid
;
FrameMerger
_frame_merger
{
FrameMerger
::
h264_prefix
};
};
namespace
mediakit
{
class
PSEncoderImp
:
public
PSEncod
er
{
class
PSEncoderImp
:
public
MpegMux
er
{
public
:
PSEncoderImp
(
uint32_t
ssrc
,
uint8_t
payload_type
=
96
);
~
PSEncoderImp
()
override
;
...
...
@@ -76,12 +30,13 @@ protected:
virtual
void
onRTP
(
Buffer
::
Ptr
rtp
)
=
0
;
protected
:
void
on
PS
(
uint32_t
stamp
,
void
*
packet
,
size_t
byte
s
)
override
;
void
on
Write
(
std
::
shared_ptr
<
Buffer
>
buffer
,
uint32_t
stamp
,
bool
key_po
s
)
override
;
private
:
std
::
shared_ptr
<
CommonRtpEncoder
>
_rtp_encoder
;
};
}
//namespace mediakit
#endif //ENABLE_RTPPROXY
#endif //ZLMEDIAKIT_PSENCODER_H
src/TS/TSMediaSourceMuxer.h
查看文件 @
89870190
...
...
@@ -12,18 +12,18 @@
#define ZLMEDIAKIT_TSMEDIASOURCEMUXER_H
#include "TSMediaSource.h"
#include "Record/
TsMuxer
.h"
#include "Record/
MPEG
.h"
namespace
mediakit
{
class
TSMediaSourceMuxer
:
public
Ts
Muxer
,
public
MediaSourceEventInterceptor
,
class
TSMediaSourceMuxer
:
public
Mpeg
Muxer
,
public
MediaSourceEventInterceptor
,
public
std
::
enable_shared_from_this
<
TSMediaSourceMuxer
>
{
public
:
using
Ptr
=
std
::
shared_ptr
<
TSMediaSourceMuxer
>
;
TSMediaSourceMuxer
(
const
string
&
vhost
,
const
string
&
app
,
const
string
&
stream_id
)
{
const
string
&
stream_id
)
:
MpegMuxer
(
false
)
{
_media_src
=
std
::
make_shared
<
TSMediaSource
>
(
vhost
,
app
,
stream_id
);
}
...
...
@@ -54,7 +54,7 @@ public:
_media_src
->
clearCache
();
}
if
(
_enabled
||
!
ts_demand
)
{
return
Ts
Muxer
::
inputFrame
(
frame
);
return
Mpeg
Muxer
::
inputFrame
(
frame
);
}
return
false
;
}
...
...
@@ -66,13 +66,13 @@ public:
}
protected
:
void
on
Ts
(
std
::
shared_ptr
<
Buffer
>
buffer
,
uint32_t
timestamp
,
bool
is_idr_fast_packet
)
override
{
void
on
Write
(
std
::
shared_ptr
<
Buffer
>
buffer
,
uint32_t
timestamp
,
bool
key_pos
)
override
{
if
(
!
buffer
)
{
return
;
}
auto
packet
=
std
::
make_shared
<
TSPacket
>
(
std
::
move
(
buffer
));
packet
->
time_stamp
=
timestamp
;
_media_src
->
onWrite
(
std
::
move
(
packet
),
is_idr_fast_packet
);
_media_src
->
onWrite
(
std
::
move
(
packet
),
key_pos
);
}
private
:
...
...
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论