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

📄 mpeg_stream.c

📁 linux下的MPEG1
💻 C
字号:
/*    $Id: mpeg_stream.c,v 1.3 2005/01/01 02:43:59 rockyb Exp $    Copyright (C) 2000, 2004 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 <string.h>#include <stdio.h>#include <stdlib.h>#include <cdio/cdio.h>#include <cdio/bytesex.h>#include <libvcd/logging.h>/* Private headers */#include "vcd_assert.h"#include "mpeg_stream.h"#include "data_structures.h"#include "mpeg.h"#include "util.h"static const char _rcsid[] = "$Id: mpeg_stream.c,v 1.3 2005/01/01 02:43:59 rockyb Exp $";struct _VcdMpegSource{  VcdDataSource *data_source;  bool scanned;    /* _get_packet cache */  unsigned _read_pkt_pos;  unsigned _read_pkt_no;  struct vcd_mpeg_stream_info info;};/* * access functions */VcdMpegSource *vcd_mpeg_source_new (VcdDataSource *mpeg_file){  VcdMpegSource *new_obj;    vcd_assert (mpeg_file != NULL);  new_obj = _vcd_malloc (sizeof (VcdMpegSource));  new_obj->data_source = mpeg_file;  new_obj->scanned = false;  return new_obj;}voidvcd_mpeg_source_destroy (VcdMpegSource *obj, bool destroy_file_obj){  int i;  vcd_assert (obj != NULL);  if (destroy_file_obj)    vcd_data_source_destroy (obj->data_source);  for (i = 0; i < 3; i++)    if (obj->info.shdr[i].aps_list)      _cdio_list_free (obj->info.shdr[i].aps_list, true);  free (obj);}const struct vcd_mpeg_stream_info *vcd_mpeg_source_get_info (VcdMpegSource *obj){  vcd_assert (obj != NULL);  vcd_assert (obj->scanned);  return &(obj->info);}longvcd_mpeg_source_stat (VcdMpegSource *obj){  vcd_assert (obj != NULL);  vcd_assert (!obj->scanned);    return obj->info.packets * 2324;}voidvcd_mpeg_source_scan (VcdMpegSource *obj, bool strict_aps, bool fix_scan_info,                      vcd_mpeg_prog_cb_t callback, void *user_data){  unsigned length = 0;  unsigned pos = 0;  unsigned pno = 0;  unsigned padbytes = 0;  unsigned padpackets = 0;  VcdMpegStreamCtx state;  CdioListNode *n;  vcd_mpeg_prog_info_t _progress = { 0, };  vcd_assert (obj != NULL);  if (obj->scanned)    {      vcd_debug ("already scanned... not rescanning");      return;    }  vcd_assert (!obj->scanned);  memset (&state, 0, sizeof (state));    if (fix_scan_info)    state.stream.scan_data_warnings = VCD_MPEG_SCAN_DATA_WARNS + 1;  vcd_data_source_seek (obj->data_source, 0);  length = vcd_data_source_stat (obj->data_source);  if (callback)    {      _progress.length = length;      callback (&_progress, user_data);    }  while (pos < length)    {      char buf[2324] = { 0, };      int read_len = MIN (sizeof (buf), (length - pos));      int pkt_len;      vcd_data_source_read (obj->data_source, buf, read_len, 1);      pkt_len = vcd_mpeg_parse_packet (buf, read_len, true, &state);      if (!pkt_len)        {          if (!pno)            vcd_error ("input mpeg stream has been deemed invalid -- aborting");          vcd_warn ("bad packet at packet #%d (stream byte offset %d)"                    " -- remaining %d bytes of stream will be ignored",                    pno, pos, length - pos);          pos = length; /* don't fall into assert... */          break;        }      if (callback && (pos - _progress.current_pos) > (length / 100))        {          _progress.current_pos = pos;          _progress.current_pack = pno;          callback (&_progress, user_data);        }      switch (state.packet.aps)        {        case APS_NONE:          break;        case APS_I:        case APS_GI:          if (strict_aps)            break; /* allow only if now strict aps */        case APS_SGI:        case APS_ASGI:          {            struct aps_data *_data = _vcd_malloc (sizeof (struct aps_data));                        _data->packet_no = pno;            _data->timestamp = state.packet.aps_pts;            if (!state.stream.shdr[state.packet.aps_idx].aps_list)              state.stream.shdr[state.packet.aps_idx].aps_list = _cdio_list_new ();                        _cdio_list_append (state.stream.shdr[state.packet.aps_idx].aps_list, _data);          }          break;        default:          vcd_assert_not_reached ();          break;        }      pos += pkt_len;      pno++;      if (pkt_len != read_len)        {          padbytes += (2324 - pkt_len);          if (!padpackets)            vcd_warn ("mpeg stream will be padded on the fly -- hope that's ok for you!");          padpackets++;          vcd_data_source_seek (obj->data_source, pos);        }    }  vcd_data_source_close (obj->data_source);  if (callback)    {      _progress.current_pos = pos;      _progress.current_pack = pno;      callback (&_progress, user_data);    }  vcd_assert (pos == length);  obj->info = state.stream;  obj->scanned = true;  obj->info.playing_time = obj->info.max_pts - obj->info.min_pts;  if (obj->info.min_pts)    vcd_debug ("pts start offset %f (max pts = %f)",                obj->info.min_pts, obj->info.max_pts);  vcd_debug ("playing time %f", obj->info.playing_time);  if (!state.stream.scan_data && state.stream.version == MPEG_VERS_MPEG2)    vcd_warn ("mpeg stream contained no scan information (user) data");  {    int i;    for (i = 0; i < 3; i++)      if (obj->info.shdr[i].aps_list)        _CDIO_LIST_FOREACH (n, obj->info.shdr[i].aps_list)        {          struct aps_data *_data = _cdio_list_node_data (n);                    _data->timestamp -= obj->info.min_pts;         }  }  if (padpackets)    vcd_warn ("autopadding requires to insert additional %d zero bytes"              " into MPEG stream (due to %d unaligned packets of %d total)",              padbytes, padpackets, state.stream.packets);  obj->info.version = state.stream.version;}static double_approx_pts (CdioList *aps_list, uint32_t packet_no){  double retval = 0;  CdioListNode *node;  struct aps_data *_laps = NULL;  double last_pts_ratio = 0;  _CDIO_LIST_FOREACH (node, aps_list)    {      struct aps_data *_aps = _cdio_list_node_data (node);      if (_laps)        {          long p = _aps->packet_no;          double t = _aps->timestamp;          p -= _laps->packet_no;          t -= _laps->timestamp;          last_pts_ratio = t / p;        }      if (_aps->packet_no >= packet_no)        break;            _laps = _aps;    }  retval = packet_no;  retval -= _laps->packet_no;  retval *= last_pts_ratio;  retval += _laps->timestamp;  return retval;}static void _set_scan_msf (msf_t *_msf, long lsn){  if (lsn == -1)    {      _msf->m = _msf->s = _msf->f = 0xff;      return;    }  cdio_lba_to_msf (lsn, _msf);  _msf->s |= 0x80;  _msf->f |= 0x80;}static void _fix_scan_info (struct vcd_mpeg_scan_data_t *scan_data_ptr,                unsigned packet_no, double pts, CdioList *aps_list){  CdioListNode *node;  long _next = -1, _prev = -1, _forw = -1, _back = -1;  _CDIO_LIST_FOREACH (node, aps_list)    {      struct aps_data *_aps = _cdio_list_node_data (node);      if (_aps->packet_no == packet_no)        continue;      else if (_aps->packet_no < packet_no)        {          _prev = _aps->packet_no;                    if (pts - _aps->timestamp < 10 && _back == -1)            _back = _aps->packet_no;        }      else if (_aps->packet_no > packet_no)        {          if (_next == -1)            _next = _aps->packet_no;          if (_aps->timestamp - pts < 10)            _forw = _aps->packet_no;        }    }  if (_back == -1)    _back = packet_no;  if (_forw == -1)    _forw = packet_no;  _set_scan_msf (&scan_data_ptr->prev_ofs, _prev);  _set_scan_msf (&scan_data_ptr->next_ofs, _next);  _set_scan_msf (&scan_data_ptr->back_ofs, _back);  _set_scan_msf (&scan_data_ptr->forw_ofs, _forw);}intvcd_mpeg_source_get_packet (VcdMpegSource *obj, unsigned long packet_no,			    void *packet_buf, struct vcd_mpeg_packet_info *flags,                            bool fix_scan_info){  unsigned length;  unsigned pos;  unsigned pno;  VcdMpegStreamCtx state;  vcd_assert (obj != NULL);  vcd_assert (obj->scanned);  vcd_assert (packet_buf != NULL);  if (packet_no >= obj->info.packets)    {      vcd_error ("invalid argument");      return -1;    }  if (packet_no < obj->_read_pkt_no)    {      vcd_warn ("rewinding mpeg stream...");      obj->_read_pkt_no = 0;      obj->_read_pkt_pos = 0;    }  memset (&state, 0, sizeof (state));  state.stream.seen_pts = true;  state.stream.min_pts = obj->info.min_pts;  state.stream.scan_data_warnings = VCD_MPEG_SCAN_DATA_WARNS + 1;  pos = obj->_read_pkt_pos;  pno = obj->_read_pkt_no;  length = vcd_data_source_stat (obj->data_source);  vcd_data_source_seek (obj->data_source, pos);  while (pos < length)    {      char buf[2324] = { 0, };      int read_len = MIN (sizeof (buf), (length - pos));      int pkt_len;            vcd_data_source_read (obj->data_source, buf, read_len, 1);      pkt_len = vcd_mpeg_parse_packet (buf, read_len,                                       fix_scan_info, &state);      vcd_assert (pkt_len > 0);      if (pno == packet_no)	{          /* optimized for sequential access,              thus save pointer to next mpeg pack */	  obj->_read_pkt_pos = pos + pkt_len;	  obj->_read_pkt_no = pno + 1;          if (fix_scan_info              && state.packet.scan_data_ptr              && obj->info.version == MPEG_VERS_MPEG2)            {              int vid_idx = 0;              double _pts;              if (state.packet.video[2])                vid_idx = 2;              else if (state.packet.video[1])                vid_idx = 1;              else                 vid_idx = 0;              if (state.packet.has_pts)                _pts = state.packet.pts - obj->info.min_pts;              else                _pts = _approx_pts (obj->info.shdr[vid_idx].aps_list, packet_no);              _fix_scan_info (state.packet.scan_data_ptr, packet_no,                               _pts, obj->info.shdr[vid_idx].aps_list);            }	  memset (packet_buf, 0, 2324);	  memcpy (packet_buf, buf, pkt_len);          if (flags)            {              *flags = state.packet;              flags->pts -= obj->info.min_pts;            }	  return 0; /* breaking out */	}      pos += pkt_len;      pno++;      if (pkt_len != read_len)	vcd_data_source_seek (obj->data_source, pos);    }  vcd_assert (pos == length);  vcd_error ("shouldnt be reached...");  return -1;}voidvcd_mpeg_source_close (VcdMpegSource *obj){  vcd_assert (obj != NULL);  vcd_data_source_close (obj->data_source);}/*  * Local variables: *  c-file-style: "gnu" *  tab-width: 8 *  indent-tabs-mode: nil * End: */

⌨️ 快捷键说明

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