📄 programstream.c
字号:
/* Ogle - A video player * Copyright (C) 2000, 2001 Bj鰎n Englund, H錵an Hjort * * 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 */#include <inttypes.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <signal.h>#include <sys/mman.h>#include <sys/types.h>#include <sys/stat.h>#include <sys/shm.h>#include <fcntl.h>#include <unistd.h>#include <sys/msg.h>#include <errno.h>#include <ogle/msgevents.h>#include <dvdread/dvd_reader.h>#include "debug_print.h"#include "ogle_endian.h"#include "programstream.h"#include "common.h"#include "queue.h"#include "mpeg.h"#ifndef SHM_SHARE_MMU#define SHM_SHARE_MMU 0#endiftypedef enum { STREAM_NOT_REGISTERED = 0, STREAM_DISCARD = 1, STREAM_DECODE = 2, STREAM_MUTED = 3} stream_state_t; typedef struct { int infile; FILE *file; int shmid; char *shmaddr; stream_state_t state; // not_registerd, in_use, muted, ...} buf_data_t;buf_data_t id_reg[256];buf_data_t id_reg_ps1[256];int register_id(uint8_t id, int subtype);int id_registered(uint8_t id, uint8_t subtype);int init_id_reg(stream_state_t default_state);//int wait_for_msg(mq_cmdtype_t cmdtype);//int eval_msg(mq_cmd_t *cmd);int get_buffer(int size);int attach_decoder_buffer(uint8_t stream_id, uint8_t subtype, int shmid);int id_stat(uint8_t id, uint8_t subtype);char *id_qaddr(uint8_t id, uint8_t subtype);FILE *id_file(uint8_t id, uint8_t subtype);void id_add(uint8_t stream_id, uint8_t subtype, stream_state_t state, int shmid, char *shmaddr, FILE *file);int put_in_q(char *q_addr, int off, int len, uint8_t PTS_DTS_flags, uint64_t PTS, uint64_t DTS, int is_new_file, int extra_cmd, PacketType_t packet_type, uint32_t packet_offset);int attach_buffer(int shmid, int size);//int chk_for_msg(void);void loadinputfile(char *infilename);void add_to_demux_q(MsgEvent_t *ev);static void handle_events(MsgEvent_t *ev);int id_infile(uint8_t id, uint8_t subtype);void id_setinfile(uint8_t id, uint8_t subtype, int newfile);uint8_t type_registered(uint8_t id, uint8_t subtype);int switch_to_stream(uint8_t id, uint8_t subtype);int switch_from_to_stream(uint8_t oldid, uint8_t oldsubtype, uint8_t newid, uint8_t newsubtype);int id_has_output(uint8_t stream_id, uint8_t subtype);int id_get_output(uint8_t id, int subtype);typedef struct { uint8_t *buf_start; int len; int in_use;} q_elem;static int msgqid = -1;static MsgEventQ_t *msgq;int scr_discontinuity = 0;uint64_t SCR_base;uint16_t SCR_ext;uint8_t SCR_flags;int packnr = 0;#define MPEG1 0x0#define MPEG2 0x1uint8_t *disk_buf;int shmid;char *shmaddr;int shmsize;static int ctrl_data_shmid;static ctrl_data_t *ctrl_data;static ctrl_time_t *ctrl_time;char *data_buf_addr;int off_from;int off_to;int demux_cmd;extern char *optarg;extern int optind, opterr, optopt;/* Variables for getbits */unsigned int bits_left = 64;uint64_t cur_word = 0;unsigned int nextbits(unsigned int nr_of_bits);int synced = 0;int audio = 0;int debug = 0;char *program_name;int dlevel;FILE *video_file;FILE *audio_file;FILE *subtitle_file;FILE *ps1_file;int video_stream = -1;int infilefd;void* infileaddr;long infilelen;uint32_t offs;char cur_filename[PATH_MAX+1];int new_file;// #define DEBUG#ifdef STATS static uint32_t stat_video_unaligned_packet_offset = 0; static uint32_t stat_video_unaligned_packet_end = 0; static uint32_t stat_video_n_packets = 0; static uint32_t stat_audio_n_packets = 0; static uint32_t stat_subpicture_n_packets = 0; static uint32_t stat_n_packets = 0;#endif //STATSvoid usage(void){ fprintf(stderr, "Usage: %s [-v <video file>] [-a <audio file>] [-s <subtitle file> -i <subtitle_id>] [-p subid=<substreambaseid>,nr=<streamnr>,file=<outputfile>] [-d <debug level>] <input file>\n", program_name);}/* 2.3 Definition of bytealigned() function */int bytealigned(void){ return !(bits_left%8);}#ifdef DEBUG#define GETBITS(a,b) getbits(a,b)#else#define GETBITS(a,b) getbits(a)#endif#ifdef DEBUGuint32_t getbits(unsigned int nr, char *func)#elsestatic inline uint32_t getbits(unsigned int nr)#endif{ uint32_t result; result = (cur_word << (64-bits_left)) >> 32; result = result >> (32-nr); bits_left -=nr; if(bits_left <= 32) { uint32_t new_word = FROM_BE_32(*(uint32_t *)(&disk_buf[offs])); offs+=4; cur_word = (cur_word << 32) | new_word; bits_left = bits_left+32; } DPRINTF(5, "%s getbits(%u): %0*i, 0x%0*x, ", func, nr, (nr-1)/3+1, result, (nr-1)/4+1, result); DPRINTBITS(6, nr, result); DPRINTF(5, "\n"); return result;}static inline void drop_bytes(int len){ uint rest; uint todo; // This is always byte-aligned. Trust us. len -= bits_left/8; rest = len % 4; offs += (len - rest); todo = bits_left+rest*8; while(todo > 32) { GETBITS(32, "skip"); todo -= 32; } GETBITS(todo, "skip"); return;}#if 1static dvd_reader_t *dvdroot;static dvd_file_t *dvdfile;int dvd_open_root(char *path){ if((dvdroot = DVDOpen(path)) == NULL) { FATAL("%s", "Couldn't open dvd\n"); exit(1); } return 0;} int dvd_close_root(void) { DVDClose(dvdroot); return 0;}static int dvd_file_num = -1;static dvd_read_domain_t dvd_file_dom = -1;int dvd_change_file(int titlenum, dvd_read_domain_t domain){ // If same as current do nothing if(titlenum == dvd_file_num && domain == dvd_file_dom) { return 0; } if(dvdfile != NULL && dvdroot != NULL) { //fprintf(stderr, "demux: closing open file when opening new\n"); DVDCloseFile(dvdfile); } if((dvdfile = DVDOpenFile(dvdroot, titlenum, domain)) == NULL) { FATAL("%s", "Couldn't open dvdfile\n"); exit(1); } dvd_file_num = titlenum; dvd_file_dom = domain; return 0;}void dvd_close_file(void){ DVDCloseFile(dvdfile); dvd_file_num = -1; dvd_file_dom = -1; }int dvd_read_block(char *buf, int boffset, int nblocks){ int blocks_read; int tries = 0; do { blocks_read = DVDReadBlocks(dvdfile, boffset, nblocks, buf); switch(blocks_read) { case -1: FATAL("%s", "dvdreadblocks failed\n"); exit(1); case 0: WARNING("%s", "dvdreadblocks returned 0\n"); if(tries > 3) { fprintf(stderr, "\n\n" "Ogle can't read any data.\n""Make sure that the CSS authentication works correctly.\n""See also the FAQ at http://www.dtek.chalmers.se/~dvd/faq.shtml\n""Three common problems are:\n""no write permission on you DVD drives device node.\n""you are trying to play a DVD from a region other than the one \n""of the DVD drive.\n""or you have never set the region on the drive.\n\n""For setting the region; a program called regionset will do this.\n""Search for dvd_disc or dvdkit on freshmeat.net\n""Beware that you can only sset the region 5 times!\n\n"); exit(1); } tries++; break; default: break; } if(blocks_read != nblocks) { WARNING("dvdreadblocks only got %d, wanted %d\n", blocks_read, nblocks); } buf += blocks_read * 2048; nblocks -= blocks_read; boffset += blocks_read; } while(nblocks > 0); return 0;}int fill_buffer(int title, dvd_read_domain_t domain, int boffset, int nblocks){ int next_write_pos; static int free_block_offs = 0; data_buf_head_t *data_buf_head; data_elem_t *data_elems; int data_elem_nr; int buf_empty = 0; int first_data_elem_nr; int off; int blocks_in_buf; int size; //fprintf(stderr, "demux: fill_buffer: title: %d, domain: %d, off: %d, blocks: %d\n", title, domain, boffset, nblocks); // get_next_demux_range(&title, &domain, &boffset, &blocks); data_buf_head = (data_buf_head_t *)data_buf_addr; if(data_buf_head == NULL) { fprintf(stderr, "*demux: fill_buffer, no buffer\n"); exit(1); } blocks_in_buf = data_buf_head->buffer_size/2048; //fprintf(stderr, "blocks_in_buf: %d\n", blocks_in_buf); data_elems = (data_elem_t *)(data_buf_addr+sizeof(data_buf_head_t)); data_elem_nr = data_buf_head->write_nr; first_data_elem_nr = data_elem_nr; //fprintf(stderr, "first_data_elem_nr: %d\n", first_data_elem_nr); while(1) { if(data_elems[data_elem_nr].in_use || buf_empty) { /* this block is in use, check if we have enough free space */ /* offset in buffer of the used block we found */ if(buf_empty) { off = blocks_in_buf; free_block_offs = 0; } else { off = data_elems[data_elem_nr].packet_offset / 2048; } if(off < free_block_offs) { /* if the block in use is before the first free block * we can either use the blocks * between the first free block and the end of the buffer * or * use the blocks * between the beginning of the buffer and the used block in use */ /* nr of blocks from first free block to end of buffer */ size = blocks_in_buf - free_block_offs; next_write_pos = free_block_offs; if(size < nblocks) { /* nr of blocks from start of buffer to the block in use */ size = off; next_write_pos = 0; } } else { /* the block in use is after the first free block in the buffer */ /* nr of blocks from first free block to the block in use */ size = off - free_block_offs; next_write_pos = free_block_offs; } if(size < nblocks) { /* the nr of contigously available blocks is too small, * wait for more free blocks */ fprintf(stderr, "*demux: SEND A BUG REPORT: need more free space, not implemented\n"); } else { /* we have enough free blocks */ break; } } /* this block is not in use, check next one */ data_elem_nr = (data_elem_nr+1) % data_buf_head->nr_of_dataelems; /* check if we have looped through all data_elems */ if(!buf_empty) { if(data_elem_nr == first_data_elem_nr) { buf_empty = 1; } } } dvd_change_file(title, domain); dvd_read_block(&disk_buf[next_write_pos*2048], boffset, nblocks); //fprintf(stderr, "next_write_pos: %d\n", next_write_pos); //fprintf(stderr, "dvd_read_block: dst: %u, offset: %d, blocks: %d\n", next_write_pos*2048, boffset, nblocks); free_block_offs = next_write_pos + nblocks; //fprintf(stderr, "free_block_offs: %d\n", free_block_offs); off_from = next_write_pos * 2048; off_to = free_block_offs * 2048; //fprintf(stderr, "off_from: %d, off_to: %d\n", off_from, off_to); return 0;}#endifunsigned int nextbits(unsigned int nr_of_bits){ uint32_t result = (cur_word << (64-bits_left)) >> 32; DPRINTF(4, "nextbits %08x\n",(result >> (32-nr_of_bits ))); return result >> (32-nr_of_bits);}static inline void marker_bit(void) { if(!GETBITS(1, "markerbit")) { WARNING("%s", "Incorrect marker_bit in stream\n"); //exit(1); }} /* 2.3 Definition of next_start_code() function */void next_start_code(void){ while(!bytealigned()) { GETBITS(1, "next_start_code"); } while(nextbits(24) != 0x000001) { GETBITS(8, "next_start_code"); } }/* Table 2-24 -- Stream_id table */void dprintf_stream_id (int debuglevel, int stream_id){#ifdef DEBUG DPRINTF(debuglevel, "0x%02x ", stream_id); if ((stream_id & 0xf0) == 0xb0) // 1011 xxxx switch (stream_id & 0x0f) { case 0x8: DPRINTF(debuglevel, "[all audio streams]\n"); return; case 0x9: DPRINTF(debuglevel, "[all video streams]\n"); return; case 0xc: DPRINTF(debuglevel, "[program stream map]\n"); return; case 0xd: DPRINTF(debuglevel, "[private_stream_1]\n"); return; case 0xe: DPRINTF(debuglevel, "[padding stream]\n"); return; case 0xf: DPRINTF(debuglevel, "[private_stream_2]\n"); return; } else if ((stream_id & 0xe0) == 0xc0) { // 110x xxxx DPRINTF(debuglevel, "[audio stream number %i]\n", stream_id & 0x1f); return; } else if ((stream_id & 0xf0) == 0xe0) { DPRINTF(debuglevel, "[video stream number %i]\n", stream_id & 0x1f); return; } else if ((stream_id & 0xf0) == 0xf0) { switch (stream_id & 0x0f) { case 0x0: DPRINTF(debuglevel, "[ECM]\n"); return; case 0x1: DPRINTF(debuglevel, "[EMM]\n"); return; case 0x2: DPRINTF(debuglevel, "[DSM CC]\n"); return; case 0x3: DPRINTF(debuglevel, "[ISO/IEC 13522 stream]\n"); return; case 0xf: DPRINTF(debuglevel, "[program stream directory]\n"); return; default: DPRINTF(debuglevel, "[reserved data stream - number %i]\n", stream_id & 0x0f);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -