for #250, support h264 video for push mpegts over udp. 2.0.110
正在显示
15 个修改的文件
包含
929 行增加
和
257 行删除
@@ -375,7 +375,8 @@ MODULE_ID="RTMP" | @@ -375,7 +375,8 @@ MODULE_ID="RTMP" | ||
375 | MODULE_DEPENDS=("CORE" "KERNEL") | 375 | MODULE_DEPENDS=("CORE" "KERNEL") |
376 | ModuleLibIncs=(${SRS_OBJS_DIR} ${LibSSLRoot}) | 376 | ModuleLibIncs=(${SRS_OBJS_DIR} ${LibSSLRoot}) |
377 | MODULE_FILES=("srs_rtmp_amf0" "srs_rtmp_io" "srs_rtmp_stack" "srs_rtmp_sdk" | 377 | MODULE_FILES=("srs_rtmp_amf0" "srs_rtmp_io" "srs_rtmp_stack" "srs_rtmp_sdk" |
378 | - "srs_rtmp_handshake" "srs_rtmp_utility" "srs_rtmp_msg_array" "srs_rtmp_buffer") | 378 | + "srs_rtmp_handshake" "srs_rtmp_utility" "srs_rtmp_msg_array" "srs_rtmp_buffer" |
379 | + "srs_raw_avc") | ||
379 | RTMP_INCS="src/protocol"; MODULE_DIR=${RTMP_INCS} . auto/modules.sh | 380 | RTMP_INCS="src/protocol"; MODULE_DIR=${RTMP_INCS} . auto/modules.sh |
380 | RTMP_OBJS="${MODULE_OBJS[@]}" | 381 | RTMP_OBJS="${MODULE_OBJS[@]}" |
381 | # | 382 | # |
@@ -45,6 +45,8 @@ file | @@ -45,6 +45,8 @@ file | ||
45 | ../../src/kernel/srs_kernel_utility.hpp, | 45 | ../../src/kernel/srs_kernel_utility.hpp, |
46 | ../../src/kernel/srs_kernel_utility.cpp, | 46 | ../../src/kernel/srs_kernel_utility.cpp, |
47 | protocol readonly separator, | 47 | protocol readonly separator, |
48 | + ../../src/protocol/srs_raw_avc.hpp, | ||
49 | + ../../src/protocol/srs_raw_avc.cpp, | ||
48 | ../../src/protocol/srs_rtmp_amf0.hpp, | 50 | ../../src/protocol/srs_rtmp_amf0.hpp, |
49 | ../../src/protocol/srs_rtmp_amf0.cpp, | 51 | ../../src/protocol/srs_rtmp_amf0.cpp, |
50 | ../../src/protocol/srs_rtmp_buffer.hpp, | 52 | ../../src/protocol/srs_rtmp_buffer.hpp, |
@@ -116,6 +116,7 @@ | @@ -116,6 +116,7 @@ | ||
116 | <ClInclude Include="..\..\src\libs\srs_librtmp.hpp" /> | 116 | <ClInclude Include="..\..\src\libs\srs_librtmp.hpp" /> |
117 | <ClInclude Include="..\..\src\libs\srs_lib_bandwidth.hpp" /> | 117 | <ClInclude Include="..\..\src\libs\srs_lib_bandwidth.hpp" /> |
118 | <ClInclude Include="..\..\src\libs\srs_lib_simple_socket.hpp" /> | 118 | <ClInclude Include="..\..\src\libs\srs_lib_simple_socket.hpp" /> |
119 | + <ClInclude Include="..\..\src\protocol\srs_raw_avc.hpp" /> | ||
119 | <ClInclude Include="..\..\src\protocol\srs_rtmp_amf0.hpp" /> | 120 | <ClInclude Include="..\..\src\protocol\srs_rtmp_amf0.hpp" /> |
120 | <ClInclude Include="..\..\src\protocol\srs_rtmp_buffer.hpp" /> | 121 | <ClInclude Include="..\..\src\protocol\srs_rtmp_buffer.hpp" /> |
121 | <ClInclude Include="..\..\src\protocol\srs_rtmp_handshake.hpp" /> | 122 | <ClInclude Include="..\..\src\protocol\srs_rtmp_handshake.hpp" /> |
@@ -193,6 +194,7 @@ | @@ -193,6 +194,7 @@ | ||
193 | <ClCompile Include="..\..\src\libs\srs_lib_bandwidth.cpp" /> | 194 | <ClCompile Include="..\..\src\libs\srs_lib_bandwidth.cpp" /> |
194 | <ClCompile Include="..\..\src\libs\srs_lib_simple_socket.cpp" /> | 195 | <ClCompile Include="..\..\src\libs\srs_lib_simple_socket.cpp" /> |
195 | <ClCompile Include="..\..\src\main\srs_main_server.cpp" /> | 196 | <ClCompile Include="..\..\src\main\srs_main_server.cpp" /> |
197 | + <ClCompile Include="..\..\src\protocol\srs_raw_avc.cpp" /> | ||
196 | <ClCompile Include="..\..\src\protocol\srs_rtmp_amf0.cpp" /> | 198 | <ClCompile Include="..\..\src\protocol\srs_rtmp_amf0.cpp" /> |
197 | <ClCompile Include="..\..\src\protocol\srs_rtmp_buffer.cpp" /> | 199 | <ClCompile Include="..\..\src\protocol\srs_rtmp_buffer.cpp" /> |
198 | <ClCompile Include="..\..\src\protocol\srs_rtmp_handshake.cpp" /> | 200 | <ClCompile Include="..\..\src\protocol\srs_rtmp_handshake.cpp" /> |
@@ -226,6 +226,9 @@ | @@ -226,6 +226,9 @@ | ||
226 | <ClCompile Include="..\..\src\app\srs_app_mpegts_udp.cpp"> | 226 | <ClCompile Include="..\..\src\app\srs_app_mpegts_udp.cpp"> |
227 | <Filter>srs</Filter> | 227 | <Filter>srs</Filter> |
228 | </ClCompile> | 228 | </ClCompile> |
229 | + <ClCompile Include="..\..\src\protocol\srs_raw_avc.cpp"> | ||
230 | + <Filter>srs</Filter> | ||
231 | + </ClCompile> | ||
229 | </ItemGroup> | 232 | </ItemGroup> |
230 | <ItemGroup> | 233 | <ItemGroup> |
231 | <ClInclude Include="..\..\src\app\srs_app_bandwidth.hpp"> | 234 | <ClInclude Include="..\..\src\app\srs_app_bandwidth.hpp"> |
@@ -414,6 +417,9 @@ | @@ -414,6 +417,9 @@ | ||
414 | <ClInclude Include="..\..\src\app\srs_app_mpegts_udp.hpp"> | 417 | <ClInclude Include="..\..\src\app\srs_app_mpegts_udp.hpp"> |
415 | <Filter>srs</Filter> | 418 | <Filter>srs</Filter> |
416 | </ClInclude> | 419 | </ClInclude> |
420 | + <ClInclude Include="..\..\src\protocol\srs_raw_avc.hpp"> | ||
421 | + <Filter>srs</Filter> | ||
422 | + </ClInclude> | ||
417 | </ItemGroup> | 423 | </ItemGroup> |
418 | <ItemGroup> | 424 | <ItemGroup> |
419 | <Filter Include="research"> | 425 | <Filter Include="research"> |
@@ -447,7 +447,7 @@ int SrsEdgeForwarder::start() | @@ -447,7 +447,7 @@ int SrsEdgeForwarder::start() | ||
447 | } | 447 | } |
448 | 448 | ||
449 | if ((ret = client->publish(req->stream, stream_id)) != ERROR_SUCCESS) { | 449 | if ((ret = client->publish(req->stream, stream_id)) != ERROR_SUCCESS) { |
450 | - srs_error("connect with server failed, stream=%s, stream_id=%d. ret=%d", | 450 | + srs_error("publish failed, stream=%s, stream_id=%d. ret=%d", |
451 | req->stream.c_str(), stream_id, ret); | 451 | req->stream.c_str(), stream_id, ret); |
452 | return ret; | 452 | return ret; |
453 | } | 453 | } |
@@ -23,6 +23,9 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | @@ -23,6 +23,9 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
23 | 23 | ||
24 | #include <srs_app_mpegts_udp.hpp> | 24 | #include <srs_app_mpegts_udp.hpp> |
25 | 25 | ||
26 | +#ifdef SRS_AUTO_STREAM_CASTER | ||
27 | + | ||
28 | +#include <stdlib.h> | ||
26 | #include <sys/socket.h> | 29 | #include <sys/socket.h> |
27 | #include <netinet/in.h> | 30 | #include <netinet/in.h> |
28 | #include <arpa/inet.h> | 31 | #include <arpa/inet.h> |
@@ -39,8 +42,12 @@ using namespace std; | @@ -39,8 +42,12 @@ using namespace std; | ||
39 | #include <srs_kernel_file.hpp> | 42 | #include <srs_kernel_file.hpp> |
40 | #include <srs_core_autofree.hpp> | 43 | #include <srs_core_autofree.hpp> |
41 | #include <srs_kernel_utility.hpp> | 44 | #include <srs_kernel_utility.hpp> |
42 | - | ||
43 | -#ifdef SRS_AUTO_STREAM_CASTER | 45 | +#include <srs_rtmp_sdk.hpp> |
46 | +#include <srs_app_st_socket.hpp> | ||
47 | +#include <srs_rtmp_utility.hpp> | ||
48 | +#include <srs_app_utility.hpp> | ||
49 | +#include <srs_rtmp_amf0.hpp> | ||
50 | +#include <srs_raw_avc.hpp> | ||
44 | 51 | ||
45 | ISrsUdpHandler::ISrsUdpHandler() | 52 | ISrsUdpHandler::ISrsUdpHandler() |
46 | { | 53 | { |
@@ -56,13 +63,25 @@ SrsMpegtsOverUdp::SrsMpegtsOverUdp(SrsConfDirective* c) | @@ -56,13 +63,25 @@ SrsMpegtsOverUdp::SrsMpegtsOverUdp(SrsConfDirective* c) | ||
56 | context = new SrsTsContext(); | 63 | context = new SrsTsContext(); |
57 | buffer = new SrsSimpleBuffer(); | 64 | buffer = new SrsSimpleBuffer(); |
58 | output = _srs_config->get_stream_caster_output(c); | 65 | output = _srs_config->get_stream_caster_output(c); |
66 | + req = NULL; | ||
67 | + io = NULL; | ||
68 | + client = NULL; | ||
69 | + stfd = NULL; | ||
70 | + stream_id = 0; | ||
71 | + avc = new SrsRawH264Stream(); | ||
72 | + h264_sps_changed = false; | ||
73 | + h264_pps_changed = false; | ||
74 | + h264_sps_pps_sent = false; | ||
59 | } | 75 | } |
60 | 76 | ||
61 | SrsMpegtsOverUdp::~SrsMpegtsOverUdp() | 77 | SrsMpegtsOverUdp::~SrsMpegtsOverUdp() |
62 | { | 78 | { |
79 | + close(); | ||
80 | + | ||
63 | srs_freep(buffer); | 81 | srs_freep(buffer); |
64 | srs_freep(stream); | 82 | srs_freep(stream); |
65 | srs_freep(context); | 83 | srs_freep(context); |
84 | + srs_freep(avc); | ||
66 | } | 85 | } |
67 | 86 | ||
68 | int SrsMpegtsOverUdp::on_udp_packet(sockaddr_in* from, char* buf, int nb_buf) | 87 | int SrsMpegtsOverUdp::on_udp_packet(sockaddr_in* from, char* buf, int nb_buf) |
@@ -207,8 +226,311 @@ int SrsMpegtsOverUdp::on_ts_message(SrsTsMessage* msg) | @@ -207,8 +226,311 @@ int SrsMpegtsOverUdp::on_ts_message(SrsTsMessage* msg) | ||
207 | return ret; | 226 | return ret; |
208 | } | 227 | } |
209 | 228 | ||
229 | + // check supported codec | ||
230 | + if (msg->channel->stream != SrsTsStreamVideoH264 && msg->channel->stream != SrsTsStreamAudioAAC) { | ||
231 | + ret = ERROR_STREAM_CASTER_TS_CODEC; | ||
232 | + srs_error("mpegts: unsupported stream codec=%d. ret=%d", msg->channel->stream, ret); | ||
233 | + return ret; | ||
234 | + } | ||
235 | + | ||
236 | + // parse the stream. | ||
237 | + SrsStream avs; | ||
238 | + if ((ret = avs.initialize(msg->payload->bytes(), msg->payload->length())) != ERROR_SUCCESS) { | ||
239 | + srs_error("mpegts: initialize av stream failed. ret=%d", ret); | ||
240 | + return ret; | ||
241 | + } | ||
242 | + | ||
243 | + // publish audio or video. | ||
244 | + if (msg->channel->stream == SrsTsStreamVideoH264) { | ||
245 | + return on_ts_video(msg, &avs); | ||
246 | + } | ||
247 | + | ||
210 | // TODO: FIXME: implements it. | 248 | // TODO: FIXME: implements it. |
211 | return ret; | 249 | return ret; |
212 | } | 250 | } |
213 | 251 | ||
252 | +int SrsMpegtsOverUdp::on_ts_video(SrsTsMessage* msg, SrsStream* avs) | ||
253 | +{ | ||
254 | + int ret = ERROR_SUCCESS; | ||
255 | + | ||
256 | + // ensure rtmp connected. | ||
257 | + if ((ret = connect()) != ERROR_SUCCESS) { | ||
258 | + return ret; | ||
259 | + } | ||
260 | + | ||
261 | + // ts tbn to flv tbn. | ||
262 | + u_int32_t dts = msg->dts / 90; | ||
263 | + u_int32_t pts = msg->dts / 90; | ||
264 | + | ||
265 | + // send each frame. | ||
266 | + while (!avs->empty()) { | ||
267 | + char* frame = NULL; | ||
268 | + int frame_size = 0; | ||
269 | + if ((ret = avc->annexb_demux(avs, &frame, &frame_size)) != ERROR_SUCCESS) { | ||
270 | + return ret; | ||
271 | + } | ||
272 | + | ||
273 | + // ignore invalid frame, | ||
274 | + // * atleast 1bytes for SPS to decode the type | ||
275 | + // * ignore the auth bytes '09f0' | ||
276 | + if (frame_size <= 2) { | ||
277 | + continue; | ||
278 | + } | ||
279 | + | ||
280 | + // it may be return error, but we must process all packets. | ||
281 | + if ((ret = write_h264_raw_frame(frame, frame_size, dts, pts)) != ERROR_SUCCESS) { | ||
282 | + if (ret = ERROR_H264_DROP_BEFORE_SPS_PPS) { | ||
283 | + continue; | ||
284 | + } | ||
285 | + return ret; | ||
286 | + } | ||
287 | + } | ||
288 | + | ||
289 | + return ret; | ||
290 | +} | ||
291 | + | ||
292 | +int SrsMpegtsOverUdp::write_h264_raw_frame(char* frame, int frame_size, u_int32_t dts, u_int32_t pts) | ||
293 | +{ | ||
294 | + int ret = ERROR_SUCCESS; | ||
295 | + | ||
296 | + // for sps | ||
297 | + if (avc->is_sps(frame, frame_size)) { | ||
298 | + std::string sps; | ||
299 | + if ((ret = avc->sps_demux(frame, frame_size, sps)) != ERROR_SUCCESS) { | ||
300 | + return ret; | ||
301 | + } | ||
302 | + | ||
303 | + if (h264_sps == sps) { | ||
304 | + return ret; | ||
305 | + } | ||
306 | + h264_sps_changed = true; | ||
307 | + h264_sps = sps; | ||
308 | + | ||
309 | + return write_h264_sps_pps(dts, pts); | ||
310 | + } | ||
311 | + | ||
312 | + // for pps | ||
313 | + if (avc->is_pps(frame, frame_size)) { | ||
314 | + std::string pps; | ||
315 | + if ((ret = avc->pps_demux(frame, frame_size, pps)) != ERROR_SUCCESS) { | ||
316 | + return ret; | ||
317 | + } | ||
318 | + | ||
319 | + if (h264_pps == pps) { | ||
320 | + return ret; | ||
321 | + } | ||
322 | + h264_pps_changed = true; | ||
323 | + h264_pps = pps; | ||
324 | + | ||
325 | + return write_h264_sps_pps(dts, pts); | ||
326 | + } | ||
327 | + | ||
328 | + // ibp frame. | ||
329 | + return write_h264_ipb_frame(frame, frame_size, dts, pts); | ||
330 | +} | ||
331 | + | ||
332 | +int SrsMpegtsOverUdp::write_h264_sps_pps(u_int32_t dts, u_int32_t pts) | ||
333 | +{ | ||
334 | + int ret = ERROR_SUCCESS; | ||
335 | + | ||
336 | + // only send when both sps and pps changed. | ||
337 | + if (!h264_sps_changed || !h264_pps_changed) { | ||
338 | + return ret; | ||
339 | + } | ||
340 | + | ||
341 | + // h264 raw to h264 packet. | ||
342 | + std::string sh; | ||
343 | + if ((ret = avc->mux_sequence_header(h264_sps, h264_pps, dts, pts, sh)) != ERROR_SUCCESS) { | ||
344 | + return ret; | ||
345 | + } | ||
346 | + | ||
347 | + // h264 packet to flv packet. | ||
348 | + int8_t frame_type = SrsCodecVideoAVCFrameKeyFrame; | ||
349 | + int8_t avc_packet_type = SrsCodecVideoAVCTypeSequenceHeader; | ||
350 | + char* flv = NULL; | ||
351 | + int nb_flv = 0; | ||
352 | + if ((ret = avc->mux_avc2flv(sh, frame_type, avc_packet_type, dts, pts, &flv, &nb_flv)) != ERROR_SUCCESS) { | ||
353 | + return ret; | ||
354 | + } | ||
355 | + | ||
356 | + // reset sps and pps. | ||
357 | + h264_sps_changed = false; | ||
358 | + h264_pps_changed = false; | ||
359 | + h264_sps_pps_sent = true; | ||
360 | + | ||
361 | + // the timestamp in rtmp message header is dts. | ||
362 | + u_int32_t timestamp = dts; | ||
363 | + return rtmp_write_packet(SrsCodecFlvTagVideo, timestamp, flv, nb_flv); | ||
364 | +} | ||
365 | + | ||
366 | +int SrsMpegtsOverUdp::write_h264_ipb_frame(char* frame, int frame_size, u_int32_t dts, u_int32_t pts) | ||
367 | +{ | ||
368 | + int ret = ERROR_SUCCESS; | ||
369 | + | ||
370 | + // when sps or pps not sent, ignore the packet. | ||
371 | + // @see https://github.com/winlinvip/simple-rtmp-server/issues/203 | ||
372 | + if (!h264_sps_pps_sent) { | ||
373 | + return ERROR_H264_DROP_BEFORE_SPS_PPS; | ||
374 | + } | ||
375 | + | ||
376 | + std::string ibp; | ||
377 | + int8_t frame_type; | ||
378 | + if ((ret = avc->mux_ipb_frame(frame, frame_size, dts, pts, ibp, frame_type)) != ERROR_SUCCESS) { | ||
379 | + return ret; | ||
380 | + } | ||
381 | + | ||
382 | + int8_t avc_packet_type = SrsCodecVideoAVCTypeNALU; | ||
383 | + char* flv = NULL; | ||
384 | + int nb_flv = 0; | ||
385 | + if ((ret = avc->mux_avc2flv(ibp, frame_type, avc_packet_type, dts, pts, &flv, &nb_flv)) != ERROR_SUCCESS) { | ||
386 | + return ret; | ||
387 | + } | ||
388 | + | ||
389 | + // the timestamp in rtmp message header is dts. | ||
390 | + u_int32_t timestamp = dts; | ||
391 | + return rtmp_write_packet(SrsCodecFlvTagVideo, timestamp, flv, nb_flv); | ||
392 | +} | ||
393 | + | ||
394 | +int SrsMpegtsOverUdp::rtmp_write_packet(char type, u_int32_t timestamp, char* data, int size) | ||
395 | +{ | ||
396 | + int ret = ERROR_SUCCESS; | ||
397 | + | ||
398 | + SrsSharedPtrMessage* msg = NULL; | ||
399 | + | ||
400 | + if ((ret = srs_rtmp_create_msg(type, timestamp, data, size, stream_id, &msg)) != ERROR_SUCCESS) { | ||
401 | + return ret; | ||
402 | + } | ||
403 | + | ||
404 | + srs_assert(msg); | ||
405 | + | ||
406 | + // send out encoded msg. | ||
407 | + if ((ret = client->send_and_free_message(msg, stream_id)) != ERROR_SUCCESS) { | ||
408 | + return ret; | ||
409 | + } | ||
410 | + | ||
411 | + return ret; | ||
412 | +} | ||
413 | + | ||
414 | +int SrsMpegtsOverUdp::connect() | ||
415 | +{ | ||
416 | + int ret = ERROR_SUCCESS; | ||
417 | + | ||
418 | + // when ok, ignore. | ||
419 | + if (io || client) { | ||
420 | + return ret; | ||
421 | + } | ||
422 | + | ||
423 | + // parse uri | ||
424 | + if (!req) { | ||
425 | + req = new SrsRequest(); | ||
426 | + | ||
427 | + size_t pos = string::npos; | ||
428 | + string uri = req->tcUrl = output; | ||
429 | + | ||
430 | + // tcUrl, stream | ||
431 | + if ((pos = uri.rfind("/")) != string::npos) { | ||
432 | + req->stream = uri.substr(pos + 1); | ||
433 | + req->tcUrl = uri = uri.substr(0, pos); | ||
434 | + } | ||
435 | + | ||
436 | + srs_discovery_tc_url(req->tcUrl, | ||
437 | + req->schema, req->host, req->vhost, req->app, req->port, | ||
438 | + req->param); | ||
439 | + } | ||
440 | + | ||
441 | + // connect host. | ||
442 | + if ((ret = srs_socket_connect(req->host, ::atoi(req->port.c_str()), ST_UTIME_NO_TIMEOUT, &stfd)) != ERROR_SUCCESS) { | ||
443 | + srs_error("mpegts: connect server %s:%s failed. ret=%d", req->host.c_str(), req->port.c_str(), ret); | ||
444 | + return ret; | ||
445 | + } | ||
446 | + io = new SrsStSocket(stfd); | ||
447 | + client = new SrsRtmpClient(io); | ||
448 | + | ||
449 | + client->set_recv_timeout(SRS_CONSTS_RTMP_RECV_TIMEOUT_US); | ||
450 | + client->set_send_timeout(SRS_CONSTS_RTMP_SEND_TIMEOUT_US); | ||
451 | + | ||
452 | + // connect to vhost/app | ||
453 | + if ((ret = client->handshake()) != ERROR_SUCCESS) { | ||
454 | + srs_error("mpegts: handshake with server failed. ret=%d", ret); | ||
455 | + return ret; | ||
456 | + } | ||
457 | + if ((ret = connect_app(req->host, req->port)) != ERROR_SUCCESS) { | ||
458 | + srs_error("mpegts: connect with server failed. ret=%d", ret); | ||
459 | + return ret; | ||
460 | + } | ||
461 | + if ((ret = client->create_stream(stream_id)) != ERROR_SUCCESS) { | ||
462 | + srs_error("mpegts: connect with server failed, stream_id=%d. ret=%d", stream_id, ret); | ||
463 | + return ret; | ||
464 | + } | ||
465 | + | ||
466 | + // publish. | ||
467 | + if ((ret = client->publish(req->stream, stream_id)) != ERROR_SUCCESS) { | ||
468 | + srs_error("mpegts: publish failed, stream=%s, stream_id=%d. ret=%d", | ||
469 | + req->stream.c_str(), stream_id, ret); | ||
470 | + return ret; | ||
471 | + } | ||
472 | + | ||
473 | + | ||
474 | + return ret; | ||
475 | +} | ||
476 | + | ||
477 | +// TODO: FIXME: refine the connect_app. | ||
478 | +int SrsMpegtsOverUdp::connect_app(string ep_server, string ep_port) | ||
479 | +{ | ||
480 | + int ret = ERROR_SUCCESS; | ||
481 | + | ||
482 | + // args of request takes the srs info. | ||
483 | + if (req->args == NULL) { | ||
484 | + req->args = SrsAmf0Any::object(); | ||
485 | + } | ||
486 | + | ||
487 | + // notify server the edge identity, | ||
488 | + // @see https://github.com/winlinvip/simple-rtmp-server/issues/147 | ||
489 | + SrsAmf0Object* data = req->args; | ||
490 | + data->set("srs_sig", SrsAmf0Any::str(RTMP_SIG_SRS_KEY)); | ||
491 | + data->set("srs_server", SrsAmf0Any::str(RTMP_SIG_SRS_KEY" "RTMP_SIG_SRS_VERSION" ("RTMP_SIG_SRS_URL_SHORT")")); | ||
492 | + data->set("srs_license", SrsAmf0Any::str(RTMP_SIG_SRS_LICENSE)); | ||
493 | + data->set("srs_role", SrsAmf0Any::str(RTMP_SIG_SRS_ROLE)); | ||
494 | + data->set("srs_url", SrsAmf0Any::str(RTMP_SIG_SRS_URL)); | ||
495 | + data->set("srs_version", SrsAmf0Any::str(RTMP_SIG_SRS_VERSION)); | ||
496 | + data->set("srs_site", SrsAmf0Any::str(RTMP_SIG_SRS_WEB)); | ||
497 | + data->set("srs_email", SrsAmf0Any::str(RTMP_SIG_SRS_EMAIL)); | ||
498 | + data->set("srs_copyright", SrsAmf0Any::str(RTMP_SIG_SRS_COPYRIGHT)); | ||
499 | + data->set("srs_primary", SrsAmf0Any::str(RTMP_SIG_SRS_PRIMARY)); | ||
500 | + data->set("srs_authors", SrsAmf0Any::str(RTMP_SIG_SRS_AUTHROS)); | ||
501 | + // for edge to directly get the id of client. | ||
502 | + data->set("srs_pid", SrsAmf0Any::number(getpid())); | ||
503 | + data->set("srs_id", SrsAmf0Any::number(_srs_context->get_id())); | ||
504 | + | ||
505 | + // local ip of edge | ||
506 | + std::vector<std::string> ips = srs_get_local_ipv4_ips(); | ||
507 | + assert(_srs_config->get_stats_network() < (int)ips.size()); | ||
508 | + std::string local_ip = ips[_srs_config->get_stats_network()]; | ||
509 | + data->set("srs_server_ip", SrsAmf0Any::str(local_ip.c_str())); | ||
510 | + | ||
511 | + // generate the tcUrl | ||
512 | + std::string param = ""; | ||
513 | + std::string tc_url = srs_generate_tc_url(ep_server, req->vhost, req->app, ep_port, param); | ||
514 | + | ||
515 | + // upnode server identity will show in the connect_app of client. | ||
516 | + // @see https://github.com/winlinvip/simple-rtmp-server/issues/160 | ||
517 | + // the debug_srs_upnode is config in vhost and default to true. | ||
518 | + bool debug_srs_upnode = _srs_config->get_debug_srs_upnode(req->vhost); | ||
519 | + if ((ret = client->connect_app(req->app, tc_url, req, debug_srs_upnode)) != ERROR_SUCCESS) { | ||
520 | + srs_error("mpegts: connect with server failed, tcUrl=%s, dsu=%d. ret=%d", | ||
521 | + tc_url.c_str(), debug_srs_upnode, ret); | ||
522 | + return ret; | ||
523 | + } | ||
524 | + | ||
525 | + return ret; | ||
526 | +} | ||
527 | + | ||
528 | +void SrsMpegtsOverUdp::close() | ||
529 | +{ | ||
530 | + srs_freep(client); | ||
531 | + srs_freep(io); | ||
532 | + srs_freep(req); | ||
533 | + srs_close_stfd(stfd); | ||
534 | +} | ||
535 | + | ||
214 | #endif | 536 | #endif |
@@ -30,6 +30,8 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | @@ -30,6 +30,8 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
30 | 30 | ||
31 | #include <srs_core.hpp> | 31 | #include <srs_core.hpp> |
32 | 32 | ||
33 | +#ifdef SRS_AUTO_STREAM_CASTER | ||
34 | + | ||
33 | class sockaddr_in; | 35 | class sockaddr_in; |
34 | #include <string> | 36 | #include <string> |
35 | 37 | ||
@@ -37,9 +39,12 @@ class SrsStream; | @@ -37,9 +39,12 @@ class SrsStream; | ||
37 | class SrsTsContext; | 39 | class SrsTsContext; |
38 | class SrsConfDirective; | 40 | class SrsConfDirective; |
39 | class SrsSimpleBuffer; | 41 | class SrsSimpleBuffer; |
42 | +class SrsRtmpClient; | ||
43 | +class SrsStSocket; | ||
44 | +class SrsRequest; | ||
45 | +class SrsRawH264Stream; | ||
40 | 46 | ||
41 | -#ifdef SRS_AUTO_STREAM_CASTER | ||
42 | - | 47 | +#include <srs_app_st.hpp> |
43 | #include <srs_kernel_ts.hpp> | 48 | #include <srs_kernel_ts.hpp> |
44 | 49 | ||
45 | /** | 50 | /** |
@@ -74,6 +79,19 @@ private: | @@ -74,6 +79,19 @@ private: | ||
74 | SrsTsContext* context; | 79 | SrsTsContext* context; |
75 | SrsSimpleBuffer* buffer; | 80 | SrsSimpleBuffer* buffer; |
76 | std::string output; | 81 | std::string output; |
82 | +private: | ||
83 | + SrsRequest* req; | ||
84 | + st_netfd_t stfd; | ||
85 | + SrsStSocket* io; | ||
86 | + SrsRtmpClient* client; | ||
87 | + int stream_id; | ||
88 | +private: | ||
89 | + SrsRawH264Stream* avc; | ||
90 | + std::string h264_sps; | ||
91 | + bool h264_sps_changed; | ||
92 | + std::string h264_pps; | ||
93 | + bool h264_pps_changed; | ||
94 | + bool h264_sps_pps_sent; | ||
77 | public: | 95 | public: |
78 | SrsMpegtsOverUdp(SrsConfDirective* c); | 96 | SrsMpegtsOverUdp(SrsConfDirective* c); |
79 | virtual ~SrsMpegtsOverUdp(); | 97 | virtual ~SrsMpegtsOverUdp(); |
@@ -83,6 +101,19 @@ public: | @@ -83,6 +101,19 @@ public: | ||
83 | // interface ISrsTsHandler | 101 | // interface ISrsTsHandler |
84 | public: | 102 | public: |
85 | virtual int on_ts_message(SrsTsMessage* msg); | 103 | virtual int on_ts_message(SrsTsMessage* msg); |
104 | +private: | ||
105 | + virtual int on_ts_video(SrsTsMessage* msg, SrsStream* avs); | ||
106 | + virtual int write_h264_raw_frame(char* frame, int frame_size, u_int32_t dts, u_int32_t pts); | ||
107 | + virtual int write_h264_sps_pps(u_int32_t dts, u_int32_t pts); | ||
108 | + virtual int write_h264_ipb_frame(char* frame, int frame_size, u_int32_t dts, u_int32_t pts); | ||
109 | + virtual int rtmp_write_packet(char type, u_int32_t timestamp, char* data, int size); | ||
110 | +private: | ||
111 | + // connect to rtmp output url. | ||
112 | + // @remark ignore when not connected, reconnect when disconnected. | ||
113 | + virtual int connect(); | ||
114 | + virtual int connect_app(std::string ep_server, std::string ep_port); | ||
115 | + // close the connected io and rtmp to ready to be re-connect. | ||
116 | + virtual void close(); | ||
86 | }; | 117 | }; |
87 | 118 | ||
88 | #endif | 119 | #endif |
@@ -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 2 | 32 | #define VERSION_MAJOR 2 |
33 | #define VERSION_MINOR 0 | 33 | #define VERSION_MINOR 0 |
34 | -#define VERSION_REVISION 109 | 34 | +#define VERSION_REVISION 110 |
35 | 35 | ||
36 | // server info. | 36 | // server info. |
37 | #define RTMP_SIG_SRS_KEY "SRS" | 37 | #define RTMP_SIG_SRS_KEY "SRS" |
@@ -53,7 +53,7 @@ enum SrsCodecAudioType | @@ -53,7 +53,7 @@ enum SrsCodecAudioType | ||
53 | // 5 = video info/command frame | 53 | // 5 = video info/command frame |
54 | enum SrsCodecVideoAVCFrame | 54 | enum SrsCodecVideoAVCFrame |
55 | { | 55 | { |
56 | - // set to the max value to reserved, for array map. | 56 | + // set to the zero to reserved, for array map. |
57 | SrsCodecVideoAVCFrameReserved = 0, | 57 | SrsCodecVideoAVCFrameReserved = 0, |
58 | SrsCodecVideoAVCFrameReserved1 = 6, | 58 | SrsCodecVideoAVCFrameReserved1 = 6, |
59 | 59 | ||
@@ -91,7 +91,7 @@ enum SrsCodecVideoAVCType | @@ -91,7 +91,7 @@ enum SrsCodecVideoAVCType | ||
91 | // 7 = AVC | 91 | // 7 = AVC |
92 | enum SrsCodecVideo | 92 | enum SrsCodecVideo |
93 | { | 93 | { |
94 | - // set to the max value to reserved, for array map. | 94 | + // set to the zero to reserved, for array map. |
95 | SrsCodecVideoReserved = 0, | 95 | SrsCodecVideoReserved = 0, |
96 | SrsCodecVideoReserved1 = 1, | 96 | SrsCodecVideoReserved1 = 1, |
97 | SrsCodecVideoReserved2 = 8, | 97 | SrsCodecVideoReserved2 = 8, |
@@ -164,6 +164,22 @@ enum SrsCodecAudioSampleRate | @@ -164,6 +164,22 @@ enum SrsCodecAudioSampleRate | ||
164 | }; | 164 | }; |
165 | 165 | ||
166 | /** | 166 | /** |
167 | +* E.4.1 FLV Tag, page 75 | ||
168 | +*/ | ||
169 | +enum SrsCodecFlvTag | ||
170 | +{ | ||
171 | + // set to the zero to reserved, for array map. | ||
172 | + SrsCodecFlvTagReserved = 0, | ||
173 | + | ||
174 | + // 8 = audio | ||
175 | + SrsCodecFlvTagAudio = 8, | ||
176 | + // 9 = video | ||
177 | + SrsCodecFlvTagVideo = 9, | ||
178 | + // 18 = script data | ||
179 | + SrsCodecFlvTagScript = 18, | ||
180 | +}; | ||
181 | + | ||
182 | +/** | ||
167 | * Annex E. The FLV File Format | 183 | * Annex E. The FLV File Format |
168 | * @see SrsAvcAacCodec for the media stream codec. | 184 | * @see SrsAvcAacCodec for the media stream codec. |
169 | */ | 185 | */ |
@@ -228,6 +228,10 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | @@ -228,6 +228,10 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
228 | #define ERROR_STREAM_CASTER_TS_PMT 4018 | 228 | #define ERROR_STREAM_CASTER_TS_PMT 4018 |
229 | #define ERROR_STREAM_CASTER_TS_PSE 4019 | 229 | #define ERROR_STREAM_CASTER_TS_PSE 4019 |
230 | #define ERROR_STREAM_CASTER_TS_ES 4020 | 230 | #define ERROR_STREAM_CASTER_TS_ES 4020 |
231 | +#define ERROR_STREAM_CASTER_TS_CODEC 4021 | ||
232 | +#define ERROR_STREAM_CASTER_AVC_SPS 4022 | ||
233 | +#define ERROR_STREAM_CASTER_AVC_PPS 4023 | ||
234 | +#define ERROR_STREAM_CASTER_FLV_TAG 4024 | ||
231 | 235 | ||
232 | /** | 236 | /** |
233 | * whether the error code is an system control error. | 237 | * whether the error code is an system control error. |
@@ -47,6 +47,7 @@ using namespace std; | @@ -47,6 +47,7 @@ using namespace std; | ||
47 | #include <srs_kernel_codec.hpp> | 47 | #include <srs_kernel_codec.hpp> |
48 | #include <srs_kernel_file.hpp> | 48 | #include <srs_kernel_file.hpp> |
49 | #include <srs_lib_bandwidth.hpp> | 49 | #include <srs_lib_bandwidth.hpp> |
50 | +#include <srs_raw_avc.hpp> | ||
50 | 51 | ||
51 | // kernel module. | 52 | // kernel module. |
52 | ISrsLog* _srs_log = new ISrsLog(); | 53 | ISrsLog* _srs_log = new ISrsLog(); |
@@ -82,6 +83,9 @@ struct Context | @@ -82,6 +83,9 @@ struct Context | ||
82 | 83 | ||
83 | // for h264 raw stream, | 84 | // for h264 raw stream, |
84 | // @see: https://github.com/winlinvip/simple-rtmp-server/issues/66#issuecomment-62240521 | 85 | // @see: https://github.com/winlinvip/simple-rtmp-server/issues/66#issuecomment-62240521 |
86 | + SrsRawH264Stream avc_raw; | ||
87 | + // for h264 raw stream, | ||
88 | + // @see: https://github.com/winlinvip/simple-rtmp-server/issues/66#issuecomment-62240521 | ||
85 | SrsStream h264_raw_stream; | 89 | SrsStream h264_raw_stream; |
86 | // about SPS, @see: 7.3.2.1.1, H.264-AVC-ISO_IEC_14496-10-2012.pdf, page 62 | 90 | // about SPS, @see: 7.3.2.1.1, H.264-AVC-ISO_IEC_14496-10-2012.pdf, page 62 |
87 | std::string h264_sps; | 91 | std::string h264_sps; |
@@ -1022,44 +1026,16 @@ int srs_rtmp_write_packet(srs_rtmp_t rtmp, char type, u_int32_t timestamp, char* | @@ -1022,44 +1026,16 @@ int srs_rtmp_write_packet(srs_rtmp_t rtmp, char type, u_int32_t timestamp, char* | ||
1022 | 1026 | ||
1023 | SrsSharedPtrMessage* msg = NULL; | 1027 | SrsSharedPtrMessage* msg = NULL; |
1024 | 1028 | ||
1025 | - if (type == SRS_RTMP_TYPE_AUDIO) { | ||
1026 | - SrsMessageHeader header; | ||
1027 | - header.initialize_audio(size, timestamp, context->stream_id); | ||
1028 | - | ||
1029 | - msg = new SrsSharedPtrMessage(); | ||
1030 | - if ((ret = msg->create(&header, data, size)) != ERROR_SUCCESS) { | ||
1031 | - srs_freep(data); | 1029 | + if ((ret = srs_rtmp_create_msg(type, timestamp, data, size, context->stream_id, &msg)) != ERROR_SUCCESS) { |
1032 | return ret; | 1030 | return ret; |
1033 | } | 1031 | } |
1034 | - } else if (type == SRS_RTMP_TYPE_VIDEO) { | ||
1035 | - SrsMessageHeader header; | ||
1036 | - header.initialize_video(size, timestamp, context->stream_id); | ||
1037 | 1032 | ||
1038 | - msg = new SrsSharedPtrMessage(); | ||
1039 | - if ((ret = msg->create(&header, data, size)) != ERROR_SUCCESS) { | ||
1040 | - srs_freep(data); | ||
1041 | - return ret; | ||
1042 | - } | ||
1043 | - } else if (type == SRS_RTMP_TYPE_SCRIPT) { | ||
1044 | - SrsMessageHeader header; | ||
1045 | - header.initialize_amf0_script(size, context->stream_id); | ||
1046 | - | ||
1047 | - msg = new SrsSharedPtrMessage(); | ||
1048 | - if ((ret = msg->create(&header, data, size)) != ERROR_SUCCESS) { | ||
1049 | - srs_freep(data); | ||
1050 | - return ret; | ||
1051 | - } | ||
1052 | - } | 1033 | + srs_assert(msg); |
1053 | 1034 | ||
1054 | - if (msg) { | ||
1055 | // send out encoded msg. | 1035 | // send out encoded msg. |
1056 | if ((ret = context->rtmp->send_and_free_message(msg, context->stream_id)) != ERROR_SUCCESS) { | 1036 | if ((ret = context->rtmp->send_and_free_message(msg, context->stream_id)) != ERROR_SUCCESS) { |
1057 | return ret; | 1037 | return ret; |
1058 | } | 1038 | } |
1059 | - } else { | ||
1060 | - // directly free data if not sent out. | ||
1061 | - srs_freep(data); | ||
1062 | - } | ||
1063 | 1039 | ||
1064 | return ret; | 1040 | return ret; |
1065 | } | 1041 | } |
@@ -1405,50 +1381,35 @@ int srs_aac_adts_frame_size(char* aac_raw_data, int ac_raw_size) | @@ -1405,50 +1381,35 @@ int srs_aac_adts_frame_size(char* aac_raw_data, int ac_raw_size) | ||
1405 | } | 1381 | } |
1406 | 1382 | ||
1407 | /** | 1383 | /** |
1408 | -* write h264 packet, with rtmp header. | ||
1409 | -* @param frame_type, SrsCodecVideoAVCFrameKeyFrame or SrsCodecVideoAVCFrameInterFrame. | ||
1410 | -* @param avc_packet_type, SrsCodecVideoAVCTypeSequenceHeader or SrsCodecVideoAVCTypeNALU. | ||
1411 | -* @param h264_raw_data the h.264 raw data, user must free it. | 1384 | +* write h264 IPB-frame. |
1412 | */ | 1385 | */ |
1413 | -int __srs_write_h264_packet(Context* context, | ||
1414 | - int8_t frame_type, int8_t avc_packet_type, | ||
1415 | - char* h264_raw_data, int h264_raw_size, u_int32_t dts, u_int32_t pts | 1386 | +int __srs_write_h264_ipb_frame(Context* context, |
1387 | + char* frame, int frame_size, u_int32_t dts, u_int32_t pts | ||
1416 | ) { | 1388 | ) { |
1417 | - // the timestamp in rtmp message header is dts. | ||
1418 | - u_int32_t timestamp = dts; | ||
1419 | - | ||
1420 | - // for h264 in RTMP video payload, there is 5bytes header: | ||
1421 | - // 1bytes, FrameType | CodecID | ||
1422 | - // 1bytes, AVCPacketType | ||
1423 | - // 3bytes, CompositionTime, the cts. | ||
1424 | - // @see: E.4.3 Video Tags, video_file_format_spec_v10_1.pdf, page 78 | ||
1425 | - int size = h264_raw_size + 5; | ||
1426 | - char* data = new char[size]; | ||
1427 | - char* p = data; | ||
1428 | - | ||
1429 | - // @see: E.4.3 Video Tags, video_file_format_spec_v10_1.pdf, page 78 | ||
1430 | - // Frame Type, Type of video frame. | ||
1431 | - // CodecID, Codec Identifier. | ||
1432 | - // set the rtmp header | ||
1433 | - *p++ = (frame_type << 4) | SrsCodecVideoAVC; | 1389 | + int ret = ERROR_SUCCESS; |
1434 | 1390 | ||
1435 | - // AVCPacketType | ||
1436 | - *p++ = avc_packet_type; | 1391 | + // when sps or pps not sent, ignore the packet. |
1392 | + // @see https://github.com/winlinvip/simple-rtmp-server/issues/203 | ||
1393 | + if (!context->h264_sps_pps_sent) { | ||
1394 | + return ERROR_H264_DROP_BEFORE_SPS_PPS; | ||
1395 | + } | ||
1437 | 1396 | ||
1438 | - // CompositionTime | ||
1439 | - // pts = dts + cts, or | ||
1440 | - // cts = pts - dts. | ||
1441 | - // where cts is the header in rtmp video packet payload header. | ||
1442 | - u_int32_t cts = pts - dts; | ||
1443 | - char* pp = (char*)&cts; | ||
1444 | - *p++ = pp[2]; | ||
1445 | - *p++ = pp[1]; | ||
1446 | - *p++ = pp[0]; | 1397 | + std::string ibp; |
1398 | + int8_t frame_type; | ||
1399 | + if ((ret = context->avc_raw.mux_ipb_frame(frame, frame_size, dts, pts, ibp, frame_type)) != ERROR_SUCCESS) { | ||
1400 | + return ret; | ||
1401 | + } | ||
1447 | 1402 | ||
1448 | - // h.264 raw data. | ||
1449 | - memcpy(p, h264_raw_data, h264_raw_size); | 1403 | + int8_t avc_packet_type = SrsCodecVideoAVCTypeNALU; |
1404 | + char* flv = NULL; | ||
1405 | + int nb_flv = 0; | ||
1406 | + if ((ret = context->avc_raw.mux_avc2flv(ibp, frame_type, avc_packet_type, dts, pts, &flv, &nb_flv)) != ERROR_SUCCESS) { | ||
1407 | + return ret; | ||
1408 | + } | ||
1450 | 1409 | ||
1451 | - return srs_rtmp_write_packet(context, SRS_RTMP_TYPE_VIDEO, timestamp, data, size); | 1410 | + // the timestamp in rtmp message header is dts. |
1411 | + u_int32_t timestamp = dts; | ||
1412 | + return srs_rtmp_write_packet(context, SRS_RTMP_TYPE_VIDEO, timestamp, flv, nb_flv); | ||
1452 | } | 1413 | } |
1453 | 1414 | ||
1454 | /** | 1415 | /** |
@@ -1463,154 +1424,29 @@ int __srs_write_h264_sps_pps(Context* context, u_int32_t dts, u_int32_t pts) | @@ -1463,154 +1424,29 @@ int __srs_write_h264_sps_pps(Context* context, u_int32_t dts, u_int32_t pts) | ||
1463 | return ret; | 1424 | return ret; |
1464 | } | 1425 | } |
1465 | 1426 | ||
1466 | - // 5bytes sps/pps header: | ||
1467 | - // configurationVersion, AVCProfileIndication, profile_compatibility, | ||
1468 | - // AVCLevelIndication, lengthSizeMinusOne | ||
1469 | - // 3bytes size of sps: | ||
1470 | - // numOfSequenceParameterSets, sequenceParameterSetLength(2B) | ||
1471 | - // Nbytes of sps. | ||
1472 | - // sequenceParameterSetNALUnit | ||
1473 | - // 3bytes size of pps: | ||
1474 | - // numOfPictureParameterSets, pictureParameterSetLength | ||
1475 | - // Nbytes of pps: | ||
1476 | - // pictureParameterSetNALUnit | ||
1477 | - int nb_packet = 5 | ||
1478 | - + 3 + (int)context->h264_sps.length() | ||
1479 | - + 3 + (int)context->h264_pps.length(); | ||
1480 | - char* packet = new char[nb_packet]; | ||
1481 | - SrsAutoFree(char, packet); | ||
1482 | - | ||
1483 | - // use stream to generate the h264 packet. | ||
1484 | - SrsStream stream; | ||
1485 | - if ((ret = stream.initialize(packet, nb_packet)) != ERROR_SUCCESS) { | ||
1486 | - return ret; | ||
1487 | - } | ||
1488 | - | ||
1489 | - // decode the SPS: | ||
1490 | - // @see: 7.3.2.1.1, H.264-AVC-ISO_IEC_14496-10-2012.pdf, page 62 | ||
1491 | - if (true) { | ||
1492 | - srs_assert((int)context->h264_sps.length() >= 4); | ||
1493 | - char* frame = (char*)context->h264_sps.data(); | ||
1494 | - | ||
1495 | - // @see: Annex A Profiles and levels, H.264-AVC-ISO_IEC_14496-10.pdf, page 205 | ||
1496 | - // Baseline profile profile_idc is 66(0x42). | ||
1497 | - // Main profile profile_idc is 77(0x4d). | ||
1498 | - // Extended profile profile_idc is 88(0x58). | ||
1499 | - u_int8_t profile_idc = frame[1]; | ||
1500 | - //u_int8_t constraint_set = frame[2]; | ||
1501 | - u_int8_t level_idc = frame[3]; | ||
1502 | - | ||
1503 | - // generate the sps/pps header | ||
1504 | - // 5.3.4.2.1 Syntax, H.264-AVC-ISO_IEC_14496-15.pdf, page 16 | ||
1505 | - // configurationVersion | ||
1506 | - stream.write_1bytes(0x01); | ||
1507 | - // AVCProfileIndication | ||
1508 | - stream.write_1bytes(profile_idc); | ||
1509 | - // profile_compatibility | ||
1510 | - stream.write_1bytes(0x00); | ||
1511 | - // AVCLevelIndication | ||
1512 | - stream.write_1bytes(level_idc); | ||
1513 | - // lengthSizeMinusOne, or NAL_unit_length, always use 4bytes size, | ||
1514 | - // so we always set it to 0x03. | ||
1515 | - stream.write_1bytes(0x03); | ||
1516 | - } | ||
1517 | - | ||
1518 | - // sps | ||
1519 | - if (true) { | ||
1520 | - // 5.3.4.2.1 Syntax, H.264-AVC-ISO_IEC_14496-15.pdf, page 16 | ||
1521 | - // numOfSequenceParameterSets, always 1 | ||
1522 | - stream.write_1bytes(0x01); | ||
1523 | - // sequenceParameterSetLength | ||
1524 | - stream.write_2bytes(context->h264_sps.length()); | ||
1525 | - // sequenceParameterSetNALUnit | ||
1526 | - stream.write_string(context->h264_sps); | ||
1527 | - } | ||
1528 | - | ||
1529 | - // pps | ||
1530 | - if (true) { | ||
1531 | - // 5.3.4.2.1 Syntax, H.264-AVC-ISO_IEC_14496-15.pdf, page 16 | ||
1532 | - // numOfPictureParameterSets, always 1 | ||
1533 | - stream.write_1bytes(0x01); | ||
1534 | - // pictureParameterSetLength | ||
1535 | - stream.write_2bytes(context->h264_pps.length()); | ||
1536 | - // pictureParameterSetNALUnit | ||
1537 | - stream.write_string(context->h264_pps); | 1427 | + // h264 raw to h264 packet. |
1428 | + std::string sh; | ||
1429 | + if ((ret = context->avc_raw.mux_sequence_header(context->h264_sps, context->h264_pps, dts, pts, sh)) != ERROR_SUCCESS) { | ||
1430 | + return ret; | ||
1538 | } | 1431 | } |
1539 | 1432 | ||
1540 | - // reset sps and pps. | ||
1541 | - context->h264_sps_changed = false; | ||
1542 | - context->h264_pps_changed = false; | ||
1543 | - context->h264_sps_pps_sent = true; | ||
1544 | - | ||
1545 | - // TODO: FIXME: for more profile. | ||
1546 | - // 5.3.4.2.1 Syntax, H.264-AVC-ISO_IEC_14496-15.pdf, page 16 | ||
1547 | - // profile_idc == 100 || profile_idc == 110 || profile_idc == 122 || profile_idc == 144 | ||
1548 | - | ||
1549 | - // send out h264 packet. | 1433 | + // h264 packet to flv packet. |
1550 | int8_t frame_type = SrsCodecVideoAVCFrameKeyFrame; | 1434 | int8_t frame_type = SrsCodecVideoAVCFrameKeyFrame; |
1551 | int8_t avc_packet_type = SrsCodecVideoAVCTypeSequenceHeader; | 1435 | int8_t avc_packet_type = SrsCodecVideoAVCTypeSequenceHeader; |
1552 | - return __srs_write_h264_packet( | ||
1553 | - context, frame_type, avc_packet_type, | ||
1554 | - packet, nb_packet, dts, pts | ||
1555 | - ); | ||
1556 | -} | ||
1557 | - | ||
1558 | -/** | ||
1559 | -* write h264 IPB-frame. | ||
1560 | -*/ | ||
1561 | -int __srs_write_h264_ipb_frame(Context* context, | ||
1562 | - char* data, int size, u_int32_t dts, u_int32_t pts | ||
1563 | -) { | ||
1564 | - int ret = ERROR_SUCCESS; | ||
1565 | - | ||
1566 | - // when sps or pps not sent, ignore the packet. | ||
1567 | - // @see https://github.com/winlinvip/simple-rtmp-server/issues/203 | ||
1568 | - if (!context->h264_sps_pps_sent) { | ||
1569 | - return ERROR_H264_DROP_BEFORE_SPS_PPS; | ||
1570 | - } | ||
1571 | - | ||
1572 | - // 5bits, 7.3.1 NAL unit syntax, | ||
1573 | - // H.264-AVC-ISO_IEC_14496-10.pdf, page 44. | ||
1574 | - // 7: SPS, 8: PPS, 5: I Frame, 1: P Frame | ||
1575 | - u_int8_t nal_unit_type = (char)data[0] & 0x1f; | ||
1576 | - | ||
1577 | - // 4bytes size of nalu: | ||
1578 | - // NALUnitLength | ||
1579 | - // Nbytes of nalu. | ||
1580 | - // NALUnit | ||
1581 | - int nb_packet = 4 + size; | ||
1582 | - char* packet = new char[nb_packet]; | ||
1583 | - SrsAutoFree(char, packet); | ||
1584 | - | ||
1585 | - // use stream to generate the h264 packet. | ||
1586 | - SrsStream stream; | ||
1587 | - if ((ret = stream.initialize(packet, nb_packet)) != ERROR_SUCCESS) { | 1436 | + char* flv = NULL; |
1437 | + int nb_flv = 0; | ||
1438 | + if ((ret = context->avc_raw.mux_avc2flv(sh, frame_type, avc_packet_type, dts, pts, &flv, &nb_flv)) != ERROR_SUCCESS) { | ||
1588 | return ret; | 1439 | return ret; |
1589 | } | 1440 | } |
1590 | 1441 | ||
1591 | - // 5.3.4.2.1 Syntax, H.264-AVC-ISO_IEC_14496-15.pdf, page 16 | ||
1592 | - // lengthSizeMinusOne, or NAL_unit_length, always use 4bytes size | ||
1593 | - u_int32_t NAL_unit_length = size; | ||
1594 | - | ||
1595 | - // mux the avc NALU in "ISO Base Media File Format" | ||
1596 | - // from H.264-AVC-ISO_IEC_14496-15.pdf, page 20 | ||
1597 | - // NALUnitLength | ||
1598 | - stream.write_4bytes(NAL_unit_length); | ||
1599 | - // NALUnit | ||
1600 | - stream.write_bytes(data, size); | ||
1601 | - | ||
1602 | - // send out h264 packet. | ||
1603 | - int8_t frame_type = SrsCodecVideoAVCFrameInterFrame; | ||
1604 | - if (nal_unit_type != 1) { | ||
1605 | - frame_type = SrsCodecVideoAVCFrameKeyFrame; | ||
1606 | - } | ||
1607 | - int8_t avc_packet_type = SrsCodecVideoAVCTypeNALU; | ||
1608 | - return __srs_write_h264_packet( | ||
1609 | - context, frame_type, avc_packet_type, | ||
1610 | - packet, nb_packet, dts, pts | ||
1611 | - ); | 1442 | + // reset sps and pps. |
1443 | + context->h264_sps_changed = false; | ||
1444 | + context->h264_pps_changed = false; | ||
1445 | + context->h264_sps_pps_sent = true; | ||
1612 | 1446 | ||
1613 | - return ret; | 1447 | + // the timestamp in rtmp message header is dts. |
1448 | + u_int32_t timestamp = dts; | ||
1449 | + return srs_rtmp_write_packet(context, SRS_RTMP_TYPE_VIDEO, timestamp, flv, nb_flv); | ||
1614 | } | 1450 | } |
1615 | 1451 | ||
1616 | /** | 1452 | /** |
@@ -1621,26 +1457,13 @@ int __srs_write_h264_raw_frame(Context* context, | @@ -1621,26 +1457,13 @@ int __srs_write_h264_raw_frame(Context* context, | ||
1621 | ) { | 1457 | ) { |
1622 | int ret = ERROR_SUCCESS; | 1458 | int ret = ERROR_SUCCESS; |
1623 | 1459 | ||
1624 | - // ignore invalid frame, | ||
1625 | - // atleast 1bytes for SPS to decode the type | ||
1626 | - if (frame_size < 1) { | ||
1627 | - return ret; | ||
1628 | - } | ||
1629 | - | ||
1630 | - // 5bits, 7.3.1 NAL unit syntax, | ||
1631 | - // H.264-AVC-ISO_IEC_14496-10.pdf, page 44. | ||
1632 | - // 7: SPS, 8: PPS, 5: I Frame, 1: P Frame | ||
1633 | - u_int8_t nal_unit_type = (char)frame[0] & 0x1f; | ||
1634 | - | ||
1635 | - if (nal_unit_type == 7) { | ||
1636 | - // atleast 1bytes for SPS to decode the type, profile, constrain and level. | ||
1637 | - if (frame_size < 4) { | 1460 | + // for sps |
1461 | + if (context->avc_raw.is_sps(frame, frame_size)) { | ||
1462 | + std::string sps; | ||
1463 | + if ((ret = context->avc_raw.sps_demux(frame, frame_size, sps)) != ERROR_SUCCESS) { | ||
1638 | return ret; | 1464 | return ret; |
1639 | } | 1465 | } |
1640 | 1466 | ||
1641 | - std::string sps; | ||
1642 | - sps.append(frame, frame_size); | ||
1643 | - | ||
1644 | if (context->h264_sps == sps) { | 1467 | if (context->h264_sps == sps) { |
1645 | return ERROR_H264_DUPLICATED_SPS; | 1468 | return ERROR_H264_DUPLICATED_SPS; |
1646 | } | 1469 | } |
@@ -1648,10 +1471,14 @@ int __srs_write_h264_raw_frame(Context* context, | @@ -1648,10 +1471,14 @@ int __srs_write_h264_raw_frame(Context* context, | ||
1648 | context->h264_sps = sps; | 1471 | context->h264_sps = sps; |
1649 | 1472 | ||
1650 | return __srs_write_h264_sps_pps(context, dts, pts); | 1473 | return __srs_write_h264_sps_pps(context, dts, pts); |
1651 | - } else if (nal_unit_type == 8) { | 1474 | + } |
1652 | 1475 | ||
1476 | + // for pps | ||
1477 | + if (context->avc_raw.is_pps(frame, frame_size)) { | ||
1653 | std::string pps; | 1478 | std::string pps; |
1654 | - pps.append(frame, frame_size); | 1479 | + if ((ret = context->avc_raw.pps_demux(frame, frame_size, pps)) != ERROR_SUCCESS) { |
1480 | + return ret; | ||
1481 | + } | ||
1655 | 1482 | ||
1656 | if (context->h264_pps == pps) { | 1483 | if (context->h264_pps == pps) { |
1657 | return ERROR_H264_DUPLICATED_PPS; | 1484 | return ERROR_H264_DUPLICATED_PPS; |
@@ -1660,11 +1487,10 @@ int __srs_write_h264_raw_frame(Context* context, | @@ -1660,11 +1487,10 @@ int __srs_write_h264_raw_frame(Context* context, | ||
1660 | context->h264_pps = pps; | 1487 | context->h264_pps = pps; |
1661 | 1488 | ||
1662 | return __srs_write_h264_sps_pps(context, dts, pts); | 1489 | return __srs_write_h264_sps_pps(context, dts, pts); |
1663 | - } else { | ||
1664 | - return __srs_write_h264_ipb_frame(context, frame, frame_size, dts, pts); | ||
1665 | } | 1490 | } |
1666 | 1491 | ||
1667 | - return ret; | 1492 | + // ibp frame. |
1493 | + return __srs_write_h264_ipb_frame(context, frame, frame_size, dts, pts); | ||
1668 | } | 1494 | } |
1669 | 1495 | ||
1670 | /** | 1496 | /** |
@@ -1692,29 +1518,21 @@ int srs_h264_write_raw_frames(srs_rtmp_t rtmp, | @@ -1692,29 +1518,21 @@ int srs_h264_write_raw_frames(srs_rtmp_t rtmp, | ||
1692 | 1518 | ||
1693 | // send each frame. | 1519 | // send each frame. |
1694 | while (!context->h264_raw_stream.empty()) { | 1520 | while (!context->h264_raw_stream.empty()) { |
1695 | - // each frame must prefixed by annexb format. | ||
1696 | - // about annexb, @see H.264-AVC-ISO_IEC_14496-10.pdf, page 211. | ||
1697 | - int pnb_start_code = 0; | ||
1698 | - if (!srs_avc_startswith_annexb(&context->h264_raw_stream, &pnb_start_code)) { | ||
1699 | - return ERROR_H264_API_NO_PREFIXED; | 1521 | + char* frame = NULL; |
1522 | + int frame_size = 0; | ||
1523 | + bool got_sps_pps = false; | ||
1524 | + if ((ret = context->avc_raw.annexb_demux(&context->h264_raw_stream, &frame, &frame_size)) != ERROR_SUCCESS) { | ||
1525 | + return ret; | ||
1700 | } | 1526 | } |
1701 | - int start = context->h264_raw_stream.pos() + pnb_start_code; | ||
1702 | 1527 | ||
1703 | - // find the last frame prefixed by annexb format. | ||
1704 | - context->h264_raw_stream.skip(pnb_start_code); | ||
1705 | - while (!context->h264_raw_stream.empty()) { | ||
1706 | - if (srs_avc_startswith_annexb(&context->h264_raw_stream, NULL)) { | ||
1707 | - break; | ||
1708 | - } | ||
1709 | - context->h264_raw_stream.skip(1); | 1528 | + // ignore invalid frame, |
1529 | + // atleast 1bytes for SPS to decode the type | ||
1530 | + if (frame_size <= 0) { | ||
1531 | + continue; | ||
1710 | } | 1532 | } |
1711 | - int size = context->h264_raw_stream.pos() - start; | ||
1712 | - | ||
1713 | - // send out the frame. | ||
1714 | - char* frame = context->h264_raw_stream.data() + start; | ||
1715 | 1533 | ||
1716 | // it may be return error, but we must process all packets. | 1534 | // it may be return error, but we must process all packets. |
1717 | - if ((ret = __srs_write_h264_raw_frame(context, frame, size, dts, pts)) != ERROR_SUCCESS) { | 1535 | + if ((ret = __srs_write_h264_raw_frame(context, frame, frame_size, dts, pts)) != ERROR_SUCCESS) { |
1718 | error_code_return = ret; | 1536 | error_code_return = ret; |
1719 | 1537 | ||
1720 | // ignore known error, process all packets. | 1538 | // ignore known error, process all packets. |
trunk/src/protocol/srs_raw_avc.cpp
0 → 100644
1 | +/* | ||
2 | +The MIT License (MIT) | ||
3 | + | ||
4 | +Copyright (c) 2013-2015 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_raw_avc.hpp> | ||
25 | + | ||
26 | +#include <string.h> | ||
27 | +using namespace std; | ||
28 | + | ||
29 | +#include <srs_kernel_error.hpp> | ||
30 | +#include <srs_kernel_stream.hpp> | ||
31 | +#include <srs_kernel_utility.hpp> | ||
32 | +#include <srs_core_autofree.hpp> | ||
33 | +#include <srs_kernel_codec.hpp> | ||
34 | + | ||
35 | +SrsRawH264Stream::SrsRawH264Stream() | ||
36 | +{ | ||
37 | +} | ||
38 | + | ||
39 | +SrsRawH264Stream::~SrsRawH264Stream() | ||
40 | +{ | ||
41 | +} | ||
42 | + | ||
43 | +int SrsRawH264Stream::annexb_demux(SrsStream* stream, char** pframe, int* pnb_frame) | ||
44 | +{ | ||
45 | + int ret = ERROR_SUCCESS; | ||
46 | + | ||
47 | + *pframe = NULL; | ||
48 | + *pnb_frame = 0; | ||
49 | + | ||
50 | + while (!stream->empty()) { | ||
51 | + // each frame must prefixed by annexb format. | ||
52 | + // about annexb, @see H.264-AVC-ISO_IEC_14496-10.pdf, page 211. | ||
53 | + int pnb_start_code = 0; | ||
54 | + if (!srs_avc_startswith_annexb(stream, &pnb_start_code)) { | ||
55 | + return ERROR_H264_API_NO_PREFIXED; | ||
56 | + } | ||
57 | + int start = stream->pos() + pnb_start_code; | ||
58 | + | ||
59 | + // find the last frame prefixed by annexb format. | ||
60 | + stream->skip(pnb_start_code); | ||
61 | + while (!stream->empty()) { | ||
62 | + if (srs_avc_startswith_annexb(stream, NULL)) { | ||
63 | + break; | ||
64 | + } | ||
65 | + stream->skip(1); | ||
66 | + } | ||
67 | + | ||
68 | + // demux the frame. | ||
69 | + *pnb_frame = stream->pos() - start; | ||
70 | + *pframe = stream->data() + start; | ||
71 | + break; | ||
72 | + } | ||
73 | + | ||
74 | + return ret; | ||
75 | +} | ||
76 | + | ||
77 | +bool SrsRawH264Stream::is_sps(char* frame, int nb_frame) | ||
78 | +{ | ||
79 | + srs_assert(nb_frame > 0); | ||
80 | + | ||
81 | + // 5bits, 7.3.1 NAL unit syntax, | ||
82 | + // H.264-AVC-ISO_IEC_14496-10.pdf, page 44. | ||
83 | + // 7: SPS, 8: PPS, 5: I Frame, 1: P Frame | ||
84 | + u_int8_t nal_unit_type = (char)frame[0] & 0x1f; | ||
85 | + | ||
86 | + return nal_unit_type == 7; | ||
87 | +} | ||
88 | + | ||
89 | +bool SrsRawH264Stream::is_pps(char* frame, int nb_frame) | ||
90 | +{ | ||
91 | + srs_assert(nb_frame > 0); | ||
92 | + | ||
93 | + // 5bits, 7.3.1 NAL unit syntax, | ||
94 | + // H.264-AVC-ISO_IEC_14496-10.pdf, page 44. | ||
95 | + // 7: SPS, 8: PPS, 5: I Frame, 1: P Frame | ||
96 | + u_int8_t nal_unit_type = (char)frame[0] & 0x1f; | ||
97 | + | ||
98 | + return nal_unit_type == 8; | ||
99 | +} | ||
100 | + | ||
101 | +int SrsRawH264Stream::sps_demux(char* frame, int nb_frame, string& sps) | ||
102 | +{ | ||
103 | + int ret = ERROR_SUCCESS; | ||
104 | + | ||
105 | + // atleast 1bytes for SPS to decode the type, profile, constrain and level. | ||
106 | + if (nb_frame < 4) { | ||
107 | + return ret; | ||
108 | + } | ||
109 | + | ||
110 | + sps = ""; | ||
111 | + if (nb_frame > 0) { | ||
112 | + sps.append(frame, nb_frame); | ||
113 | + } | ||
114 | + | ||
115 | + // should never be empty. | ||
116 | + if (sps.empty()) { | ||
117 | + return ERROR_STREAM_CASTER_AVC_SPS; | ||
118 | + } | ||
119 | + | ||
120 | + return ret; | ||
121 | +} | ||
122 | + | ||
123 | +int SrsRawH264Stream::pps_demux(char* frame, int nb_frame, string& pps) | ||
124 | +{ | ||
125 | + int ret = ERROR_SUCCESS; | ||
126 | + | ||
127 | + pps = ""; | ||
128 | + if (nb_frame > 0) { | ||
129 | + pps.append(frame, nb_frame); | ||
130 | + } | ||
131 | + | ||
132 | + // should never be empty. | ||
133 | + if (pps.empty()) { | ||
134 | + return ERROR_STREAM_CASTER_AVC_PPS; | ||
135 | + } | ||
136 | + | ||
137 | + return ret; | ||
138 | +} | ||
139 | + | ||
140 | +int SrsRawH264Stream::mux_sequence_header(string sps, string pps, u_int32_t dts, u_int32_t pts, string& sh) | ||
141 | +{ | ||
142 | + int ret = ERROR_SUCCESS; | ||
143 | + | ||
144 | + // 5bytes sps/pps header: | ||
145 | + // configurationVersion, AVCProfileIndication, profile_compatibility, | ||
146 | + // AVCLevelIndication, lengthSizeMinusOne | ||
147 | + // 3bytes size of sps: | ||
148 | + // numOfSequenceParameterSets, sequenceParameterSetLength(2B) | ||
149 | + // Nbytes of sps. | ||
150 | + // sequenceParameterSetNALUnit | ||
151 | + // 3bytes size of pps: | ||
152 | + // numOfPictureParameterSets, pictureParameterSetLength | ||
153 | + // Nbytes of pps: | ||
154 | + // pictureParameterSetNALUnit | ||
155 | + int nb_packet = 5 | ||
156 | + + 3 + (int)sps.length() | ||
157 | + + 3 + (int)pps.length(); | ||
158 | + char* packet = new char[nb_packet]; | ||
159 | + SrsAutoFree(char, packet); | ||
160 | + | ||
161 | + // use stream to generate the h264 packet. | ||
162 | + SrsStream stream; | ||
163 | + if ((ret = stream.initialize(packet, nb_packet)) != ERROR_SUCCESS) { | ||
164 | + return ret; | ||
165 | + } | ||
166 | + | ||
167 | + // decode the SPS: | ||
168 | + // @see: 7.3.2.1.1, H.264-AVC-ISO_IEC_14496-10-2012.pdf, page 62 | ||
169 | + if (true) { | ||
170 | + srs_assert((int)sps.length() >= 4); | ||
171 | + char* frame = (char*)sps.data(); | ||
172 | + | ||
173 | + // @see: Annex A Profiles and levels, H.264-AVC-ISO_IEC_14496-10.pdf, page 205 | ||
174 | + // Baseline profile profile_idc is 66(0x42). | ||
175 | + // Main profile profile_idc is 77(0x4d). | ||
176 | + // Extended profile profile_idc is 88(0x58). | ||
177 | + u_int8_t profile_idc = frame[1]; | ||
178 | + //u_int8_t constraint_set = frame[2]; | ||
179 | + u_int8_t level_idc = frame[3]; | ||
180 | + | ||
181 | + // generate the sps/pps header | ||
182 | + // 5.3.4.2.1 Syntax, H.264-AVC-ISO_IEC_14496-15.pdf, page 16 | ||
183 | + // configurationVersion | ||
184 | + stream.write_1bytes(0x01); | ||
185 | + // AVCProfileIndication | ||
186 | + stream.write_1bytes(profile_idc); | ||
187 | + // profile_compatibility | ||
188 | + stream.write_1bytes(0x00); | ||
189 | + // AVCLevelIndication | ||
190 | + stream.write_1bytes(level_idc); | ||
191 | + // lengthSizeMinusOne, or NAL_unit_length, always use 4bytes size, | ||
192 | + // so we always set it to 0x03. | ||
193 | + stream.write_1bytes(0x03); | ||
194 | + } | ||
195 | + | ||
196 | + // sps | ||
197 | + if (true) { | ||
198 | + // 5.3.4.2.1 Syntax, H.264-AVC-ISO_IEC_14496-15.pdf, page 16 | ||
199 | + // numOfSequenceParameterSets, always 1 | ||
200 | + stream.write_1bytes(0x01); | ||
201 | + // sequenceParameterSetLength | ||
202 | + stream.write_2bytes(sps.length()); | ||
203 | + // sequenceParameterSetNALUnit | ||
204 | + stream.write_string(sps); | ||
205 | + } | ||
206 | + | ||
207 | + // pps | ||
208 | + if (true) { | ||
209 | + // 5.3.4.2.1 Syntax, H.264-AVC-ISO_IEC_14496-15.pdf, page 16 | ||
210 | + // numOfPictureParameterSets, always 1 | ||
211 | + stream.write_1bytes(0x01); | ||
212 | + // pictureParameterSetLength | ||
213 | + stream.write_2bytes(pps.length()); | ||
214 | + // pictureParameterSetNALUnit | ||
215 | + stream.write_string(pps); | ||
216 | + } | ||
217 | + | ||
218 | + // TODO: FIXME: for more profile. | ||
219 | + // 5.3.4.2.1 Syntax, H.264-AVC-ISO_IEC_14496-15.pdf, page 16 | ||
220 | + // profile_idc == 100 || profile_idc == 110 || profile_idc == 122 || profile_idc == 144 | ||
221 | + | ||
222 | + sh = ""; | ||
223 | + sh.append(packet, nb_packet); | ||
224 | + | ||
225 | + return ret; | ||
226 | +} | ||
227 | + | ||
228 | +int SrsRawH264Stream::mux_ipb_frame(char* frame, int nb_frame, u_int32_t dts, u_int32_t pts, string& ibp, int8_t& frame_type) | ||
229 | +{ | ||
230 | + int ret = ERROR_SUCCESS; | ||
231 | + | ||
232 | + // 5bits, 7.3.1 NAL unit syntax, | ||
233 | + // H.264-AVC-ISO_IEC_14496-10.pdf, page 44. | ||
234 | + // 7: SPS, 8: PPS, 5: I Frame, 1: P Frame | ||
235 | + u_int8_t nal_unit_type = (char)frame[0] & 0x1f; | ||
236 | + | ||
237 | + // 4bytes size of nalu: | ||
238 | + // NALUnitLength | ||
239 | + // Nbytes of nalu. | ||
240 | + // NALUnit | ||
241 | + int nb_packet = 4 + nb_frame; | ||
242 | + char* packet = new char[nb_packet]; | ||
243 | + SrsAutoFree(char, packet); | ||
244 | + | ||
245 | + // use stream to generate the h264 packet. | ||
246 | + SrsStream stream; | ||
247 | + if ((ret = stream.initialize(packet, nb_packet)) != ERROR_SUCCESS) { | ||
248 | + return ret; | ||
249 | + } | ||
250 | + | ||
251 | + // 5.3.4.2.1 Syntax, H.264-AVC-ISO_IEC_14496-15.pdf, page 16 | ||
252 | + // lengthSizeMinusOne, or NAL_unit_length, always use 4bytes size | ||
253 | + u_int32_t NAL_unit_length = nb_frame; | ||
254 | + | ||
255 | + // mux the avc NALU in "ISO Base Media File Format" | ||
256 | + // from H.264-AVC-ISO_IEC_14496-15.pdf, page 20 | ||
257 | + // NALUnitLength | ||
258 | + stream.write_4bytes(NAL_unit_length); | ||
259 | + // NALUnit | ||
260 | + stream.write_bytes(frame, nb_frame); | ||
261 | + | ||
262 | + // send out h264 packet. | ||
263 | + frame_type = SrsCodecVideoAVCFrameInterFrame; | ||
264 | + if (nal_unit_type != 1) { | ||
265 | + frame_type = SrsCodecVideoAVCFrameKeyFrame; | ||
266 | + } | ||
267 | + | ||
268 | + ibp = ""; | ||
269 | + ibp.append(packet, nb_packet); | ||
270 | + | ||
271 | + return ret; | ||
272 | +} | ||
273 | + | ||
274 | +int SrsRawH264Stream::mux_avc2flv(string video, int8_t frame_type, int8_t avc_packet_type, u_int32_t dts, u_int32_t pts, char** flv, int* nb_flv) | ||
275 | +{ | ||
276 | + int ret = ERROR_SUCCESS; | ||
277 | + | ||
278 | + // for h264 in RTMP video payload, there is 5bytes header: | ||
279 | + // 1bytes, FrameType | CodecID | ||
280 | + // 1bytes, AVCPacketType | ||
281 | + // 3bytes, CompositionTime, the cts. | ||
282 | + // @see: E.4.3 Video Tags, video_file_format_spec_v10_1.pdf, page 78 | ||
283 | + int size = video.length() + 5; | ||
284 | + char* data = new char[size]; | ||
285 | + char* p = data; | ||
286 | + | ||
287 | + // @see: E.4.3 Video Tags, video_file_format_spec_v10_1.pdf, page 78 | ||
288 | + // Frame Type, Type of video frame. | ||
289 | + // CodecID, Codec Identifier. | ||
290 | + // set the rtmp header | ||
291 | + *p++ = (frame_type << 4) | SrsCodecVideoAVC; | ||
292 | + | ||
293 | + // AVCPacketType | ||
294 | + *p++ = avc_packet_type; | ||
295 | + | ||
296 | + // CompositionTime | ||
297 | + // pts = dts + cts, or | ||
298 | + // cts = pts - dts. | ||
299 | + // where cts is the header in rtmp video packet payload header. | ||
300 | + u_int32_t cts = pts - dts; | ||
301 | + char* pp = (char*)&cts; | ||
302 | + *p++ = pp[2]; | ||
303 | + *p++ = pp[1]; | ||
304 | + *p++ = pp[0]; | ||
305 | + | ||
306 | + // h.264 raw data. | ||
307 | + memcpy(p, video.data(), video.length()); | ||
308 | + | ||
309 | + *flv = data; | ||
310 | + *nb_flv = size; | ||
311 | + | ||
312 | + return ret; | ||
313 | +} | ||
314 | + |
trunk/src/protocol/srs_raw_avc.hpp
0 → 100644
1 | +/* | ||
2 | +The MIT License (MIT) | ||
3 | + | ||
4 | +Copyright (c) 2013-2015 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_PROTOCOL_RAW_AVC_HPP | ||
25 | +#define SRS_PROTOCOL_RAW_AVC_HPP | ||
26 | + | ||
27 | +/* | ||
28 | +#include <srs_raw_avc.hpp> | ||
29 | +*/ | ||
30 | + | ||
31 | +#include <srs_core.hpp> | ||
32 | + | ||
33 | +#include <string> | ||
34 | + | ||
35 | +class SrsStream; | ||
36 | + | ||
37 | +/** | ||
38 | +* the raw h.264 stream, in annexb. | ||
39 | +*/ | ||
40 | +class SrsRawH264Stream | ||
41 | +{ | ||
42 | +public: | ||
43 | + SrsRawH264Stream(); | ||
44 | + virtual ~SrsRawH264Stream(); | ||
45 | +public: | ||
46 | + /** | ||
47 | + * demux the stream in annexb format. | ||
48 | + * @param stream the input stream bytes. | ||
49 | + * @param pframe the output h.264 frame in stream. user should never free it. | ||
50 | + * @param pnb_frame the output h.264 frame size. | ||
51 | + */ | ||
52 | + virtual int annexb_demux(SrsStream* stream, char** pframe, int* pnb_frame); | ||
53 | + /** | ||
54 | + * whether the frame is sps or pps. | ||
55 | + */ | ||
56 | + virtual bool is_sps(char* frame, int nb_frame); | ||
57 | + virtual bool is_pps(char* frame, int nb_frame); | ||
58 | + /** | ||
59 | + * demux the sps or pps to string. | ||
60 | + * @param sps/pps output the sps/pps. | ||
61 | + */ | ||
62 | + virtual int sps_demux(char* frame, int nb_frame, std::string& sps); | ||
63 | + virtual int pps_demux(char* frame, int nb_frame, std::string& pps); | ||
64 | +public: | ||
65 | + /** | ||
66 | + * h264 raw data to h264 packet, without flv payload header. | ||
67 | + * mux the sps/pps to flv sequence header packet. | ||
68 | + * @param sh output the sequence header. | ||
69 | + */ | ||
70 | + virtual int mux_sequence_header(std::string sps, std::string pps, u_int32_t dts, u_int32_t pts, std::string& sh); | ||
71 | + /** | ||
72 | + * h264 raw data to h264 packet, without flv payload header. | ||
73 | + * mux the ibp to flv ibp packet. | ||
74 | + * @param ibp output the packet. | ||
75 | + * @param frame_type output the frame type. | ||
76 | + */ | ||
77 | + virtual int mux_ipb_frame(char* frame, int nb_frame, u_int32_t dts, u_int32_t pts, std::string& ibp, int8_t& frame_type); | ||
78 | + /** | ||
79 | + * mux the avc video packet to flv video packet. | ||
80 | + * @param frame_type, SrsCodecVideoAVCFrameKeyFrame or SrsCodecVideoAVCFrameInterFrame. | ||
81 | + * @param avc_packet_type, SrsCodecVideoAVCTypeSequenceHeader or SrsCodecVideoAVCTypeNALU. | ||
82 | + * @param video the h.264 raw data. | ||
83 | + * @param flv output the muxed flv packet. | ||
84 | + * @param nb_flv output the muxed flv size. | ||
85 | + */ | ||
86 | + virtual int mux_avc2flv(std::string video, int8_t frame_type, int8_t avc_packet_type, u_int32_t dts, u_int32_t pts, char** flv, int* nb_flv); | ||
87 | +}; | ||
88 | + | ||
89 | +#endif |
@@ -30,6 +30,7 @@ using namespace std; | @@ -30,6 +30,7 @@ using namespace std; | ||
30 | #include <srs_kernel_utility.hpp> | 30 | #include <srs_kernel_utility.hpp> |
31 | #include <srs_kernel_stream.hpp> | 31 | #include <srs_kernel_stream.hpp> |
32 | #include <srs_rtmp_stack.hpp> | 32 | #include <srs_rtmp_stack.hpp> |
33 | +#include <srs_kernel_codec.hpp> | ||
33 | 34 | ||
34 | void srs_discovery_tc_url( | 35 | void srs_discovery_tc_url( |
35 | string tcUrl, | 36 | string tcUrl, |
@@ -287,3 +288,61 @@ int srs_chunk_header_c3( | @@ -287,3 +288,61 @@ int srs_chunk_header_c3( | ||
287 | return p - cache; | 288 | return p - cache; |
288 | } | 289 | } |
289 | 290 | ||
291 | +int __srs_rtmp_create_msg(char type, u_int32_t timestamp, char* data, int size, int stream_id, SrsSharedPtrMessage** ppmsg) | ||
292 | +{ | ||
293 | + int ret = ERROR_SUCCESS; | ||
294 | + | ||
295 | + *ppmsg = NULL; | ||
296 | + SrsSharedPtrMessage* msg = NULL; | ||
297 | + | ||
298 | + if (type == SrsCodecFlvTagAudio) { | ||
299 | + SrsMessageHeader header; | ||
300 | + header.initialize_audio(size, timestamp, stream_id); | ||
301 | + | ||
302 | + msg = new SrsSharedPtrMessage(); | ||
303 | + if ((ret = msg->create(&header, data, size)) != ERROR_SUCCESS) { | ||
304 | + srs_freep(msg); | ||
305 | + return ret; | ||
306 | + } | ||
307 | + } else if (type == SrsCodecFlvTagVideo) { | ||
308 | + SrsMessageHeader header; | ||
309 | + header.initialize_video(size, timestamp, stream_id); | ||
310 | + | ||
311 | + msg = new SrsSharedPtrMessage(); | ||
312 | + if ((ret = msg->create(&header, data, size)) != ERROR_SUCCESS) { | ||
313 | + srs_freep(msg); | ||
314 | + return ret; | ||
315 | + } | ||
316 | + } else if (type == SrsCodecFlvTagScript) { | ||
317 | + SrsMessageHeader header; | ||
318 | + header.initialize_amf0_script(size, stream_id); | ||
319 | + | ||
320 | + msg = new SrsSharedPtrMessage(); | ||
321 | + if ((ret = msg->create(&header, data, size)) != ERROR_SUCCESS) { | ||
322 | + srs_freep(msg); | ||
323 | + return ret; | ||
324 | + } | ||
325 | + } else { | ||
326 | + ret = ERROR_STREAM_CASTER_FLV_TAG; | ||
327 | + srs_error("rtmp unknown tag type=%#x. ret=%d", type, ret); | ||
328 | + return ret; | ||
329 | + } | ||
330 | + | ||
331 | + *ppmsg = msg; | ||
332 | + | ||
333 | + return ret; | ||
334 | +} | ||
335 | + | ||
336 | +int srs_rtmp_create_msg(char type, u_int32_t timestamp, char* data, int size, int stream_id, SrsSharedPtrMessage** ppmsg) | ||
337 | +{ | ||
338 | + int ret = ERROR_SUCCESS; | ||
339 | + | ||
340 | + // only when failed, we must free the data. | ||
341 | + if ((ret = __srs_rtmp_create_msg(type, timestamp, data, size, stream_id, ppmsg)) != ERROR_SUCCESS) { | ||
342 | + srs_freep(data); | ||
343 | + return ret; | ||
344 | + } | ||
345 | + | ||
346 | + return ret; | ||
347 | +} | ||
348 | + |
@@ -34,6 +34,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | @@ -34,6 +34,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
34 | #include <srs_kernel_consts.hpp> | 34 | #include <srs_kernel_consts.hpp> |
35 | 35 | ||
36 | class SrsMessageHeader; | 36 | class SrsMessageHeader; |
37 | +class SrsSharedPtrMessage; | ||
37 | 38 | ||
38 | /** | 39 | /** |
39 | * parse the tcUrl, output the schema, host, vhost, app and port. | 40 | * parse the tcUrl, output the schema, host, vhost, app and port. |
@@ -110,5 +111,12 @@ extern int srs_chunk_header_c3( | @@ -110,5 +111,12 @@ extern int srs_chunk_header_c3( | ||
110 | char* cache, int nb_cache | 111 | char* cache, int nb_cache |
111 | ); | 112 | ); |
112 | 113 | ||
114 | +/** | ||
115 | +* create shared ptr message from bytes. | ||
116 | +* @param data the packet bytes. user should never free it. | ||
117 | +* @param ppmsg output the shared ptr message. user should free it. | ||
118 | +*/ | ||
119 | +extern int srs_rtmp_create_msg(char type, u_int32_t timestamp, char* data, int size, int stream_id, SrsSharedPtrMessage** ppmsg); | ||
120 | + | ||
113 | #endif | 121 | #endif |
114 | 122 |
-
请 注册 或 登录 后发表评论