⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mpeg.c

📁 linux下的MPEG1
💻 C
📖 第 1 页 / 共 2 页
字号:
/*  $Id: mpeg.c,v 1.2 2004/04/11 12:20:32 miguelfreitas Exp $  Copyright (C) 2000 Herbert Valerio Riedel <hvr@gnu.org>  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*/#ifdef HAVE_CONFIG_H# include "config.h"#endif#include <stdio.h>#include <cdio/cdio.h>/* Private headers */#include "bitvec.h"#include "mpeg.h"#include "util.h"static const char _rcsid[] = "$Id: mpeg.c,v 1.2 2004/04/11 12:20:32 miguelfreitas Exp $";#define MPEG_START_CODE_PATTERN  ((uint32_t) 0x00000100)#define MPEG_START_CODE_MASK     ((uint32_t) 0xffffff00)#define MPEG_PICTURE_CODE        ((uint32_t) 0x00000100)/* [...slice codes... 0x1a7] */#define MPEG_USER_CODE           ((uint32_t) 0x000001b2)#define MPEG_SEQUENCE_CODE       ((uint32_t) 0x000001b3)#define MPEG_EXT_CODE            ((uint32_t) 0x000001b5)#define MPEG_SEQ_END_CODE        ((uint32_t) 0x000001b7)#define MPEG_GOP_CODE            ((uint32_t) 0x000001b8)#define MPEG_PROGRAM_END_CODE    ((uint32_t) 0x000001b9)#define MPEG_PACK_HEADER_CODE    ((uint32_t) 0x000001ba)#define MPEG_SYSTEM_HEADER_CODE  ((uint32_t) 0x000001bb)#define MPEG_PRIVATE_1_CODE      ((uint32_t) 0x000001bd)#define MPEG_PAD_CODE            ((uint32_t) 0x000001be)#define MPEG_AUDIO_C0_CODE       ((uint32_t) 0x000001c0) /* default */#define MPEG_AUDIO_C1_CODE       ((uint32_t) 0x000001c1) /* 2nd audio stream id (dual channel) */#define MPEG_AUDIO_C2_CODE       ((uint32_t) 0x000001c2) /* 3rd audio stream id (surround sound) */#define MPEG_VIDEO_E0_CODE       ((uint32_t) 0x000001e0) /* motion */#define MPEG_VIDEO_E1_CODE       ((uint32_t) 0x000001e1) /* lowres still */#define MPEG_VIDEO_E2_CODE       ((uint32_t) 0x000001e2) /* hires still */#define PICT_TYPE_I             1#define PICT_TYPE_P             2#define PICT_TYPE_B             3#define PICT_TYPE_D             4static struct {  mpeg_norm_t norm;  unsigned hsize;  unsigned vsize;  int frate_idx;} const norm_table[] = {  { MPEG_NORM_FILM,   352, 240, 1 },  { MPEG_NORM_PAL,    352, 288, 3 },  { MPEG_NORM_NTSC,   352, 240, 4 },  { MPEG_NORM_PAL_S,  480, 576, 3 },  { MPEG_NORM_NTSC_S, 480, 480, 4 },  { MPEG_NORM_OTHER, }};static const double frame_rates[16] =  {  0.0, 24000.0/1001, 24.0, 25.0,   30000.0/1001, 30.0,  50.0, 60000.0/1001,   60.0, 0.0, };#ifdef DEBUG# define MARKER(buf, offset) \ vcd_assert (vcd_bitvec_read_bit (buf, offset) == 1)#else# define MARKER(buf, offset) \ { if (GNUC_UNLIKELY (vcd_bitvec_read_bit (buf, offset) != 1)) vcd_debug ("mpeg: some marker is not set..."); }#endifstatic inline bool_start_code_p (uint32_t code){  return (code & MPEG_START_CODE_MASK) == MPEG_START_CODE_PATTERN;}static inline int _vid_streamid_idx (uint8_t streamid){  switch (streamid | MPEG_START_CODE_PATTERN)    {    case MPEG_VIDEO_E0_CODE:      return 0;      break;    case MPEG_VIDEO_E1_CODE:      return 1;      break;    case MPEG_VIDEO_E2_CODE:      return 2;      break;    default:      vcd_assert_not_reached ();      break;    }    return -1;}static inline int _aud_streamid_idx (uint8_t streamid){  switch (streamid | MPEG_START_CODE_PATTERN)    {    case MPEG_AUDIO_C0_CODE:      return 0;      break;    case MPEG_AUDIO_C1_CODE:      return 1;      break;    case MPEG_AUDIO_C2_CODE:      return 2;      break;    default:      vcd_assert_not_reached ();      break;    }    return -1;}/* used for SCR, PTS and DTS */static inline uint64_t_parse_timecode (const uint8_t *buf, unsigned *offset){  uint64_t _retval;  _retval = vcd_bitvec_read_bits (buf, offset, 3);  MARKER (buf, offset);  _retval <<= 15;  _retval |= vcd_bitvec_read_bits (buf, offset, 15);        MARKER (buf, offset);  _retval <<= 15;  _retval |= vcd_bitvec_read_bits (buf, offset, 15);  MARKER (buf, offset);  return _retval;}static void_parse_sequence_header (uint8_t streamid, const uint8_t *buf, 			VcdMpegStreamCtx *state){  unsigned offset = 0;  unsigned hsize, vsize, aratio, frate, brate, bufsize, constr;  const uint8_t *data = buf;  const int vid_idx = _vid_streamid_idx (streamid);  const double aspect_ratios[16] =     {       0.0000, 1.0000, 0.6735, 0.7031,      0.7615, 0.8055, 0.8437, 0.8935,      0.9375, 0.9815, 1.0255, 1.0695,      1.1250, 1.1575, 1.2015, 0.0000    };  if (state->stream.shdr[vid_idx].seen) /* we have it already */    return;    hsize = vcd_bitvec_read_bits (data, &offset, 12);  vsize = vcd_bitvec_read_bits (data, &offset, 12);  aratio = vcd_bitvec_read_bits (data, &offset, 4);  frate = vcd_bitvec_read_bits (data, &offset, 4);  brate = vcd_bitvec_read_bits (data, &offset, 18);  MARKER (data, &offset);  bufsize = vcd_bitvec_read_bits (data, &offset, 10);  constr = vcd_bitvec_read_bits (data, &offset, 1);  /* skip intra quantizer matrix */  if (vcd_bitvec_read_bits (data, &offset, 1))    offset += 64 << 3;  /* skip non-intra quantizer matrix */  if (vcd_bitvec_read_bits (data, &offset, 1))    offset += 64 << 3;    state->stream.shdr[vid_idx].hsize = hsize;  state->stream.shdr[vid_idx].vsize = vsize;  state->stream.shdr[vid_idx].aratio = aspect_ratios[aratio];  state->stream.shdr[vid_idx].frate = frame_rates[frate];  state->stream.shdr[vid_idx].bitrate = 400 * brate;  state->stream.shdr[vid_idx].vbvsize = bufsize * 16 * 1024;   state->stream.shdr[vid_idx].constrained_flag = (constr != 0);  state->stream.shdr[vid_idx].seen = true;}static void_parse_gop_header (uint8_t streamid, const uint8_t *buf, 		   VcdMpegStreamCtx *state){  const uint8_t *data = buf;  unsigned offset = 0;    bool drop_flag;   /* bool close_gop; */  /* bool broken_link; */  unsigned hour, minute, second, frame;  drop_flag = vcd_bitvec_read_bits(data, &offset, 1) != 0;    hour = vcd_bitvec_read_bits(data, &offset, 5);  minute = vcd_bitvec_read_bits(data, &offset, 6);  MARKER (data, &offset);  second = vcd_bitvec_read_bits(data, &offset, 6);  frame = vcd_bitvec_read_bits(data, &offset, 6);  /* close_gop = vcd_bitvec_read_bits(data, &offset, 1) != 0; */  /* broken_link = vcd_bitvec_read_bits(data, &offset, 1) != 0; */  state->packet.gop = true;  state->packet.gop_timecode.h = hour;  state->packet.gop_timecode.m = minute;  state->packet.gop_timecode.s = second;  state->packet.gop_timecode.f = frame;}static inline void_check_scan_data (const char str[], const msf_t *msf,                  VcdMpegStreamCtx *state){  char tmp[16];  if (state->stream.scan_data_warnings > VCD_MPEG_SCAN_DATA_WARNS)    return;  if (state->stream.scan_data_warnings == VCD_MPEG_SCAN_DATA_WARNS)    {      vcd_warn ("mpeg user scan data: from now on, scan information "                "data errors will not be reported anymore---consider"                " enabling the 'update scan offsets' option, "                "if it is not enabled already!");      state->stream.scan_data_warnings++;      return;    }        if (msf->m == 0xff      && msf->s == 0xff      && msf->f == 0xff)    return;  if ((msf->s & 0x80) == 0      || (msf->f & 0x80) == 0)    {      snprintf (tmp, sizeof (tmp), "%.2x:%.2x.%.2x", msf->m, msf->s, msf->f);      vcd_warn ("mpeg user scan data: msb of second or frame field "                "not set for '%s': [%s]", str, tmp);      state->stream.scan_data_warnings++;      return;    }  if ((msf->m >> 4) > 9      || ((0x80 ^ msf->s) >> 4) > 9            || ((0x80 ^ msf->f) >> 4) > 9      || (msf->m & 0xf) > 9      || (msf->s & 0xf) > 9      || (msf->f & 0xf) > 9)    {      snprintf (tmp, sizeof (tmp), "%.2x:%.2x.%.2x",                msf->m, 0x80 ^ msf->s, 0x80 ^ msf->f);      vcd_warn ("mpeg user scan data: one or more BCD fields out of range "                "for '%s': [%s]", str, tmp);      state->stream.scan_data_warnings++;    }}static void_parse_user_data (uint8_t streamid, const void *buf, unsigned len,                   unsigned offset,                  VcdMpegStreamCtx *state){  unsigned pos = 0;  PRAGMA_BEGIN_PACKED  struct {    uint8_t tag;    uint8_t len;    uint8_t data[EMPTY_ARRAY_SIZE];  } GNUC_PACKED const *udg = buf;  PRAGMA_END_PACKED  if (udg->tag == 0x00) /* if first tag's already 0x00 */    {      vcd_debug ("strange (possibly non-compliant) user_data seen...");    }  else while (pos + 2 < len)    {      if (udg->tag == 0x00)        break;      if (pos + udg->len >= len)        break;      if (udg->len < 2)        break;      switch (udg->tag)        {        case 0x00:          vcd_assert_not_reached ();          break;        case 0x10: /* scan information */          {            struct vcd_mpeg_scan_data_t *usdi = (void *) udg;            vcd_assert (sizeof (struct vcd_mpeg_scan_data_t) == 14);                        if (GNUC_UNLIKELY (usdi->len != 14))              {                vcd_warn ("invalid user scan data length (%d != 14)", usdi->len);                break;              }            vcd_assert (usdi->len == 14);            _check_scan_data ("previous_I_offset", &usdi->prev_ofs, state);            _check_scan_data ("next_I_offset    ", &usdi->next_ofs, state);            _check_scan_data ("backward_I_offset", &usdi->back_ofs, state);            _check_scan_data ("forward_I_offset ", &usdi->forw_ofs, state);                      state->packet.scan_data_ptr = usdi;            state->stream.scan_data++;          }          break;        case 0x11: /* closed caption data */          vcd_debug ("closed caption data seen -- not supported yet (len = %d)", udg->len);          break;        default:          vcd_warn ("unknown user data tag id 0x%.2x encountered", udg->tag);          return; /* since we cannot rely on udg->len anymore... */          break;        }      pos += udg->len;      vcd_assert (udg->len >= 2);      udg = (void *) &udg->data[udg->len - 2];    }    vcd_assert (pos <= len);}static int_analyze_pes_header (const uint8_t *buf, int len,                     VcdMpegStreamCtx *state){  bool _has_pts = false;  bool _has_dts = false;  int64_t pts = 0;  mpeg_vers_t pes_mpeg_ver = MPEG_VERS_INVALID;  int pos;  if (vcd_bitvec_peek_bits (buf, 0, 2) == 2) /* %10 - ISO13818-1 */    {      unsigned pos2 = 0;      pes_mpeg_ver = MPEG_VERS_MPEG2;      pos2 += 2;      pos2 += 2; /* PES_scrambling_control */      pos2++; /* PES_priority */      pos2++; /* data_alignment_indicator */      pos2++; /* copyright */      pos2++; /* original_or_copy */      switch (vcd_bitvec_read_bits (buf, &pos2, 2)) /* PTS_DTS_flags */        {        case 2: /* %10 */          _has_pts = true;          break;                  case 3: /* %11 */          _has_dts = _has_pts = true;          break;        default:          /* NOOP */          break;        }      pos2++; /* ESCR_flag */            pos2++; /* */      pos2++; /* */      pos2++; /* */      pos2++; /* */      pos2++; /* PES_extension_flag */      pos = vcd_bitvec_read_bits (buf, &pos2, 8); /* PES_header_data_length */      pos += pos2 >> 3;      if (_has_pts && _has_dts)        {          vcd_assert (vcd_bitvec_peek_bits (buf, pos2, 4) == 3); /* %0011 */          pos2 += 4;          pts = _parse_timecode (buf, &pos2);          vcd_assert (vcd_bitvec_peek_bits (buf, pos2, 4) == 1); /* %0001 */          pos2 += 4;          /* dts = */ _parse_timecode (buf, &pos2);        }      else if (_has_pts)        {          vcd_assert (vcd_bitvec_peek_bits (buf, pos2, 4) == 2); /* %0010 */          pos2 += 4;          pts = _parse_timecode (buf, &pos2);        }    }  else /* ISO11172-1 */    {      unsigned pos2 = 0;      pes_mpeg_ver = MPEG_VERS_MPEG1;      /* get rid of stuffing bytes */      while (((pos2 + 8) < (len << 3))              && vcd_bitvec_peek_bits (buf, pos2, 8) == 0xff)        pos2 += 8;      if (vcd_bitvec_peek_bits (buf, pos2, 2) == 1) /* %01 */        {          pos2 += 2;          pos2++;     /* STD_buffer_scale */          pos2 += 13; /* STD_buffer_size */        }      switch (vcd_bitvec_peek_bits (buf, pos2, 4))         {        case 0x2: /* %0010 */          pos2 += 4;          _has_pts = true;          pts = _parse_timecode (buf, &pos2);          break;        case 0x3: /* %0011 */          pos2 += 4;          _has_dts = _has_pts = true;          pts = _parse_timecode (buf, &pos2);          vcd_assert (vcd_bitvec_peek_bits (buf, pos2, 4) == 1); /* %0001 */          pos2 += 4;          /* dts = */ _parse_timecode (buf, &pos2);          break;        case 0x0: /* %0000 */          vcd_assert (vcd_bitvec_peek_bits (buf, pos2, 8) == 0x0f);          pos2 += 8;          break;        case 0xf: /* %1111 - actually a syntax error! */          vcd_assert (vcd_bitvec_peek_bits (buf, pos2, 8) == 0xff);          vcd_warn ("Unexpected stuffing byte noticed in ISO11172 PES header!");          pos2 += 8;          break;         default:          vcd_error ("Error in ISO11172 PES header");          break;        }      pos = pos2 >> 3;    }  if (_has_pts)    {      double pts2;            pts2 = (double) pts / 90000.0;      if (!state->stream.seen_pts)        {          state->stream.max_pts = state->stream.min_pts = pts2;          state->stream.seen_pts = true;        }      else        {          state->stream.max_pts = MAX (state->stream.max_pts, pts2);          state->stream.min_pts = MIN (state->stream.min_pts, pts2);        }      state->packet.has_pts = true;      state->packet.pts = pts2;    }  if (state->stream.version != pes_mpeg_ver)    vcd_warn ("pack header mpeg version does not match pes header mpeg version");  return pos;}static void_analyze_audio_pes (uint8_t streamid, const uint8_t *buf, int len, bool only_pts,		    VcdMpegStreamCtx *state){  const int aud_idx = _aud_streamid_idx (streamid);  unsigned bitpos;  vcd_assert (aud_idx != -1);  bitpos = _analyze_pes_header (buf, len, state);  /* if only pts extraction was needed, we are done here... */  if (only_pts)    return;  if (state->stream.ahdr[aud_idx].seen)    return;  bitpos <<= 3;  while (bitpos <= (len << 3))    {      unsigned syncword = vcd_bitvec_peek_bits (buf, bitpos, 12);      if (syncword != 0xfff)        {          bitpos += 8;          continue;        }      bitpos += 12;      if (GNUC_UNLIKELY (!vcd_bitvec_read_bits (buf, &bitpos, 1)))        {          vcd_debug ("non-MPEG1 audio stream header seen");          break;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -