📄 mpegtsenc.c
字号:
/* * MPEG2 transport stream (aka DVB) muxer * Copyright (c) 2003 Fabrice Bellard. * * This file is part of FFmpeg. * * FFmpeg is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * FFmpeg is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */#include "avformat.h"#include "crc.h"#include "mpegts.h"/* write DVB SI sections *//*********************************************//* mpegts section writer */typedef struct MpegTSSection { int pid; int cc; void (*write_packet)(struct MpegTSSection *s, const uint8_t *packet); void *opaque;} MpegTSSection;/* NOTE: 4 bytes must be left at the end for the crc32 */static void mpegts_write_section(MpegTSSection *s, uint8_t *buf, int len){ unsigned int crc; unsigned char packet[TS_PACKET_SIZE]; const unsigned char *buf_ptr; unsigned char *q; int first, b, len1, left; crc = bswap_32(av_crc(av_crc_get_table(AV_CRC_32_IEEE), -1, buf, len - 4)); buf[len - 4] = (crc >> 24) & 0xff; buf[len - 3] = (crc >> 16) & 0xff; buf[len - 2] = (crc >> 8) & 0xff; buf[len - 1] = (crc) & 0xff; /* send each packet */ buf_ptr = buf; while (len > 0) { first = (buf == buf_ptr); q = packet; *q++ = 0x47; b = (s->pid >> 8); if (first) b |= 0x40; *q++ = b; *q++ = s->pid; s->cc = (s->cc + 1) & 0xf; *q++ = 0x10 | s->cc; if (first) *q++ = 0; /* 0 offset */ len1 = TS_PACKET_SIZE - (q - packet); if (len1 > len) len1 = len; memcpy(q, buf_ptr, len1); q += len1; /* add known padding data */ left = TS_PACKET_SIZE - (q - packet); if (left > 0) memset(q, 0xff, left); s->write_packet(s, packet); buf_ptr += len1; len -= len1; }}static inline void put16(uint8_t **q_ptr, int val){ uint8_t *q; q = *q_ptr; *q++ = val >> 8; *q++ = val; *q_ptr = q;}static int mpegts_write_section1(MpegTSSection *s, int tid, int id, int version, int sec_num, int last_sec_num, uint8_t *buf, int len){ uint8_t section[1024], *q; unsigned int tot_len; tot_len = 3 + 5 + len + 4; /* check if not too big */ if (tot_len > 1024) return -1; q = section; *q++ = tid; put16(&q, 0xb000 | (len + 5 + 4)); /* 5 byte header + 4 byte CRC */ put16(&q, id); *q++ = 0xc1 | (version << 1); /* current_next_indicator = 1 */ *q++ = sec_num; *q++ = last_sec_num; memcpy(q, buf, len); mpegts_write_section(s, section, tot_len); return 0;}/*********************************************//* mpegts writer */#define DEFAULT_PMT_START_PID 0x1000#define DEFAULT_START_PID 0x0100#define DEFAULT_PROVIDER_NAME "FFmpeg"#define DEFAULT_SERVICE_NAME "Service01"/* default network id, transport stream and service identifiers */#define DEFAULT_ONID 0x0001#define DEFAULT_TSID 0x0001#define DEFAULT_SID 0x0001/* a PES packet header is generated every DEFAULT_PES_HEADER_FREQ packets */#define DEFAULT_PES_HEADER_FREQ 16#define DEFAULT_PES_PAYLOAD_SIZE ((DEFAULT_PES_HEADER_FREQ - 1) * 184 + 170)/* we retransmit the SI info at this rate */#define SDT_RETRANS_TIME 500#define PAT_RETRANS_TIME 100#define PCR_RETRANS_TIME 20typedef struct MpegTSWriteStream { struct MpegTSService *service; int pid; /* stream associated pid */ int cc; int payload_index; int64_t payload_pts; int64_t payload_dts; uint8_t payload[DEFAULT_PES_PAYLOAD_SIZE];} MpegTSWriteStream;typedef struct MpegTSService { MpegTSSection pmt; /* MPEG2 pmt table context */ int sid; /* service ID */ char *name; char *provider_name; int pcr_pid; int pcr_packet_count; int pcr_packet_freq;} MpegTSService;typedef struct MpegTSWrite { MpegTSSection pat; /* MPEG2 pat table */ MpegTSSection sdt; /* MPEG2 sdt table context */ MpegTSService **services; int sdt_packet_count; int sdt_packet_freq; int pat_packet_count; int pat_packet_freq; int nb_services; int onid; int tsid;} MpegTSWrite;static void mpegts_write_pat(AVFormatContext *s){ MpegTSWrite *ts = s->priv_data; MpegTSService *service; uint8_t data[1012], *q; int i; q = data; for(i = 0; i < ts->nb_services; i++) { service = ts->services[i]; put16(&q, service->sid); put16(&q, 0xe000 | service->pmt.pid); } mpegts_write_section1(&ts->pat, PAT_TID, ts->tsid, 0, 0, 0, data, q - data);}static void mpegts_write_pmt(AVFormatContext *s, MpegTSService *service){ // MpegTSWrite *ts = s->priv_data; uint8_t data[1012], *q, *desc_length_ptr, *program_info_length_ptr; int val, stream_type, i; q = data; put16(&q, 0xe000 | service->pcr_pid); program_info_length_ptr = q; q += 2; /* patched after */ /* put program info here */ val = 0xf000 | (q - program_info_length_ptr - 2); program_info_length_ptr[0] = val >> 8; program_info_length_ptr[1] = val; for(i = 0; i < s->nb_streams; i++) { AVStream *st = s->streams[i]; MpegTSWriteStream *ts_st = st->priv_data; switch(st->codec->codec_id) { case CODEC_ID_MPEG1VIDEO: case CODEC_ID_MPEG2VIDEO: stream_type = STREAM_TYPE_VIDEO_MPEG2; break; case CODEC_ID_MPEG4: stream_type = STREAM_TYPE_VIDEO_MPEG4; break; case CODEC_ID_H264: stream_type = STREAM_TYPE_VIDEO_H264; break; case CODEC_ID_MP2: case CODEC_ID_MP3: stream_type = STREAM_TYPE_AUDIO_MPEG1; break; case CODEC_ID_AAC: stream_type = STREAM_TYPE_AUDIO_AAC; break; case CODEC_ID_AC3: stream_type = STREAM_TYPE_AUDIO_AC3; break; default: stream_type = STREAM_TYPE_PRIVATE_DATA; break; } *q++ = stream_type; put16(&q, 0xe000 | ts_st->pid); desc_length_ptr = q; q += 2; /* patched after */ /* write optional descriptors here */ switch(st->codec->codec_type) { case CODEC_TYPE_AUDIO: if (strlen(st->language) == 3) { *q++ = 0x0a; /* ISO 639 language descriptor */ *q++ = 4; *q++ = st->language[0]; *q++ = st->language[1]; *q++ = st->language[2]; *q++ = 0; /* undefined type */ } break; case CODEC_TYPE_SUBTITLE: { const char *language; language = st->language; if (strlen(language) != 3) language = "eng"; *q++ = 0x59; *q++ = 8; *q++ = language[0]; *q++ = language[1]; *q++ = language[2]; *q++ = 0x10; /* normal subtitles (0x20 = if hearing pb) */ put16(&q, 1); /* page id */ put16(&q, 1); /* ancillary page id */ } break; } val = 0xf000 | (q - desc_length_ptr - 2); desc_length_ptr[0] = val >> 8; desc_length_ptr[1] = val; } mpegts_write_section1(&service->pmt, PMT_TID, service->sid, 0, 0, 0, data, q - data);}/* NOTE: str == NULL is accepted for an empty string */static void putstr8(uint8_t **q_ptr, const char *str){ uint8_t *q; int len; q = *q_ptr; if (!str) len = 0; else len = strlen(str); *q++ = len; memcpy(q, str, len); q += len; *q_ptr = q;}static void mpegts_write_sdt(AVFormatContext *s){ MpegTSWrite *ts = s->priv_data; MpegTSService *service; uint8_t data[1012], *q, *desc_list_len_ptr, *desc_len_ptr; int i, running_status, free_ca_mode, val; q = data; put16(&q, ts->onid); *q++ = 0xff; for(i = 0; i < ts->nb_services; i++) { service = ts->services[i]; put16(&q, service->sid); *q++ = 0xfc | 0x00; /* currently no EIT info */ desc_list_len_ptr = q; q += 2; running_status = 4; /* running */ free_ca_mode = 0; /* write only one descriptor for the service name and provider */ *q++ = 0x48; desc_len_ptr = q; q++; *q++ = 0x01; /* digital television service */ putstr8(&q, service->provider_name); putstr8(&q, service->name); desc_len_ptr[0] = q - desc_len_ptr - 1; /* fill descriptor length */ val = (running_status << 13) | (free_ca_mode << 12) | (q - desc_list_len_ptr - 2); desc_list_len_ptr[0] = val >> 8; desc_list_len_ptr[1] = val; } mpegts_write_section1(&ts->sdt, SDT_TID, ts->tsid, 0, 0, 0, data, q - data);}static MpegTSService *mpegts_add_service(MpegTSWrite *ts, int sid, const char *provider_name, const char *name){ MpegTSService *service; service = av_mallocz(sizeof(MpegTSService)); if (!service) return NULL; service->pmt.pid = DEFAULT_PMT_START_PID + ts->nb_services - 1; service->sid = sid; service->provider_name = av_strdup(provider_name); service->name = av_strdup(name); service->pcr_pid = 0x1fff;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -