📄 mpeg2_ps.c
字号:
/* * The contents of this file are subject to the Mozilla Public * License Version 1.1 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or * implied. See the License for the specific language governing * rights and limitations under the License. * * The Original Code is MPEG4IP. * * The Initial Developer of the Original Code is Cisco Systems Inc. * Portions created by Cisco Systems Inc. are * Copyright (C) Cisco Systems Inc. 2004. All Rights Reserved. * * Contributor(s): * Bill May wmay@cisco.com *//* * mpeg2ps.c - parse program stream and vob files */#include "mpeg2_ps.h"static GFINLINE u16 convert16 (u8 *p){#ifdef GPAC_BIG_ENDIAN return *(u16 *)p;#else u16 val = p[0]; val <<= 8; return (val | p[1]);#endif}static GFINLINE u32 convert32 (u8 *p){#ifdef GPAC_BIG_ENDIAN return *(u32 *)p;#else u32 val; val = p[0]; val <<= 8; val |= p[1]; val <<= 8; val |= p[2]; val <<= 8; val |= p[3]; return val;#endif}#define FDNULL 0/* * structure for passing timestamps around */typedef struct mpeg2ps_ts_t{ Bool have_pts; Bool have_dts; u64 pts; u64 dts;} mpeg2ps_ts_t;typedef struct mpeg2ps_record_pes_t{ struct mpeg2ps_record_pes_t *next_rec; u64 dts; u64 location;} mpeg2ps_record_pes_t;s32 MPEG12_FindNextStartCode(unsigned char *pbuffer, u32 buflen, u32 *optr, u32 *scode){ u32 value; u32 offset; if (buflen < 4) return -1; for (offset = 0; offset < buflen - 3; offset++, pbuffer++) {#ifdef GPAC_BIG_ENDIAN value = *(u32 *)pbuffer >> 8;#else value = (pbuffer[0] << 16) | (pbuffer[1] << 8) | (pbuffer[2] << 0); #endif if (value == MPEG12_START_CODE_PREFIX) { *optr = offset; *scode = (value << 8) | pbuffer[3]; return 0; } } return -1;}s32 MPEG12_FindNextSliceStart(unsigned char *pbuffer, u32 startoffset, u32 buflen, u32 *slice_offset){ u32 slicestart, code; while (MPEG12_FindNextStartCode(pbuffer + startoffset, buflen - startoffset, &slicestart, &code) >= 0) { if ((code >= MPEG12_SLICE_MIN_START) && (code <= MPEG12_SLICE_MAX_START)) { *slice_offset = slicestart + startoffset; return 0; } startoffset += slicestart + 4; } return -1;}#ifndef GPAC_READ_ONLY/* * information about reading a stream */typedef struct mpeg2ps_stream_t { mpeg2ps_record_pes_t *record_first, *record_last; FILE *m_fd; Bool is_video; u8 m_stream_id; // program stream id u8 m_substream_id; // substream, for program stream id == 0xbd mpeg2ps_ts_t next_pes_ts, frame_ts; u32 frames_since_last_ts; u64 last_ts; Bool have_frame_loaded; /* * pes_buffer processing. this contains the raw elementary stream data */ u8 *pes_buffer; u32 pes_buffer_size; u32 pes_buffer_size_max; u32 pes_buffer_on; u32 frame_len; u32 pict_header_offset; // for mpeg video // timing information and locations. s64 first_pes_loc; u64 start_dts; Bool first_pes_has_dts; s64 end_dts_loc; u64 end_dts; // audio stuff u32 freq; u32 channels; u32 bitrate; u32 samples_per_frame; u32 layer; // video stuff u32 h, w, par; Double frame_rate; s32 have_mpeg2; Double bit_rate; u64 ticks_per_frame;} mpeg2ps_stream_t;/* * main interface structure - contains stream pointers and other * information */struct mpeg2ps_ { mpeg2ps_stream_t *video_streams[16]; mpeg2ps_stream_t *audio_streams[32]; char *filename; FILE *fd; u64 first_dts; u32 audio_cnt, video_cnt; s64 end_loc; u64 max_dts; u64 max_time; // time is in msec.};/************************************************************************* * File access routines. Could all be inlined *************************************************************************/static FILE *file_open (const char *name){ return gf_f64_open(name, "rb");}static Bool file_okay (FILE *fd){ return (fd!=NULL) ? 1 : 0;}static void file_close (FILE *fd){ fclose(fd);}static Bool file_read_bytes(FILE *fd, u8 *buffer, u32 len){ u32 readval = fread(buffer, 1, len, fd); return readval == len;}// note: len could be negative.static void file_skip_bytes (FILE *fd, s32 len){ gf_f64_seek(fd, len, SEEK_CUR);}#define file_location(__f) gf_f64_tell(__f)#define file_seek_to(__f, __off) gf_f64_seek(__f, __off, SEEK_SET)static s64 file_size(FILE *fd){ s64 ret; gf_f64_seek(fd, 0, SEEK_END); ret = gf_f64_tell(fd); gf_f64_seek(fd, 0, SEEK_SET); return ret;}static mpeg2ps_record_pes_t *create_record (s64 loc, u64 ts){ mpeg2ps_record_pes_t *ret; GF_SAFEALLOC(ret, mpeg2ps_record_pes_t); ret->next_rec = NULL; ret->dts = ts; ret->location = loc; return ret;}#define MPEG2PS_RECORD_TIME ((u64) (5 * 90000))void mpeg2ps_record_pts (mpeg2ps_stream_t *sptr, s64 location, mpeg2ps_ts_t *pTs){ u64 ts; mpeg2ps_record_pes_t *p, *q; if (sptr->is_video) { if (pTs->have_dts == 0) return; ts = pTs->dts; } else { if (pTs->have_pts == 0) return; ts = pTs->pts; } if (sptr->record_first == NULL) { sptr->record_first = sptr->record_last = create_record(location, ts); return; } if (ts > sptr->record_last->dts) { if (ts < MPEG2PS_RECORD_TIME + sptr->record_last->dts) return; sptr->record_last->next_rec = create_record(location, ts); sptr->record_last = sptr->record_last->next_rec; return; } if (ts < sptr->record_first->dts) { if (ts < MPEG2PS_RECORD_TIME + sptr->record_first->dts) return; p = create_record(location, ts); p->next_rec = sptr->record_first; sptr->record_first = p; return; } p = sptr->record_first; q = p->next_rec; while (q != NULL && q->dts < ts) { p = q; q = q->next_rec; } if (p->dts + MPEG2PS_RECORD_TIME <= ts && ts + MPEG2PS_RECORD_TIME <= q->dts) { p->next_rec = create_record(location, ts); p->next_rec->next_rec = q; }}static Double mpeg12_frame_rate_table[16] ={ 0.0, /* Pad */ 24000.0/1001.0, /* Official frame rates */ 24.0, 25.0, 30000.0/1001.0, 30.0, 50.0, ((60.0*1000.0)/1001.0), 60.0, 1, /* Unofficial economy rates */ 5, 10, 12, 15, 0, 0,};#define SEQ_ID 1int MPEG12_ParseSeqHdr(unsigned char *pbuffer, u32 buflen, s32 *have_mpeg2, u32 *height, u32 *width, Double *frame_rate, Double *bitrate, u32 *aspect_ratio){ u32 aspect_code; u32 framerate_code; u32 bitrate_int; u32 bitrate_ext; u32 scode, ix; s32 found = -1; *have_mpeg2 = 0; buflen -= 6; bitrate_int = 0; for (ix = 0; ix < buflen; ix++, pbuffer++) { scode = (pbuffer[0] << 24) | (pbuffer[1] << 16) | (pbuffer[2] << 8) | pbuffer[3]; if (scode == MPEG12_SEQUENCE_START_CODE) { pbuffer += sizeof(u32); *width = (pbuffer[0]); *width <<= 4; *width |= ((pbuffer[1] >> 4) &0xf); *height = (pbuffer[1] & 0xf); *height <<= 8; *height |= pbuffer[2]; aspect_code = (pbuffer[3] >> 4) & 0xf; if (aspect_ratio != NULL) { u32 par = 0; switch (aspect_code) { default: *aspect_ratio = 0; break; case 2: par = 4; par<<=16; par |= 3; break; case 3: par = 16; par<<=16; par |= 9; break; case 4: par = 2; par<<=16; par |= 21; break; } *aspect_ratio = par; } framerate_code = pbuffer[3] & 0xf; *frame_rate = mpeg12_frame_rate_table[framerate_code]; // 18 bits bitrate_int = (pbuffer[4] << 10) | (pbuffer[5] << 2) | ((pbuffer[6] >> 6) & 0x3); *bitrate = bitrate_int; *bitrate *= 400.0; ix += sizeof(u32) + 7; pbuffer += 7; found = 0; } else if (found == 0) { if (scode == MPEG12_EXT_START_CODE) { pbuffer += sizeof(u32); ix += sizeof(u32); switch ((pbuffer[0] >> 4) & 0xf) { case SEQ_ID: *have_mpeg2 = 1; *height = ((pbuffer[1] & 0x1) << 13) | ((pbuffer[2] & 0x80) << 5) | (*height & 0x0fff); *width = (((pbuffer[2] >> 5) & 0x3) << 12) | (*width & 0x0fff); bitrate_ext = (pbuffer[2] & 0x1f) << 7; bitrate_ext |= (pbuffer[3] >> 1) & 0x7f; bitrate_int |= (bitrate_ext << 18); *bitrate = bitrate_int; *bitrate *= 400.0; break; default: break; } pbuffer++; ix++; } else if (scode == MPEG12_PICTURE_START_CODE) { return found; } } } return found;}s32 MPEG12_PictHdrType (unsigned char *pbuffer){ pbuffer += sizeof(u32); return ((pbuffer[1] >> 3) & 0x7);}u16 MPEG12_PictHdrTempRef(unsigned char *pbuffer){ pbuffer += sizeof(u32); return ((pbuffer[0] << 2) | ((pbuffer[1] >> 6) & 0x3));}static u64 read_pts (u8 *pak){ u64 pts; u16 temp; pts = ((pak[0] >> 1) & 0x7); pts <<= 15; temp = convert16(&pak[1]) >> 1; pts |= temp; pts <<= 15; temp = convert16(&pak[3]) >> 1; pts |= temp; return pts;}static mpeg2ps_stream_t *mpeg2ps_stream_create (u8 stream_id, u8 substream){ mpeg2ps_stream_t *ptr; GF_SAFEALLOC(ptr, mpeg2ps_stream_t); ptr->m_stream_id = stream_id; ptr->m_substream_id = substream; ptr->is_video = stream_id >= 0xe0; ptr->pes_buffer = (u8 *)malloc(4*4096); ptr->pes_buffer_size_max = 4 * 4096; return ptr;}static void mpeg2ps_stream_destroy (mpeg2ps_stream_t *sptr){ mpeg2ps_record_pes_t *p; while (sptr->record_first != NULL) { p = sptr->record_first; sptr->record_first = p->next_rec; free(p); } if (sptr->m_fd != FDNULL) { file_close(sptr->m_fd); sptr->m_fd = FDNULL; } if (sptr->pes_buffer) free(sptr->pes_buffer); free(sptr);}/* * adv_past_pack_hdr - read the pack header, advance past it * we don't do anything with the data */static void adv_past_pack_hdr (FILE *fd, u8 *pak, u32 read_from_start){ u8 stuffed; u8 readbyte; u8 val; if (read_from_start < 5) { file_skip_bytes(fd, 5 - read_from_start); file_read_bytes(fd, &readbyte, 1); val = readbyte; } else { val = pak[4]; } // we've read 6 bytes if ((val & 0xc0) != 0x40) { // mpeg1 file_skip_bytes(fd, 12 - read_from_start); // skip 6 more bytes return;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -