正在显示
7 个修改的文件
包含
505 行增加
和
249 行删除
@@ -486,7 +486,7 @@ Supported operating systems and hardware: | @@ -486,7 +486,7 @@ Supported operating systems and hardware: | ||
486 | ). | 486 | ). |
487 | 1. Support HLS(h.264+mp3) streaming, read | 487 | 1. Support HLS(h.264+mp3) streaming, read |
488 | [#301](https://github.com/winlinvip/simple-rtmp-server/issues/301). | 488 | [#301](https://github.com/winlinvip/simple-rtmp-server/issues/301). |
489 | -1. [dev] Support push MPEG-TS over UDP to SRS, read | 489 | +1. Support push MPEG-TS over UDP to SRS, read |
490 | [#250](https://github.com/winlinvip/simple-rtmp-server/issues/250). | 490 | [#250](https://github.com/winlinvip/simple-rtmp-server/issues/250). |
491 | 1. [no-plan] Support <500ms latency, FRSC(Fast RTMP-compatible Stream Channel tech). | 491 | 1. [no-plan] Support <500ms latency, FRSC(Fast RTMP-compatible Stream Channel tech). |
492 | 1. [no-plan] Support RTMP 302 redirect [#92](https://github.com/winlinvip/simple-rtmp-server/issues/92). | 492 | 1. [no-plan] Support RTMP 302 redirect [#92](https://github.com/winlinvip/simple-rtmp-server/issues/92). |
@@ -525,6 +525,7 @@ Supported operating systems and hardware: | @@ -525,6 +525,7 @@ Supported operating systems and hardware: | ||
525 | 525 | ||
526 | ### SRS 2.0 history | 526 | ### SRS 2.0 history |
527 | 527 | ||
528 | +* v2.0, 2015-01-31, for [#250](https://github.com/winlinvip/simple-rtmp-server/issues/250), support push MPEGTS over UDP to SRS. 2.0.111 | ||
528 | * v2.0, 2015-01-29, build libfdk-aac in ffmpeg. 2.0.108 | 529 | * v2.0, 2015-01-29, build libfdk-aac in ffmpeg. 2.0.108 |
529 | * v2.0, 2015-01-25, for [#301](https://github.com/winlinvip/simple-rtmp-server/issues/301), hls support h.264+mp3, ok for vlc. 2.0.107 | 530 | * v2.0, 2015-01-25, for [#301](https://github.com/winlinvip/simple-rtmp-server/issues/301), hls support h.264+mp3, ok for vlc. 2.0.107 |
530 | * v2.0, 2015-01-25, for [#301](https://github.com/winlinvip/simple-rtmp-server/issues/301), http ts stream support h.264+mp3. 2.0.106 | 531 | * v2.0, 2015-01-25, for [#301](https://github.com/winlinvip/simple-rtmp-server/issues/301), http ts stream support h.264+mp3. 2.0.106 |
@@ -76,10 +76,20 @@ int SrsMpegtsQueue::push(SrsSharedPtrMessage* msg) | @@ -76,10 +76,20 @@ int SrsMpegtsQueue::push(SrsSharedPtrMessage* msg) | ||
76 | { | 76 | { |
77 | int ret = ERROR_SUCCESS; | 77 | int ret = ERROR_SUCCESS; |
78 | 78 | ||
79 | - if (msgs.find(msg->timestamp) != msgs.end()) { | ||
80 | - srs_warn("mpegts: free the msg for dts exists, dts=%"PRId64, msg->timestamp); | ||
81 | - srs_freep(msg); | ||
82 | - return ret; | 79 | + // TODO: FIXME: use right way. |
80 | + for (int i = 0; i < 10; i++) { | ||
81 | + if (msgs.find(msg->timestamp) == msgs.end()) { | ||
82 | + break; | ||
83 | + } | ||
84 | + | ||
85 | + // adjust the ts, add 1ms. | ||
86 | + msg->timestamp += 1; | ||
87 | + | ||
88 | + if (i >= 5) { | ||
89 | + srs_warn("mpegts: free the msg for dts exists, dts=%"PRId64, msg->timestamp); | ||
90 | + srs_freep(msg); | ||
91 | + return ret; | ||
92 | + } | ||
83 | } | 93 | } |
84 | 94 | ||
85 | if (msg->is_audio()) { | 95 | if (msg->is_audio()) { |
@@ -114,6 +124,8 @@ SrsSharedPtrMessage* SrsMpegtsQueue::dequeue() | @@ -114,6 +124,8 @@ SrsSharedPtrMessage* SrsMpegtsQueue::dequeue() | ||
114 | if (msg->is_video()) { | 124 | if (msg->is_video()) { |
115 | nb_videos--; | 125 | nb_videos--; |
116 | } | 126 | } |
127 | + | ||
128 | + return msg; | ||
117 | } | 129 | } |
118 | 130 | ||
119 | return NULL; | 131 | return NULL; |
@@ -131,6 +143,7 @@ SrsMpegtsOverUdp::SrsMpegtsOverUdp(SrsConfDirective* c) | @@ -131,6 +143,7 @@ SrsMpegtsOverUdp::SrsMpegtsOverUdp(SrsConfDirective* c) | ||
131 | stfd = NULL; | 143 | stfd = NULL; |
132 | stream_id = 0; | 144 | stream_id = 0; |
133 | avc = new SrsRawH264Stream(); | 145 | avc = new SrsRawH264Stream(); |
146 | + aac = new SrsRawAacStream(); | ||
134 | h264_sps_changed = false; | 147 | h264_sps_changed = false; |
135 | h264_pps_changed = false; | 148 | h264_pps_changed = false; |
136 | h264_sps_pps_sent = false; | 149 | h264_sps_pps_sent = false; |
@@ -145,6 +158,7 @@ SrsMpegtsOverUdp::~SrsMpegtsOverUdp() | @@ -145,6 +158,7 @@ SrsMpegtsOverUdp::~SrsMpegtsOverUdp() | ||
145 | srs_freep(stream); | 158 | srs_freep(stream); |
146 | srs_freep(context); | 159 | srs_freep(context); |
147 | srs_freep(avc); | 160 | srs_freep(avc); |
161 | + srs_freep(aac); | ||
148 | srs_freep(queue); | 162 | srs_freep(queue); |
149 | } | 163 | } |
150 | 164 | ||
@@ -309,6 +323,9 @@ int SrsMpegtsOverUdp::on_ts_message(SrsTsMessage* msg) | @@ -309,6 +323,9 @@ int SrsMpegtsOverUdp::on_ts_message(SrsTsMessage* msg) | ||
309 | if (msg->channel->stream == SrsTsStreamVideoH264) { | 323 | if (msg->channel->stream == SrsTsStreamVideoH264) { |
310 | return on_ts_video(msg, &avs); | 324 | return on_ts_video(msg, &avs); |
311 | } | 325 | } |
326 | + if (msg->channel->stream == SrsTsStreamAudioAAC) { | ||
327 | + return on_ts_audio(msg, &avs); | ||
328 | + } | ||
312 | 329 | ||
313 | // TODO: FIXME: implements it. | 330 | // TODO: FIXME: implements it. |
314 | return ret; | 331 | return ret; |
@@ -326,6 +343,10 @@ int SrsMpegtsOverUdp::on_ts_video(SrsTsMessage* msg, SrsStream* avs) | @@ -326,6 +343,10 @@ int SrsMpegtsOverUdp::on_ts_video(SrsTsMessage* msg, SrsStream* avs) | ||
326 | // ts tbn to flv tbn. | 343 | // ts tbn to flv tbn. |
327 | u_int32_t dts = msg->dts / 90; | 344 | u_int32_t dts = msg->dts / 90; |
328 | u_int32_t pts = msg->dts / 90; | 345 | u_int32_t pts = msg->dts / 90; |
346 | + | ||
347 | + // the whole ts pes video packet must be a flv frame packet. | ||
348 | + char* ibpframe = avs->data() + avs->pos(); | ||
349 | + int ibpframe_size = avs->size() - avs->pos(); | ||
329 | 350 | ||
330 | // send each frame. | 351 | // send each frame. |
331 | while (!avs->empty()) { | 352 | while (!avs->empty()) { |
@@ -342,59 +363,50 @@ int SrsMpegtsOverUdp::on_ts_video(SrsTsMessage* msg, SrsStream* avs) | @@ -342,59 +363,50 @@ int SrsMpegtsOverUdp::on_ts_video(SrsTsMessage* msg, SrsStream* avs) | ||
342 | continue; | 363 | continue; |
343 | } | 364 | } |
344 | 365 | ||
345 | - // it may be return error, but we must process all packets. | ||
346 | - if ((ret = write_h264_raw_frame(frame, frame_size, dts, pts)) != ERROR_SUCCESS) { | ||
347 | - if (ret == ERROR_H264_DROP_BEFORE_SPS_PPS) { | 366 | + // for sps |
367 | + if (avc->is_sps(frame, frame_size)) { | ||
368 | + std::string sps; | ||
369 | + if ((ret = avc->sps_demux(frame, frame_size, sps)) != ERROR_SUCCESS) { | ||
370 | + return ret; | ||
371 | + } | ||
372 | + | ||
373 | + if (h264_sps == sps) { | ||
348 | continue; | 374 | continue; |
349 | } | 375 | } |
350 | - return ret; | ||
351 | - } | ||
352 | - | ||
353 | - // for video, drop others with same pts/dts. | ||
354 | - break; | ||
355 | - } | ||
356 | - | ||
357 | - return ret; | ||
358 | -} | ||
359 | - | ||
360 | -int SrsMpegtsOverUdp::write_h264_raw_frame(char* frame, int frame_size, u_int32_t dts, u_int32_t pts) | ||
361 | -{ | ||
362 | - int ret = ERROR_SUCCESS; | ||
363 | - | ||
364 | - // for sps | ||
365 | - if (avc->is_sps(frame, frame_size)) { | ||
366 | - std::string sps; | ||
367 | - if ((ret = avc->sps_demux(frame, frame_size, sps)) != ERROR_SUCCESS) { | ||
368 | - return ret; | ||
369 | - } | 376 | + h264_sps_changed = true; |
377 | + h264_sps = sps; | ||
370 | 378 | ||
371 | - if (h264_sps == sps) { | ||
372 | - return ret; | 379 | + if ((ret = write_h264_sps_pps(dts, pts)) != ERROR_SUCCESS) { |
380 | + return ret; | ||
381 | + } | ||
382 | + continue; | ||
373 | } | 383 | } |
374 | - h264_sps_changed = true; | ||
375 | - h264_sps = sps; | ||
376 | - | ||
377 | - return write_h264_sps_pps(dts, pts); | ||
378 | - } | ||
379 | 384 | ||
380 | - // for pps | ||
381 | - if (avc->is_pps(frame, frame_size)) { | ||
382 | - std::string pps; | ||
383 | - if ((ret = avc->pps_demux(frame, frame_size, pps)) != ERROR_SUCCESS) { | ||
384 | - return ret; | ||
385 | - } | 385 | + // for pps |
386 | + if (avc->is_pps(frame, frame_size)) { | ||
387 | + std::string pps; | ||
388 | + if ((ret = avc->pps_demux(frame, frame_size, pps)) != ERROR_SUCCESS) { | ||
389 | + return ret; | ||
390 | + } | ||
386 | 391 | ||
387 | - if (h264_pps == pps) { | ||
388 | - return ret; | ||
389 | - } | ||
390 | - h264_pps_changed = true; | ||
391 | - h264_pps = pps; | 392 | + if (h264_pps == pps) { |
393 | + continue; | ||
394 | + } | ||
395 | + h264_pps_changed = true; | ||
396 | + h264_pps = pps; | ||
392 | 397 | ||
393 | - return write_h264_sps_pps(dts, pts); | 398 | + if ((ret = write_h264_sps_pps(dts, pts)) != ERROR_SUCCESS) { |
399 | + return ret; | ||
400 | + } | ||
401 | + continue; | ||
402 | + } | ||
403 | + | ||
404 | + break; | ||
394 | } | 405 | } |
395 | 406 | ||
396 | // ibp frame. | 407 | // ibp frame. |
397 | - return write_h264_ipb_frame(frame, frame_size, dts, pts); | 408 | + srs_info("mpegts: demux avc ibp frame size=%d, dts=%d", ibpframe_size, dts); |
409 | + return write_h264_ipb_frame(ibpframe, ibpframe_size, dts, pts); | ||
398 | } | 410 | } |
399 | 411 | ||
400 | int SrsMpegtsOverUdp::write_h264_sps_pps(u_int32_t dts, u_int32_t pts) | 412 | int SrsMpegtsOverUdp::write_h264_sps_pps(u_int32_t dts, u_int32_t pts) |
@@ -421,14 +433,18 @@ int SrsMpegtsOverUdp::write_h264_sps_pps(u_int32_t dts, u_int32_t pts) | @@ -421,14 +433,18 @@ int SrsMpegtsOverUdp::write_h264_sps_pps(u_int32_t dts, u_int32_t pts) | ||
421 | return ret; | 433 | return ret; |
422 | } | 434 | } |
423 | 435 | ||
436 | + // the timestamp in rtmp message header is dts. | ||
437 | + u_int32_t timestamp = dts; | ||
438 | + if ((ret = rtmp_write_packet(SrsCodecFlvTagVideo, timestamp, flv, nb_flv)) != ERROR_SUCCESS) { | ||
439 | + return ret; | ||
440 | + } | ||
441 | + | ||
424 | // reset sps and pps. | 442 | // reset sps and pps. |
425 | h264_sps_changed = false; | 443 | h264_sps_changed = false; |
426 | h264_pps_changed = false; | 444 | h264_pps_changed = false; |
427 | h264_sps_pps_sent = true; | 445 | h264_sps_pps_sent = true; |
428 | - | ||
429 | - // the timestamp in rtmp message header is dts. | ||
430 | - u_int32_t timestamp = dts; | ||
431 | - return rtmp_write_packet(SrsCodecFlvTagVideo, timestamp, flv, nb_flv); | 446 | + |
447 | + return ret; | ||
432 | } | 448 | } |
433 | 449 | ||
434 | int SrsMpegtsOverUdp::write_h264_ipb_frame(char* frame, int frame_size, u_int32_t dts, u_int32_t pts) | 450 | int SrsMpegtsOverUdp::write_h264_ipb_frame(char* frame, int frame_size, u_int32_t dts, u_int32_t pts) |
@@ -459,6 +475,72 @@ int SrsMpegtsOverUdp::write_h264_ipb_frame(char* frame, int frame_size, u_int32_ | @@ -459,6 +475,72 @@ int SrsMpegtsOverUdp::write_h264_ipb_frame(char* frame, int frame_size, u_int32_ | ||
459 | return rtmp_write_packet(SrsCodecFlvTagVideo, timestamp, flv, nb_flv); | 475 | return rtmp_write_packet(SrsCodecFlvTagVideo, timestamp, flv, nb_flv); |
460 | } | 476 | } |
461 | 477 | ||
478 | +int SrsMpegtsOverUdp::on_ts_audio(SrsTsMessage* msg, SrsStream* avs) | ||
479 | +{ | ||
480 | + int ret = ERROR_SUCCESS; | ||
481 | + | ||
482 | + // ensure rtmp connected. | ||
483 | + if ((ret = connect()) != ERROR_SUCCESS) { | ||
484 | + return ret; | ||
485 | + } | ||
486 | + | ||
487 | + // ts tbn to flv tbn. | ||
488 | + u_int32_t dts = msg->dts / 90; | ||
489 | + | ||
490 | + // send each frame. | ||
491 | + while (!avs->empty()) { | ||
492 | + char* frame = NULL; | ||
493 | + int frame_size = 0; | ||
494 | + SrsRawAacStreamCodec codec; | ||
495 | + if ((ret = aac->adts_demux(avs, &frame, &frame_size, codec)) != ERROR_SUCCESS) { | ||
496 | + return ret; | ||
497 | + } | ||
498 | + | ||
499 | + // ignore invalid frame, | ||
500 | + // * atleast 1bytes for aac to decode the data. | ||
501 | + if (frame_size <= 0) { | ||
502 | + continue; | ||
503 | + } | ||
504 | + srs_info("mpegts: demux aac frame size=%d, dts=%d", frame_size, dts); | ||
505 | + | ||
506 | + // generate sh. | ||
507 | + if (aac_specific_config.empty()) { | ||
508 | + std::string sh; | ||
509 | + if ((ret = aac->mux_sequence_header(&codec, sh)) != ERROR_SUCCESS) { | ||
510 | + return ret; | ||
511 | + } | ||
512 | + aac_specific_config = sh; | ||
513 | + | ||
514 | + codec.aac_packet_type = 0; | ||
515 | + | ||
516 | + if ((ret = write_audio_raw_frame((char*)sh.data(), (int)sh.length(), &codec, dts)) != ERROR_SUCCESS) { | ||
517 | + return ret; | ||
518 | + } | ||
519 | + } | ||
520 | + | ||
521 | + // audio raw data. | ||
522 | + codec.aac_packet_type = 1; | ||
523 | + if ((ret = write_audio_raw_frame(frame, frame_size, &codec, dts)) != ERROR_SUCCESS) { | ||
524 | + return ret; | ||
525 | + } | ||
526 | + } | ||
527 | + | ||
528 | + return ret; | ||
529 | +} | ||
530 | + | ||
531 | +int SrsMpegtsOverUdp::write_audio_raw_frame(char* frame, int frame_size, SrsRawAacStreamCodec* codec, u_int32_t dts) | ||
532 | +{ | ||
533 | + int ret = ERROR_SUCCESS; | ||
534 | + | ||
535 | + char* data = NULL; | ||
536 | + int size = 0; | ||
537 | + if ((ret = aac->mux_aac2flv(frame, frame_size, codec, dts, &data, &size)) != ERROR_SUCCESS) { | ||
538 | + return ret; | ||
539 | + } | ||
540 | + | ||
541 | + return rtmp_write_packet(SrsCodecFlvTagAudio, dts, data, size); | ||
542 | +} | ||
543 | + | ||
462 | int SrsMpegtsOverUdp::rtmp_write_packet(char type, u_int32_t timestamp, char* data, int size) | 544 | int SrsMpegtsOverUdp::rtmp_write_packet(char type, u_int32_t timestamp, char* data, int size) |
463 | { | 545 | { |
464 | int ret = ERROR_SUCCESS; | 546 | int ret = ERROR_SUCCESS; |
@@ -482,6 +564,10 @@ int SrsMpegtsOverUdp::rtmp_write_packet(char type, u_int32_t timestamp, char* da | @@ -482,6 +564,10 @@ int SrsMpegtsOverUdp::rtmp_write_packet(char type, u_int32_t timestamp, char* da | ||
482 | if ((msg = queue->dequeue()) == NULL) { | 564 | if ((msg = queue->dequeue()) == NULL) { |
483 | break; | 565 | break; |
484 | } | 566 | } |
567 | + | ||
568 | + // TODO: FIXME: use pithy print. | ||
569 | + srs_info("mpegts: send msg %s dts=%"PRId64", size=%d", | ||
570 | + msg->is_audio()? "A":msg->is_video()? "V":"N", msg->timestamp, msg->size); | ||
485 | 571 | ||
486 | // send out encoded msg. | 572 | // send out encoded msg. |
487 | if ((ret = client->send_and_free_message(msg, stream_id)) != ERROR_SUCCESS) { | 573 | if ((ret = client->send_and_free_message(msg, stream_id)) != ERROR_SUCCESS) { |
@@ -45,6 +45,8 @@ class SrsStSocket; | @@ -45,6 +45,8 @@ class SrsStSocket; | ||
45 | class SrsRequest; | 45 | class SrsRequest; |
46 | class SrsRawH264Stream; | 46 | class SrsRawH264Stream; |
47 | class SrsSharedPtrMessage; | 47 | class SrsSharedPtrMessage; |
48 | +class SrsRawAacStream; | ||
49 | +class SrsRawAacStreamCodec; | ||
48 | 50 | ||
49 | #include <srs_app_st.hpp> | 51 | #include <srs_app_st.hpp> |
50 | #include <srs_kernel_ts.hpp> | 52 | #include <srs_kernel_ts.hpp> |
@@ -114,6 +116,10 @@ private: | @@ -114,6 +116,10 @@ private: | ||
114 | std::string h264_pps; | 116 | std::string h264_pps; |
115 | bool h264_pps_changed; | 117 | bool h264_pps_changed; |
116 | bool h264_sps_pps_sent; | 118 | bool h264_sps_pps_sent; |
119 | +private: | ||
120 | + SrsRawAacStream* aac; | ||
121 | + std::string aac_specific_config; | ||
122 | +private: | ||
117 | SrsMpegtsQueue* queue; | 123 | SrsMpegtsQueue* queue; |
118 | public: | 124 | public: |
119 | SrsMpegtsOverUdp(SrsConfDirective* c); | 125 | SrsMpegtsOverUdp(SrsConfDirective* c); |
@@ -126,9 +132,11 @@ public: | @@ -126,9 +132,11 @@ public: | ||
126 | virtual int on_ts_message(SrsTsMessage* msg); | 132 | virtual int on_ts_message(SrsTsMessage* msg); |
127 | private: | 133 | private: |
128 | virtual int on_ts_video(SrsTsMessage* msg, SrsStream* avs); | 134 | virtual int on_ts_video(SrsTsMessage* msg, SrsStream* avs); |
129 | - virtual int write_h264_raw_frame(char* frame, int frame_size, u_int32_t dts, u_int32_t pts); | ||
130 | virtual int write_h264_sps_pps(u_int32_t dts, u_int32_t pts); | 135 | virtual int write_h264_sps_pps(u_int32_t dts, u_int32_t pts); |
131 | virtual int write_h264_ipb_frame(char* frame, int frame_size, u_int32_t dts, u_int32_t pts); | 136 | virtual int write_h264_ipb_frame(char* frame, int frame_size, u_int32_t dts, u_int32_t pts); |
137 | + virtual int on_ts_audio(SrsTsMessage* msg, SrsStream* avs); | ||
138 | + virtual int write_audio_raw_frame(char* frame, int frame_size, SrsRawAacStreamCodec* codec, u_int32_t dts); | ||
139 | +private: | ||
132 | virtual int rtmp_write_packet(char type, u_int32_t timestamp, char* data, int size); | 140 | virtual int rtmp_write_packet(char type, u_int32_t timestamp, char* data, int size); |
133 | private: | 141 | private: |
134 | // connect to rtmp output url. | 142 | // connect to rtmp output url. |
@@ -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 110 | 34 | +#define VERSION_REVISION 111 |
35 | 35 | ||
36 | // server info. | 36 | // server info. |
37 | #define RTMP_SIG_SRS_KEY "SRS" | 37 | #define RTMP_SIG_SRS_KEY "SRS" |
@@ -81,9 +81,10 @@ struct Context | @@ -81,9 +81,10 @@ struct Context | ||
81 | SimpleSocketStream* skt; | 81 | SimpleSocketStream* skt; |
82 | int stream_id; | 82 | int stream_id; |
83 | 83 | ||
84 | - // for h264 raw stream, | ||
85 | - // @see: https://github.com/winlinvip/simple-rtmp-server/issues/66#issuecomment-62240521 | 84 | + // the remux raw codec. |
86 | SrsRawH264Stream avc_raw; | 85 | SrsRawH264Stream avc_raw; |
86 | + SrsRawAacStream aac_raw; | ||
87 | + | ||
87 | // for h264 raw stream, | 88 | // for h264 raw stream, |
88 | // @see: https://github.com/winlinvip/simple-rtmp-server/issues/66#issuecomment-62240521 | 89 | // @see: https://github.com/winlinvip/simple-rtmp-server/issues/66#issuecomment-62240521 |
89 | SrsStream h264_raw_stream; | 90 | SrsStream h264_raw_stream; |
@@ -1073,106 +1074,44 @@ srs_bool srs_rtmp_is_onMetaData(char type, char* data, int size) | @@ -1073,106 +1074,44 @@ srs_bool srs_rtmp_is_onMetaData(char type, char* data, int size) | ||
1073 | * directly write a audio frame. | 1074 | * directly write a audio frame. |
1074 | */ | 1075 | */ |
1075 | int __srs_write_audio_raw_frame(Context* context, | 1076 | int __srs_write_audio_raw_frame(Context* context, |
1076 | - char sound_format, char sound_rate, char sound_size, char sound_type, | ||
1077 | - char aac_packet_type, char* frame, int frame_size, u_int32_t timestamp | 1077 | + char* frame, int frame_size, SrsRawAacStreamCodec* codec, u_int32_t timestamp |
1078 | ) { | 1078 | ) { |
1079 | - | ||
1080 | - // for audio frame, there is 1 or 2 bytes header: | ||
1081 | - // 1bytes, SoundFormat|SoundRate|SoundSize|SoundType | ||
1082 | - // 1bytes, AACPacketType for SoundFormat == 10, 0 is sequence header. | ||
1083 | - int size = frame_size + 1; | ||
1084 | - if (sound_format == SrsCodecAudioAAC) { | ||
1085 | - size += 1; | ||
1086 | - } | ||
1087 | - char* data = new char[size]; | ||
1088 | - char* p = data; | ||
1089 | - | ||
1090 | - u_int8_t audio_header = sound_type & 0x01; | ||
1091 | - audio_header |= (sound_size << 1) & 0x02; | ||
1092 | - audio_header |= (sound_rate << 2) & 0x0c; | ||
1093 | - audio_header |= (sound_format << 4) & 0xf0; | ||
1094 | - | ||
1095 | - *p++ = audio_header; | ||
1096 | - | ||
1097 | - if (sound_format == SrsCodecAudioAAC) { | ||
1098 | - *p++ = aac_packet_type; | 1079 | + int ret = ERROR_SUCCESS; |
1080 | + | ||
1081 | + char* data = NULL; | ||
1082 | + int size = 0; | ||
1083 | + if ((ret = context->aac_raw.mux_aac2flv(frame, frame_size, codec, timestamp, &data, &size)) != ERROR_SUCCESS) { | ||
1084 | + return ret; | ||
1099 | } | 1085 | } |
1100 | 1086 | ||
1101 | - memcpy(p, frame, frame_size); | ||
1102 | - | ||
1103 | return srs_rtmp_write_packet(context, SRS_RTMP_TYPE_AUDIO, timestamp, data, size); | 1087 | return srs_rtmp_write_packet(context, SRS_RTMP_TYPE_AUDIO, timestamp, data, size); |
1104 | } | 1088 | } |
1105 | 1089 | ||
1106 | /** | 1090 | /** |
1107 | * write aac frame in adts. | 1091 | * write aac frame in adts. |
1108 | */ | 1092 | */ |
1109 | -int __srs_write_aac_adts_frame(Context* context, | ||
1110 | - char sound_format, char sound_rate, char sound_size, char sound_type, | ||
1111 | - char aac_profile, char aac_samplerate, char aac_channel, | ||
1112 | - char* frame, int frame_size, u_int32_t timestamp | 1093 | +int __srs_write_aac_adts_frame(Context* context, |
1094 | + SrsRawAacStreamCodec* codec, char* frame, int frame_size, u_int32_t timestamp | ||
1113 | ) { | 1095 | ) { |
1114 | int ret = ERROR_SUCCESS; | 1096 | int ret = ERROR_SUCCESS; |
1115 | 1097 | ||
1116 | - // override the aac samplerate by user specified. | ||
1117 | - // @see https://github.com/winlinvip/simple-rtmp-server/issues/212#issuecomment-64146899 | ||
1118 | - switch (sound_rate) { | ||
1119 | - case SrsCodecAudioSampleRate11025: | ||
1120 | - aac_samplerate = 0x0a; break; | ||
1121 | - case SrsCodecAudioSampleRate22050: | ||
1122 | - aac_samplerate = 0x07; break; | ||
1123 | - case SrsCodecAudioSampleRate44100: | ||
1124 | - aac_samplerate = 0x04; break; | ||
1125 | - default: | ||
1126 | - break; | ||
1127 | - } | ||
1128 | - | ||
1129 | // send out aac sequence header if not sent. | 1098 | // send out aac sequence header if not sent. |
1130 | if (context->aac_specific_config.empty()) { | 1099 | if (context->aac_specific_config.empty()) { |
1131 | - char ch = 0; | ||
1132 | - // @see aac-mp4a-format-ISO_IEC_14496-3+2001.pdf | ||
1133 | - // AudioSpecificConfig (), page 33 | ||
1134 | - // 1.6.2.1 AudioSpecificConfig | ||
1135 | - // audioObjectType; 5 bslbf | ||
1136 | - ch = (aac_profile << 3) & 0xf8; | ||
1137 | - // 3bits left. | ||
1138 | - | ||
1139 | - // samplingFrequencyIndex; 4 bslbf | ||
1140 | - ch |= (aac_samplerate >> 1) & 0x07; | ||
1141 | - context->aac_specific_config += ch; | ||
1142 | - ch = (aac_samplerate << 7) & 0x80; | ||
1143 | - if (aac_samplerate == 0x0f) { | ||
1144 | - return ERROR_AAC_DATA_INVALID; | ||
1145 | - } | ||
1146 | - // 7bits left. | ||
1147 | - | ||
1148 | - // channelConfiguration; 4 bslbf | ||
1149 | - ch |= (aac_channel << 3) & 0x78; | ||
1150 | - // 3bits left. | ||
1151 | - | ||
1152 | - // only support aac profile 1-4. | ||
1153 | - if (aac_profile < 1 || aac_profile > 4) { | ||
1154 | - return ERROR_AAC_DATA_INVALID; | 1100 | + std::string sh; |
1101 | + if ((ret = context->aac_raw.mux_sequence_header(codec, sh)) != ERROR_SUCCESS) { | ||
1102 | + return ret; | ||
1155 | } | 1103 | } |
1156 | - // GASpecificConfig(), page 451 | ||
1157 | - // 4.4.1 Decoder configuration (GASpecificConfig) | ||
1158 | - // frameLengthFlag; 1 bslbf | ||
1159 | - // dependsOnCoreCoder; 1 bslbf | ||
1160 | - // extensionFlag; 1 bslbf | ||
1161 | - context->aac_specific_config += ch; | ||
1162 | - | ||
1163 | - char* sh = (char*)context->aac_specific_config.data(); | ||
1164 | - int nb_sh = (int)context->aac_specific_config.length(); | ||
1165 | - if ((ret = __srs_write_audio_raw_frame(context, | ||
1166 | - sound_format, sound_rate, sound_size, sound_type, | ||
1167 | - 0, sh, nb_sh, timestamp)) != ERROR_SUCCESS | ||
1168 | - ) { | 1104 | + context->aac_specific_config = sh; |
1105 | + | ||
1106 | + codec->aac_packet_type = 0; | ||
1107 | + | ||
1108 | + if ((ret = __srs_write_audio_raw_frame(context, (char*)sh.data(), (int)sh.length(), codec, timestamp)) != ERROR_SUCCESS) { | ||
1169 | return ret; | 1109 | return ret; |
1170 | } | 1110 | } |
1171 | } | 1111 | } |
1172 | 1112 | ||
1173 | - return __srs_write_audio_raw_frame(context, | ||
1174 | - sound_format, sound_rate, sound_size, sound_type, | ||
1175 | - 1, frame, frame_size, timestamp); | 1113 | + codec->aac_packet_type = 1; |
1114 | + return __srs_write_audio_raw_frame(context, frame, frame_size, codec, timestamp); | ||
1176 | } | 1115 | } |
1177 | 1116 | ||
1178 | /** | 1117 | /** |
@@ -1180,126 +1119,32 @@ int __srs_write_aac_adts_frame(Context* context, | @@ -1180,126 +1119,32 @@ int __srs_write_aac_adts_frame(Context* context, | ||
1180 | */ | 1119 | */ |
1181 | int __srs_write_aac_adts_frames(Context* context, | 1120 | int __srs_write_aac_adts_frames(Context* context, |
1182 | char sound_format, char sound_rate, char sound_size, char sound_type, | 1121 | char sound_format, char sound_rate, char sound_size, char sound_type, |
1183 | - char* frame, int frame_size, u_int32_t timestamp | 1122 | + char* frames, int frames_size, u_int32_t timestamp |
1184 | ) { | 1123 | ) { |
1185 | int ret = ERROR_SUCCESS; | 1124 | int ret = ERROR_SUCCESS; |
1186 | 1125 | ||
1187 | SrsStream* stream = &context->aac_raw_stream; | 1126 | SrsStream* stream = &context->aac_raw_stream; |
1188 | - if ((ret = stream->initialize(frame, frame_size)) != ERROR_SUCCESS) { | 1127 | + if ((ret = stream->initialize(frames, frames_size)) != ERROR_SUCCESS) { |
1189 | return ret; | 1128 | return ret; |
1190 | } | 1129 | } |
1191 | 1130 | ||
1192 | while (!stream->empty()) { | 1131 | while (!stream->empty()) { |
1193 | - int adts_header_start = stream->pos(); | ||
1194 | - | ||
1195 | - // decode the ADTS. | ||
1196 | - // @see aac-mp4a-format-ISO_IEC_14496-3+2001.pdf, page 75, | ||
1197 | - // 1.A.2.2 Audio_Data_Transport_Stream frame, ADTS | ||
1198 | - // @see https://github.com/winlinvip/simple-rtmp-server/issues/212#issuecomment-64145885 | ||
1199 | - // byte_alignment() | ||
1200 | - | ||
1201 | - // adts_fixed_header: | ||
1202 | - // 12bits syncword, | ||
1203 | - // 16bits left. | ||
1204 | - // adts_variable_header: | ||
1205 | - // 28bits | ||
1206 | - // 12+16+28=56bits | ||
1207 | - // adts_error_check: | ||
1208 | - // 16bits if protection_absent | ||
1209 | - // 56+16=72bits | ||
1210 | - // if protection_absent: | ||
1211 | - // require(7bytes)=56bits | ||
1212 | - // else | ||
1213 | - // require(9bytes)=72bits | ||
1214 | - if (!stream->require(7)) { | ||
1215 | - return ERROR_AAC_ADTS_HEADER; | ||
1216 | - } | ||
1217 | - | ||
1218 | - // for aac, the frame must be ADTS format. | ||
1219 | - if (!srs_aac_startswith_adts(stream)) { | ||
1220 | - return ERROR_AAC_REQUIRED_ADTS; | ||
1221 | - } | ||
1222 | - | ||
1223 | - // Syncword 12 bslbf | ||
1224 | - stream->read_1bytes(); | ||
1225 | - // 4bits left. | ||
1226 | - // adts_fixed_header(), 1.A.2.2.1 Fixed Header of ADTS | ||
1227 | - // ID 1 bslbf | ||
1228 | - // Layer 2 uimsbf | ||
1229 | - // protection_absent 1 bslbf | ||
1230 | - int8_t fh0 = (stream->read_1bytes() & 0x0f); | ||
1231 | - /*int8_t fh_id = (fh0 >> 3) & 0x01;*/ | ||
1232 | - /*int8_t fh_layer = (fh0 >> 1) & 0x03;*/ | ||
1233 | - int8_t fh_protection_absent = fh0 & 0x01; | ||
1234 | - | ||
1235 | - int16_t fh1 = stream->read_2bytes(); | ||
1236 | - // Profile_ObjectType 2 uimsbf | ||
1237 | - // sampling_frequency_index 4 uimsbf | ||
1238 | - // private_bit 1 bslbf | ||
1239 | - // channel_configuration 3 uimsbf | ||
1240 | - // original/copy 1 bslbf | ||
1241 | - // home 1 bslbf | ||
1242 | - int8_t fh_Profile_ObjectType = (fh1 >> 14) & 0x03; | ||
1243 | - int8_t fh_sampling_frequency_index = (fh1 >> 10) & 0x0f; | ||
1244 | - /*int8_t fh_private_bit = (fh1 >> 9) & 0x01;*/ | ||
1245 | - int8_t fh_channel_configuration = (fh1 >> 6) & 0x07; | ||
1246 | - /*int8_t fh_original = (fh1 >> 5) & 0x01;*/ | ||
1247 | - /*int8_t fh_home = (fh1 >> 4) & 0x01;*/ | ||
1248 | - // @remark, Emphasis is removed, | ||
1249 | - // @see https://github.com/winlinvip/simple-rtmp-server/issues/212#issuecomment-64154736 | ||
1250 | - //int8_t fh_Emphasis = (fh1 >> 2) & 0x03; | ||
1251 | - // 4bits left. | ||
1252 | - // adts_variable_header(), 1.A.2.2.2 Variable Header of ADTS | ||
1253 | - // copyright_identification_bit 1 bslbf | ||
1254 | - // copyright_identification_start 1 bslbf | ||
1255 | - /*int8_t fh_copyright_identification_bit = (fh1 >> 3) & 0x01;*/ | ||
1256 | - /*int8_t fh_copyright_identification_start = (fh1 >> 2) & 0x01;*/ | ||
1257 | - // aac_frame_length 13 bslbf: Length of the frame including headers and error_check in bytes. | ||
1258 | - // use the left 2bits as the 13 and 12 bit, | ||
1259 | - // the aac_frame_length is 13bits, so we move 13-2=11. | ||
1260 | - int16_t fh_aac_frame_length = (fh1 << 11) & 0x0800; | ||
1261 | - | ||
1262 | - int32_t fh2 = stream->read_3bytes(); | ||
1263 | - // aac_frame_length 13 bslbf: consume the first 13-2=11bits | ||
1264 | - // the fh2 is 24bits, so we move right 24-11=13. | ||
1265 | - fh_aac_frame_length |= (fh2 >> 13) & 0x07ff; | ||
1266 | - // adts_buffer_fullness 11 bslbf | ||
1267 | - /*int16_t fh_adts_buffer_fullness = (fh2 >> 2) & 0x7ff;*/ | ||
1268 | - // no_raw_data_blocks_in_frame 2 uimsbf | ||
1269 | - /*int16_t fh_no_raw_data_blocks_in_frame = fh2 & 0x03;*/ | ||
1270 | - // adts_error_check(), 1.A.2.2.3 Error detection | ||
1271 | - if (!fh_protection_absent) { | ||
1272 | - if (!stream->require(2)) { | ||
1273 | - return ERROR_AAC_ADTS_HEADER; | ||
1274 | - } | ||
1275 | - // crc_check 16 Rpchof | ||
1276 | - /*int16_t crc_check = */stream->read_2bytes(); | ||
1277 | - } | ||
1278 | - | ||
1279 | - // TODO: check the fh_sampling_frequency_index | ||
1280 | - // TODO: check the fh_channel_configuration | ||
1281 | - | ||
1282 | - // raw_data_blocks | ||
1283 | - int adts_header_size = stream->pos() - adts_header_start; | ||
1284 | - int raw_data_size = fh_aac_frame_length - adts_header_size; | ||
1285 | - if (!stream->require(raw_data_size)) { | ||
1286 | - return ERROR_AAC_ADTS_HEADER; | 1132 | + char* frame = NULL; |
1133 | + int frame_size = 0; | ||
1134 | + SrsRawAacStreamCodec codec; | ||
1135 | + if ((ret = context->aac_raw.adts_demux(stream, &frame, &frame_size, codec)) != ERROR_SUCCESS) { | ||
1136 | + return ret; | ||
1287 | } | 1137 | } |
1288 | - | ||
1289 | - // the profile = object_id + 1 | ||
1290 | - // @see aac-mp4a-format-ISO_IEC_14496-3+2001.pdf, page 78, | ||
1291 | - // Table 1. A.9 – MPEG-2 Audio profiles and MPEG-4 Audio object types | ||
1292 | - char aac_profile = fh_Profile_ObjectType + 1; | ||
1293 | - | ||
1294 | - char* raw_data = stream->data() + stream->pos(); | ||
1295 | - if ((ret = __srs_write_aac_adts_frame(context, | ||
1296 | - sound_format, sound_rate, sound_size, sound_type, | ||
1297 | - aac_profile, fh_sampling_frequency_index, fh_channel_configuration, | ||
1298 | - raw_data, raw_data_size, timestamp)) != ERROR_SUCCESS | ||
1299 | - ) { | 1138 | + |
1139 | + // override by user specified. | ||
1140 | + codec.sound_format = sound_format; | ||
1141 | + codec.sound_rate = sound_rate; | ||
1142 | + codec.sound_size = sound_size; | ||
1143 | + codec.sound_type = sound_type; | ||
1144 | + | ||
1145 | + if ((ret = __srs_write_aac_adts_frame(context, &codec, frame, frame_size, timestamp)) != ERROR_SUCCESS) { | ||
1300 | return ret; | 1146 | return ret; |
1301 | } | 1147 | } |
1302 | - stream->skip(raw_data_size); | ||
1303 | } | 1148 | } |
1304 | 1149 | ||
1305 | return ret; | 1150 | return ret; |
@@ -1328,10 +1173,16 @@ int srs_audio_write_raw_frame(srs_rtmp_t rtmp, | @@ -1328,10 +1173,16 @@ int srs_audio_write_raw_frame(srs_rtmp_t rtmp, | ||
1328 | sound_format, sound_rate, sound_size, sound_type, | 1173 | sound_format, sound_rate, sound_size, sound_type, |
1329 | frame, frame_size, timestamp); | 1174 | frame, frame_size, timestamp); |
1330 | } else { | 1175 | } else { |
1176 | + // use codec info for aac. | ||
1177 | + SrsRawAacStreamCodec codec; | ||
1178 | + codec.sound_format = sound_format; | ||
1179 | + codec.sound_rate = sound_rate; | ||
1180 | + codec.sound_size = sound_size; | ||
1181 | + codec.sound_type = sound_type; | ||
1182 | + codec.aac_packet_type = 0; | ||
1183 | + | ||
1331 | // for other data, directly write frame. | 1184 | // for other data, directly write frame. |
1332 | - return __srs_write_audio_raw_frame(context, | ||
1333 | - sound_format, sound_rate, sound_size, sound_type, | ||
1334 | - 0, frame, frame_size, timestamp); | 1185 | + return __srs_write_audio_raw_frame(context, frame, frame_size, &codec, timestamp); |
1335 | } | 1186 | } |
1336 | 1187 | ||
1337 | 1188 |
@@ -27,6 +27,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | @@ -27,6 +27,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
27 | using namespace std; | 27 | using namespace std; |
28 | 28 | ||
29 | #include <srs_kernel_error.hpp> | 29 | #include <srs_kernel_error.hpp> |
30 | +#include <srs_kernel_log.hpp> | ||
30 | #include <srs_kernel_stream.hpp> | 31 | #include <srs_kernel_stream.hpp> |
31 | #include <srs_kernel_utility.hpp> | 32 | #include <srs_kernel_utility.hpp> |
32 | #include <srs_core_autofree.hpp> | 33 | #include <srs_core_autofree.hpp> |
@@ -312,3 +313,254 @@ int SrsRawH264Stream::mux_avc2flv(string video, int8_t frame_type, int8_t avc_pa | @@ -312,3 +313,254 @@ int SrsRawH264Stream::mux_avc2flv(string video, int8_t frame_type, int8_t avc_pa | ||
312 | return ret; | 313 | return ret; |
313 | } | 314 | } |
314 | 315 | ||
316 | +SrsRawAacStream::SrsRawAacStream() | ||
317 | +{ | ||
318 | +} | ||
319 | + | ||
320 | +SrsRawAacStream::~SrsRawAacStream() | ||
321 | +{ | ||
322 | +} | ||
323 | + | ||
324 | +int SrsRawAacStream::adts_demux(SrsStream* stream, char** pframe, int* pnb_frame, SrsRawAacStreamCodec& codec) | ||
325 | +{ | ||
326 | + int ret = ERROR_SUCCESS; | ||
327 | + | ||
328 | + while (!stream->empty()) { | ||
329 | + int adts_header_start = stream->pos(); | ||
330 | + | ||
331 | + // decode the ADTS. | ||
332 | + // @see aac-mp4a-format-ISO_IEC_14496-3+2001.pdf, page 75, | ||
333 | + // 1.A.2.2 Audio_Data_Transport_Stream frame, ADTS | ||
334 | + // @see https://github.com/winlinvip/simple-rtmp-server/issues/212#issuecomment-64145885 | ||
335 | + // byte_alignment() | ||
336 | + | ||
337 | + // adts_fixed_header: | ||
338 | + // 12bits syncword, | ||
339 | + // 16bits left. | ||
340 | + // adts_variable_header: | ||
341 | + // 28bits | ||
342 | + // 12+16+28=56bits | ||
343 | + // adts_error_check: | ||
344 | + // 16bits if protection_absent | ||
345 | + // 56+16=72bits | ||
346 | + // if protection_absent: | ||
347 | + // require(7bytes)=56bits | ||
348 | + // else | ||
349 | + // require(9bytes)=72bits | ||
350 | + if (!stream->require(7)) { | ||
351 | + return ERROR_AAC_ADTS_HEADER; | ||
352 | + } | ||
353 | + | ||
354 | + // for aac, the frame must be ADTS format. | ||
355 | + if (!srs_aac_startswith_adts(stream)) { | ||
356 | + return ERROR_AAC_REQUIRED_ADTS; | ||
357 | + } | ||
358 | + | ||
359 | + // Syncword 12 bslbf | ||
360 | + stream->read_1bytes(); | ||
361 | + // 4bits left. | ||
362 | + // adts_fixed_header(), 1.A.2.2.1 Fixed Header of ADTS | ||
363 | + // ID 1 bslbf | ||
364 | + // Layer 2 uimsbf | ||
365 | + // protection_absent 1 bslbf | ||
366 | + int8_t fh0 = (stream->read_1bytes() & 0x0f); | ||
367 | + /*int8_t fh_id = (fh0 >> 3) & 0x01;*/ | ||
368 | + /*int8_t fh_layer = (fh0 >> 1) & 0x03;*/ | ||
369 | + int8_t fh_protection_absent = fh0 & 0x01; | ||
370 | + | ||
371 | + int16_t fh1 = stream->read_2bytes(); | ||
372 | + // Profile_ObjectType 2 uimsbf | ||
373 | + // sampling_frequency_index 4 uimsbf | ||
374 | + // private_bit 1 bslbf | ||
375 | + // channel_configuration 3 uimsbf | ||
376 | + // original/copy 1 bslbf | ||
377 | + // home 1 bslbf | ||
378 | + int8_t fh_Profile_ObjectType = (fh1 >> 14) & 0x03; | ||
379 | + int8_t fh_sampling_frequency_index = (fh1 >> 10) & 0x0f; | ||
380 | + /*int8_t fh_private_bit = (fh1 >> 9) & 0x01;*/ | ||
381 | + int8_t fh_channel_configuration = (fh1 >> 6) & 0x07; | ||
382 | + /*int8_t fh_original = (fh1 >> 5) & 0x01;*/ | ||
383 | + /*int8_t fh_home = (fh1 >> 4) & 0x01;*/ | ||
384 | + // @remark, Emphasis is removed, | ||
385 | + // @see https://github.com/winlinvip/simple-rtmp-server/issues/212#issuecomment-64154736 | ||
386 | + //int8_t fh_Emphasis = (fh1 >> 2) & 0x03; | ||
387 | + // 4bits left. | ||
388 | + // adts_variable_header(), 1.A.2.2.2 Variable Header of ADTS | ||
389 | + // copyright_identification_bit 1 bslbf | ||
390 | + // copyright_identification_start 1 bslbf | ||
391 | + /*int8_t fh_copyright_identification_bit = (fh1 >> 3) & 0x01;*/ | ||
392 | + /*int8_t fh_copyright_identification_start = (fh1 >> 2) & 0x01;*/ | ||
393 | + // aac_frame_length 13 bslbf: Length of the frame including headers and error_check in bytes. | ||
394 | + // use the left 2bits as the 13 and 12 bit, | ||
395 | + // the aac_frame_length is 13bits, so we move 13-2=11. | ||
396 | + int16_t fh_aac_frame_length = (fh1 << 11) & 0x0800; | ||
397 | + | ||
398 | + int32_t fh2 = stream->read_3bytes(); | ||
399 | + // aac_frame_length 13 bslbf: consume the first 13-2=11bits | ||
400 | + // the fh2 is 24bits, so we move right 24-11=13. | ||
401 | + fh_aac_frame_length |= (fh2 >> 13) & 0x07ff; | ||
402 | + // adts_buffer_fullness 11 bslbf | ||
403 | + /*int16_t fh_adts_buffer_fullness = (fh2 >> 2) & 0x7ff;*/ | ||
404 | + // no_raw_data_blocks_in_frame 2 uimsbf | ||
405 | + /*int16_t fh_no_raw_data_blocks_in_frame = fh2 & 0x03;*/ | ||
406 | + // adts_error_check(), 1.A.2.2.3 Error detection | ||
407 | + if (!fh_protection_absent) { | ||
408 | + if (!stream->require(2)) { | ||
409 | + return ERROR_AAC_ADTS_HEADER; | ||
410 | + } | ||
411 | + // crc_check 16 Rpchof | ||
412 | + /*int16_t crc_check = */stream->read_2bytes(); | ||
413 | + } | ||
414 | + | ||
415 | + // TODO: check the fh_sampling_frequency_index | ||
416 | + // TODO: check the fh_channel_configuration | ||
417 | + | ||
418 | + // raw_data_blocks | ||
419 | + int adts_header_size = stream->pos() - adts_header_start; | ||
420 | + int raw_data_size = fh_aac_frame_length - adts_header_size; | ||
421 | + if (!stream->require(raw_data_size)) { | ||
422 | + return ERROR_AAC_ADTS_HEADER; | ||
423 | + } | ||
424 | + | ||
425 | + // the profile = object_id + 1 | ||
426 | + // @see aac-mp4a-format-ISO_IEC_14496-3+2001.pdf, page 78, | ||
427 | + // Table 1. A.9 ¨C MPEG-2 Audio profiles and MPEG-4 Audio object types | ||
428 | + char aac_profile = fh_Profile_ObjectType + 1; | ||
429 | + | ||
430 | + // the codec info. | ||
431 | + codec.protection_absent = fh_protection_absent; | ||
432 | + codec.Profile_ObjectType = fh_Profile_ObjectType; | ||
433 | + codec.sampling_frequency_index = fh_sampling_frequency_index; | ||
434 | + codec.channel_configuration = fh_channel_configuration; | ||
435 | + codec.aac_frame_length = fh_aac_frame_length; | ||
436 | + | ||
437 | + codec.aac_profile = aac_profile; | ||
438 | + codec.aac_samplerate = fh_sampling_frequency_index; | ||
439 | + codec.aac_channel = fh_channel_configuration; | ||
440 | + | ||
441 | + // @see srs_audio_write_raw_frame(). | ||
442 | + codec.sound_format = 10; // AAC | ||
443 | + if (fh_sampling_frequency_index <= 0x0c && fh_sampling_frequency_index > 0x0a) { | ||
444 | + codec.sound_rate = SrsCodecAudioSampleRate5512; | ||
445 | + } else if (fh_sampling_frequency_index <= 0x0a && fh_sampling_frequency_index > 0x07) { | ||
446 | + codec.sound_rate = SrsCodecAudioSampleRate11025; | ||
447 | + } else if (fh_sampling_frequency_index <= 0x07 && fh_sampling_frequency_index > 0x04) { | ||
448 | + codec.sound_rate = SrsCodecAudioSampleRate22050; | ||
449 | + } else if (fh_sampling_frequency_index <= 0x04) { | ||
450 | + codec.sound_rate = SrsCodecAudioSampleRate44100; | ||
451 | + } else { | ||
452 | + codec.sound_rate = SrsCodecAudioSampleRate44100; | ||
453 | + srs_warn("adts invalid sample rate for flv, rate=%#x", fh_sampling_frequency_index); | ||
454 | + } | ||
455 | + codec.sound_size = srs_max(0, srs_min(1, fh_channel_configuration - 1)); | ||
456 | + // TODO: FIXME: finger it out the sound size by adts. | ||
457 | + codec.sound_size = 1; // 0(8bits) or 1(16bits). | ||
458 | + | ||
459 | + // frame data. | ||
460 | + *pframe = stream->data() + stream->pos(); | ||
461 | + *pnb_frame = raw_data_size; | ||
462 | + stream->skip(raw_data_size); | ||
463 | + | ||
464 | + break; | ||
465 | + } | ||
466 | + | ||
467 | + return ret; | ||
468 | +} | ||
469 | + | ||
470 | +int SrsRawAacStream::mux_sequence_header(SrsRawAacStreamCodec* codec, string& sh) | ||
471 | +{ | ||
472 | + int ret = ERROR_SUCCESS; | ||
473 | + | ||
474 | + char aac_channel = codec->aac_channel; | ||
475 | + char aac_profile = codec->aac_profile; | ||
476 | + char aac_samplerate = codec->aac_samplerate; | ||
477 | + | ||
478 | + // override the aac samplerate by user specified. | ||
479 | + // @see https://github.com/winlinvip/simple-rtmp-server/issues/212#issuecomment-64146899 | ||
480 | + switch (codec->sound_rate) { | ||
481 | + case SrsCodecAudioSampleRate11025: | ||
482 | + aac_samplerate = 0x0a; break; | ||
483 | + case SrsCodecAudioSampleRate22050: | ||
484 | + aac_samplerate = 0x07; break; | ||
485 | + case SrsCodecAudioSampleRate44100: | ||
486 | + aac_samplerate = 0x04; break; | ||
487 | + default: | ||
488 | + break; | ||
489 | + } | ||
490 | + | ||
491 | + sh = ""; | ||
492 | + | ||
493 | + char ch = 0; | ||
494 | + // @see aac-mp4a-format-ISO_IEC_14496-3+2001.pdf | ||
495 | + // AudioSpecificConfig (), page 33 | ||
496 | + // 1.6.2.1 AudioSpecificConfig | ||
497 | + // audioObjectType; 5 bslbf | ||
498 | + ch = (aac_profile << 3) & 0xf8; | ||
499 | + // 3bits left. | ||
500 | + | ||
501 | + // samplingFrequencyIndex; 4 bslbf | ||
502 | + ch |= (aac_samplerate >> 1) & 0x07; | ||
503 | + sh += ch; | ||
504 | + ch = (aac_samplerate << 7) & 0x80; | ||
505 | + if (aac_samplerate == 0x0f) { | ||
506 | + return ERROR_AAC_DATA_INVALID; | ||
507 | + } | ||
508 | + // 7bits left. | ||
509 | + | ||
510 | + // channelConfiguration; 4 bslbf | ||
511 | + ch |= (aac_channel << 3) & 0x78; | ||
512 | + // 3bits left. | ||
513 | + | ||
514 | + // only support aac profile 1-4. | ||
515 | + if (aac_profile < 1 || aac_profile > 4) { | ||
516 | + return ERROR_AAC_DATA_INVALID; | ||
517 | + } | ||
518 | + // GASpecificConfig(), page 451 | ||
519 | + // 4.4.1 Decoder configuration (GASpecificConfig) | ||
520 | + // frameLengthFlag; 1 bslbf | ||
521 | + // dependsOnCoreCoder; 1 bslbf | ||
522 | + // extensionFlag; 1 bslbf | ||
523 | + sh += ch; | ||
524 | + | ||
525 | + return ret; | ||
526 | +} | ||
527 | + | ||
528 | +int SrsRawAacStream::mux_aac2flv(char* frame, int nb_frame, SrsRawAacStreamCodec* codec, u_int32_t dts, char** flv, int* nb_flv) | ||
529 | +{ | ||
530 | + int ret = ERROR_SUCCESS; | ||
531 | + | ||
532 | + char sound_format = codec->sound_format; | ||
533 | + char sound_type = codec->sound_type; | ||
534 | + char sound_size = codec->sound_size; | ||
535 | + char sound_rate = codec->sound_rate; | ||
536 | + char aac_packet_type = codec->aac_packet_type; | ||
537 | + | ||
538 | + // for audio frame, there is 1 or 2 bytes header: | ||
539 | + // 1bytes, SoundFormat|SoundRate|SoundSize|SoundType | ||
540 | + // 1bytes, AACPacketType for SoundFormat == 10, 0 is sequence header. | ||
541 | + int size = nb_frame + 1; | ||
542 | + if (sound_format == SrsCodecAudioAAC) { | ||
543 | + size += 1; | ||
544 | + } | ||
545 | + char* data = new char[size]; | ||
546 | + char* p = data; | ||
547 | + | ||
548 | + u_int8_t audio_header = sound_type & 0x01; | ||
549 | + audio_header |= (sound_size << 1) & 0x02; | ||
550 | + audio_header |= (sound_rate << 2) & 0x0c; | ||
551 | + audio_header |= (sound_format << 4) & 0xf0; | ||
552 | + | ||
553 | + *p++ = audio_header; | ||
554 | + | ||
555 | + if (sound_format == SrsCodecAudioAAC) { | ||
556 | + *p++ = aac_packet_type; | ||
557 | + } | ||
558 | + | ||
559 | + memcpy(p, frame, nb_frame); | ||
560 | + | ||
561 | + *flv = data; | ||
562 | + *nb_flv = size; | ||
563 | + | ||
564 | + return ret; | ||
565 | +} | ||
566 | + |
@@ -86,4 +86,62 @@ public: | @@ -86,4 +86,62 @@ public: | ||
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); | 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 | }; | 87 | }; |
88 | 88 | ||
89 | +/** | ||
90 | +* the header of adts sample. | ||
91 | +*/ | ||
92 | +struct SrsRawAacStreamCodec | ||
93 | +{ | ||
94 | + int8_t protection_absent; | ||
95 | + int8_t Profile_ObjectType; | ||
96 | + int8_t sampling_frequency_index; | ||
97 | + int8_t channel_configuration; | ||
98 | + int16_t aac_frame_length; | ||
99 | + | ||
100 | + // calc by Profile_ObjectType+1 | ||
101 | + char aac_profile; | ||
102 | + char aac_samplerate; | ||
103 | + char aac_channel; | ||
104 | + | ||
105 | + char sound_format; | ||
106 | + char sound_rate; | ||
107 | + char sound_size; | ||
108 | + char sound_type; | ||
109 | + // 0 for sh; 1 for raw data. | ||
110 | + int8_t aac_packet_type; | ||
111 | +}; | ||
112 | + | ||
113 | +/** | ||
114 | +* the raw aac stream, in adts. | ||
115 | +*/ | ||
116 | +class SrsRawAacStream | ||
117 | +{ | ||
118 | +public: | ||
119 | + SrsRawAacStream(); | ||
120 | + virtual ~SrsRawAacStream(); | ||
121 | +public: | ||
122 | + /** | ||
123 | + * demux the stream in adts format. | ||
124 | + * @param stream the input stream bytes. | ||
125 | + * @param pframe the output aac frame in stream. user should never free it. | ||
126 | + * @param pnb_frame the output aac frame size. | ||
127 | + * @param codec the output codec info. | ||
128 | + */ | ||
129 | + virtual int adts_demux(SrsStream* stream, char** pframe, int* pnb_frame, SrsRawAacStreamCodec& codec); | ||
130 | + /** | ||
131 | + * aac raw data to aac packet, without flv payload header. | ||
132 | + * mux the aac specific config to flv sequence header packet. | ||
133 | + * @param sh output the sequence header. | ||
134 | + */ | ||
135 | + virtual int mux_sequence_header(SrsRawAacStreamCodec* codec, std::string& sh); | ||
136 | + /** | ||
137 | + * mux the aac audio packet to flv audio packet. | ||
138 | + * @param frame the aac raw data. | ||
139 | + * @param nb_frame the count of aac frame. | ||
140 | + * @param codec the codec info of aac. | ||
141 | + * @param flv output the muxed flv packet. | ||
142 | + * @param nb_flv output the muxed flv size. | ||
143 | + */ | ||
144 | + virtual int mux_aac2flv(char* frame, int nb_frame, SrsRawAacStreamCodec* codec, u_int32_t dts, char** flv, int* nb_flv); | ||
145 | +}; | ||
146 | + | ||
89 | #endif | 147 | #endif |
-
请 注册 或 登录 后发表评论