Mercurial > libavformat.hg
comparison mpegtsenc.c @ 250:2d4dcb1d3e21 libavformat
generate correct PTS in transport stream - use mpeg2 encoder by default
author | bellard |
---|---|
date | Tue, 16 Sep 2003 12:56:42 +0000 |
parents | 3d92f793fd67 |
children | 622892a75ddb |
comparison
equal
deleted
inserted
replaced
249:86232f9cd4f0 | 250:2d4dcb1d3e21 |
---|---|
183 #define DEFAULT_TSID 0x0001 | 183 #define DEFAULT_TSID 0x0001 |
184 #define DEFAULT_SID 0x0001 | 184 #define DEFAULT_SID 0x0001 |
185 | 185 |
186 /* a PES packet header is generated every DEFAULT_PES_HEADER_FREQ packets */ | 186 /* a PES packet header is generated every DEFAULT_PES_HEADER_FREQ packets */ |
187 #define DEFAULT_PES_HEADER_FREQ 16 | 187 #define DEFAULT_PES_HEADER_FREQ 16 |
188 #define DEFAULT_PES_PAYLOAD_SIZE ((DEFAULT_PES_HEADER_FREQ - 1) * 184 + 170) | |
188 | 189 |
189 /* we retransmit the SI info at this rate */ | 190 /* we retransmit the SI info at this rate */ |
190 #define SDT_RETRANS_TIME 500 | 191 #define SDT_RETRANS_TIME 500 |
191 #define PAT_RETRANS_TIME 100 | 192 #define PAT_RETRANS_TIME 100 |
192 | 193 |
193 typedef struct MpegTSWriteStream { | 194 typedef struct MpegTSWriteStream { |
194 int pid; /* stream associated pid */ | 195 int pid; /* stream associated pid */ |
195 int cc; | 196 int cc; |
196 int packet_index; | 197 int payload_index; |
197 int pes_packet_count; | 198 int64_t payload_pts; |
198 uint8_t packet[TS_PACKET_SIZE]; | 199 uint8_t payload[DEFAULT_PES_PAYLOAD_SIZE]; |
199 } MpegTSWriteStream; | 200 } MpegTSWriteStream; |
200 | 201 |
201 typedef struct MpegTSService { | 202 typedef struct MpegTSService { |
202 MpegTSSection pmt; /* MPEG2 pmt table context */ | 203 MpegTSSection pmt; /* MPEG2 pmt table context */ |
203 int pcr_pid; | 204 int pcr_pid; |
396 ts_st = av_mallocz(sizeof(MpegTSWriteStream)); | 397 ts_st = av_mallocz(sizeof(MpegTSWriteStream)); |
397 if (!ts_st) | 398 if (!ts_st) |
398 goto fail; | 399 goto fail; |
399 st->priv_data = ts_st; | 400 st->priv_data = ts_st; |
400 ts_st->pid = DEFAULT_START_PID + i; | 401 ts_st->pid = DEFAULT_START_PID + i; |
402 ts_st->payload_pts = AV_NOPTS_VALUE; | |
401 /* update PCR pid if needed */ | 403 /* update PCR pid if needed */ |
402 if (st->codec.codec_type == CODEC_TYPE_VIDEO && | 404 if (st->codec.codec_type == CODEC_TYPE_VIDEO && |
403 service->pcr_pid == 0x1fff) | 405 service->pcr_pid == 0x1fff) |
404 service->pcr_pid = ts_st->pid; | 406 service->pcr_pid = ts_st->pid; |
405 total_bit_rate += st->codec.bit_rate; | 407 total_bit_rate += st->codec.bit_rate; |
451 mpegts_write_pmt(s, ts->services[i]); | 453 mpegts_write_pmt(s, ts->services[i]); |
452 } | 454 } |
453 } | 455 } |
454 } | 456 } |
455 | 457 |
458 /* NOTE: pes_data contains all the PES packet */ | |
459 static void mpegts_write_pes(AVFormatContext *s, AVStream *st, | |
460 const uint8_t *payload, int payload_size, | |
461 int64_t pts) | |
462 { | |
463 MpegTSWriteStream *ts_st = st->priv_data; | |
464 uint8_t buf[TS_PACKET_SIZE]; | |
465 uint8_t *q; | |
466 int val, is_start, len, ts_len, header_len; | |
467 | |
468 is_start = 1; | |
469 while (payload_size > 0) { | |
470 retransmit_si_info(s); | |
471 | |
472 /* prepare packet header */ | |
473 q = buf; | |
474 *q++ = 0x47; | |
475 val = (ts_st->pid >> 8); | |
476 if (is_start) | |
477 val |= 0x40; | |
478 *q++ = val; | |
479 *q++ = ts_st->pid; | |
480 *q++ = 0x10 | ts_st->cc; | |
481 ts_st->cc = (ts_st->cc + 1) & 0xf; | |
482 if (is_start) { | |
483 /* write PES header */ | |
484 *q++ = 0x00; | |
485 *q++ = 0x00; | |
486 *q++ = 0x01; | |
487 if (st->codec.codec_type == CODEC_TYPE_VIDEO) | |
488 *q++ = 0xe0; | |
489 else | |
490 *q++ = 0xc0; | |
491 if (pts != AV_NOPTS_VALUE) | |
492 header_len = 8; | |
493 else | |
494 header_len = 3; | |
495 len = payload_size + header_len; | |
496 *q++ = len >> 8; | |
497 *q++ = len; | |
498 *q++ = 0x80; | |
499 if (pts != AV_NOPTS_VALUE) { | |
500 *q++ = 0x80; /* PTS only */ | |
501 *q++ = 0x05; /* header len */ | |
502 val = (0x02 << 4) | | |
503 (((pts >> 30) & 0x07) << 1) | 1; | |
504 *q++ = val; | |
505 val = (((pts >> 15) & 0x7fff) << 1) | 1; | |
506 *q++ = val >> 8; | |
507 *q++ = val; | |
508 val = (((pts) & 0x7fff) << 1) | 1; | |
509 *q++ = val >> 8; | |
510 *q++ = val; | |
511 } else { | |
512 *q++ = 0x00; | |
513 *q++ = 0x00; | |
514 } | |
515 is_start = 0; | |
516 } | |
517 /* write header */ | |
518 ts_len = q - buf; | |
519 put_buffer(&s->pb, buf, ts_len); | |
520 /* write data */ | |
521 len = TS_PACKET_SIZE - ts_len; | |
522 if (len > payload_size) | |
523 len = payload_size; | |
524 put_buffer(&s->pb, payload, len); | |
525 payload += len; | |
526 payload_size -= len; | |
527 ts_len += len; | |
528 /* stuffing */ | |
529 len = TS_PACKET_SIZE - ts_len; | |
530 if (len > 0) { | |
531 memset(buf, 0xff, len); | |
532 put_buffer(&s->pb, buf, len); | |
533 } | |
534 } | |
535 put_flush_packet(&s->pb); | |
536 } | |
537 | |
456 static int mpegts_write_packet(AVFormatContext *s, int stream_index, | 538 static int mpegts_write_packet(AVFormatContext *s, int stream_index, |
457 const uint8_t *buf, int size, int64_t pts1) | 539 const uint8_t *buf, int size, int64_t pts1) |
458 { | 540 { |
459 AVStream *st = s->streams[stream_index]; | 541 AVStream *st = s->streams[stream_index]; |
460 MpegTSWriteStream *ts_st = st->priv_data; | 542 MpegTSWriteStream *ts_st = st->priv_data; |
461 uint8_t *q; | 543 int len; |
462 int val, write_pts, is_start, len; | |
463 int64_t pts; | |
464 | 544 |
465 while (size > 0) { | 545 while (size > 0) { |
466 if (ts_st->packet_index == 0) { | 546 len = DEFAULT_PES_PAYLOAD_SIZE - ts_st->payload_index; |
467 retransmit_si_info(s); | 547 if (len > size) |
468 | 548 len = size; |
469 /* new PES header ? */ | 549 memcpy(ts_st->payload + ts_st->payload_index, buf, len); |
470 is_start = 0; | 550 buf += len; |
471 if (++ts_st->pes_packet_count == DEFAULT_PES_HEADER_FREQ) { | 551 size -= len; |
472 ts_st->pes_packet_count = 0; | 552 ts_st->payload_index += len; |
473 is_start = 1; | 553 if (ts_st->payload_pts == AV_NOPTS_VALUE) |
474 } | 554 ts_st->payload_pts = pts1; |
475 /* prepare packet header */ | 555 if (ts_st->payload_index >= DEFAULT_PES_PAYLOAD_SIZE) { |
476 q = ts_st->packet; | 556 mpegts_write_pes(s, st, ts_st->payload, ts_st->payload_index, |
477 *q++ = 0x47; | 557 ts_st->payload_pts); |
478 val = (ts_st->pid >> 8); | 558 ts_st->payload_pts = AV_NOPTS_VALUE; |
479 if (is_start) | 559 ts_st->payload_index = 0; |
480 val |= 0x40; | |
481 *q++ = val; | |
482 *q++ = ts_st->pid; | |
483 *q++ = 0x10 | ts_st->cc; | |
484 ts_st->cc = (ts_st->cc + 1) & 0xf; | |
485 if (is_start) { | |
486 /* write PES header */ | |
487 *q++ = 0x00; | |
488 *q++ = 0x00; | |
489 *q++ = 0x01; | |
490 if (st->codec.codec_type == CODEC_TYPE_VIDEO) | |
491 *q++ = 0xe0; | |
492 else | |
493 *q++ = 0xc0; | |
494 *q++ = 0; /* unbounded size */ | |
495 *q++ = 0; | |
496 *q++ = 0x80; | |
497 write_pts = 0; /* XXX: enable it */ | |
498 if (write_pts) { | |
499 *q++ = 0x80; /* PTS only */ | |
500 *q++ = 0x05; /* header len */ | |
501 pts = pts1; | |
502 val = (0x02 << 4) | | |
503 (((pts >> 30) & 0x07) << 1) | 1; | |
504 *q++ = val; | |
505 val = (((pts >> 15) & 0x7fff) << 1) | 1; | |
506 *q++ = val >> 8; | |
507 *q++ = val; | |
508 val = (((pts) & 0x7fff) << 1) | 1; | |
509 *q++ = val >> 8; | |
510 *q++ = val; | |
511 } else { | |
512 *q++ = 0x00; | |
513 *q++ = 0x00; | |
514 } | |
515 } | |
516 ts_st->packet_index = q - ts_st->packet; | |
517 } | 560 } |
518 len = TS_PACKET_SIZE - ts_st->packet_index; | 561 } |
519 if (len == 0) { | |
520 put_buffer(&s->pb, ts_st->packet, TS_PACKET_SIZE); | |
521 ts_st->packet_index = 0; | |
522 } else { | |
523 if (len > size) | |
524 len = size; | |
525 memcpy(ts_st->packet + ts_st->packet_index, buf, len); | |
526 size -= len; | |
527 buf += len; | |
528 ts_st->packet_index += len; | |
529 } | |
530 } | |
531 put_flush_packet(&s->pb); | |
532 return 0; | 562 return 0; |
533 } | 563 } |
534 | 564 |
535 static int mpegts_write_end(AVFormatContext *s) | 565 static int mpegts_write_end(AVFormatContext *s) |
536 { | 566 { |
542 | 572 |
543 /* flush current packets */ | 573 /* flush current packets */ |
544 for(i = 0; i < s->nb_streams; i++) { | 574 for(i = 0; i < s->nb_streams; i++) { |
545 st = s->streams[i]; | 575 st = s->streams[i]; |
546 ts_st = st->priv_data; | 576 ts_st = st->priv_data; |
547 if (ts_st->packet_index != 0) { | 577 if (ts_st->payload_index > 0) { |
548 /* put a known value at the end */ | 578 mpegts_write_pes(s, st, ts_st->payload, ts_st->payload_index, |
549 memset(ts_st->packet + ts_st->packet_index, 0xff, | 579 ts_st->payload_pts); |
550 TS_PACKET_SIZE - ts_st->packet_index); | |
551 put_buffer(&s->pb, ts_st->packet, TS_PACKET_SIZE); | |
552 } | 580 } |
553 } | 581 } |
554 put_flush_packet(&s->pb); | 582 put_flush_packet(&s->pb); |
555 | 583 |
556 for(i = 0; i < ts->nb_services; i++) { | 584 for(i = 0; i < ts->nb_services; i++) { |
573 "MPEG2 transport stream format", | 601 "MPEG2 transport stream format", |
574 "video/x-mpegts", | 602 "video/x-mpegts", |
575 "ts", | 603 "ts", |
576 sizeof(MpegTSWrite), | 604 sizeof(MpegTSWrite), |
577 CODEC_ID_MP2, | 605 CODEC_ID_MP2, |
578 CODEC_ID_MPEG1VIDEO, | 606 CODEC_ID_MPEG2VIDEO, |
579 mpegts_write_header, | 607 mpegts_write_header, |
580 mpegts_write_packet, | 608 mpegts_write_packet, |
581 mpegts_write_end, | 609 mpegts_write_end, |
582 }; | 610 }; |