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 }; |
