📄 parse-mpeg.c
字号:
if (ng_debug > 1) fprintf(stderr,"pts: %8.3f | id 0x%02x %s\n", pts/90000.0,id,pes_s[id]); if (ts) *ts = pts; } return size;}int mpeg_get_audio_rate(unsigned char *header){ int rate = 44100; if (mpeg_getbits(header,12,1) == 1) { /* MPEG 1.0 */ switch (mpeg_getbits(header,20,2)) { case 0: rate = 44100; break; case 1: rate = 48000; break; case 2: rate = 32000; break; } if (ng_debug) fprintf(stderr,"mpeg: MPEG1 audio, rate %d\n",rate); } else { /* MPEG 2.0 */ switch (mpeg_getbits(header,20,2)) { case 0: rate = 22050; break; case 1: rate = 24000; break; case 2: rate = 16000; break; } if (ng_debug) fprintf(stderr,"mpeg: MPEG2 audio, rate %d\n",rate); } return rate;}unsigned char* mpeg_find_audio_hdr(unsigned char *buf, int off, int size){ int i; for (i = off; i < size-1; i++) { if (0xff != buf[i]) continue; if (0xf0 == (buf[i+1] & 0xf0)) return buf+i; } return NULL;}int mpeg_get_video_fmt(struct mpeg_handle *h, unsigned char *header){ if (header[0] != 0x00 || header[1] != 0x00 || header[2] != 0x01 || header[3] != 0xb3) return -1; h->vfmt.fmtid = VIDEO_MPEG; h->vfmt.width = (mpeg_getbits(header,32,12) + 15) & ~15; h->vfmt.height = (mpeg_getbits(header,44,12) + 15) & ~15; h->ratio = mpeg_getbits(header,56,4); h->rate = mpeg_getbits(header,60,4); if (ng_debug) fprintf(stderr,"mpeg: MPEG video, %dx%d [ratio=%s,rate=%s]\n", h->vfmt.width, h->vfmt.height, ratio_s[h->ratio], rate_s[h->rate]); return 0;}int mpeg_check_video_fmt(struct mpeg_handle *h, unsigned char *header){ int width, height, ratio; int change = 0; if (header[0] != 0x00 || header[1] != 0x00 || header[2] != 0x01 || header[3] != 0xb3) return 0; width = (mpeg_getbits(header,32,12) + 15) & ~15; height = (mpeg_getbits(header,44,12) + 15) & ~15; ratio = mpeg_getbits(header,56,4); if (width != h->vfmt.width || height != h->vfmt.height) { if (ng_debug) fprintf(stderr,"mpeg: size change: %dx%d => %dx%d\n", h->vfmt.width, h->vfmt.height, width, height); change++; } if (ratio != h->ratio) { if (ng_debug) fprintf(stderr,"mpeg: ratio change: %s => %s\n", ratio_s[h->ratio], ratio_s[ratio]); change++; } h->vfmt.height = height; h->vfmt.width = width; h->ratio = ratio; return change;}/* ----------------------------------------------------------------------- *//* program streams */size_t mpeg_find_ps_packet(struct mpeg_handle *h, int packet, int mask, off_t *pos){ unsigned char *buf; size_t size; off_t start = *pos; /* read header */ for (;;) { buf = mpeg_get_data(h,*pos,16); if (NULL == buf) return 0; if (buf[0] != 0x00 || buf[1] != 0x00 || buf[2] != 0x01) return 0; size = mpeg_getbits(buf,32,16) + 6; /* handle special cases */ switch (buf[3]) { case 0xba: /* packet start code */ if (0x01 == mpeg_getbits(buf,32,2)) { /* MPEG 2 */ size = 14 + mpeg_getbits(buf,109,3); } else if (0x02 == mpeg_getbits(buf,32,4)) { /* MPEG 1 */ size = 12; } else { /* Huh? */ return 0; } break; case 0xb9: /* mpeg program end code */ return 0; } if (ng_debug > 1) fprintf(stderr,"mpeg: packet 0x%x at 0x%08" PRIx64 "+%d [need 0x%x]\n", (int)buf[3],(int64_t)*pos,(int)size,packet); /* our packet ? */ if ((buf[3] & mask) == packet) return size; *pos += size; /* don't search unlimited ... */ if (*pos - start > FILE_BUF_MIN) return 0; }}/* ----------------------------------------------------------------------- *//* transport streams */static void parse_pmt_desc(unsigned char *desc, int dlen, struct psi_program *program, int pid){ int i,t,l; for (i = 0; i < dlen; i += desc[i+1] +2) { t = desc[i]; l = desc[i+1]; switch (t) { case 0x56: if (!program->t_pid) program->t_pid = pid; break; } }}static char* get_lang_tag(unsigned char *desc, int dlen){ int i,t,l; for (i = 0; i < dlen; i += desc[i+1] +2) { t = desc[i]; l = desc[i+1]; if (0x0a == t) return desc+i+2; } return NULL;}static void dump_data(unsigned char *data, int len){ int i; for (i = 0; i < len; i++) { if (isprint(data[i])) fprintf(stderr,"%c", data[i]); else fprintf(stderr,"\\x%02x", (int)data[i]); }}void mpeg_dump_desc(unsigned char *desc, int dlen){ int i,j,t,l,l2,l3; for (i = 0; i < dlen; i += desc[i+1] +2) { t = desc[i]; l = desc[i+1]; switch (t) { case 0x0a: /* ??? (pmt) */ fprintf(stderr," lang=%3.3s",desc+i+2); break; case 0x45: /* vbi data (pmt) */ fprintf(stderr," vbidata="); dump_data(desc+i+2,l); break; case 0x52: /* stream identifier */ fprintf(stderr," sid=%d",(int)desc[i+2]); break; case 0x56: /* teletext (pmt) */ fprintf(stderr," teletext=%3.3s",desc+i+2); break; case 0x59: /* subtitles (pmt) */ fprintf(stderr," subtitles=%3.3s",desc+i+2); break; case 0x6a: /* ac3 (pmt) */ fprintf(stderr," ac3"); break; case 0x40: /* network name (nit) */ fprintf(stderr," name="); dump_data(desc+i+2,l); break; case 0x43: /* satellite delivery system (nit) */ fprintf(stderr," dvb-s"); break; case 0x44: /* cable delivery system (nit) */ fprintf(stderr," dvb-c"); break; case 0x5a: /* terrestrial delivery system (nit) */ fprintf(stderr," dvb-t"); break; case 0x48: /* service (sdt) */ fprintf(stderr," service=%d,",desc[i+2]); l2 = desc[i+3]; dump_data(desc+i+4,desc[i+3]); fprintf(stderr,","); dump_data(desc+i+l2+5,desc[i+l2+4]); break; case 0x4d: /* event (eid) */ fprintf(stderr," short=[%3.3s|",desc+i+2); l2 = desc[i+5]; l3 = desc[i+6+l2]; dump_data(desc+i+6,l2); fprintf(stderr,"|"); dump_data(desc+i+7+l2,l3); fprintf(stderr,"]"); break; case 0x4e: /* event (eid) */ fprintf(stderr," *ext event"); break; case 0x4f: /* event (eid) */ fprintf(stderr," *time shift event"); break; case 0x50: /* event (eid) */ fprintf(stderr," *component"); break; case 0x54: /* event (eid) */ fprintf(stderr," content="); for (j = 0; j < l; j+=2) fprintf(stderr,"%s0x%02x", j ? "," : "", desc[i+j+2]); break; case 0x55: /* event (eid) */ fprintf(stderr," *parental rating"); break; default: fprintf(stderr," %02x[",desc[i]); dump_data(desc+i+2,l); fprintf(stderr,"]"); } }}int mpeg_parse_psi_pat(struct psi_info *info, unsigned char *data, int verbose){ struct list_head *item; struct psi_program *pr; int tsid,pnr,version,current; int j,len,pid; len = mpeg_getbits(data,12,12) + 3 - 4; tsid = mpeg_getbits(data,24,16); version = mpeg_getbits(data,42,5); current = mpeg_getbits(data,47,1); if (!current) return len+4; if (info->tsid == tsid && info->pat_version == version) return len+4; info->tsid = tsid; info->pat_version = version; info->pat_updated = 1; if (verbose) fprintf(stderr, "ts [pat]: tsid %d ver %2d [%d/%d]\n", tsid, version, mpeg_getbits(data,48, 8), mpeg_getbits(data,56, 8)); for (j = 64; j < len*8; j += 32) { pnr = mpeg_getbits(data,j+0,16); pid = mpeg_getbits(data,j+19,13); if (0 == pnr) { /* network */ if (verbose > 1) fprintf(stderr," pid 0x%04x [network]\n", pid); } else { /* program */ pr = psi_program_get(info, tsid, pnr, 1); pr->p_pid = pid; pr->updated = 1; pr->seen = 1; if (NULL == info->pr) info->pr = pr; } } if (verbose > 1) { list_for_each(item,&info->programs) { pr = list_entry(item, struct psi_program, next); if (pr->tsid != tsid) continue; fprintf(stderr," pid 0x%04x => pnr %2d [program map%s]\n", pr->p_pid, pr->pnr, pr->seen ? ",seen" : ""); } fprintf(stderr,"\n"); } return len+4;}int mpeg_parse_psi_pmt(struct psi_program *program, unsigned char *data, int verbose){ int pnr,version,current; int j,len,dlen,type,pid,slen; char *lang; len = mpeg_getbits(data,12,12) + 3 - 4; pnr = mpeg_getbits(data,24,16); version = mpeg_getbits(data,42,5); current = mpeg_getbits(data,47,1); if (!current) return len+4; if (program->pnr == pnr && program->version == version) return len+4; program->version = version; program->updated = 1; dlen = mpeg_getbits(data,84,12); /* TODO: decode descriptor? */ if (verbose) { fprintf(stderr, "ts [pmt]: pnr %d ver %2d [%d/%d] pcr 0x%04x " "pid 0x%04x type %2d #", pnr, version, mpeg_getbits(data,48, 8), mpeg_getbits(data,56, 8), mpeg_getbits(data,69,13), program->p_pid, program->type); mpeg_dump_desc(data + 96/8, dlen); fprintf(stderr,"\n"); } j = 96 + dlen*8; program->v_pid = 0; program->a_pid = 0; program->t_pid = 0; memset(program->audio,0,sizeof(program->audio)); while (j < len*8) { type = mpeg_getbits(data,j,8); pid = mpeg_getbits(data,j+11,13); dlen = mpeg_getbits(data,j+28,12); switch (type) { case 1: case 2: /* video */ if (!program->v_pid) program->v_pid = pid; break; case 3: case 4: /* audio */ if (!program->a_pid) program->a_pid = pid; lang = get_lang_tag(data + (j+40)/8, dlen); slen = strlen(program->audio); snprintf(program->audio + slen, sizeof(program->audio) - slen, "%s%.3s:%d", slen ? " " : "", lang ? lang : "xxx", pid); break; case 6: /* private data */ parse_pmt_desc(data + (j+40)/8, dlen, program, pid); break; } if (verbose > 1) { fprintf(stderr, " pid 0x%04x => %-32s #", pid, stream_type_s[type]); mpeg_dump_desc(data + (j+40)/8, dlen); fprintf(stderr,"\n"); } j += 40 + dlen*8; } if (verbose > 1) fprintf(stderr,"\n"); return len+4;}int mpeg_parse_psi(struct psi_info *info, struct mpeg_handle *h, int verbose){ int i,tid; if (h->ts.payload) { for (i = h->ts.data[0]+1; i < h->ts.size;) { tid = mpeg_getbits(h->ts.data,i*8,8); switch (tid) { case 0: i += mpeg_parse_psi_pat(info, h->ts.data+i, verbose); break; case 1: fprintf(stderr, "ts: conditional access\n"); return 0; case 2: i += mpeg_parse_psi_pmt(info->pr, h->ts.data+i, verbose); break; case 3: fprintf(stderr, "ts: description\n"); return 0; case 0xff: /* end of data */ return 0; default: fprintf(stderr, "ts: unknown table id %d\n",tid); return 0; } } } return 0;}/* ----------------------------------------------------------------------- */int mpeg_find_ts_packet(struct mpeg_handle *h, int wanted, off_t *pos){ unsigned char *packet; int asize = 0; off_t start; for (start = *pos; *pos - start < FILE_BUF_MIN; *pos += TS_SIZE) { memset(&h->ts, 0, sizeof(h->ts)); packet = mpeg_get_data(h, *pos, TS_SIZE); if (NULL == packet) { fprintf(stderr,"mpeg ts: no more data\n"); return -1; } if (packet[0] != 0x47) { if (ng_log_bad_stream) fprintf(stderr,"mpeg ts: warning %d: packet id mismatch\n", h->errors); h->errors++; continue; } h->ts.tei = mpeg_getbits(packet, 8,1); h->ts.payload = mpeg_getbits(packet, 9,1); h->ts.pid = mpeg_getbits(packet,11,13); h->ts.scramble = mpeg_getbits(packet,24,2); h->ts.adapt = mpeg_getbits(packet,26,2); h->ts.cont = mpeg_getbits(packet,28,4); if (0 == h->ts.adapt) /* reserved -- should discard */ continue; if (0x1fff == h->ts.pid) /* NULL packet -- discard */ continue; if (h->ts.pid != wanted) /* need something else */ continue; switch (h->ts.adapt) { case 3: /* adaptation + payload */ asize = mpeg_getbits(packet,32,8) +1; h->ts.data = packet + (4 + asize); h->ts.size = TS_SIZE - (4 + asize); if (h->ts.size > TS_SIZE) { if (ng_log_bad_stream) fprintf(stderr,"mpeg ts: warning %d: broken adaptation" " size [%lx]\n",h->errors,(unsigned long)(*pos)); h->errors++; continue; } /* fall throuth */ case 2: /* adaptation only */ /* TODO: parse adaptation field */ break; case 1: /* payload only */ h->ts.data = packet + 4; h->ts.size = TS_SIZE - 4; break; } if (ng_debug > 2) fprintf(stderr,"mpeg ts: pl=%d pid=%d adapt=%d cont=%d size=%d [%d]\n", h->ts.payload, h->ts.pid, h->ts.adapt, h->ts.cont, h->ts.size, asize); return 0; } return -1;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -