正在显示
7 个修改的文件
包含
441 行增加
和
9 行删除
| @@ -50,6 +50,7 @@ url: rtmp://127.0.0.1:1935/live/livestream | @@ -50,6 +50,7 @@ url: rtmp://127.0.0.1:1935/live/livestream | ||
| 50 | * nginx v1.5.0: 139524 lines <br/> | 50 | * nginx v1.5.0: 139524 lines <br/> |
| 51 | 51 | ||
| 52 | ### History | 52 | ### History |
| 53 | +* v0.5, 2013-11-24, support write ts file. | ||
| 53 | * v0.5, 2013-11-21, add ts_info tool to demux ts file. | 54 | * v0.5, 2013-11-21, add ts_info tool to demux ts file. |
| 54 | * v0.5, 2013-11-16, add rtmp players(OSMF/jwplayer5/jwplayer6). | 55 | * v0.5, 2013-11-16, add rtmp players(OSMF/jwplayer5/jwplayer6). |
| 55 | * v0.4, 2013-11-10, v0.4 released. 12500 lines. | 56 | * v0.4, 2013-11-10, v0.4 released. 12500 lines. |
trunk/configure
100644 → 100755
| @@ -24,12 +24,35 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | @@ -24,12 +24,35 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
| 24 | #include <srs_core_codec.hpp> | 24 | #include <srs_core_codec.hpp> |
| 25 | 25 | ||
| 26 | #include <string.h> | 26 | #include <string.h> |
| 27 | +#include <stdlib.h> | ||
| 27 | 28 | ||
| 28 | #include <srs_core_error.hpp> | 29 | #include <srs_core_error.hpp> |
| 29 | #include <srs_core_stream.hpp> | 30 | #include <srs_core_stream.hpp> |
| 30 | #include <srs_core_log.hpp> | 31 | #include <srs_core_log.hpp> |
| 31 | #include <srs_core_autofree.hpp> | 32 | #include <srs_core_autofree.hpp> |
| 32 | 33 | ||
| 34 | +SrsCodecBuffer::SrsCodecBuffer() | ||
| 35 | +{ | ||
| 36 | + size = 0; | ||
| 37 | + bytes = NULL; | ||
| 38 | +} | ||
| 39 | + | ||
| 40 | +void SrsCodecBuffer::append(void* data, int len) | ||
| 41 | +{ | ||
| 42 | + srs_assert(data); | ||
| 43 | + srs_assert(len > 0); | ||
| 44 | + | ||
| 45 | + bytes = (char*)realloc(bytes, size + len); | ||
| 46 | + memcpy(bytes + size, data, len); | ||
| 47 | + size += len; | ||
| 48 | +} | ||
| 49 | + | ||
| 50 | +void SrsCodecBuffer::free() | ||
| 51 | +{ | ||
| 52 | + size = 0; | ||
| 53 | + srs_freepa(bytes); | ||
| 54 | +} | ||
| 55 | + | ||
| 33 | SrsCodecSample::SrsCodecSample() | 56 | SrsCodecSample::SrsCodecSample() |
| 34 | { | 57 | { |
| 35 | clear(); | 58 | clear(); |
| @@ -83,8 +106,11 @@ SrsCodec::SrsCodec() | @@ -83,8 +106,11 @@ SrsCodec::SrsCodec() | ||
| 83 | video_codec_id = 0; | 106 | video_codec_id = 0; |
| 84 | audio_data_rate = 0; | 107 | audio_data_rate = 0; |
| 85 | audio_codec_id = 0; | 108 | audio_codec_id = 0; |
| 86 | - profile = 0; | ||
| 87 | - level = 0; | 109 | + avc_profile = 0; |
| 110 | + avc_level = 0; | ||
| 111 | + aac_profile = 0; | ||
| 112 | + aac_sample_rate = 0; | ||
| 113 | + aac_channels = 0; | ||
| 88 | avc_extra_size = 0; | 114 | avc_extra_size = 0; |
| 89 | avc_extra_data = NULL; | 115 | avc_extra_data = NULL; |
| 90 | aac_extra_size = 0; | 116 | aac_extra_size = 0; |
| @@ -160,6 +186,39 @@ int SrsCodec::audio_aac_demux(int8_t* data, int size, SrsCodecSample* sample) | @@ -160,6 +186,39 @@ int SrsCodec::audio_aac_demux(int8_t* data, int size, SrsCodecSample* sample) | ||
| 160 | aac_extra_data = new char[aac_extra_size]; | 186 | aac_extra_data = new char[aac_extra_size]; |
| 161 | memcpy(aac_extra_data, stream->current(), aac_extra_size); | 187 | memcpy(aac_extra_data, stream->current(), aac_extra_size); |
| 162 | } | 188 | } |
| 189 | + | ||
| 190 | + // only need to decode the first 2bytes: | ||
| 191 | + // audioObjectType, aac_profile, 5bits. | ||
| 192 | + // samplingFrequencyIndex, aac_sample_rate, 4bits. | ||
| 193 | + // channelConfiguration, aac_channels, 4bits | ||
| 194 | + if (!stream->require(2)) { | ||
| 195 | + ret = ERROR_HLS_DECODE_ERROR; | ||
| 196 | + srs_error("hls decode audio aac sequence header failed. ret=%d", ret); | ||
| 197 | + return ret; | ||
| 198 | + } | ||
| 199 | + aac_profile = stream->read_1bytes(); | ||
| 200 | + aac_sample_rate = stream->read_1bytes(); | ||
| 201 | + | ||
| 202 | + aac_channels = (aac_sample_rate >> 3) & 0x0f; | ||
| 203 | + aac_sample_rate = ((aac_profile << 1) & 0x0e) | ((aac_sample_rate >> 7) & 0x01); | ||
| 204 | + aac_profile = (aac_profile >> 3) & 0x1f; | ||
| 205 | + | ||
| 206 | + if (aac_profile == 0 || aac_profile == 0x1f) { | ||
| 207 | + ret = ERROR_HLS_DECODE_ERROR; | ||
| 208 | + srs_error("hls decode audio aac sequence header failed, " | ||
| 209 | + "adts object=%d invalid. ret=%d", aac_profile, ret); | ||
| 210 | + return ret; | ||
| 211 | + } | ||
| 212 | + | ||
| 213 | + // aac_profile = audioObjectType - 1 | ||
| 214 | + aac_profile--; | ||
| 215 | + | ||
| 216 | + if (aac_profile > 3) { | ||
| 217 | + // Mark all extended profiles as LC | ||
| 218 | + // to make Android as happy as possible. | ||
| 219 | + // @see: ngx_rtmp_hls_parse_aac_header | ||
| 220 | + aac_profile = 1; | ||
| 221 | + } | ||
| 163 | } else if (aac_packet_type == SrsCodecAudioTypeRawData) { | 222 | } else if (aac_packet_type == SrsCodecAudioTypeRawData) { |
| 164 | // ensure the sequence header demuxed | 223 | // ensure the sequence header demuxed |
| 165 | if (aac_extra_size <= 0 || !aac_extra_data) { | 224 | if (aac_extra_size <= 0 || !aac_extra_data) { |
| @@ -181,8 +181,21 @@ enum SrsCodecAudioSoundType | @@ -181,8 +181,21 @@ enum SrsCodecAudioSoundType | ||
| 181 | */ | 181 | */ |
| 182 | struct SrsCodecBuffer | 182 | struct SrsCodecBuffer |
| 183 | { | 183 | { |
| 184 | + /** | ||
| 185 | + * @remark user must manage the bytes. | ||
| 186 | + */ | ||
| 184 | int size; | 187 | int size; |
| 185 | char* bytes; | 188 | char* bytes; |
| 189 | + | ||
| 190 | + SrsCodecBuffer(); | ||
| 191 | + void append(void* data, int len); | ||
| 192 | + | ||
| 193 | + /** | ||
| 194 | + * free the bytes, | ||
| 195 | + * user can invoke it to free the bytes, | ||
| 196 | + * the SrsCodecBuffer never free automatically. | ||
| 197 | + */ | ||
| 198 | + void free(); | ||
| 186 | }; | 199 | }; |
| 187 | 200 | ||
| 188 | /** | 201 | /** |
| @@ -227,9 +240,9 @@ public: | @@ -227,9 +240,9 @@ public: | ||
| 227 | // @see: SrsCodecVideo | 240 | // @see: SrsCodecVideo |
| 228 | int video_codec_id; | 241 | int video_codec_id; |
| 229 | // profile_idc, H.264-AVC-ISO_IEC_14496-10.pdf, page 45. | 242 | // profile_idc, H.264-AVC-ISO_IEC_14496-10.pdf, page 45. |
| 230 | - u_int8_t profile; | 243 | + u_int8_t avc_profile; |
| 231 | // level_idc, H.264-AVC-ISO_IEC_14496-10.pdf, page 45. | 244 | // level_idc, H.264-AVC-ISO_IEC_14496-10.pdf, page 45. |
| 232 | - u_int8_t level; | 245 | + u_int8_t avc_level; |
| 233 | int width; | 246 | int width; |
| 234 | int height; | 247 | int height; |
| 235 | int video_data_rate; // in bps | 248 | int video_data_rate; // in bps |
| @@ -243,6 +256,13 @@ public: | @@ -243,6 +256,13 @@ public: | ||
| 243 | // @see: SrsCodecAudioType | 256 | // @see: SrsCodecAudioType |
| 244 | int audio_codec_id; | 257 | int audio_codec_id; |
| 245 | int audio_data_rate; // in bps | 258 | int audio_data_rate; // in bps |
| 259 | + // 1.6.2.1 AudioSpecificConfig, in aac-mp4a-format-ISO_IEC_14496-3+2001.pdf, page 33. | ||
| 260 | + // audioObjectType, value defines in 7.1 Profiles, aac-iso-13818-7.pdf, page 40. | ||
| 261 | + u_int8_t aac_profile; | ||
| 262 | + // samplingFrequencyIndex | ||
| 263 | + u_int8_t aac_sample_rate; | ||
| 264 | + // channelConfiguration | ||
| 265 | + u_int8_t aac_channels; | ||
| 246 | // the avc extra data, the AVC sequence header, | 266 | // the avc extra data, the AVC sequence header, |
| 247 | // without the flv codec header, | 267 | // without the flv codec header, |
| 248 | // @see: ffmpeg, AVCodecContext::extradata | 268 | // @see: ffmpeg, AVCodecContext::extradata |
| @@ -112,5 +112,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | @@ -112,5 +112,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
| 112 | #define ERROR_HLS_BUSY 602 | 112 | #define ERROR_HLS_BUSY 602 |
| 113 | #define ERROR_HLS_OPEN_FAILED 603 | 113 | #define ERROR_HLS_OPEN_FAILED 603 |
| 114 | #define ERROR_HLS_WRITE_FAILED 604 | 114 | #define ERROR_HLS_WRITE_FAILED 604 |
| 115 | +#define ERROR_HLS_AAC_FRAME_LENGTH 605 | ||
| 116 | +#define ERROR_HLS_AVC_SAMPLE_SIZE 606 | ||
| 115 | 117 | ||
| 116 | #endif | 118 | #endif |
| @@ -26,6 +26,8 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | @@ -26,6 +26,8 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
| 26 | #include <sys/types.h> | 26 | #include <sys/types.h> |
| 27 | #include <sys/stat.h> | 27 | #include <sys/stat.h> |
| 28 | #include <fcntl.h> | 28 | #include <fcntl.h> |
| 29 | +#include <stdlib.h> | ||
| 30 | +#include <string.h> | ||
| 29 | 31 | ||
| 30 | #include <srs_core_error.hpp> | 32 | #include <srs_core_error.hpp> |
| 31 | #include <srs_core_codec.hpp> | 33 | #include <srs_core_codec.hpp> |
| @@ -275,18 +277,249 @@ u_int8_t mpegts_header[] = { | @@ -275,18 +277,249 @@ u_int8_t mpegts_header[] = { | ||
| 275 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff | 277 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff |
| 276 | }; | 278 | }; |
| 277 | 279 | ||
| 280 | +// @see: NGX_RTMP_HLS_DELAY, 700ms, ts_tbn=90000 | ||
| 281 | +#define SRS_HLS_DELAY 63000 | ||
| 282 | + | ||
| 283 | +// @see: ngx_rtmp_mpegts.c | ||
| 284 | +// TODO: support full mpegts feature in future. | ||
| 285 | +class SrsMpegtsWriter | ||
| 286 | +{ | ||
| 287 | +public: | ||
| 288 | + static int write_header(int fd) | ||
| 289 | + { | ||
| 290 | + int ret = ERROR_SUCCESS; | ||
| 291 | + | ||
| 292 | + if (::write(fd, mpegts_header, sizeof(mpegts_header)) != sizeof(mpegts_header)) { | ||
| 293 | + ret = ERROR_HLS_WRITE_FAILED; | ||
| 294 | + srs_error("write ts file header failed. ret=%d", ret); | ||
| 295 | + return ret; | ||
| 296 | + } | ||
| 297 | + | ||
| 298 | + return ret; | ||
| 299 | + } | ||
| 300 | + static int write_frame(int fd, mpegts_frame* frame, SrsCodecBuffer* buffer) | ||
| 301 | + { | ||
| 302 | + int ret = ERROR_SUCCESS; | ||
| 303 | + | ||
| 304 | + char* last = buffer->bytes + buffer->size; | ||
| 305 | + char* pos = buffer->bytes; | ||
| 306 | + | ||
| 307 | + bool first = true; | ||
| 308 | + while (pos < last) { | ||
| 309 | + static char packet[188]; | ||
| 310 | + char* p = packet; | ||
| 311 | + | ||
| 312 | + frame->cc++; | ||
| 313 | + | ||
| 314 | + // sync_byte; //8bits | ||
| 315 | + *p++ = 0x47; | ||
| 316 | + // pid; //13bits | ||
| 317 | + *p++ = (frame->pid >> 8) & 0x1f; | ||
| 318 | + // payload_unit_start_indicator; //1bit | ||
| 319 | + if (first) { | ||
| 320 | + p[-1] |= 0x40; | ||
| 321 | + } | ||
| 322 | + *p++ = frame->pid; | ||
| 323 | + | ||
| 324 | + // transport_scrambling_control; //2bits | ||
| 325 | + // adaption_field_control; //2bits, 0x01: PayloadOnly | ||
| 326 | + // continuity_counter; //4bits | ||
| 327 | + *p++ = 0x10 | (frame->cc & 0x0f); | ||
| 328 | + | ||
| 329 | + if (first) { | ||
| 330 | + first = false; | ||
| 331 | + if (frame->key) { | ||
| 332 | + p[-1] |= 0x20; // Both Adaption and Payload | ||
| 333 | + *p++ = 7; // size | ||
| 334 | + *p++ = 0x50; // random access + PCR | ||
| 335 | + p = write_pcr(p, frame->dts - SRS_HLS_DELAY); | ||
| 336 | + } | ||
| 337 | + | ||
| 338 | + // PES header | ||
| 339 | + // packet_start_code_prefix; //24bits, '00 00 01' | ||
| 340 | + *p++ = 0x00; | ||
| 341 | + *p++ = 0x00; | ||
| 342 | + *p++ = 0x01; | ||
| 343 | + //8bits | ||
| 344 | + *p++ = frame->sid; | ||
| 345 | + | ||
| 346 | + // pts(33bits) need 5bytes. | ||
| 347 | + u_int8_t header_size = 5; | ||
| 348 | + u_int8_t flags = 0x80; // pts | ||
| 349 | + | ||
| 350 | + // dts(33bits) need 5bytes also | ||
| 351 | + if (frame->dts != frame->pts) { | ||
| 352 | + header_size += 5; | ||
| 353 | + flags |= 0x40; // dts | ||
| 354 | + } | ||
| 355 | + | ||
| 356 | + // 3bytes: flag fields from PES_packet_length to PES_header_data_length | ||
| 357 | + int pes_size = (last - pos) + header_size + 3; | ||
| 358 | + if (pes_size > 0xffff) { | ||
| 359 | + /** | ||
| 360 | + * when actual packet length > 0xffff(65535), | ||
| 361 | + * which exceed the max u_int16_t packet length, | ||
| 362 | + * use 0 packet length, the next unit start indicates the end of packet. | ||
| 363 | + */ | ||
| 364 | + pes_size = 0; | ||
| 365 | + } | ||
| 366 | + | ||
| 367 | + // PES_packet_length; //16bits | ||
| 368 | + *p++ = (pes_size >> 8); | ||
| 369 | + *p++ = pes_size; | ||
| 370 | + | ||
| 371 | + // PES_scrambling_control; //2bits, '10' | ||
| 372 | + // PES_priority; //1bit | ||
| 373 | + // data_alignment_indicator; //1bit | ||
| 374 | + // copyright; //1bit | ||
| 375 | + // original_or_copy; //1bit | ||
| 376 | + *p++ = 0x80; /* H222 */ | ||
| 377 | + | ||
| 378 | + // PTS_DTS_flags; //2bits | ||
| 379 | + // ESCR_flag; //1bit | ||
| 380 | + // ES_rate_flag; //1bit | ||
| 381 | + // DSM_trick_mode_flag; //1bit | ||
| 382 | + // additional_copy_info_flag; //1bit | ||
| 383 | + // PES_CRC_flag; //1bit | ||
| 384 | + // PES_extension_flag; //1bit | ||
| 385 | + *p++ = flags; | ||
| 386 | + | ||
| 387 | + // PES_header_data_length; //8bits | ||
| 388 | + *p++ = header_size; | ||
| 389 | + | ||
| 390 | + // pts; // 33bits | ||
| 391 | + p = write_pts(p, flags >> 6, frame->pts + SRS_HLS_DELAY); | ||
| 392 | + | ||
| 393 | + // dts; // 33bits | ||
| 394 | + if (frame->dts != frame->pts) { | ||
| 395 | + p = write_pts(p, 1, frame->dts + SRS_HLS_DELAY); | ||
| 396 | + } | ||
| 397 | + } | ||
| 398 | + | ||
| 399 | + int body_size = sizeof(packet) - (p - packet); | ||
| 400 | + int in_size = last - pos; | ||
| 401 | + | ||
| 402 | + if (body_size <= in_size) { | ||
| 403 | + memcpy(p, pos, body_size); | ||
| 404 | + pos += body_size; | ||
| 405 | + } else { | ||
| 406 | + p = fill_stuff(p, packet, body_size, in_size); | ||
| 407 | + memcpy(p, pos, in_size); | ||
| 408 | + pos = last; | ||
| 409 | + } | ||
| 410 | + | ||
| 411 | + // write ts packet | ||
| 412 | + if (::write(fd, packet, sizeof(packet)) != sizeof(packet)) { | ||
| 413 | + ret = ERROR_HLS_WRITE_FAILED; | ||
| 414 | + srs_error("write ts file failed. ret=%d", ret); | ||
| 415 | + return ret; | ||
| 416 | + } | ||
| 417 | + } | ||
| 418 | + | ||
| 419 | + // write success, clear and free the buffer | ||
| 420 | + buffer->free(); | ||
| 421 | + | ||
| 422 | + return ret; | ||
| 423 | + } | ||
| 424 | +private: | ||
| 425 | + static char* fill_stuff(char* pes_body_end, char* packet, int body_size, int in_size) | ||
| 426 | + { | ||
| 427 | + char* p = pes_body_end; | ||
| 428 | + | ||
| 429 | + // insert the stuff bytes before PES body | ||
| 430 | + int stuff_size = (body_size - in_size); | ||
| 431 | + | ||
| 432 | + // adaption_field_control; //2bits | ||
| 433 | + if (packet[3] & 0x20) { | ||
| 434 | + // has adaptation | ||
| 435 | + // packet[4]: adaption_field_length | ||
| 436 | + // packet[5]: adaption field data | ||
| 437 | + // base: start of PES body | ||
| 438 | + char* base = &packet[5] + packet[4]; | ||
| 439 | + int len = p - base; | ||
| 440 | + p = (char*)memmove(base + stuff_size, base, len) + len; | ||
| 441 | + // increase the adaption field size. | ||
| 442 | + packet[4] += stuff_size; | ||
| 443 | + | ||
| 444 | + return p; | ||
| 445 | + } | ||
| 446 | + | ||
| 447 | + // create adaption field. | ||
| 448 | + // adaption_field_control; //2bits | ||
| 449 | + packet[3] |= 0x20; | ||
| 450 | + // base: start of PES body | ||
| 451 | + char* base = &packet[4]; | ||
| 452 | + int len = p - base; | ||
| 453 | + p = (char*)memmove(base + stuff_size, base, len) + len; | ||
| 454 | + // adaption_field_length; //8bits | ||
| 455 | + packet[4] = (stuff_size - 1); | ||
| 456 | + if (stuff_size >= 2) { | ||
| 457 | + // adaption field flags. | ||
| 458 | + packet[5] = 0; | ||
| 459 | + // adaption data. | ||
| 460 | + if (stuff_size > 2) { | ||
| 461 | + memset(&packet[6], 0xff, stuff_size - 2); | ||
| 462 | + } | ||
| 463 | + } | ||
| 464 | + | ||
| 465 | + return p; | ||
| 466 | + } | ||
| 467 | + static char* write_pcr(char* p, int64_t pcr) | ||
| 468 | + { | ||
| 469 | + *p++ = (char) (pcr >> 25); | ||
| 470 | + *p++ = (char) (pcr >> 17); | ||
| 471 | + *p++ = (char) (pcr >> 9); | ||
| 472 | + *p++ = (char) (pcr >> 1); | ||
| 473 | + *p++ = (char) (pcr << 7 | 0x7e); | ||
| 474 | + *p++ = 0; | ||
| 475 | + | ||
| 476 | + return p; | ||
| 477 | + } | ||
| 478 | + static char* write_pts(char* p, u_int8_t fb, int64_t pts) | ||
| 479 | + { | ||
| 480 | + int32_t val; | ||
| 481 | + | ||
| 482 | + val = fb << 4 | (((pts >> 30) & 0x07) << 1) | 1; | ||
| 483 | + *p++ = val; | ||
| 484 | + | ||
| 485 | + val = (((pts >> 15) & 0x7fff) << 1) | 1; | ||
| 486 | + *p++ = (val >> 8); | ||
| 487 | + *p++ = val; | ||
| 488 | + | ||
| 489 | + val = (((pts) & 0x7fff) << 1) | 1; | ||
| 490 | + *p++ = (val >> 8); | ||
| 491 | + *p++ = val; | ||
| 492 | + | ||
| 493 | + return p; | ||
| 494 | + } | ||
| 495 | +}; | ||
| 496 | + | ||
| 278 | // the mpegts header specifed the video/audio pid. | 497 | // the mpegts header specifed the video/audio pid. |
| 279 | #define TS_VIDEO_PID 256 | 498 | #define TS_VIDEO_PID 256 |
| 280 | #define TS_AUDIO_PID 257 | 499 | #define TS_AUDIO_PID 257 |
| 281 | 500 | ||
| 501 | +// ts aac stream id. | ||
| 502 | +#define TS_AUDIO_AAC 0xc0 | ||
| 503 | +// ts avc stream id. | ||
| 504 | +#define TS_VIDEO_AVC 0xe0 | ||
| 505 | + | ||
| 282 | SrsTSMuxer::SrsTSMuxer() | 506 | SrsTSMuxer::SrsTSMuxer() |
| 283 | { | 507 | { |
| 284 | fd = -1; | 508 | fd = -1; |
| 509 | + | ||
| 510 | + audio_buffer = new SrsCodecBuffer(); | ||
| 511 | + video_buffer = new SrsCodecBuffer(); | ||
| 285 | } | 512 | } |
| 286 | 513 | ||
| 287 | SrsTSMuxer::~SrsTSMuxer() | 514 | SrsTSMuxer::~SrsTSMuxer() |
| 288 | { | 515 | { |
| 289 | close(); | 516 | close(); |
| 517 | + | ||
| 518 | + audio_buffer->free(); | ||
| 519 | + video_buffer->free(); | ||
| 520 | + | ||
| 521 | + srs_freep(audio_buffer); | ||
| 522 | + srs_freep(video_buffer); | ||
| 290 | } | 523 | } |
| 291 | 524 | ||
| 292 | int SrsTSMuxer::open(std::string _path) | 525 | int SrsTSMuxer::open(std::string _path) |
| @@ -306,9 +539,7 @@ int SrsTSMuxer::open(std::string _path) | @@ -306,9 +539,7 @@ int SrsTSMuxer::open(std::string _path) | ||
| 306 | } | 539 | } |
| 307 | 540 | ||
| 308 | // write mpegts header | 541 | // write mpegts header |
| 309 | - if (::write(fd, mpegts_header, sizeof(mpegts_header)) != sizeof(mpegts_header)) { | ||
| 310 | - ret = ERROR_HLS_WRITE_FAILED; | ||
| 311 | - srs_error("write ts file header %s failed. ret=%d", path.c_str(), ret); | 542 | + if ((ret = SrsMpegtsWriter::write_header(fd)) != ERROR_SUCCESS) { |
| 312 | return ret; | 543 | return ret; |
| 313 | } | 544 | } |
| 314 | 545 | ||
| @@ -319,7 +550,64 @@ int SrsTSMuxer::write_audio(u_int32_t time, SrsCodec* codec, SrsCodecSample* sam | @@ -319,7 +550,64 @@ int SrsTSMuxer::write_audio(u_int32_t time, SrsCodec* codec, SrsCodecSample* sam | ||
| 319 | { | 550 | { |
| 320 | int ret = ERROR_SUCCESS; | 551 | int ret = ERROR_SUCCESS; |
| 321 | 552 | ||
| 322 | - static u_int8_t packet[188]; | 553 | + for (int i = 0; i < sample->nb_buffers; i++) { |
| 554 | + SrsCodecBuffer* buf = &sample->buffers[i]; | ||
| 555 | + int32_t size = buf->size; | ||
| 556 | + | ||
| 557 | + if (!buf->bytes || size <= 0 || size > 0x1fff) { | ||
| 558 | + ret = ERROR_HLS_AAC_FRAME_LENGTH; | ||
| 559 | + srs_error("invalid aac frame length=%d, ret=%d", size, ret); | ||
| 560 | + return ret; | ||
| 561 | + } | ||
| 562 | + | ||
| 563 | + // AAC-ADTS | ||
| 564 | + // 6.2 Audio Data Transport Stream, ADTS | ||
| 565 | + // in aac-iso-13818-7.pdf, page 26. | ||
| 566 | + // fixed 7bytes header | ||
| 567 | + static u_int8_t adts_header[7] = {0xff, 0xf1, 0x00, 0x00, 0x00, 0x0f, 0xfc}; | ||
| 568 | + /* | ||
| 569 | + // adts_fixed_header | ||
| 570 | + // 2B, 16bits | ||
| 571 | + int16_t syncword; //12bits, '1111 1111 1111' | ||
| 572 | + int8_t ID; //1bit, '0' | ||
| 573 | + int8_t layer; //2bits, '00' | ||
| 574 | + int8_t protection_absent; //1bit, can be '1' | ||
| 575 | + // 12bits | ||
| 576 | + int8_t profile; //2bit, 7.1 Profiles, page 40 | ||
| 577 | + TSAacSampleFrequency sampling_frequency_index; //4bits, Table 35, page 46 | ||
| 578 | + int8_t private_bit; //1bit, can be '0' | ||
| 579 | + int8_t channel_configuration; //3bits, Table 8 | ||
| 580 | + int8_t original_or_copy; //1bit, can be '0' | ||
| 581 | + int8_t home; //1bit, can be '0' | ||
| 582 | + | ||
| 583 | + // adts_variable_header | ||
| 584 | + // 28bits | ||
| 585 | + int8_t copyright_identification_bit; //1bit, can be '0' | ||
| 586 | + int8_t copyright_identification_start; //1bit, can be '0' | ||
| 587 | + int16_t frame_length; //13bits | ||
| 588 | + int16_t adts_buffer_fullness; //11bits, 7FF signals that the bitstream is a variable rate bitstream. | ||
| 589 | + int8_t number_of_raw_data_blocks_in_frame; //2bits, 0 indicating 1 raw_data_block() | ||
| 590 | + */ | ||
| 591 | + // profile, 2bits | ||
| 592 | + adts_header[2] = (codec->aac_profile << 6) & 0xc0; | ||
| 593 | + // sampling_frequency_index 4bits | ||
| 594 | + adts_header[2] |= (codec->aac_sample_rate << 2) & 0x3c; | ||
| 595 | + // channel_configuration 3bits | ||
| 596 | + adts_header[2] |= (codec->aac_channels >> 1) & 0x01; | ||
| 597 | + adts_header[3] = (codec->aac_channels << 5) & 0xc0; | ||
| 598 | + // frame_length 13bits | ||
| 599 | + adts_header[3] |= (size >> 11) & 0x03; | ||
| 600 | + adts_header[4] = (size >> 3) & 0xff; | ||
| 601 | + adts_header[5] = (size << 5) & 0xcf; | ||
| 602 | + | ||
| 603 | + // copy to audio buffer | ||
| 604 | + audio_buffer->append(adts_header, sizeof(adts_header)); | ||
| 605 | + audio_buffer->append(buf->bytes, buf->size); | ||
| 606 | + } | ||
| 607 | + | ||
| 608 | + audio_frame.dts = audio_frame.pts = time * 90; | ||
| 609 | + audio_frame.pid = TS_AUDIO_PID; | ||
| 610 | + audio_frame.sid = TS_AUDIO_AAC; | ||
| 323 | 611 | ||
| 324 | return ret; | 612 | return ret; |
| 325 | } | 613 | } |
| @@ -328,7 +616,45 @@ int SrsTSMuxer::write_video(u_int32_t time, SrsCodec* codec, SrsCodecSample* sam | @@ -328,7 +616,45 @@ int SrsTSMuxer::write_video(u_int32_t time, SrsCodec* codec, SrsCodecSample* sam | ||
| 328 | { | 616 | { |
| 329 | int ret = ERROR_SUCCESS; | 617 | int ret = ERROR_SUCCESS; |
| 330 | 618 | ||
| 331 | - static u_int8_t packet[188]; | 619 | + static u_int8_t aud_nal[] = { 0x00, 0x00, 0x00, 0x01, 0x09, 0xf0 }; |
| 620 | + video_buffer->append(aud_nal, sizeof(aud_nal)); | ||
| 621 | + | ||
| 622 | + for (int i = 0; i < sample->nb_buffers; i++) { | ||
| 623 | + SrsCodecBuffer* buf = &sample->buffers[i]; | ||
| 624 | + int32_t size = buf->size; | ||
| 625 | + | ||
| 626 | + if (!buf->bytes || size <= 0) { | ||
| 627 | + ret = ERROR_HLS_AVC_SAMPLE_SIZE; | ||
| 628 | + srs_error("invalid avc sample length=%d, ret=%d", size, ret); | ||
| 629 | + return ret; | ||
| 630 | + } | ||
| 631 | + | ||
| 632 | + // sample start prefix, '00 00 00 01' or '00 00 01' | ||
| 633 | + u_int8_t* p = aud_nal + 1; | ||
| 634 | + u_int8_t* end = p + 3; | ||
| 635 | + | ||
| 636 | + // first AnnexB prefix is long (4 bytes) | ||
| 637 | + if (i == 0) { | ||
| 638 | + p = aud_nal; | ||
| 639 | + } | ||
| 640 | + video_buffer->append(p, end - p); | ||
| 641 | + | ||
| 642 | + // sample data | ||
| 643 | + video_buffer->append(buf->bytes, buf->size); | ||
| 644 | + } | ||
| 645 | + | ||
| 646 | + video_frame.dts = time * 90; | ||
| 647 | + video_frame.pts = video_frame.dts + sample->cts * 90; | ||
| 648 | + video_frame.pid = TS_VIDEO_PID; | ||
| 649 | + video_frame.sid = TS_VIDEO_AVC; | ||
| 650 | + video_frame.key = sample->frame_type == SrsCodecVideoAVCFrameKeyFrame; | ||
| 651 | + | ||
| 652 | + if ((ret = SrsMpegtsWriter::write_frame(fd, &video_frame, video_buffer)) != ERROR_SUCCESS) { | ||
| 653 | + return ret; | ||
| 654 | + } | ||
| 655 | + if ((ret = SrsMpegtsWriter::write_frame(fd, &audio_frame, audio_buffer)) != ERROR_SUCCESS) { | ||
| 656 | + return ret; | ||
| 657 | + } | ||
| 332 | 658 | ||
| 333 | return ret; | 659 | return ret; |
| 334 | } | 660 | } |
| @@ -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 | class SrsOnMetaDataPacket; | 34 | class SrsOnMetaDataPacket; |
| 35 | class SrsCommonMessage; | 35 | class SrsCommonMessage; |
| 36 | class SrsCodecSample; | 36 | class SrsCodecSample; |
| 37 | +class SrsCodecBuffer; | ||
| 37 | class SrsTSMuxer; | 38 | class SrsTSMuxer; |
| 38 | class SrsCodec; | 39 | class SrsCodec; |
| 39 | 40 | ||
| @@ -56,11 +57,34 @@ public: | @@ -56,11 +57,34 @@ public: | ||
| 56 | virtual int on_video(SrsCommonMessage* video); | 57 | virtual int on_video(SrsCommonMessage* video); |
| 57 | }; | 58 | }; |
| 58 | 59 | ||
| 60 | +// @see: ngx_rtmp_mpegts_frame_t | ||
| 61 | +struct mpegts_frame | ||
| 62 | +{ | ||
| 63 | + int64_t pts; | ||
| 64 | + int64_t dts; | ||
| 65 | + int pid; | ||
| 66 | + int sid; | ||
| 67 | + int cc; | ||
| 68 | + bool key; | ||
| 69 | + | ||
| 70 | + mpegts_frame() | ||
| 71 | + { | ||
| 72 | + pts = dts = 0; | ||
| 73 | + pid = sid = cc = 0; | ||
| 74 | + key = false; | ||
| 75 | + } | ||
| 76 | +}; | ||
| 77 | + | ||
| 59 | class SrsTSMuxer | 78 | class SrsTSMuxer |
| 60 | { | 79 | { |
| 61 | private: | 80 | private: |
| 62 | int fd; | 81 | int fd; |
| 63 | std::string path; | 82 | std::string path; |
| 83 | +private: | ||
| 84 | + mpegts_frame audio_frame; | ||
| 85 | + SrsCodecBuffer* audio_buffer; | ||
| 86 | + mpegts_frame video_frame; | ||
| 87 | + SrsCodecBuffer* video_buffer; | ||
| 64 | public: | 88 | public: |
| 65 | SrsTSMuxer(); | 89 | SrsTSMuxer(); |
| 66 | virtual ~SrsTSMuxer(); | 90 | virtual ~SrsTSMuxer(); |
-
请 注册 或 登录 后发表评论