📄 parse-mpeg.c
字号:
/* * parse mpeg program + transport streams. * */#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <string.h>#include <ctype.h>#include <errno.h>#include <iconv.h>#include <inttypes.h>#include "grab-ng.h"#include "parse-mpeg.h"#define FILE_BUF_MIN (512*1024)#define FILE_BUF_MAX (8*1024*1024)#define FILE_BLKSIZE (16*1024)#ifndef PRId64# warning Hmm, your C99 support is incomplete, will guess (should be ok for 32bit archs)# define PRId64 "lld"# define PRIx64 "llx"# define PRIu64 "llu"#endifint ng_mpeg_vpid = 0;int ng_mpeg_apid = 0;int ng_read_timeout = 3; /* seconds *//* ----------------------------------------------------------------------- *//* static data */int mpeg_rate_n[16] = { [ 1 ] = 24000, [ 2 ] = 24000, [ 3 ] = 25000, [ 4 ] = 30000, [ 5 ] = 30000, [ 6 ] = 50000, [ 7 ] = 60000, [ 8 ] = 60000,};int mpeg_rate_d[16] = { [ 1 ] = 1001, [ 2 ] = 1000, [ 3 ] = 1000, [ 4 ] = 1001, [ 5 ] = 1000, [ 6 ] = 1000, [ 7 ] = 1001, [ 8 ] = 1000,};static char *rate_s[16] = { [ 0 ] = "illegal", [ 1 ] = "24000/1001", [ 2 ] = "24", [ 3 ] = "25", [ 4 ] = "30000/1001", [ 5 ] = "30", [ 6 ] = "50", [ 7 ] = "60000/1001", [ 8 ] = "60", [ 9 ... 15 ] = "reserved",};static char *ratio_s[] = { [ 0 ] = "illegal", [ 1 ] = "square sample", [ 2 ] = "3:4", [ 3 ] = "9:16", [ 4 ] = "1:2,21", [ 5 ... 15 ] = "reserved",};const char *mpeg_frame_s[] = { [ NG_FRAME_UNKNOWN ] = "unknown", [ NG_FRAME_I_FRAME ] = "I frame", [ NG_FRAME_P_FRAME ] = "P frame", [ NG_FRAME_B_FRAME ] = "B frame",};static const char *pes_s[] = { [ 0x00 ... 0xff ] = "*UNKNOWN* stream", [ 0xbc ] = "program stream map", [ 0xbd ] = "private stream 1", [ 0xbe ] = "padding stream", [ 0xbf ] = "private stream 2", [ 0xc0 ... 0xdf ] = "audio stream", [ 0xe0 ... 0xef ] = "video stream", [ 0xf0 ] = "ECM stream", [ 0xf1 ] = "EMM stream", [ 0xf2 ] = "DSMCC stream", [ 0xf3 ] = "13522 stream", [ 0xf4 ] = "H.222.1 type A", [ 0xf5 ] = "H.222.1 type B", [ 0xf6 ] = "H.222.1 type C", [ 0xf7 ] = "H.222.1 type D", [ 0xf8 ] = "H.222.1 type E", [ 0xf9 ] = "ancillary stream", [ 0xfa ... 0xfe ] = "reserved data stream", [ 0xff ] = "program stream directory",};static const char *stream_type_s[] = { [ 0x00 ] = "reserved", [ 0x01 ] = "ISO 11172 Video", [ 0x02 ] = "ISO 13818-2 Video", [ 0x03 ] = "ISO 11172 Audio", [ 0x04 ] = "ISO 13818-3 Audio", [ 0x05 ] = "ISO 13818-1 private sections", [ 0x06 ] = "ISO 13818-1 private data", [ 0x07 ] = "ISO 13522 MHEG", [ 0x08 ] = "ISO 13818-1 Annex A DSS CC", [ 0x09 ] = "ITU-T H.222.1", [ 0x0a ] = "ISO 13818-6 type A", [ 0x0b ] = "ISO 13818-6 type B", [ 0x0c ] = "ISO 13818-6 type C", [ 0x0d ] = "ISO 13818-6 type D", [ 0x0e ] = "ISO 13818-6 auxiliary", [ 0x0f ... 0x7f ] = "reserved", [ 0x80 ... 0xff ] = "user private",};/* ----------------------------------------------------------------------- */char *psi_charset[0x20] = { [ 0x00 ... 0x1f ] = "reserved", [ 0x00 ] = "ISO-8859-1", [ 0x01 ] = "ISO-8859-5", [ 0x02 ] = "ISO-8859-6", [ 0x03 ] = "ISO-8859-7", [ 0x04 ] = "ISO-8859-8", [ 0x05 ] = "ISO-8859-9", [ 0x06 ] = "ISO-8859-10", [ 0x07 ] = "ISO-8859-11", [ 0x08 ] = "ISO-8859-12", [ 0x09 ] = "ISO-8859-13", [ 0x0a ] = "ISO-8859-14", [ 0x0b ] = "ISO-8859-15", [ 0x10 ] = "fixme", [ 0x11 ] = "UCS-2BE", // correct? [ 0x12 ] = "EUC-KR", [ 0x13 ] = "GB2312", [ 0x14 ] = "BIG5"};char *psi_service_type[0x100] = { [ 0x00 ... 0xff ] = "reserved", [ 0x80 ... 0xfe ] = "user defined", [ 0x01 ] = "digital television service", [ 0x02 ] = "digital radio sound service", [ 0x03 ] = "teletext service", [ 0x04 ] = "NVOD reference service", [ 0x05 ] = "NVOD time-shifted service", [ 0x06 ] = "mosaic service", [ 0x07 ] = "PAL coded signal", [ 0x08 ] = "SECAM coded signal", [ 0x09 ] = "D/D2-MAC", [ 0x0a ] = "FM Radio", [ 0x0b ] = "NTSC coded signal", [ 0x0c ] = "data broadcast service", [ 0x0d ] = "reserved for CI", [ 0x0e ] = "RCS Map", [ 0x0f ] = "RCS FLS", [ 0x10 ] = "DVB MHP service",};/* ----------------------------------------------------------------------- *//* handle psi_ structs */struct psi_info* psi_info_alloc(void){ struct psi_info *info; info = malloc(sizeof(*info)); memset(info,0,sizeof(*info)); INIT_LIST_HEAD(&info->streams); INIT_LIST_HEAD(&info->programs); info->pat_version = PSI_NEW; info->sdt_version = PSI_NEW; info->nit_version = PSI_NEW; return info;}void psi_info_free(struct psi_info *info){ struct psi_program *program; struct psi_stream *stream; struct list_head *item,*safe; list_for_each_safe(item,safe,&info->streams) { stream = list_entry(item, struct psi_stream, next); list_del(&stream->next); free(stream); } list_for_each_safe(item,safe,&info->programs) { program = list_entry(item, struct psi_program, next); list_del(&program->next); free(program); } free(info);}struct psi_stream* psi_stream_get(struct psi_info *info, int tsid, int alloc){ struct psi_stream *stream; struct list_head *item; list_for_each(item,&info->streams) { stream = list_entry(item, struct psi_stream, next); if (stream->tsid == tsid) return stream; } if (!alloc) return NULL; stream = malloc(sizeof(*stream)); memset(stream,0,sizeof(*stream)); stream->tsid = tsid; stream->updated = 1; list_add_tail(&stream->next,&info->streams); return stream;}struct psi_program* psi_program_get(struct psi_info *info, int tsid, int pnr, int alloc){ struct psi_program *program; struct list_head *item; list_for_each(item,&info->programs) { program = list_entry(item, struct psi_program, next); if (program->tsid == tsid && program->pnr == pnr) return program; } if (!alloc) return NULL; program = malloc(sizeof(*program)); memset(program,0,sizeof(*program)); program->tsid = tsid; program->pnr = pnr; program->version = PSI_NEW; program->updated = 1; list_add_tail(&program->next,&info->programs); return program;}/* ----------------------------------------------------------------------- *//* bit fiddeling */unsigned int mpeg_getbits(unsigned char *buf, int start, int count){ unsigned int result = 0; unsigned char bit; while (count) { result <<= 1; bit = 1 << (7 - (start % 8)); result |= (buf[start/8] & bit) ? 1 : 0; start++; count--; } return result;}void hexdump(char *prefix, unsigned char *data, size_t size){ char ascii[17]; int i; for (i = 0; i < size; i++) { if (0 == (i%16)) { fprintf(stderr,"%s%s%04x:", prefix ? prefix : "", prefix ? ": " : "", i); memset(ascii,0,sizeof(ascii)); } if (0 == (i%4)) fprintf(stderr," "); fprintf(stderr," %02x",data[i]); ascii[i%16] = isprint(data[i]) ? data[i] : '.'; if (15 == (i%16)) fprintf(stderr," %s\n",ascii); } if (0 != (i%16)) { while (0 != (i%16)) { if (0 == (i%4)) fprintf(stderr," "); fprintf(stderr," "); i++; }; fprintf(stderr," %s\n",ascii); }}/* ----------------------------------------------------------------------- *//* common code */struct mpeg_handle* mpeg_init(void){ struct mpeg_handle *h; h = malloc(sizeof(*h)); if (NULL == h) return NULL; memset(h,0,sizeof(*h)); h->fd = -1; h->pgsize = getpagesize(); h->init = 1; return h;}void mpeg_fini(struct mpeg_handle *h){ if (h->vbuf) ng_release_video_buf(h->vbuf); if (-1 != h->fd) close(h->fd); if (h->buffer) free(h->buffer); free(h);}unsigned char* mpeg_get_data(struct mpeg_handle *h, off_t pos, size_t size){ fd_set set; struct timeval tv; off_t low; size_t rdbytes; int rc; if (pos < h->boff) { /* shouldn't happen */ fprintf(stderr,"mpeg: panic: seek backwards [pos=%ld,boff=%ld]\n", (long)pos,(long)h->boff); exit(1); } low = 0; if (!h->init && pos > h->init_offset*6) { if (h->video_offset > h->init_offset && h->audio_offset > h->init_offset) low = (h->video_offset < h->audio_offset) ? h->video_offset : h->audio_offset; else if (h->audio_offset > h->init_offset) low = h->audio_offset; else if (h->video_offset > h->init_offset) low = h->video_offset; } if (low > h->boff + h->balloc*3/4 && low < h->boff + h->bsize && !h->beof) { /* move data window */ rdbytes = (low - h->boff) & ~(h->pgsize - 1); memmove(h->buffer, h->buffer + rdbytes, h->balloc - rdbytes); h->boff += rdbytes; h->bsize -= rdbytes; if (ng_debug) fprintf(stderr,"mpeg: %dk file buffer shift\n", (int)(rdbytes >> 10)); } while (pos+size + 2*TS_SIZE > h->boff + h->balloc && !h->beof) { /* enlarge buffer */ if (0 == h->bsize) { h->balloc = FILE_BUF_MIN; h->buffer = malloc(h->balloc); } else { h->balloc *= 2; if (h->balloc > FILE_BUF_MAX) { fprintf(stderr,"mpeg: panic: file buffer limit exceeded " "(l=%d,b=%d,v=%d,a=%d)\n", FILE_BUF_MAX,(int)h->balloc, (int)h->video_offset,(int)h->audio_offset); exit(1); } h->buffer = realloc(h->buffer,h->balloc); } if (ng_debug) fprintf(stderr,"mpeg: %dk file buffer\n",(int)(h->balloc >> 10)); } while (pos+size > h->boff + h->bsize) { if (h->beof) return NULL; /* read data */ rdbytes = h->balloc - h->bsize; if (rdbytes > FILE_BLKSIZE) rdbytes = FILE_BLKSIZE; rdbytes -= rdbytes % TS_SIZE; rc = read(h->fd, h->buffer + h->bsize, rdbytes); switch (rc) { case -1: switch (errno) { case EAGAIN: /* must wait for data ... */ if (!h->init) { if (ng_log_resync) fprintf(stderr,"mpeg: sync: must wait for data\n"); h->slowdown++; } FD_ZERO(&set); FD_SET(h->fd,&set); tv.tv_sec = ng_read_timeout; tv.tv_usec = 0; switch (select(h->fd+1,&set,NULL,NULL,&tv)) { case -1: fprintf(stderr,"mpeg: select: %s\n",strerror(errno)); h->beof = 1; break; case 0: fprintf(stderr,"mpeg: select: timeout (%d sec)\n", ng_read_timeout); h->beof = 1; break; } break; case EOVERFLOW: if (ng_log_resync) fprintf(stderr,"mpeg: sync: kernel buffer overflow\n"); break; default: fprintf(stderr,"mpeg: read: %s [%d]\n",strerror(errno),errno); h->beof = 1; break; } break; case 0: if (ng_debug) fprintf(stderr,"mpeg: EOF\n"); h->beof = 1; break; default: h->bsize += rc; break; } } return h->buffer + (pos - h->boff);}size_t mpeg_parse_pes_packet(struct mpeg_handle *h, unsigned char *packet, uint64_t *ts, int *al){ uint64_t pts, dts; int id; size_t size; int i, val; pts = 0; dts = 0; id = 0; *al = 0; for (i = 48; i < 48 + 8*16; i += 8) if (0xff != mpeg_getbits(packet,i,8)) break; if (mpeg_getbits(packet,i,2) == 0x02) { /* MPEG 2 */ id = mpeg_getbits(packet, i-24, 8); *al = mpeg_getbits(packet, i+ 5, 1); size = mpeg_getbits(packet, i+16, 8); size += i/8 + 3; switch (mpeg_getbits(packet, i+8, 2)) { case 3: dts = (uint64_t)mpeg_getbits(packet, i + 68, 3) << 30; dts |= (uint64_t)mpeg_getbits(packet, i + 72, 15) << 15; dts |= (uint64_t)mpeg_getbits(packet, i + 88, 15); /* fall */ case 2: pts = (uint64_t)mpeg_getbits(packet, i + 28, 3) << 30; pts |= (uint64_t)mpeg_getbits(packet, i + 32, 15) << 15; pts |= (uint64_t)mpeg_getbits(packet, i + 48, 15); break; } if (ng_debug > 2) fprintf(stderr,"mpeg2 pes: pl=%d al=%d copy=%d orig=%d ts=%d hl=%d | " " pts=%" PRIx64 " dts=%" PRIx64 " size=%d\n", mpeg_getbits(packet, i - 16, 16), mpeg_getbits(packet, i + 5, 1), mpeg_getbits(packet, i + 6, 1), mpeg_getbits(packet, i + 7, 1), mpeg_getbits(packet, i + 8, 2), mpeg_getbits(packet, i + 16, 8), pts, dts, (int)size); if (ng_debug > 3) { hexdump("mpeg2 pes",packet,32); fprintf(stderr,"--\n"); } } else { /* MPEG 1 */ if (mpeg_getbits(packet,i,2) == 0x01) i += 16; val = mpeg_getbits(packet,i,8); if ((val & 0xf0) == 0x20) { pts = (uint64_t)mpeg_getbits(packet, i + 4, 3) << 30; pts |= (uint64_t)mpeg_getbits(packet, i + 8, 15) << 15; pts |= (uint64_t)mpeg_getbits(packet, i + 24, 15); i += 40; } else if ((val & 0xf0) == 0x30) { pts = (uint64_t)mpeg_getbits(packet, i + 4, 3) << 30; pts |= (uint64_t)mpeg_getbits(packet, i + 8, 15) << 15; pts |= (uint64_t)mpeg_getbits(packet, i + 24, 15); i += 80; } else if (val == 0x0f) i += 8; size = i/8; } if (pts) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -