1
+ #include <string>
2
+ #include <chrono>
3
+ #include <iterator>
4
+ #include "ffmpeghandler.h"
5
+ #include "log.h"
6
+
7
+ FFmpegHandler ::FFmpegHandler () {
8
+ streamHandler = nullptr ;
9
+ }
10
+
11
+ FFmpegHandler ::~FFmpegHandler () {
12
+ stopVideo ();
13
+ }
14
+
15
+ std ::vector < std ::string > FFmpegHandler ::prepareStreamCmd (const m3u_stream & stream ) {
16
+ // create parameter list
17
+ std ::vector < std ::string > callStr {
18
+ "ffmpeg" , "-hide_banner" , "-re" , "-y"
19
+ };
20
+
21
+ // add main input
22
+ callStr .emplace_back ("-i" );
23
+ callStr .emplace_back (stream .url );
24
+
25
+ // add optional audio input
26
+ std ::vector < std ::string > audioMetadata ;
27
+ for (auto a : stream .audio ) {
28
+ callStr .emplace_back ("- i ");
29
+ callStr .emplace_back (a .uri );
30
+ }
31
+
32
+ // transmux
33
+ callStr .emplace_back ("-codec" );
34
+ callStr .emplace_back ("copy" );
35
+
36
+ // main input
37
+ if (!stream .audio .empty ()) {
38
+ callStr .emplace_back ("-map" );
39
+ callStr .emplace_back ("0:v" );
40
+
41
+ int idx = 1 ;
42
+ for (auto a : stream .audio ) {
43
+ callStr .emplace_back ("-map" );
44
+ callStr .emplace_back (std ::to_string (idx ) + ":a" );
45
+ idx ++ ;
46
+ }
47
+
48
+ // TODO: Metadata einfügen, sofern vorhanden
49
+ callStr .insert (std ::end (callStr ), std ::begin (audioMetadata ), std ::end (audioMetadata ));
50
+ }
51
+
52
+ callStr .emplace_back ("-streamid" );
53
+ callStr .emplace_back ("0:" + std ::to_string (stream .vpid ));
54
+
55
+ int aidx = 1 ;
56
+ for (auto a : stream .apids ) {
57
+ callStr .emplace_back ("-streamid" );
58
+ callStr .emplace_back (std ::to_string (aidx ) + ":" + std ::to_string (a ));
59
+ aidx ++ ;
60
+ }
61
+
62
+ callStr .emplace_back ("-f" );
63
+ callStr .emplace_back ("mpegts" );
64
+
65
+ callStr .emplace_back ("-mpegts_transport_stream_id" );
66
+ callStr .emplace_back (std ::to_string (stream .tpid ));
67
+
68
+ callStr .emplace_back ("-mpegts_pmt_start_pid" );
69
+ callStr .emplace_back ("4096" );
70
+
71
+ callStr .emplace_back ("-mpegts_service_id" );
72
+ callStr .emplace_back (std ::to_string (stream .spid ));
73
+
74
+ callStr .emplace_back ("-mpegts_original_network_id" );
75
+ callStr .emplace_back ("65281" );
76
+
77
+ callStr .emplace_back ("-mpegts_flags" );
78
+ callStr .emplace_back ("system_b" );
79
+
80
+ callStr .emplace_back ("-mpegts_flags" );
81
+ callStr .emplace_back ("nit" );
82
+
83
+ callStr .emplace_back ("-metadata" );
84
+ callStr .emplace_back ("service_name=" + stream .channelName );
85
+
86
+ callStr .emplace_back ("pipe:1" );
87
+
88
+ std ::ostringstream paramOut ;
89
+ if (!callStr .empty ()) {
90
+ std ::copy (callStr .begin (), callStr .end () - 1 , std ::ostream_iterator < std ::string > (paramOut , " "));
91
+ paramOut << callStr .back ();
92
+ }
93
+
94
+ debug2 ("FFmpeg call: %s\n" , paramOut .str ().c_str ());
95
+
96
+ return callStr ;
97
+ }
98
+
99
+ bool FFmpegHandler ::streamVideo (const m3u_stream & stream ) {
100
+ // create parameter list
101
+ std ::vector < std ::string > callStr = prepareStreamCmd (stream );
102
+
103
+ streamHandler = new TinyProcessLib ::Process (callStr , "" ,
104
+ [this ](const char * bytes , size_t n ) {
105
+ debug4 ("Queue size %ld\n" , tsPackets .size ());
106
+
107
+ std ::lock_guard < std ::mutex > guard (queueMutex );
108
+ tsPackets .emplace (bytes , n );
109
+ },
110
+
111
+ [this ](const char * bytes , size_t n ) {
112
+ // TODO: ffmpeg prints many information on stderr
113
+ // How to handle this? ignore? filter?
114
+
115
+ // std::string msg = std::string(bytes, n);
116
+ // printf("Error: %s\n", msg.c_str());
117
+ },
118
+
119
+ true
120
+ );
121
+
122
+ return true;
123
+ }
124
+
125
+ void FFmpegHandler ::stopVideo () {
126
+ if (streamHandler != nullptr ) {
127
+ streamHandler -> kill (true);
128
+ streamHandler -> get_exit_status ();
129
+ delete streamHandler ;
130
+ streamHandler = nullptr ;
131
+ }
132
+
133
+ std ::queue < std ::string > empty ;
134
+ std ::swap (tsPackets , empty );
135
+ }
136
+
137
+ int FFmpegHandler ::popPackets (unsigned char * bufferAddrP , unsigned int bufferLenP ) {
138
+ std ::lock_guard < std ::mutex > guard (queueMutex );
139
+ if (!tsPackets .empty ()) {
140
+ std ::string front = tsPackets .front ();
141
+
142
+ if (bufferLenP < front .size ()) {
143
+ error ("WARNING: BufferLen %u < Size %ld\n" , bufferLenP , front .size ());
144
+ return -1 ;
145
+ }
146
+
147
+ debug4 ("Read from queue, size %ld\n" , front .size ());
148
+
149
+ memcpy (bufferAddrP , front .data (), front .size ());
150
+
151
+ tsPackets .pop ();
152
+ return front .size ();
153
+ }
154
+
155
+ return -1 ;
156
+ }
0 commit comments