winlin

fix st thread exit bug, never implict invoke the st_thread_exit, which may cause…

… memory leak. 0.9.112
@@ -468,7 +468,8 @@ MODULE_FILES=("srs_app_server" "srs_app_conn" "srs_app_rtmp_conn" "srs_app_socke @@ -468,7 +468,8 @@ MODULE_FILES=("srs_app_server" "srs_app_conn" "srs_app_rtmp_conn" "srs_app_socke
468 "srs_app_thread" "srs_app_bandwidth" "srs_app_st" "srs_app_log" "srs_app_config" 468 "srs_app_thread" "srs_app_bandwidth" "srs_app_st" "srs_app_log" "srs_app_config"
469 "srs_app_pithy_print" "srs_app_reload" "srs_app_http_api" "srs_app_http_conn" "srs_app_http_hooks" 469 "srs_app_pithy_print" "srs_app_reload" "srs_app_http_api" "srs_app_http_conn" "srs_app_http_hooks"
470 "srs_app_json" "srs_app_ingest" "srs_app_ffmpeg" "srs_app_utility" "srs_app_dvr" "srs_app_edge" 470 "srs_app_json" "srs_app_ingest" "srs_app_ffmpeg" "srs_app_utility" "srs_app_dvr" "srs_app_edge"
471 - "srs_app_kbps" "srs_app_heartbeat" "srs_app_empty" "srs_app_http_client") 471 + "srs_app_kbps" "srs_app_heartbeat" "srs_app_empty" "srs_app_http_client"
  472 + "srs_app_flv")
472 APP_INCS="src/app"; MODULE_DIR=${APP_INCS} . auto/modules.sh 473 APP_INCS="src/app"; MODULE_DIR=${APP_INCS} . auto/modules.sh
473 APP_OBJS="${MODULE_OBJS[@]}" 474 APP_OBJS="${MODULE_OBJS[@]}"
474 # 475 #
@@ -39,272 +39,7 @@ using namespace std; @@ -39,272 +39,7 @@ using namespace std;
39 #include <srs_kernel_utility.hpp> 39 #include <srs_kernel_utility.hpp>
40 #include <srs_app_http_hooks.hpp> 40 #include <srs_app_http_hooks.hpp>
41 #include <srs_app_codec.hpp> 41 #include <srs_app_codec.hpp>
42 -  
43 -SrsFileStream::SrsFileStream()  
44 -{  
45 - fd = -1;  
46 -}  
47 -  
48 -SrsFileStream::~SrsFileStream()  
49 -{  
50 - close();  
51 -}  
52 -  
53 -int SrsFileStream::open(string file)  
54 -{  
55 - int ret = ERROR_SUCCESS;  
56 -  
57 - if (fd > 0) {  
58 - ret = ERROR_SYSTEM_FILE_ALREADY_OPENED;  
59 - srs_error("file %s already opened. ret=%d", _file.c_str(), ret);  
60 - return ret;  
61 - }  
62 -  
63 - int flags = O_CREAT|O_WRONLY|O_TRUNC;  
64 - mode_t mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH;  
65 -  
66 - if ((fd = ::open(file.c_str(), flags, mode)) < 0) {  
67 - ret = ERROR_SYSTEM_FILE_OPENE;  
68 - srs_error("open file %s failed. ret=%d", file.c_str(), ret);  
69 - return ret;  
70 - }  
71 -  
72 - _file = file;  
73 -  
74 - return ret;  
75 -}  
76 -  
77 -int SrsFileStream::close()  
78 -{  
79 - int ret = ERROR_SUCCESS;  
80 -  
81 - if (fd < 0) {  
82 - return ret;  
83 - }  
84 -  
85 - if (::close(fd) < 0) {  
86 - ret = ERROR_SYSTEM_FILE_CLOSE;  
87 - srs_error("close file %s failed. ret=%d", _file.c_str(), ret);  
88 - return ret;  
89 - }  
90 - fd = -1;  
91 -  
92 - return ret;  
93 -}  
94 -  
95 -bool SrsFileStream::is_open()  
96 -{  
97 - return fd > 0;  
98 -}  
99 -  
100 -int SrsFileStream::read(void* buf, size_t count, ssize_t* pnread)  
101 -{  
102 - int ret = ERROR_SUCCESS;  
103 -  
104 - ssize_t nread;  
105 - if ((nread = ::read(fd, buf, count)) < 0) {  
106 - ret = ERROR_SYSTEM_FILE_READ;  
107 - srs_error("read from file %s failed. ret=%d", _file.c_str(), ret);  
108 - return ret;  
109 - }  
110 -  
111 - if (nread == 0) {  
112 - ret = ERROR_SYSTEM_FILE_EOF;  
113 - return ret;  
114 - }  
115 -  
116 - if (pnread != NULL) {  
117 - *pnread = nread;  
118 - }  
119 -  
120 - return ret;  
121 -}  
122 -  
123 -int SrsFileStream::write(void* buf, size_t count, ssize_t* pnwrite)  
124 -{  
125 - int ret = ERROR_SUCCESS;  
126 -  
127 - ssize_t nwrite;  
128 - if ((nwrite = ::write(fd, buf, count)) < 0) {  
129 - ret = ERROR_SYSTEM_FILE_WRITE;  
130 - srs_error("write to file %s failed. ret=%d", _file.c_str(), ret);  
131 - return ret;  
132 - }  
133 -  
134 - if (pnwrite != NULL) {  
135 - *pnwrite = nwrite;  
136 - }  
137 -  
138 - return ret;  
139 -}  
140 -  
141 -int64_t SrsFileStream::tellg()  
142 -{  
143 - return (int64_t)::lseek(fd, 0, SEEK_CUR);  
144 -}  
145 -  
146 -SrsFlvEncoder::SrsFlvEncoder()  
147 -{  
148 - _fs = NULL;  
149 - tag_stream = new SrsStream();  
150 -}  
151 -  
152 -SrsFlvEncoder::~SrsFlvEncoder()  
153 -{  
154 - srs_freep(tag_stream);  
155 -}  
156 -  
157 -int SrsFlvEncoder::initialize(SrsFileStream* fs)  
158 -{  
159 - int ret = ERROR_SUCCESS;  
160 -  
161 - _fs = fs;  
162 -  
163 - return ret;  
164 -}  
165 -  
166 -int SrsFlvEncoder::write_header()  
167 -{  
168 - int ret = ERROR_SUCCESS;  
169 -  
170 - static char flv_header[] = {  
171 - 'F', 'L', 'V', // Signatures "FLV"  
172 - (char)0x01, // File version (for example, 0x01 for FLV version 1)  
173 - (char)0x00, // 4, audio; 1, video; 5 audio+video.  
174 - (char)0x00, (char)0x00, (char)0x00, (char)0x09, // DataOffset UI32 The length of this header in bytes  
175 - (char)0x00, (char)0x00, (char)0x00, (char)0x00// PreviousTagSize0 UI32 Always 0  
176 - };  
177 -  
178 - // flv specification should set the audio and video flag,  
179 - // actually in practise, application generally ignore this flag,  
180 - // so we generally set the audio/video to 0.  
181 -  
182 - // write data.  
183 - if ((ret = _fs->write(flv_header, sizeof(flv_header), NULL)) != ERROR_SUCCESS) {  
184 - srs_error("write flv header failed. ret=%d", ret);  
185 - return ret;  
186 - }  
187 -  
188 - return ret;  
189 -}  
190 -  
191 -int SrsFlvEncoder::write_metadata(char* data, int size)  
192 -{  
193 - int ret = ERROR_SUCCESS;  
194 -  
195 - static char tag_header[] = {  
196 - (char)18, // TagType UB [5], 18 = script data  
197 - (char)0x00, (char)0x00, (char)0x00, // DataSize UI24 Length of the message.  
198 - (char)0x00, (char)0x00, (char)0x00, // Timestamp UI24 Time in milliseconds at which the data in this tag applies.  
199 - (char)0x00, // TimestampExtended UI8  
200 - (char)0x00, (char)0x00, (char)0x00, // StreamID UI24 Always 0.  
201 - };  
202 -  
203 - // write data size.  
204 - if ((ret = tag_stream->initialize(tag_header + 1, 3)) != ERROR_SUCCESS) {  
205 - return ret;  
206 - }  
207 - tag_stream->write_3bytes(size);  
208 -  
209 - if ((ret = write_tag(tag_header, sizeof(tag_header), data, size)) != ERROR_SUCCESS) {  
210 - srs_error("write flv data tag failed. ret=%d", ret);  
211 - return ret;  
212 - }  
213 -  
214 - return ret;  
215 -}  
216 -  
217 -int SrsFlvEncoder::write_audio(int64_t timestamp, char* data, int size)  
218 -{  
219 - int ret = ERROR_SUCCESS;  
220 -  
221 - timestamp &= 0x7fffffff;  
222 -  
223 - static char tag_header[] = {  
224 - (char)8, // TagType UB [5], 8 = audio  
225 - (char)0x00, (char)0x00, (char)0x00, // DataSize UI24 Length of the message.  
226 - (char)0x00, (char)0x00, (char)0x00, // Timestamp UI24 Time in milliseconds at which the data in this tag applies.  
227 - (char)0x00, // TimestampExtended UI8  
228 - (char)0x00, (char)0x00, (char)0x00, // StreamID UI24 Always 0.  
229 - };  
230 -  
231 - // write data size.  
232 - if ((ret = tag_stream->initialize(tag_header + 1, 7)) != ERROR_SUCCESS) {  
233 - return ret;  
234 - }  
235 - tag_stream->write_3bytes(size);  
236 - tag_stream->write_3bytes(timestamp);  
237 - // default to little-endian  
238 - tag_stream->write_1bytes((timestamp >> 24) & 0xFF);  
239 -  
240 - if ((ret = write_tag(tag_header, sizeof(tag_header), data, size)) != ERROR_SUCCESS) {  
241 - srs_error("write flv audio tag failed. ret=%d", ret);  
242 - return ret;  
243 - }  
244 -  
245 - return ret;  
246 -}  
247 -  
248 -int SrsFlvEncoder::write_video(int64_t timestamp, char* data, int size)  
249 -{  
250 - int ret = ERROR_SUCCESS;  
251 -  
252 - timestamp &= 0x7fffffff;  
253 -  
254 - static char tag_header[] = {  
255 - (char)9, // TagType UB [5], 9 = video  
256 - (char)0x00, (char)0x00, (char)0x00, // DataSize UI24 Length of the message.  
257 - (char)0x00, (char)0x00, (char)0x00, // Timestamp UI24 Time in milliseconds at which the data in this tag applies.  
258 - (char)0x00, // TimestampExtended UI8  
259 - (char)0x00, (char)0x00, (char)0x00, // StreamID UI24 Always 0.  
260 - };  
261 -  
262 - // write data size.  
263 - if ((ret = tag_stream->initialize(tag_header + 1, 7)) != ERROR_SUCCESS) {  
264 - return ret;  
265 - }  
266 - tag_stream->write_3bytes(size);  
267 - tag_stream->write_3bytes(timestamp);  
268 - // default to little-endian  
269 - tag_stream->write_1bytes((timestamp >> 24) & 0xFF);  
270 -  
271 - if ((ret = write_tag(tag_header, sizeof(tag_header), data, size)) != ERROR_SUCCESS) {  
272 - srs_error("write flv video tag failed. ret=%d", ret);  
273 - return ret;  
274 - }  
275 -  
276 - return ret;  
277 -}  
278 -  
279 -int SrsFlvEncoder::write_tag(char* header, int header_size, char* tag, int tag_size)  
280 -{  
281 - int ret = ERROR_SUCCESS;  
282 -  
283 - // write tag header.  
284 - if ((ret = _fs->write(header, header_size, NULL)) != ERROR_SUCCESS) {  
285 - srs_error("write flv tag header failed. ret=%d", ret);  
286 - return ret;  
287 - }  
288 -  
289 - // write tag data.  
290 - if ((ret = _fs->write(tag, tag_size, NULL)) != ERROR_SUCCESS) {  
291 - srs_error("write flv tag failed. ret=%d", ret);  
292 - return ret;  
293 - }  
294 -  
295 - // PreviousTagSizeN UI32 Size of last tag, including its header, in bytes.  
296 - static char pre_size[4];  
297 - if ((ret = tag_stream->initialize(pre_size, 4)) != ERROR_SUCCESS) {  
298 - return ret;  
299 - }  
300 - tag_stream->write_4bytes(tag_size + header_size);  
301 - if ((ret = _fs->write(pre_size, sizeof(pre_size), NULL)) != ERROR_SUCCESS) {  
302 - srs_error("write flv previous tag size failed. ret=%d", ret);  
303 - return ret;  
304 - }  
305 -  
306 - return ret;  
307 -} 42 +#include <srs_app_flv.hpp>
308 43
309 SrsFlvSegment::SrsFlvSegment() 44 SrsFlvSegment::SrsFlvSegment()
310 { 45 {
@@ -37,79 +37,8 @@ class SrsStream; @@ -37,79 +37,8 @@ class SrsStream;
37 class SrsRtmpJitter; 37 class SrsRtmpJitter;
38 class SrsOnMetaDataPacket; 38 class SrsOnMetaDataPacket;
39 class SrsSharedPtrMessage; 39 class SrsSharedPtrMessage;
40 -  
41 -/**  
42 -* file stream to read/write file.  
43 -*/  
44 -class SrsFileStream  
45 -{  
46 -private:  
47 - std::string _file;  
48 - int fd;  
49 -public:  
50 - SrsFileStream();  
51 - virtual ~SrsFileStream();  
52 -public:  
53 - virtual int open(std::string file);  
54 - virtual int close();  
55 - virtual bool is_open();  
56 -public:  
57 - /**  
58 - * @param pnread, return the read size. NULL to ignore.  
59 - */  
60 - virtual int read(void* buf, size_t count, ssize_t* pnread);  
61 - /**  
62 - * @param pnwrite, return the write size. NULL to ignore.  
63 - */  
64 - virtual int write(void* buf, size_t count, ssize_t* pnwrite);  
65 - /**  
66 - * tell current offset of stream.  
67 - */  
68 - virtual int64_t tellg();  
69 -};  
70 -  
71 -/**  
72 -* encode data to flv file.  
73 -*/  
74 -class SrsFlvEncoder  
75 -{  
76 -private:  
77 - SrsFileStream* _fs;  
78 -private:  
79 - SrsStream* tag_stream;  
80 -public:  
81 - SrsFlvEncoder();  
82 - virtual ~SrsFlvEncoder();  
83 -public:  
84 - /**  
85 - * initialize the underlayer file stream,  
86 - * user can initialize multiple times to encode multiple flv files.  
87 - */  
88 - virtual int initialize(SrsFileStream* fs);  
89 -public:  
90 - /**  
91 - * write flv header.  
92 - * write following:  
93 - * 1. E.2 The FLV header  
94 - * 2. PreviousTagSize0 UI32 Always 0  
95 - * that is, 9+4=13bytes.  
96 - */  
97 - virtual int write_header();  
98 - /**  
99 - * write flv metadata.  
100 - * serialize from:  
101 - * AMF0 string: onMetaData,  
102 - * AMF0 object: the metadata object.  
103 - */  
104 - virtual int write_metadata(char* data, int size);  
105 - /**  
106 - * write audio/video packet.  
107 - */  
108 - virtual int write_audio(int64_t timestamp, char* data, int size);  
109 - virtual int write_video(int64_t timestamp, char* data, int size);  
110 -private:  
111 - virtual int write_tag(char* header, int header_size, char* tag, int tag_size);  
112 -}; 40 +class SrsFileStream;
  41 +class SrsFlvEncoder;
113 42
114 /** 43 /**
115 * a piece of flv segment. 44 * a piece of flv segment.
  1 +/*
  2 +The MIT License (MIT)
  3 +
  4 +Copyright (c) 2013-2014 winlin
  5 +
  6 +Permission is hereby granted, free of charge, to any person obtaining a copy of
  7 +this software and associated documentation files (the "Software"), to deal in
  8 +the Software without restriction, including without limitation the rights to
  9 +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
  10 +the Software, and to permit persons to whom the Software is furnished to do so,
  11 +subject to the following conditions:
  12 +
  13 +The above copyright notice and this permission notice shall be included in all
  14 +copies or substantial portions of the Software.
  15 +
  16 +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17 +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
  18 +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
  19 +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
  20 +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  21 +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  22 +*/
  23 +
  24 +#include <srs_app_flv.hpp>
  25 +
  26 +#include <fcntl.h>
  27 +#include <sstream>
  28 +using namespace std;
  29 +
  30 +#include <srs_app_config.hpp>
  31 +#include <srs_kernel_error.hpp>
  32 +#include <srs_protocol_rtmp.hpp>
  33 +#include <srs_protocol_rtmp_stack.hpp>
  34 +#include <srs_app_source.hpp>
  35 +#include <srs_core_autofree.hpp>
  36 +#include <srs_kernel_stream.hpp>
  37 +#include <srs_kernel_utility.hpp>
  38 +#include <srs_app_http_hooks.hpp>
  39 +#include <srs_app_codec.hpp>
  40 +
  41 +SrsFileStream::SrsFileStream()
  42 +{
  43 + fd = -1;
  44 +}
  45 +
  46 +SrsFileStream::~SrsFileStream()
  47 +{
  48 + close();
  49 +}
  50 +
  51 +int SrsFileStream::open(string file)
  52 +{
  53 + int ret = ERROR_SUCCESS;
  54 +
  55 + if (fd > 0) {
  56 + ret = ERROR_SYSTEM_FILE_ALREADY_OPENED;
  57 + srs_error("file %s already opened. ret=%d", _file.c_str(), ret);
  58 + return ret;
  59 + }
  60 +
  61 + int flags = O_CREAT|O_WRONLY|O_TRUNC;
  62 + mode_t mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH;
  63 +
  64 + if ((fd = ::open(file.c_str(), flags, mode)) < 0) {
  65 + ret = ERROR_SYSTEM_FILE_OPENE;
  66 + srs_error("open file %s failed. ret=%d", file.c_str(), ret);
  67 + return ret;
  68 + }
  69 +
  70 + _file = file;
  71 +
  72 + return ret;
  73 +}
  74 +
  75 +int SrsFileStream::close()
  76 +{
  77 + int ret = ERROR_SUCCESS;
  78 +
  79 + if (fd < 0) {
  80 + return ret;
  81 + }
  82 +
  83 + if (::close(fd) < 0) {
  84 + ret = ERROR_SYSTEM_FILE_CLOSE;
  85 + srs_error("close file %s failed. ret=%d", _file.c_str(), ret);
  86 + return ret;
  87 + }
  88 + fd = -1;
  89 +
  90 + return ret;
  91 +}
  92 +
  93 +bool SrsFileStream::is_open()
  94 +{
  95 + return fd > 0;
  96 +}
  97 +
  98 +int SrsFileStream::read(void* buf, size_t count, ssize_t* pnread)
  99 +{
  100 + int ret = ERROR_SUCCESS;
  101 +
  102 + ssize_t nread;
  103 + if ((nread = ::read(fd, buf, count)) < 0) {
  104 + ret = ERROR_SYSTEM_FILE_READ;
  105 + srs_error("read from file %s failed. ret=%d", _file.c_str(), ret);
  106 + return ret;
  107 + }
  108 +
  109 + if (nread == 0) {
  110 + ret = ERROR_SYSTEM_FILE_EOF;
  111 + return ret;
  112 + }
  113 +
  114 + if (pnread != NULL) {
  115 + *pnread = nread;
  116 + }
  117 +
  118 + return ret;
  119 +}
  120 +
  121 +int SrsFileStream::write(void* buf, size_t count, ssize_t* pnwrite)
  122 +{
  123 + int ret = ERROR_SUCCESS;
  124 +
  125 + ssize_t nwrite;
  126 + if ((nwrite = ::write(fd, buf, count)) < 0) {
  127 + ret = ERROR_SYSTEM_FILE_WRITE;
  128 + srs_error("write to file %s failed. ret=%d", _file.c_str(), ret);
  129 + return ret;
  130 + }
  131 +
  132 + if (pnwrite != NULL) {
  133 + *pnwrite = nwrite;
  134 + }
  135 +
  136 + return ret;
  137 +}
  138 +
  139 +int64_t SrsFileStream::tellg()
  140 +{
  141 + return (int64_t)::lseek(fd, 0, SEEK_CUR);
  142 +}
  143 +
  144 +SrsFlvEncoder::SrsFlvEncoder()
  145 +{
  146 + _fs = NULL;
  147 + tag_stream = new SrsStream();
  148 +}
  149 +
  150 +SrsFlvEncoder::~SrsFlvEncoder()
  151 +{
  152 + srs_freep(tag_stream);
  153 +}
  154 +
  155 +int SrsFlvEncoder::initialize(SrsFileStream* fs)
  156 +{
  157 + int ret = ERROR_SUCCESS;
  158 +
  159 + _fs = fs;
  160 +
  161 + return ret;
  162 +}
  163 +
  164 +int SrsFlvEncoder::write_header()
  165 +{
  166 + int ret = ERROR_SUCCESS;
  167 +
  168 + static char flv_header[] = {
  169 + 'F', 'L', 'V', // Signatures "FLV"
  170 + (char)0x01, // File version (for example, 0x01 for FLV version 1)
  171 + (char)0x00, // 4, audio; 1, video; 5 audio+video.
  172 + (char)0x00, (char)0x00, (char)0x00, (char)0x09, // DataOffset UI32 The length of this header in bytes
  173 + (char)0x00, (char)0x00, (char)0x00, (char)0x00// PreviousTagSize0 UI32 Always 0
  174 + };
  175 +
  176 + // flv specification should set the audio and video flag,
  177 + // actually in practise, application generally ignore this flag,
  178 + // so we generally set the audio/video to 0.
  179 +
  180 + // write data.
  181 + if ((ret = _fs->write(flv_header, sizeof(flv_header), NULL)) != ERROR_SUCCESS) {
  182 + srs_error("write flv header failed. ret=%d", ret);
  183 + return ret;
  184 + }
  185 +
  186 + return ret;
  187 +}
  188 +
  189 +int SrsFlvEncoder::write_metadata(char* data, int size)
  190 +{
  191 + int ret = ERROR_SUCCESS;
  192 +
  193 + static char tag_header[] = {
  194 + (char)18, // TagType UB [5], 18 = script data
  195 + (char)0x00, (char)0x00, (char)0x00, // DataSize UI24 Length of the message.
  196 + (char)0x00, (char)0x00, (char)0x00, // Timestamp UI24 Time in milliseconds at which the data in this tag applies.
  197 + (char)0x00, // TimestampExtended UI8
  198 + (char)0x00, (char)0x00, (char)0x00, // StreamID UI24 Always 0.
  199 + };
  200 +
  201 + // write data size.
  202 + if ((ret = tag_stream->initialize(tag_header + 1, 3)) != ERROR_SUCCESS) {
  203 + return ret;
  204 + }
  205 + tag_stream->write_3bytes(size);
  206 +
  207 + if ((ret = write_tag(tag_header, sizeof(tag_header), data, size)) != ERROR_SUCCESS) {
  208 + srs_error("write flv data tag failed. ret=%d", ret);
  209 + return ret;
  210 + }
  211 +
  212 + return ret;
  213 +}
  214 +
  215 +int SrsFlvEncoder::write_audio(int64_t timestamp, char* data, int size)
  216 +{
  217 + int ret = ERROR_SUCCESS;
  218 +
  219 + timestamp &= 0x7fffffff;
  220 +
  221 + static char tag_header[] = {
  222 + (char)8, // TagType UB [5], 8 = audio
  223 + (char)0x00, (char)0x00, (char)0x00, // DataSize UI24 Length of the message.
  224 + (char)0x00, (char)0x00, (char)0x00, // Timestamp UI24 Time in milliseconds at which the data in this tag applies.
  225 + (char)0x00, // TimestampExtended UI8
  226 + (char)0x00, (char)0x00, (char)0x00, // StreamID UI24 Always 0.
  227 + };
  228 +
  229 + // write data size.
  230 + if ((ret = tag_stream->initialize(tag_header + 1, 7)) != ERROR_SUCCESS) {
  231 + return ret;
  232 + }
  233 + tag_stream->write_3bytes(size);
  234 + tag_stream->write_3bytes(timestamp);
  235 + // default to little-endian
  236 + tag_stream->write_1bytes((timestamp >> 24) & 0xFF);
  237 +
  238 + if ((ret = write_tag(tag_header, sizeof(tag_header), data, size)) != ERROR_SUCCESS) {
  239 + srs_error("write flv audio tag failed. ret=%d", ret);
  240 + return ret;
  241 + }
  242 +
  243 + return ret;
  244 +}
  245 +
  246 +int SrsFlvEncoder::write_video(int64_t timestamp, char* data, int size)
  247 +{
  248 + int ret = ERROR_SUCCESS;
  249 +
  250 + timestamp &= 0x7fffffff;
  251 +
  252 + static char tag_header[] = {
  253 + (char)9, // TagType UB [5], 9 = video
  254 + (char)0x00, (char)0x00, (char)0x00, // DataSize UI24 Length of the message.
  255 + (char)0x00, (char)0x00, (char)0x00, // Timestamp UI24 Time in milliseconds at which the data in this tag applies.
  256 + (char)0x00, // TimestampExtended UI8
  257 + (char)0x00, (char)0x00, (char)0x00, // StreamID UI24 Always 0.
  258 + };
  259 +
  260 + // write data size.
  261 + if ((ret = tag_stream->initialize(tag_header + 1, 7)) != ERROR_SUCCESS) {
  262 + return ret;
  263 + }
  264 + tag_stream->write_3bytes(size);
  265 + tag_stream->write_3bytes(timestamp);
  266 + // default to little-endian
  267 + tag_stream->write_1bytes((timestamp >> 24) & 0xFF);
  268 +
  269 + if ((ret = write_tag(tag_header, sizeof(tag_header), data, size)) != ERROR_SUCCESS) {
  270 + srs_error("write flv video tag failed. ret=%d", ret);
  271 + return ret;
  272 + }
  273 +
  274 + return ret;
  275 +}
  276 +
  277 +int SrsFlvEncoder::write_tag(char* header, int header_size, char* tag, int tag_size)
  278 +{
  279 + int ret = ERROR_SUCCESS;
  280 +
  281 + // write tag header.
  282 + if ((ret = _fs->write(header, header_size, NULL)) != ERROR_SUCCESS) {
  283 + srs_error("write flv tag header failed. ret=%d", ret);
  284 + return ret;
  285 + }
  286 +
  287 + // write tag data.
  288 + if ((ret = _fs->write(tag, tag_size, NULL)) != ERROR_SUCCESS) {
  289 + srs_error("write flv tag failed. ret=%d", ret);
  290 + return ret;
  291 + }
  292 +
  293 + // PreviousTagSizeN UI32 Size of last tag, including its header, in bytes.
  294 + static char pre_size[4];
  295 + if ((ret = tag_stream->initialize(pre_size, 4)) != ERROR_SUCCESS) {
  296 + return ret;
  297 + }
  298 + tag_stream->write_4bytes(tag_size + header_size);
  299 + if ((ret = _fs->write(pre_size, sizeof(pre_size), NULL)) != ERROR_SUCCESS) {
  300 + srs_error("write flv previous tag size failed. ret=%d", ret);
  301 + return ret;
  302 + }
  303 +
  304 + return ret;
  305 +}
  306 +
  1 +/*
  2 +The MIT License (MIT)
  3 +
  4 +Copyright (c) 2013-2014 winlin
  5 +
  6 +Permission is hereby granted, free of charge, to any person obtaining a copy of
  7 +this software and associated documentation files (the "Software"), to deal in
  8 +the Software without restriction, including without limitation the rights to
  9 +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
  10 +the Software, and to permit persons to whom the Software is furnished to do so,
  11 +subject to the following conditions:
  12 +
  13 +The above copyright notice and this permission notice shall be included in all
  14 +copies or substantial portions of the Software.
  15 +
  16 +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17 +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
  18 +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
  19 +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
  20 +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  21 +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  22 +*/
  23 +
  24 +#ifndef SRS_APP_FLV_HPP
  25 +#define SRS_APP_FLV_HPP
  26 +
  27 +/*
  28 +#include <srs_app_flv.hpp>
  29 +*/
  30 +#include <srs_core.hpp>
  31 +
  32 +class SrsStream;
  33 +
  34 +/**
  35 +* file stream to read/write file.
  36 +*/
  37 +class SrsFileStream
  38 +{
  39 +private:
  40 + std::string _file;
  41 + int fd;
  42 +public:
  43 + SrsFileStream();
  44 + virtual ~SrsFileStream();
  45 +public:
  46 + virtual int open(std::string file);
  47 + virtual int close();
  48 + virtual bool is_open();
  49 +public:
  50 + /**
  51 + * @param pnread, return the read size. NULL to ignore.
  52 + */
  53 + virtual int read(void* buf, size_t count, ssize_t* pnread);
  54 + /**
  55 + * @param pnwrite, return the write size. NULL to ignore.
  56 + */
  57 + virtual int write(void* buf, size_t count, ssize_t* pnwrite);
  58 + /**
  59 + * tell current offset of stream.
  60 + */
  61 + virtual int64_t tellg();
  62 +};
  63 +
  64 +/**
  65 +* encode data to flv file.
  66 +*/
  67 +class SrsFlvEncoder
  68 +{
  69 +private:
  70 + SrsFileStream* _fs;
  71 +private:
  72 + SrsStream* tag_stream;
  73 +public:
  74 + SrsFlvEncoder();
  75 + virtual ~SrsFlvEncoder();
  76 +public:
  77 + /**
  78 + * initialize the underlayer file stream,
  79 + * user can initialize multiple times to encode multiple flv files.
  80 + */
  81 + virtual int initialize(SrsFileStream* fs);
  82 +public:
  83 + /**
  84 + * write flv header.
  85 + * write following:
  86 + * 1. E.2 The FLV header
  87 + * 2. PreviousTagSize0 UI32 Always 0
  88 + * that is, 9+4=13bytes.
  89 + */
  90 + virtual int write_header();
  91 + /**
  92 + * write flv metadata.
  93 + * serialize from:
  94 + * AMF0 string: onMetaData,
  95 + * AMF0 object: the metadata object.
  96 + */
  97 + virtual int write_metadata(char* data, int size);
  98 + /**
  99 + * write audio/video packet.
  100 + */
  101 + virtual int write_audio(int64_t timestamp, char* data, int size);
  102 + virtual int write_video(int64_t timestamp, char* data, int size);
  103 +private:
  104 + virtual int write_tag(char* header, int header_size, char* tag, int tag_size);
  105 +};
  106 +
  107 +#endif
@@ -176,7 +176,9 @@ void* SrsThread::thread_fun(void* arg) @@ -176,7 +176,9 @@ void* SrsThread::thread_fun(void* arg)
176 176
177 obj->thread_cycle(); 177 obj->thread_cycle();
178 178
179 - st_thread_exit(NULL); 179 + // never use the following exit function,
  180 + // it will cause the SRS memory leak.
  181 + //st_thread_exit(NULL);
180 182
181 return NULL; 183 return NULL;
182 } 184 }
@@ -31,7 +31,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -31,7 +31,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 // current release version 31 // current release version
32 #define VERSION_MAJOR "0" 32 #define VERSION_MAJOR "0"
33 #define VERSION_MINOR "9" 33 #define VERSION_MINOR "9"
34 -#define VERSION_REVISION "111" 34 +#define VERSION_REVISION "112"
35 #define RTMP_SIG_SRS_VERSION VERSION_MAJOR"."VERSION_MINOR"."VERSION_REVISION 35 #define RTMP_SIG_SRS_VERSION VERSION_MAJOR"."VERSION_MINOR"."VERSION_REVISION
36 // server info. 36 // server info.
37 #define RTMP_SIG_SRS_KEY "SRS" 37 #define RTMP_SIG_SRS_KEY "SRS"
@@ -57,6 +57,8 @@ file @@ -57,6 +57,8 @@ file
57 ..\app\srs_app_encoder.cpp, 57 ..\app\srs_app_encoder.cpp,
58 ..\app\srs_app_ffmpeg.hpp, 58 ..\app\srs_app_ffmpeg.hpp,
59 ..\app\srs_app_ffmpeg.cpp, 59 ..\app\srs_app_ffmpeg.cpp,
  60 + ..\app\srs_app_flv.hpp,
  61 + ..\app\srs_app_flv.cpp,
60 ..\app\srs_app_forward.hpp, 62 ..\app\srs_app_forward.hpp,
61 ..\app\srs_app_forward.cpp, 63 ..\app\srs_app_forward.cpp,
62 ..\app\srs_app_heartbeat.hpp, 64 ..\app\srs_app_heartbeat.hpp,