📄 demux_ts.c
字号:
/* * Demultiplexer for MPEG2 Transport Streams. * * Written by Nico <nsabbi@libero.it> * Kind feedback is appreciated; 'sucks' and alike is not. * Originally based on demux_pva.c written by Matteo Giani and FFmpeg (libavformat) sources * * This file is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This file 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */#include <stdio.h>#include <stdlib.h>#include <string.h>#include "config.h"#include "mp_msg.h"#include "help_mp.h"#include "stream.h"#include "demuxer.h"#include "parse_es.h"#include "stheader.h"#include "bswap.h"#include "../unrarlib.h"#include "ms_hdr.h"#include "mpeg_hdr.h"#define TS_PH_PACKET_SIZE 192#define TS_FEC_PACKET_SIZE 204#define TS_PACKET_SIZE 188#define NB_PID_MAX 8192#define MAX_HEADER_SIZE 6 /* enough for PES header + length */#define MAX_CHECK_SIZE 65535#define TS_MAX_PROBE_SIZE 2000000 /* dont forget to change this in cfg-common.h too */#define NUM_CONSECUTIVE_TS_PACKETS 32#define NUM_CONSECUTIVE_AUDIO_PACKETS 348#define MAX_A52_FRAME_SIZE 3840int ts_prog;int ts_keep_broken=0;off_t ts_probe = TS_MAX_PROBE_SIZE;extern char *dvdsub_lang, *audio_lang; //for -alangextern int demux_aid_vid_mismatch;typedef enum{ UNKNOWN = -1, VIDEO_MPEG1 = 0x10000001, VIDEO_MPEG2 = 0x10000002, VIDEO_MPEG4 = 0x10000004, VIDEO_H264 = 0x10000005, VIDEO_AVC = mmioFOURCC('a', 'v', 'c', '1'), AUDIO_MP2 = 0x50, AUDIO_A52 = 0x2000, AUDIO_LPCM_BE = 0x10001, AUDIO_AAC = mmioFOURCC('M', 'P', '4', 'A'), SPU_DVD = 0x3000000, SPU_DVB = 0x3000001, PES_PRIVATE1 = 0xBD00000, SL_PES_STREAM = 0xD000000, SL_SECTION = 0xD100000, MP4_OD = 0xD200000,} es_stream_type_t;typedef struct { uint8_t *buffer; uint16_t buffer_len;} ts_section_t;typedef struct { int size; unsigned char *start; uint16_t payload_size; es_stream_type_t type, subtype; float pts, last_pts; int pid; char lang[4]; int last_cc; // last cc code (-1 if first packet) int is_synced; ts_section_t section; uint8_t *extradata; int extradata_alloc, extradata_len; struct { uint8_t au_start, au_end, last_au_end; } sl;} ES_stream_t;typedef struct MpegTSContext { int packet_size; // raw packet size, including FEC if present e.g. 188 bytes ES_stream_t *pids[NB_PID_MAX];} MpegTSContext;typedef struct { demux_stream_t *ds; demux_packet_t *pack; int offset, buffer_size;} av_fifo_t;typedef struct { int32_t object_type; //aka codec used int32_t stream_type; //video, audio etc. uint8_t buf[4096]; uint16_t buf_size; uint8_t szm1;} mp4_decoder_config_t;typedef struct { //flags uint8_t flags; uint8_t au_start; uint8_t au_end; uint8_t random_accesspoint; uint8_t random_accesspoint_only; uint8_t padding; uint8_t use_ts; uint8_t idle; uint8_t duration; uint32_t ts_resolution, ocr_resolution; uint8_t ts_len, ocr_len, au_len, instant_bitrate_len, degr_len, au_seqnum_len, packet_seqnum_len; uint32_t timescale; uint16_t au_duration, cts_duration; uint64_t ocr, dts, cts;} mp4_sl_config_t;typedef struct { uint16_t id; uint8_t flags; mp4_decoder_config_t decoder; mp4_sl_config_t sl;} mp4_es_descr_t;typedef struct { uint16_t id; uint8_t flags; mp4_es_descr_t *es; uint16_t es_cnt;} mp4_od_t;typedef struct { uint8_t skip; uint8_t table_id; uint8_t ssi; uint16_t section_length; uint16_t ts_id; uint8_t version_number; uint8_t curr_next; uint8_t section_number; uint8_t last_section_number; struct pat_progs_t { uint16_t id; uint16_t pmt_pid; } *progs; uint16_t progs_cnt; ts_section_t section;} pat_t;typedef struct { uint16_t progid; uint8_t skip; uint8_t table_id; uint8_t ssi; uint16_t section_length; uint8_t version_number; uint8_t curr_next; uint8_t section_number; uint8_t last_section_number; uint16_t PCR_PID; uint16_t prog_descr_length; ts_section_t section; uint16_t es_cnt; struct pmt_es_t { uint16_t pid; uint32_t type; //it's 8 bit long, but cast to the right type as FOURCC uint16_t descr_length; uint8_t format_descriptor[5]; uint8_t lang[4]; uint16_t mp4_es_id; } *es; mp4_od_t iod, *od; mp4_es_descr_t *mp4es; int od_cnt, mp4es_cnt;} pmt_t;typedef struct { MpegTSContext ts; int last_pid; av_fifo_t fifo[3]; //0 for audio, 1 for video, 2 for subs pat_t pat; pmt_t *pmt; uint16_t pmt_cnt; uint32_t prog; int keep_broken; char packet[TS_FEC_PACKET_SIZE];} ts_priv_t;typedef struct { es_stream_type_t type; ts_section_t section;} TS_pids_t;#define IS_AUDIO(x) (((x) == AUDIO_MP2) || ((x) == AUDIO_A52) || ((x) == AUDIO_LPCM_BE) || ((x) == AUDIO_AAC))#define IS_VIDEO(x) (((x) == VIDEO_MPEG1) || ((x) == VIDEO_MPEG2) || ((x) == VIDEO_MPEG4) || ((x) == VIDEO_H264) || ((x) == VIDEO_AVC))static int ts_parse(demuxer_t *demuxer, ES_stream_t *es, unsigned char *packet, int probe);extern void resync_audio_stream( sh_audio_t *sh_audio );static uint8_t get_packet_size(const unsigned char *buf, int size){ int i; if (size < (TS_FEC_PACKET_SIZE * NUM_CONSECUTIVE_TS_PACKETS)) return 0; for(i=0; i<NUM_CONSECUTIVE_TS_PACKETS; i++) { if (buf[i * TS_PACKET_SIZE] != 0x47) { mp_msg(MSGT_DEMUX, MSGL_DBG2, "GET_PACKET_SIZE, pos %d, char: %2x\n", i, buf[i * TS_PACKET_SIZE]); goto try_fec; } } return TS_PACKET_SIZE;try_fec: for(i=0; i<NUM_CONSECUTIVE_TS_PACKETS; i++) { if (buf[i * TS_FEC_PACKET_SIZE] != 0x47){ mp_msg(MSGT_DEMUX, MSGL_DBG2, "GET_PACKET_SIZE, pos %d, char: %2x\n", i, buf[i * TS_PACKET_SIZE]); goto try_philips; } } return TS_FEC_PACKET_SIZE; try_philips: for(i=0; i<NUM_CONSECUTIVE_TS_PACKETS; i++) { if (buf[i * TS_PH_PACKET_SIZE] != 0x47) return 0; } return TS_PH_PACKET_SIZE;}int ts_check_file(demuxer_t * demuxer){ const int buf_size = (TS_FEC_PACKET_SIZE * NUM_CONSECUTIVE_TS_PACKETS); unsigned char buf[TS_FEC_PACKET_SIZE * NUM_CONSECUTIVE_TS_PACKETS], done = 0, *ptr; uint32_t _read, i, count = 0, is_ts; int cc[NB_PID_MAX], last_cc[NB_PID_MAX], pid, cc_ok, c, good, bad; uint8_t size = 0; off_t pos = 0; off_t init_pos; mp_msg(MSGT_DEMUX, MSGL_V, "Checking for MPEG-TS...\n"); init_pos = stream_tell(demuxer->stream); is_ts = 0; while(! done) { i = 1; c = 0; while(((c=stream_read_char(demuxer->stream)) != 0x47) && (c >= 0) && (i < MAX_CHECK_SIZE) && ! demuxer->stream->eof ) i++; if(c != 0x47) { mp_msg(MSGT_DEMUX, MSGL_V, "THIS DOESN'T LOOK LIKE AN MPEG-TS FILE!\n"); is_ts = 0; done = 1; continue; } pos = stream_tell(demuxer->stream) - 1; buf[0] = c; _read = stream_read(demuxer->stream, &buf[1], buf_size-1); if(_read < buf_size-1) { mp_msg(MSGT_DEMUX, MSGL_V, "COULDN'T READ ENOUGH DATA, EXITING TS_CHECK\n"); stream_reset(demuxer->stream); return 0; } size = get_packet_size(buf, buf_size); if(size) { done = 1; is_ts = 1; } if(pos - init_pos >= MAX_CHECK_SIZE) { done = 1; is_ts = 0; } } mp_msg(MSGT_DEMUX, MSGL_V, "TRIED UP TO POSITION %llu, FOUND %x, packet_size= %d, SEEMS A TS? %d\n", (uint64_t) pos, c, size, is_ts); stream_seek(demuxer->stream, pos); if(! is_ts) return 0; //LET'S CHECK continuity counters good = bad = 0; for(count = 0; count < NB_PID_MAX; count++) { cc[count] = last_cc[count] = -1; } for(count = 0; count < NUM_CONSECUTIVE_TS_PACKETS; count++) { ptr = &(buf[size * count]); pid = ((ptr[1] & 0x1f) << 8) | ptr[2]; mp_msg(MSGT_DEMUX, MSGL_DBG2, "BUF: %02x %02x %02x %02x, PID %d, SIZE: %d \n", ptr[0], ptr[1], ptr[2], ptr[3], pid, size); if((pid == 8191) || (pid < 16)) continue; cc[pid] = (ptr[3] & 0xf); cc_ok = (last_cc[pid] < 0) || ((((last_cc[pid] + 1) & 0x0f) == cc[pid])); mp_msg(MSGT_DEMUX, MSGL_DBG2, "PID %d, COMPARE CC %d AND LAST_CC %d\n", pid, cc[pid], last_cc[pid]); if(! cc_ok) //return 0; bad++; else good++; last_cc[pid] = cc[pid]; } mp_msg(MSGT_DEMUX, MSGL_V, "GOOD CC: %d, BAD CC: %d\n", good, bad); if(good >= bad) return size; else return 0;}static inline int32_t progid_idx_in_pmt(ts_priv_t *priv, uint16_t progid){ int x; if(priv->pmt == NULL) return -1; for(x = 0; x < priv->pmt_cnt; x++) { if(priv->pmt[x].progid == progid) return x; } return -1;}static inline int32_t progid_for_pid(ts_priv_t *priv, int pid, int32_t req) //finds the first program listing a pid{ int i, j; pmt_t *pmt; if(priv->pmt == NULL) return -1; for(i=0; i < priv->pmt_cnt; i++) { pmt = &(priv->pmt[i]); if(pmt->es == NULL) return -1; for(j = 0; j < pmt->es_cnt; j++) { if(pmt->es[j].pid == pid) { if((req == 0) || (req == pmt->progid)) return pmt->progid; } } } return -1;}static inline int pid_match_lang(ts_priv_t *priv, uint16_t pid, char *lang){ uint16_t i, j; pmt_t *pmt; if(priv->pmt == NULL) return -1; for(i=0; i < priv->pmt_cnt; i++) { pmt = &(priv->pmt[i]); if(pmt->es == NULL) return -1; for(j = 0; j < pmt->es_cnt; j++) { if(pmt->es[j].pid != pid) continue; mp_msg(MSGT_DEMUXER, MSGL_V, "CMP LANG %s AND %s, pids: %d %d\n",pmt->es[j].lang, lang, pmt->es[j].pid, pid); if(strncmp(pmt->es[j].lang, lang, 3) == 0) { return 1; } } } return -1;}typedef struct { int32_t atype, vtype, stype; //types int32_t apid, vpid, spid; //stream ids char slang[4], alang[4]; //languages int16_t prog; off_t probe;} tsdemux_init_t;//stripped down version of a52_syncinfo() from liba52//copyright belongs to Michel Lespinasse <walken@zoy.org> and Aaron Holtzman <aholtzma@ess.engr.uvic.ca>static int a52_framesize(uint8_t * buf){ int rate[] = { 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, 448, 512, 576, 640 }; uint8_t halfrate[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3}; int frmsizecod, bitrate, half; if((buf[0] != 0x0b) || (buf[1] != 0x77)) /* syncword */ return 0; if(buf[5] >= 0x60) /* bsid >= 12 */ return 0; half = halfrate[buf[5] >> 3]; frmsizecod = buf[4] & 63; if(frmsizecod >= 38) return 0; bitrate = rate[frmsizecod >> 1]; switch(buf[4] & 0xc0) { case 0: /* 48 KHz */ return 4 * bitrate; case 0x40: /* 44.1 KHz */ return 2 * (320 * bitrate / 147 + (frmsizecod & 1)); case 0x80: /* 32 KHz */ return 6 * bitrate; } return 0;}//second stage: returns the count of A52 syncwords foundstatic int a52_check(char *buf, int len){ int cnt, frame_length, ok; cnt = ok = 0; if(len < 8) return 0; while(cnt < len - 7) { if(buf[cnt] == 0x0B && buf[cnt+1] == 0x77) { frame_length = a52_framesize(&buf[cnt]); if(frame_length>=7 && frame_length<=3840) { cnt += frame_length; ok++; } else cnt++; } else cnt++; } mp_msg(MSGT_DEMUXER, MSGL_V, "A52_CHECK(%d input bytes), found %d frame syncwords of %d bytes length\n", len, ok, frame_length); return ok;}static off_t ts_detect_streams(demuxer_t *demuxer, tsdemux_init_t *param){ int video_found = 0, audio_found = 0, sub_found = 0, i, num_packets = 0, req_apid, req_vpid, req_spid; int is_audio, is_video, is_sub, has_tables; int32_t p, chosen_pid = 0; off_t pos=0, ret = 0, init_pos; ES_stream_t es; unsigned char tmp[TS_FEC_PACKET_SIZE]; ts_priv_t *priv = (ts_priv_t*) demuxer->priv; struct { char *buf; int pos; } pes_priv1[8192], *pptr; char *tmpbuf; priv->last_pid = 8192; //invalid pid req_apid = param->apid; req_vpid = param->vpid; req_spid = param->spid; has_tables = 0; memset(pes_priv1, 0, sizeof(pes_priv1)); init_pos = stream_tell(demuxer->stream); mp_msg(MSGT_DEMUXER, MSGL_INFO, "PROBING UP TO %llu, PROG: %d\n", (uint64_t) param->probe, param->prog);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -