📄 mpeg2demux.c
字号:
/* * MPEG2-TS over IEEE 1394 decoder - receive and decode MPEG-2 transport * streams according to IEC 61883-4 * * Copyright (C) 2000-2007, Manfred Weihs <mweihs@users.sourceforge.net> * * This program 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 program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *//* * Exception from GNU General Public License: * There are two functions (head_check and decode_header) in this file * which are modifications of functions taken from mpg123. * The modifications are under GNU GPL, but the the original code is * under copyright (C) 1995-1999 by Michael Hipp and has its own license. * mpg123 can be obtained under http://www.mpg123.de *//* MPEG 2 transport stream demultiplexer many ideas and some code taken from Alex Theo de Jong (NIST, February 1996)*/#include <stdlib.h>#include <stdio.h>#include <pthread.h>#include <sys/time.h>#include <errno.h>#include "iso1394dataflowsource.h"#include "synchronisation.h"#include "audio/audiobuffer.h"#include "video/videobuffer.h"#include "mpeg2demux.h"#include "audio/common.h"#define MAX_PIDS 0x2000 /* Maximum number of PIDs in one stream (= 2^13) */#define MAX_PROGRAMS 150 /* maximum number of programs (determines entries in PAT and PMT) */#define PMT_BUFFERS 10 /* number of PMT buffers (this is the number of _uncompleted_ PMT sections which can be hold in memory at a given time) */#define SYNC_BYTE 0x47#define PACKET_START_CODE_PREFIX 0x000001#define PRIVATE_STREAM_2 0xbf#define PADDING_STREAM 0xbeextern int debug;struct stream_description { int stream_type,elementary_PID; struct stream_description *next;};struct ProgramMapTableEntry { int PCR_PID,program_number; struct stream_description *streams; struct ProgramMapTableEntry *next;};struct PAT_entry{ unsigned short int program_number,program_map_PID;};struct PMT_buffer_entry{ int pid; unsigned int byte_count; unsigned char buffer[1024];};struct TimestampStorage { int have_timestamp; unsigned long long timestamp;};static volatile int terminate; /* tell demux thread to terminate */struct TimestampStorage audio_pts = { 0, 0};static int audio_pid, video_pid, pcr_pid;static int current_program; /* program we are currently decoding, -1 means no special program */static int track_program; /* program number we track, -1 means no program -2 means any program -3 means first program of PAT *//* various counters */static int transport_packets, transport_packet_errors, sync_byte_errors, lost_packets, audio_packets, video_packets,audio_frames,pcr_packets;static int pidcount[MAX_PIDS];static unsigned char continuity_counters[MAX_PIDS];/* Transport Header Info */static int transport_error_indicator, payload_unit_start_indicator, pid, adaptation_field_control, transport_scrambling_control;/* program associated table */static struct PAT_entry PAT[MAX_PROGRAMS];static unsigned char PAT_temp[(MAX_PROGRAMS+1)*4]; /* one quadlet for crc */static int current_pat_section,rest_of_pat_section; /* number of pat section currently read and remaining number of bytes */static unsigned char *PAT_position; /* current position in PAT; NULL if no PAT is pending */static unsigned char PAT_header[8]; /* puffer for the head of the current PAT section */static int PAT_have_bytes_of_header;static int PAT_version,PAT_last_section;static pthread_t demux_thread;static pthread_mutex_t mutex_decoders; /* this mutex is necessary to prevent the demux to access the decoders (their buffers) during reset */static int transport_stream_id, number_of_programs;/* program map table */static struct PMT_buffer_entry pmt_buffer[PMT_BUFFERS]; /* pmt sections will be stored here, until they are complete, and will be interpreted afterwards */static struct ProgramMapTableEntry *program_map_table;static pthread_mutex_t mutex_PMT;/* global (static) variables needed by audiobufferfill */static int have_mpegaudio_header;static int bytes_already_in_audiobuffer; /* number of bytes we already read *//* global (static) variables needed by get_audio_head */static unsigned long old_mpegaudio_head,skipped_mpegaudio_bytes;/* global (static) variables needed by head_read */static unsigned char audio_hbuf[4];static int audio_header_bytes_read;static int get_sync_byte() { return (getbits8() == SYNC_BYTE) ? 1 : 0; }static void copy_PAT_temp2PAT(int prognum); /* needed by get_program_association_table */static int get_program_association_table_rest(int expect_start);static int get_and_parse_program_association_table_header();static int get_program_association_table(int start);static int get_pes_packet();static int get_pes_packet_data(int stream_id);static int get_pes_packet_header(unsigned long long *pts, unsigned long long *dts, int *havepts);static int get_PMT_packet(int section_start);static int get_audio_data();static int get_video_data();static void set_pids_internal(int videopid, int audiopid, int pcrpid);/* audio fifo management */static int head_read(unsigned long *head);static int head_check(unsigned long head);static int decode_header(struct frame *fr,unsigned long newhead, int *ssize);static int get_audio_head(struct frame *fr, int *ssize);static int audiobufferfill();/** returns the pid of an audio stream, -1 if no audio stream exists */static int getAudioPid(const struct ProgramMapTableEntry *pmt){ int result=-1; struct stream_description *hilf; hilf=pmt->streams; while (hilf) { if (hilf->stream_type==3 || hilf->stream_type==4) result=hilf->elementary_PID; hilf=hilf->next; } return result;}/** returns the pid of an video stream, -1 if no video stream exists */static int getVideoPid(const struct ProgramMapTableEntry *pmt){ int result=-1; struct stream_description *hilf; hilf=pmt->streams; while (hilf) { if (hilf->stream_type==1 || hilf->stream_type==2) result=hilf->elementary_PID; hilf=hilf->next; } return result;} /** returns the pid of the pcr */static int getPCRPid(const struct ProgramMapTableEntry *pmt) { return pmt->PCR_PID;}static void cleanPMTEntry(struct ProgramMapTableEntry *pmt){ while (pmt->streams) { struct stream_description *sd=pmt->streams; pmt->streams = sd->next; free(sd); }}static struct ProgramMapTableEntry* getProgramMapTableEntry(int number){ struct ProgramMapTableEntry* temp=program_map_table; while (temp && (temp->program_number != number)) { temp=temp->next; } return temp;}static int isProgramMapTable(int PID){ int i; for (i=0;i < number_of_programs;i++) if (PAT[i].program_map_PID == PID) return PAT[i].program_number?1:2; return 0;}static int getFirstProgram(){ int i; for (i=0;i < number_of_programs;i++) if (PAT[i].program_number) return PAT[i].program_number; return -1;}/* returns the index in the pmt buffer or the index of an empty one, if it not yet exists of -1 if the buffer is full */static int get_PMT_Buffer_Index(int number){ int hilf=-1,i; for (i=0;i < PMT_BUFFERS;i++) if (pmt_buffer[i].pid == number) return i; else if ((pmt_buffer[i].pid == -1) && (hilf == -1)) hilf=i; return hilf;}static int get_adaptation_field();static int get_payload();static int get_transport_packet(){ if (get_sync_byte()){ /* check for sync byte */ unsigned int bits=getbits16(); unsigned char continuity_counter; transport_packets++; transport_error_indicator=bits >> 15; payload_unit_start_indicator=(bits >> 14) & 1; pid=bits & 0x00001fff; transport_scrambling_control=(nextbits8() >> 6)&0x3; adaptation_field_control=(nextbits8() >> 4)&0x3; continuity_counter= getbits8() & 0xf; if (!pidcount[pid]++) { if (debug) { fprintf(stdout,"new pid: %d\n", pid); } } if (transport_error_indicator){ transport_packet_errors++; return 0; /* error set! */ } if (pid==0x1fff){ return 1; /* padding; just go to next */ } if (pidcount[pid] > 1) /* only check continuity counters, if this is not the first packet */ { if (continuity_counters[pid] == continuity_counter && adaptation_field_control & 1) { if (debug) { fprintf(stdout,"skipping duplicate packet in stream %d\n", pid); } return 1; } if (adaptation_field_control & 1) continuity_counters[pid]=(continuity_counters[pid] +1) & 0x0f; if (continuity_counters[pid]!=continuity_counter) { if (adaptation_field_control & 2) /* has adaptation_field */ { fprintf(stderr,"maybe lost %d packet(s) of stream %d; could also be discontinous; adaption field control: %d\n", (continuity_counter-continuity_counters[pid] + 16) % 16, pid, adaptation_field_control); } else { fprintf(stderr,"lost %d packet(s) of stream %d\n", (continuity_counter-continuity_counters[pid] + 16) % 16, pid); lost_packets++; if (!pid) /* (== PAT) */ PAT_position=0; /* we have to discard, what we already read from pat */ if (isProgramMapTable(pid)) { int bufferindex=get_PMT_Buffer_Index(pid); if (bufferindex != -1) pmt_buffer[bufferindex].pid=-1; /* we have to throw away any started PMT section */ } } } } continuity_counters[pid]=continuity_counter; if (adaptation_field_control==2 || adaptation_field_control==3) get_adaptation_field(); if (adaptation_field_control==1 || adaptation_field_control==3) get_payload(); return 1; } else { sync_byte_errors++; fprintf(stderr,"sync error\n"); return 0; }}static void* transport_stream(void* arg){ do { if (nextpacket()) { if (!get_transport_packet()) { fprintf(stderr, "incorrect packet %d\n", transport_packets); } } else { fprintf(stderr, "source did not deliver packet\n"); if ((videobufferend + 1) % VIDEOPESPACKETSINBUFFER == videobufferstart) { /* if buffer is full */ fprintf(stderr,"Video buffer full! Cannot deliver clearscreen event\n"); } else { /* send clearscreen to video system */ videobuffer[videobufferend].flags = VIDEOBUFFER_FLAGS_CLEARSCREEN; videobufferend++; videobufferend %= VIDEOPESPACKETSINBUFFER; /* advance ringbuffercounter */ if (sem_post(&videobuffer_sem)) { fprintf(stderr,"Cannot V semaphore\n"); exit(0); } videobuffer[videobufferend].havedts=0; videobuffer[videobufferend].continuation=1; /* next packet should be continuation of started one */ videobuffer[videobufferend].length=0; videobuffer[videobufferend].flags = 0; } } } while (!terminate); return NULL;}int mpeg2demux_init(){ int i; audio_pid=-1; /* disable all pids at start */ video_pid=-1; pcr_pid=-1; track_program=-1; current_program=-1; have_mpegaudio_header=0; /* initialization for audiobufferfill */ old_mpegaudio_head = 0,skipped_mpegaudio_bytes=0; /* initialization for get_audio_head */ transport_packets=0; transport_packet_errors=0; sync_byte_errors=0; lost_packets=0; audio_packets=0; video_packets=0; pcr_packets=0; audio_frames=0; number_of_programs=0; PAT_position=NULL; for (i=0;i < MAX_PIDS;i++) pidcount[i]=0; program_map_table=NULL; for (i=0; i < PMT_BUFFERS;i++) pmt_buffer[i].pid=-1; (void) pthread_mutex_init(&mutex_PMT,NULL);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -