📄 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */#include <mplaylib.h>#include <mplaylib.h>#include <mplaylib.h>#include "config.h"#include "mp_msg.h"#include "help_mp.h"#include "stream/stream.h"#include "demuxer.h"#include "parse_es.h"#include "stheader.h"#include "unrarlib.h"#include "ms_hdr.h"#include "mpeg_hdr.h"#undef memcpy#define memcpy uc_memcpy#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 3840#ifndef SIZE_MAX#define SIZE_MAX ((size_t)-1)#endif#define TYPE_AUDIO 1#define TYPE_VIDEO 2int ts_prog;int ts_keep_broken=0;off_t ts_probe = 0;extern char *dvdsub_lang, *audio_lang; //for -alangtypedef enum{ UNKNOWN = -1, VIDEO_MPEG1 = 0x10000001, VIDEO_MPEG2 = 0x10000002, VIDEO_MPEG4 = 0x10000004, VIDEO_H264 = 0x10000005, VIDEO_AVC = mmioFOURCC('a', 'v', 'c', '1'), VIDEO_VC1 = mmioFOURCC('W', 'V', 'C', '1'), AUDIO_MP2 = 0x50, AUDIO_A52 = 0x2000, AUDIO_DTS = 0x2001, 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 { void *sh; int id; int type;} sh_av_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]; sh_av_t streams[NB_PID_MAX];} MpegTSContext;typedef struct { demux_stream_t *ds; demux_packet_t *pack; int offset, buffer_size;} av_fifo_t;#define MAX_EXTRADATA_SIZE 64*1024typedef struct { int32_t object_type; //aka codec used int32_t stream_type; //video, audio etc. uint8_t buf[MAX_EXTRADATA_SIZE]; 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 { uint64_t size; float duration; float first_pts; float last_pts;} TS_stream_info;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; uint32_t vbitrate; int keep_broken; int last_aid; int last_vid; char packet[TS_FEC_PACKET_SIZE]; TS_stream_info vstr, astr;} 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) || ((x) == AUDIO_DTS))#define IS_VIDEO(x) (((x) == VIDEO_MPEG1) || ((x) == VIDEO_MPEG2) || ((x) == VIDEO_MPEG4) || ((x) == VIDEO_H264) || ((x) == VIDEO_AVC) || ((x) == VIDEO_VC1))static int ts_parse(demuxer_t *demuxer, ES_stream_t *es, unsigned char *packet, int probe);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;}static int parse_avc_sps(uint8_t *buf, int len, int *w, int *h);static void ts_add_stream(demuxer_t * demuxer, ES_stream_t *es){ int i; ts_priv_t *priv = (ts_priv_t*) demuxer->priv; if(priv->ts.streams[es->pid].sh) return; if((IS_AUDIO(es->type) || IS_AUDIO(es->subtype)) && priv->last_aid+1 < MAX_A_STREAMS) { sh_audio_t *sh = new_sh_audio_aid(demuxer, priv->last_aid, es->pid); if(sh) { sh->format = IS_AUDIO(es->type) ? es->type : es->subtype; sh->ds = demuxer->audio; priv->ts.streams[es->pid].id = priv->last_aid; priv->ts.streams[es->pid].sh = sh; priv->ts.streams[es->pid].type = TYPE_AUDIO; mp_msg(MSGT_DEMUX, MSGL_V, "\r\nADDED AUDIO PID %d, type: %x stream n. %d\r\n", es->pid, sh->format, priv->last_aid); priv->last_aid++; } if(es->extradata && es->extradata_len) { sh->wf = (WAVEFORMATEX *) malloc(sizeof (WAVEFORMATEX) + es->extradata_len); sh->wf->cbSize = es->extradata_len; memcpy(sh->wf + 1, es->extradata, es->extradata_len); } } if((IS_VIDEO(es->type) || IS_VIDEO(es->subtype)) && priv->last_vid+1 < MAX_V_STREAMS) { sh_video_t *sh = new_sh_video_vid(demuxer, priv->last_vid, es->pid); if(sh) { sh->format = IS_VIDEO(es->type) ? es->type : es->subtype;; sh->ds = demuxer->video; priv->ts.streams[es->pid].id = priv->last_vid; priv->ts.streams[es->pid].sh = sh; priv->ts.streams[es->pid].type = TYPE_VIDEO; mp_msg(MSGT_DEMUX, MSGL_V, "\r\nADDED VIDEO PID %d, type: %x stream n. %d\r\n", es->pid, sh->format, priv->last_vid); priv->last_vid++; if(sh->format == VIDEO_AVC && es->extradata && es->extradata_len) { int w = 0, h = 0; sh->bih = (BITMAPINFOHEADER *) calloc(1, sizeof(BITMAPINFOHEADER) + es->extradata_len); sh->bih->biSize= sizeof(BITMAPINFOHEADER) + es->extradata_len; sh->bih->biCompression = sh->format; memcpy(sh->bih + 1, es->extradata, es->extradata_len); mp_msg(MSGT_DEMUXER,MSGL_DBG2, "EXTRADATA(%d BYTES): \n", es->extradata_len); for(i = 0;i < es->extradata_len; i++) mp_msg(MSGT_DEMUXER,MSGL_DBG2, "%02x ", (int) es->extradata[i]); mp_msg(MSGT_DEMUXER,MSGL_DBG2,"\n"); if(parse_avc_sps(es->extradata, es->extradata_len, &w, &h)) { sh->bih->biWidth = w; sh->bih->biHeight = h; } } } }}static 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 %"PRIu64", 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 uint16_t prog; off_t probe;} tsdemux_init_t;//stripped down version of a52_syncinfo() from liba52
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -