📄 demux_ts.c
字号:
//copyright belongs to Michel Lespinasse <walken@zoy.org> and Aaron Holtzman <aholtzma@ess.engr.uvic.ca>int mp_a52_framesize(uint8_t * buf, int *srate){ 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 */ *srate = 48000 >> half; return 4 * bitrate; case 0x40: /* 44.1 KHz */ *srate = 44100 >> half; return 2 * (320 * bitrate / 147 + (frmsizecod & 1)); case 0x80: /* 32 KHz */ *srate = 32000 >> half; 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, srate; cnt = ok = 0; if(len < 8) return 0; while(cnt < len - 7) { if(buf[cnt] == 0x0B && buf[cnt+1] == 0x77) { frame_length = mp_a52_framesize(&buf[cnt], &srate); 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, end_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_V, "PROBING UP TO %"PRIu64", PROG: %d\n", (uint64_t) param->probe, param->prog); end_pos = init_pos + (param->probe ? param->probe : TS_MAX_PROBE_SIZE); while(1) { pos = stream_tell(demuxer->stream); if(pos > end_pos || demuxer->stream->eof) break; if(ts_parse(demuxer, &es, tmp, 1)) { //Non PES-aligned A52 audio may escape detection if PMT is not present; //in this case we try to find at least 3 A52 syncwords if((es.type == PES_PRIVATE1) && (! audio_found) && req_apid > -2) { pptr = &pes_priv1[es.pid]; if(pptr->pos < 64*1024) { tmpbuf = (char*) realloc(pptr->buf, pptr->pos + es.size); if(tmpbuf != NULL) { pptr->buf = tmpbuf; memcpy(&(pptr->buf[ pptr->pos ]), es.start, es.size); pptr->pos += es.size; if(a52_check(pptr->buf, pptr->pos) > 2) { param->atype = AUDIO_A52; param->apid = es.pid; es.type = AUDIO_A52; } } } } is_audio = IS_AUDIO(es.type) || ((es.type==SL_PES_STREAM) && IS_AUDIO(es.subtype)); is_video = IS_VIDEO(es.type) || ((es.type==SL_PES_STREAM) && IS_VIDEO(es.subtype)); is_sub = ((es.type == SPU_DVD) || (es.type == SPU_DVB)); if((! is_audio) && (! is_video) && (! is_sub)) continue; if(is_audio && req_apid==-2) continue; if(is_video) { mp_msg(MSGT_IDENTIFY, MSGL_V, "ID_VIDEO_ID=%d\n", es.pid); chosen_pid = (req_vpid == es.pid); if((! chosen_pid) && (req_vpid > 0)) continue; } else if(is_audio) { mp_msg(MSGT_IDENTIFY, MSGL_V, "ID_AUDIO_ID=%d\n", es.pid); if (es.lang[0] > 0) mp_msg(MSGT_IDENTIFY, MSGL_V, "ID_AID_%d_LANG=%s\n", es.pid, es.lang); if(req_apid > 0) { chosen_pid = (req_apid == es.pid); if(! chosen_pid) continue; } else if(param->alang[0] > 0 && es.lang[0] > 0) { if(pid_match_lang(priv, es.pid, param->alang) == -1) continue; chosen_pid = 1; param->apid = req_apid = es.pid; } } else if(is_sub) { mp_msg(MSGT_IDENTIFY, MSGL_V, "ID_SUBTITLE_ID=%d\n", es.pid); if (es.lang[0] > 0) mp_msg(MSGT_IDENTIFY, MSGL_V, "ID_SID_%d_LANG=%s\n", es.pid, es.lang); chosen_pid = (req_spid == es.pid); if((! chosen_pid) && (req_spid > 0)) continue; } if(req_apid < 0 && (param->alang[0] == 0) && req_vpid < 0 && req_spid < 0) chosen_pid = 1; if((ret == 0) && chosen_pid) { ret = stream_tell(demuxer->stream); } p = progid_for_pid(priv, es.pid, param->prog); if(p != -1) has_tables++; if((param->prog == 0) && (p != -1)) { if(chosen_pid) param->prog = p; } if((param->prog > 0) && (param->prog != p)) { if(audio_found) { if(is_video && (req_vpid == es.pid)) { param->vtype = IS_VIDEO(es.type) ? es.type : es.subtype; param->vpid = es.pid; video_found = 1; break; } } if(video_found) { if(is_audio && (req_apid == es.pid)) { param->atype = IS_AUDIO(es.type) ? es.type : es.subtype; param->apid = es.pid; audio_found = 1; break; } } continue; } mp_msg(MSGT_DEMUXER, MSGL_DBG2, "TYPE: %x, PID: %d, PROG FOUND: %d\n", es.type, es.pid, param->prog); if(is_video) { if((req_vpid == -1) || (req_vpid == es.pid)) { param->vtype = IS_VIDEO(es.type) ? es.type : es.subtype; param->vpid = es.pid; video_found = 1; } } if(((req_vpid == -2) || (num_packets >= NUM_CONSECUTIVE_AUDIO_PACKETS)) && audio_found && !param->probe) { //novideo or we have at least 348 audio packets (64 KB) without video (TS with audio only) param->vtype = 0; break; } if(is_sub) { if((req_spid == -1) || (req_spid == es.pid)) { param->stype = es.type; param->spid = es.pid; sub_found = 1; } } if(is_audio) { if((req_apid == -1) || (req_apid == es.pid)) { param->atype = IS_AUDIO(es.type) ? es.type : es.subtype; param->apid = es.pid; audio_found = 1; } } if(audio_found && (param->apid == es.pid) && (! video_found)) num_packets++; if((has_tables==0) && (video_found && audio_found) && (pos >= 1000000)) break; } } for(i=0; i<8192; i++) { if(pes_priv1[i].buf != NULL) { free(pes_priv1[i].buf); pes_priv1[i].buf = NULL; pes_priv1[i].pos = 0; } } if(video_found) { if(param->vtype == VIDEO_MPEG1) mp_msg(MSGT_DEMUXER, MSGL_INFO, "VIDEO MPEG1(pid=%d) ", param->vpid); else if(param->vtype == VIDEO_MPEG2) mp_msg(MSGT_DEMUXER, MSGL_INFO, "VIDEO MPEG2(pid=%d) ", param->vpid); else if(param->vtype == VIDEO_MPEG4) mp_msg(MSGT_DEMUXER, MSGL_INFO, "VIDEO MPEG4(pid=%d) ", param->vpid); else if(param->vtype == VIDEO_H264) mp_msg(MSGT_DEMUXER, MSGL_INFO, "VIDEO H264(pid=%d) ", param->vpid); else if(param->vtype == VIDEO_VC1) mp_msg(MSGT_DEMUXER, MSGL_INFO, "VIDEO VC1(pid=%d) ", param->vpid); else if(param->vtype == VIDEO_AVC) mp_msg(MSGT_DEMUXER, MSGL_INFO, "VIDEO AVC(NAL-H264, pid=%d) ", param->vpid); } else { param->vtype = UNKNOWN; //WE DIDN'T MATCH ANY VIDEO STREAM mp_msg(MSGT_DEMUXER, MSGL_INFO, "NO VIDEO! "); } if(param->atype == AUDIO_MP2) mp_msg(MSGT_DEMUXER, MSGL_INFO, "AUDIO MPA(pid=%d)", param->apid); else if(param->atype == AUDIO_A52) mp_msg(MSGT_DEMUXER, MSGL_INFO, "AUDIO A52(pid=%d)", param->apid); else if(param->atype == AUDIO_DTS) mp_msg(MSGT_DEMUXER, MSGL_INFO, "AUDIO DTS(pid=%d)", param->apid); else if(param->atype == AUDIO_LPCM_BE) mp_msg(MSGT_DEMUXER, MSGL_INFO, "AUDIO LPCM(pid=%d)", param->apid); else if(param->atype == AUDIO_AAC) mp_msg(MSGT_DEMUXER, MSGL_INFO, "AUDIO AAC(pid=%d)", param->apid); else { audio_found = 0; param->atype = UNKNOWN; //WE DIDN'T MATCH ANY AUDIO STREAM, SO WE FORCE THE DEMUXER TO IGNORE AUDIO mp_msg(MSGT_DEMUXER, MSGL_INFO, "NO AUDIO! "); } if(param->stype == SPU_DVD || param->stype == SPU_DVB) mp_msg(MSGT_DEMUXER, MSGL_INFO, " SUB %s(pid=%d) ", (param->stype==SPU_DVD ? "DVD" : "DVB"), param->spid); else { param->stype = UNKNOWN; mp_msg(MSGT_DEMUXER, MSGL_INFO, " NO SUBS (yet)! "); } if(video_found || audio_found) { if(demuxer->stream->eof && (ret == 0)) ret = init_pos; mp_msg(MSGT_DEMUXER, MSGL_INFO, " PROGRAM N. %d\n", param->prog); } else mp_msg(MSGT_DEMUXER, MSGL_INFO, "\n"); for(i=0; i<8192; i++) { if(priv->ts.pids[i] != NULL) { priv->ts.pids[i]->payload_size = 0; priv->ts.pids[i]->pts = priv->ts.pids[i]->last_pts = 0; priv->ts.pids[i]->last_cc = -1; priv->ts.pids[i]->is_synced = 0; } } return ret;}static int parse_avc_sps(uint8_t *buf, int len, int *w, int *h){ int sps, sps_len; unsigned char *ptr; mp_mpeg_header_t picture; if(len < 6) return 0; sps = buf[5] & 0x1f; if(!sps) return 0; sps_len = (buf[6] << 8) | buf[7]; if(!sps_len || (sps_len > len - 8)) return 0; ptr = &(buf[8]); picture.display_picture_width = picture.display_picture_height = 0; h264_parse_sps(&picture, ptr, len - 8); if(!picture.display_picture_width || !picture.display_picture_height) return 0; *w = picture.display_picture_width; *h = picture.display_picture_height; return 1;}static demuxer_t *demux_open_ts(demuxer_t * demuxer){ int i; uint8_t packet_size; sh_video_t *sh_video; sh_audio_t *sh_audio; off_t start_pos; tsdemux_init_t params; ts_priv_t * priv = (ts_priv_t*) demuxer->priv; mp_msg(MSGT_DEMUX, MSGL_V, "DEMUX OPEN, AUDIO_ID: %d, VIDEO_ID: %d, SUBTITLE_ID: %d,\n", demuxer->audio->id, demuxer->video->id, demuxer->sub->id); demuxer->type= DEMUXER_TYPE_MPEG_TS; stream_reset(demuxer->stream); packet_size = ts_check_file(demuxer); if(!packet_size) return NULL; priv = calloc(1, sizeof(ts_priv_t)); if(priv == NULL) { mp_msg(MSGT_DEMUX, MSGL_FATAL, "DEMUX_OPEN_TS, couldn't allocate enough memory for ts->priv, exit\n"); return NULL; } for(i=0; i < 8192; i++) { priv->ts.pids[i] = NULL; priv->ts.streams[i].id = -3; } priv->pat.progs = NULL; priv->pat.progs_cnt = 0; priv->pat.section.buffer = NULL; priv->pat.section.buffer_len = 0; priv->pmt = NULL; priv->pmt_cnt = 0; priv->keep_broken = ts_keep_broken; priv->ts.packet_size = packet_size; demuxer->priv = priv; if(demuxer->stream->type != STREAMTYPE_FILE) demuxer->seekable = 1; else demuxer->seekable = 1; params.atype = params.vtype = params.stype = UNKNOWN; params.apid = demuxer->audio->id; params.vpid = demuxer->video->id; params.spid = demuxer->sub->id; params.prog = ts_prog; params.probe = ts_probe; if(dvdsub_lang != NULL) { strncpy(params.slang, dvdsub_lang, 3); params.slang[3] = 0; } else memset(params.slang, 0, 4); if(audio_lang != NULL) { strncpy(params.alang, audio_lang, 3); params.alang[3] = 0; } else memset(params.alang, 0, 4); start_pos = ts_detect_streams(demuxer, ¶ms); demuxer->sub->id = params.spid; priv->prog = params.prog; if(params.vtype != UNKNOWN) { ts_add_stream(demuxer, priv->ts.pids[params.vpid]); sh_video = priv->ts.streams[params.vpid].sh; demuxer->video->id = priv->ts.streams[params.vpid].id; sh_video->ds = demuxer->video; sh_video->format = params.vtype; demuxer->video->sh = sh_video; } if(params.atype != UNKNOWN) { ES_stream_t *es = priv->ts.pids[params.apid]; if(!IS_AUDIO(es->type) && !IS_AUDIO(es->subtype) && IS_AUDIO(params.atype)) es->subtype = params.atype; ts_add_stream(demuxer, priv->ts.pids[params.apid]); sh_audio = priv->ts.streams[params.apid].sh; demuxer->audio->id = priv->ts.streams[params.apid].id; sh_audio->ds = demuxer->audio; sh_audio->format = params.atype; demuxer->audio->sh = sh_audio; } mp_msg(MSGT_DEMUXER,MSGL_V, "Opened TS demuxer, audio: %x(pid %d), video: %x(pid %d)...POS=%"PRIu64", PROBE=%"PRIu64"\n", params.atype, demuxer->audio->id, params.vtype, demuxer->video->id, (uint64_t) start_pos, ts_probe); start_pos = (start_pos <= priv->ts.packet_size ? 0 : start_pos - priv->ts.packet_size); demuxer->movi_start = start_pos; stream_reset(demuxer->stream); stream_seek(demuxer->stream, start_pos); //IF IT'S FROM A PIPE IT WILL FAIL, BUT WHO CARES? priv->last_pid = 8192; //invalid pid for(i = 0; i < 3; i++) { priv->fifo[i].pack = NULL; priv->fifo[i].offset = 0; } priv->fifo[0].ds = demuxer->audio; priv->fifo[1].ds = demuxer->video; priv->fifo[2].ds = demuxer->sub; priv->fifo[0].buffer_size = 1536; priv->fifo[1].buffer_size = 32767; priv->fifo[2].buffer_size = 32767; priv->pat.section.buffer_len = 0; for(i = 0; i < priv->pmt_cnt; i++) priv->pmt[i].section.buffer_len = 0; demuxer->filepos = stream_tell(demuxer->stream); return demuxer;}static void demux_close_ts(demuxer_t * demuxer){ uint16_t i; ts_priv_t *priv = (ts_priv_t*) demuxer->priv; if(priv) { if(priv->pat.section.buffer) free(priv->pat.section.buffer); if(priv->pat.progs) free(priv->pat.progs); if(priv->pmt) { for(i = 0; i < priv->pmt_cnt; i++) { if(priv->pmt[i].section.buffer) free(priv->pmt[i].section.buffer); if(priv->pmt[i].es) free(priv->pmt[i].es); } free(priv->pmt); } free(priv); } demuxer->priv=NULL;}extern unsigned char mp_getbits(unsigned char*, unsigned int, unsigned char);#define getbits mp_getbitsstatic int mp4_parse_sl_packet(pmt_t *pmt, uint8_t *buf, uint16_t packet_len, int pid, ES_stream_t *pes_es){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -