summaryrefslogtreecommitdiff
path: root/src/input/vcd/libvcd/mpeg.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/input/vcd/libvcd/mpeg.c')
-rw-r--r--src/input/vcd/libvcd/mpeg.c1177
1 files changed, 0 insertions, 1177 deletions
diff --git a/src/input/vcd/libvcd/mpeg.c b/src/input/vcd/libvcd/mpeg.c
deleted file mode 100644
index 545a44fbc..000000000
--- a/src/input/vcd/libvcd/mpeg.c
+++ /dev/null
@@ -1,1177 +0,0 @@
-/*
- $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 4
-
-static 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..."); }
-#endif
-
-static 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;
- }
-
- switch (vcd_bitvec_read_bits (buf, &bitpos, 2)) /* layer */
- {
- case 3: /* %11 */
- state->stream.ahdr[aud_idx].layer = 1;
- break;
- case 2: /* %10 */
- state->stream.ahdr[aud_idx].layer = 2;
- break;
- case 1: /* %01 */
- state->stream.ahdr[aud_idx].layer = 3;
- break;
- case 0: /* %00 */
- state->stream.ahdr[aud_idx].layer = 0;
- break;
- }
-
- bitpos++; /* protection_bit */
-
- {
- const int bits = vcd_bitvec_read_bits (buf, &bitpos, 4);
-
- const unsigned bit_rates[4][16] = {
- {0, },
- {0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, 0},
- {0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, 0},
- {0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 0}
- };
-
- vcd_assert (IN(state->stream.ahdr[aud_idx].layer, 0, 3));
- vcd_assert (IN(bits, 0, 15));
-
- state->stream.ahdr[aud_idx].bitrate = 1024 * bit_rates[state->stream.ahdr[aud_idx].layer][bits];
- }
-
- switch (vcd_bitvec_read_bits (buf, &bitpos, 2)) /* sampling_frequency */
- {
- case 0: /* %00 */
- state->stream.ahdr[aud_idx].sampfreq = 44100;
- break;
- case 1: /* %01 */
- state->stream.ahdr[aud_idx].sampfreq = 48000;
- break;
- case 2: /* %10 */
- state->stream.ahdr[aud_idx].sampfreq = 32000;
- break;
- case 3: /* %11 */
- state->stream.ahdr[aud_idx].sampfreq = 0;
- break;
- }
-
- bitpos++; /* padding_bit */
-
- bitpos++; /* private_bit */
-
- state->stream.ahdr[aud_idx].mode = 1 + vcd_bitvec_read_bits (buf, &bitpos, 2); /* mode */
-
- state->stream.ahdr[aud_idx].seen = true;
-
- /* we got the info, let's jump outta here */
- break;
- }
-}
-
-static void
-_analyze_video_pes (uint8_t streamid, const uint8_t *buf, int len, bool only_pts,
- VcdMpegStreamCtx *state)
-{
- const int vid_idx = _vid_streamid_idx (streamid);
-
- int pos, pes_header;
- int sequence_header_pos = -1;
- int gop_header_pos = -1;
- int ipicture_header_pos = -1;
-
- vcd_assert (vid_idx != -1);
-
- pes_header = pos = _analyze_pes_header (buf, len, state);
-
- /* if only pts extraction was needed, we are done here... */
- if (only_pts)
- return;
-
- while (pos + 4 <= len)
- {
- uint32_t code = vcd_bitvec_peek_bits32 (buf, pos << 3);
-
- if (!_start_code_p (code))
- {
- pos++;
- continue;
- }
-
- switch (code)
- {
- case MPEG_PICTURE_CODE:
- pos += 4;
-
- if (vcd_bitvec_peek_bits (buf, (pos << 3) + 10, 3) == 1)
- ipicture_header_pos = pos;
- break;
-
- case MPEG_SEQUENCE_CODE:
- pos += 4;
- sequence_header_pos = pos;
- _parse_sequence_header (streamid, buf + pos, state);
- break;
-
- case MPEG_GOP_CODE:
- pos += 4;
- if (pos + 4 > len)
- break;
- gop_header_pos = pos;
- _parse_gop_header (streamid, buf + pos, state);
- state->packet.gop = true;
- break;
-
- case MPEG_USER_CODE:
- pos += 4;
- if (pos + 4 > len)
- break;
- _parse_user_data (streamid, buf + pos, len - pos, pos, state);
- break;
-
- case MPEG_EXT_CODE:
- default:
- pos += 4;
- break;
- }
- }
-
- /* decide whether this packet qualifies as access point */
- state->packet.aps = APS_NONE; /* paranoia */
-
- if (state->packet.has_pts
- && ipicture_header_pos != -1)
- {
- enum aps_t _aps_type = APS_NONE;
-
- switch (state->stream.version)
- {
- case MPEG_VERS_MPEG1:
- case MPEG_VERS_MPEG2:
- if (sequence_header_pos != -1
- && sequence_header_pos < gop_header_pos
- && gop_header_pos < ipicture_header_pos)
- _aps_type = (sequence_header_pos - 4 == pes_header) ? APS_ASGI : APS_SGI;
- else if (gop_header_pos != 1
- && gop_header_pos < ipicture_header_pos)
- _aps_type = APS_GI;
- else
- _aps_type = APS_I;
-
- break;
-
- default:
- break;
- }
-
- if (_aps_type)
- {
- const double pts2 = state->packet.pts;
-
- if (state->stream.shdr[vid_idx].last_aps_pts > pts2)
- vcd_warn ("APS' pts seems out of order (actual pts %f, last seen pts %f) "
- "-- ignoring this aps",
- pts2, state->stream.shdr[vid_idx].last_aps_pts);
- else
- {
- state->packet.aps_idx = vid_idx;
- state->packet.aps = _aps_type;
- state->packet.aps_pts = pts2;
- state->stream.shdr[vid_idx].last_aps_pts = pts2;
- }
- }
- }
-}
-
-static void
-_register_streamid (uint8_t streamid, VcdMpegStreamCtx *state)
-{
- const uint32_t code = MPEG_START_CODE_PATTERN | streamid;
-
- switch (code)
- {
- case MPEG_VIDEO_E0_CODE:
- case MPEG_VIDEO_E1_CODE:
- case MPEG_VIDEO_E2_CODE:
- state->packet.video[_vid_streamid_idx (streamid)] = true;
- break;
-
- case MPEG_AUDIO_C0_CODE:
- case MPEG_AUDIO_C1_CODE:
- case MPEG_AUDIO_C2_CODE:
- state->packet.audio[_aud_streamid_idx (streamid)] = true;
- break;
-
- case MPEG_PAD_CODE:
- state->packet.padding = true;
- break;
-
- case MPEG_SYSTEM_HEADER_CODE:
- state->packet.system_header = true;
- break;
- }
-}
-
-static void
-_analyze_system_header (const uint8_t *buf, int len,
- VcdMpegStreamCtx *state)
-{
- unsigned bitpos = 0;
-
- MARKER (buf, &bitpos);
-
- bitpos += 22; /* rate_bound */
-
- MARKER (buf, &bitpos);
-
- bitpos += 6; /* audio_bound */
-
- bitpos++; /* fixed_flag */
- bitpos++; /* CSPS_flag */
- bitpos++; /* system_audio_lock_flag */
- bitpos++; /* system_video_lock_flag */
-
- MARKER (buf, &bitpos);
-
- bitpos += 5; /* video_bound */
-
- bitpos += 1; /* packet_rate_restriction_flag -- only ISO 13818-1 */
- bitpos += 7; /* reserved */
-
- while (vcd_bitvec_peek_bits (buf, bitpos, 1) == 1
- && bitpos <= (len << 3))
- {
- const uint8_t stream_id = vcd_bitvec_read_bits (buf, &bitpos, 8);
-
- bitpos += 2; /* %11 */
-
- bitpos++; /* P-STD_buffer_bound_scale */
- bitpos += 13; /* P-STD_buffer_size_bound */
-
- _register_streamid (stream_id, state);
- }
-
- vcd_assert (bitpos <= (len << 3));
-}
-
-static void
-_analyze_private_1_stream (const uint8_t *buf, int len,
- VcdMpegStreamCtx *state)
-{
- unsigned bitpos = _analyze_pes_header (buf, len, state);
- int ogt_idx = -1;
-
- uint8_t private_data_id;
-
- bitpos <<= 3;
-
- private_data_id = vcd_bitvec_read_bits (buf, &bitpos, 8);
-
- switch (private_data_id)
- {
- uint8_t sub_stream_id;
-
- case 0x00:
- case 0x01:
- case 0x02:
- case 0x03:
- /* CVD subs */
- ogt_idx = private_data_id;
-
- if (!state->stream.ogt[ogt_idx])
- vcd_debug ("Assuming CVD-style subtitles for data_id 0x%.2x in private stream 1", ogt_idx);
-
- break;
-
- case 0x70:
- /* SVCD OGT */
- sub_stream_id = vcd_bitvec_read_bits (buf, &bitpos, 8);
-
- if (sub_stream_id < 4)
- {
- ogt_idx = sub_stream_id;
- if (!state->stream.ogt[ogt_idx])
- vcd_debug ("subtitles detect for channel 0x%.2x", ogt_idx);
- }
- else
- vcd_warn ("sub_stream_id out of range (0x%.2x)", sub_stream_id);
- break;
-
- default:
- vcd_warn ("unknown private_data_id for private stream 1 seen (0x%.2x)",
- private_data_id);
- return;
- break;
- }
-
- if (ogt_idx >= 0)
- state->stream.ogt[ogt_idx] = state->packet.ogt[ogt_idx] = true;
-}
-
-int
-vcd_mpeg_parse_packet (const void *_buf, unsigned buflen, bool parse_pes,
- VcdMpegStreamCtx *ctx)
-{
- const uint8_t *buf = _buf;
- int pos;
-
- vcd_assert (buf != NULL);
- vcd_assert (ctx != NULL);
-
- /* clear packet info */
- memset (&(ctx->packet), 0, sizeof (ctx->packet));
-
- ctx->stream.packets++;
-
- for (pos = 0; pos < buflen && !buf[pos]; pos++);
-
- if (pos == buflen)
- {
- ctx->packet.zero = true;
- return buflen;
- }
-
- /* verify the packet begins with a pack header */
- if (vcd_bitvec_peek_bits32 (buf, 0) != MPEG_PACK_HEADER_CODE)
- {
- const uint32_t _code = vcd_bitvec_peek_bits32 (buf, 0);
-
- vcd_warn ("mpeg scan: pack header code (0x%8.8x) expected, "
- "but 0x%8.8x found (buflen = %d)",
- (unsigned int) MPEG_PACK_HEADER_CODE,
- (unsigned int) _code, buflen);
-
- ctx->stream.packets--;
-
- if (!ctx->stream.packets)
- {
- if (_code == MPEG_SEQUENCE_CODE)
- vcd_warn ("...this looks like a elementary video stream"
- " but a multiplexed program stream was required.");
-
- if ((0xfff00000 & _code) == 0xfff00000)
- vcd_warn ("...this looks like a elementary audio stream"
- " but a multiplexed program stream was required.");
-
- if (_code == 0x52494646)
- vcd_warn ("...this looks like a RIFF header"
- " but a plain multiplexed program stream was required.");
- }
- else if (_code == MPEG_PROGRAM_END_CODE)
- vcd_warn ("...PEM (program end marker) found instead of pack header;"
- " should be in last 4 bytes of pack");
-
- return 0;
- }
-
- /* take a look at the pack header */
- pos = 0;
-
- while (pos + 4 <= buflen)
- {
- uint32_t code = vcd_bitvec_peek_bits32 (buf, pos << 3);
-
- /* skip zero bytes... */
- if (!code)
- {
- pos += (pos + 4 == buflen) ? 4 : 2;
- continue;
- }
-
- /* continue until start code seen */
- if (!_start_code_p (code))
- {
- pos++;
- continue;
- }
-
- switch (code)
- {
- uint16_t size;
- int bits;
- unsigned bitpos;
-
- case MPEG_PACK_HEADER_CODE:
- if (pos)
- return pos;
-
- pos += 4;
-
- bitpos = pos << 3;
- bits = vcd_bitvec_peek_bits (buf, bitpos, 4);
-
- if (bits == 0x2) /* %0010 ISO11172-1 */
- {
- uint64_t _scr;
- uint32_t _muxrate;
-
- bitpos += 4;
-
- if (!ctx->stream.version)
- ctx->stream.version = MPEG_VERS_MPEG1;
-
- if (ctx->stream.version != MPEG_VERS_MPEG1)
- vcd_warn ("mixed mpeg versions?");
-
- _scr = _parse_timecode (buf, &bitpos);
-
- MARKER (buf, &bitpos);
-
- _muxrate = vcd_bitvec_read_bits (buf, &bitpos, 22);
-
- MARKER (buf, &bitpos);
-
- vcd_assert (bitpos % 8 == 0);
- pos = bitpos >> 3;
-
- ctx->packet.scr = _scr;
- ctx->stream.muxrate = ctx->packet.muxrate = _muxrate * 50 * 8;
- }
- else if (bits >> 2 == 0x1) /* %01xx ISO13818-1 */
- {
- uint64_t _scr;
- uint32_t _muxrate;
- int tmp;
-
- bitpos += 2;
-
- if (!ctx->stream.version)
- ctx->stream.version = MPEG_VERS_MPEG2;
-
- if (ctx->stream.version != MPEG_VERS_MPEG2)
- vcd_warn ("mixed mpeg versions?");
-
- _scr = _parse_timecode (buf, &bitpos);
-
- _scr *= 300;
- _scr += vcd_bitvec_read_bits (buf, &bitpos, 9); /* SCR ext */
-
- MARKER (buf, &bitpos);
-
- _muxrate = vcd_bitvec_read_bits (buf, &bitpos, 22);
-
- MARKER (buf, &bitpos);
- MARKER (buf, &bitpos);
-
- bitpos += 5; /* reserved */
-
- tmp = vcd_bitvec_read_bits (buf, &bitpos, 3) << 3;
-
- bitpos += tmp;
-
- vcd_assert (bitpos % 8 == 0);
- pos = bitpos >> 3;
-
- ctx->packet.scr = _scr;
- ctx->stream.muxrate = ctx->packet.muxrate = _muxrate * 50 * 8;
- }
- else
- {
- vcd_warn ("packet not recognized as either version 1 or 2 (%d)"
- " -- assuming v1", bits);
- }
-
- break;
-
- case MPEG_SYSTEM_HEADER_CODE:
- case MPEG_PAD_CODE:
- case MPEG_PRIVATE_1_CODE:
- case MPEG_VIDEO_E0_CODE:
- case MPEG_VIDEO_E1_CODE:
- case MPEG_VIDEO_E2_CODE:
- case MPEG_AUDIO_C0_CODE:
- case MPEG_AUDIO_C1_CODE:
- case MPEG_AUDIO_C2_CODE:
- pos += 4;
- size = vcd_bitvec_peek_bits16 (buf, pos << 3);
- pos += 2;
-
- if (pos + size > buflen)
- {
- vcd_warn ("packet length beyond buffer"
- " (pos = %d + size = %d > buflen = %d) "
- "-- stream may be truncated or packet length > 2324 bytes!",
- pos, size, buflen);
- ctx->stream.packets--;
- return 0;
- }
-
- _register_streamid (code & 0xff, ctx);
-
- switch (code)
- {
- case MPEG_SYSTEM_HEADER_CODE:
- _analyze_system_header (buf + pos, size, ctx);
- break;
-
- case MPEG_VIDEO_E0_CODE:
- case MPEG_VIDEO_E1_CODE:
- case MPEG_VIDEO_E2_CODE:
- _analyze_video_pes (code & 0xff, buf + pos, size, !parse_pes, ctx);
- break;
-
- case MPEG_AUDIO_C0_CODE:
- case MPEG_AUDIO_C1_CODE:
- case MPEG_AUDIO_C2_CODE:
- _analyze_audio_pes (code & 0xff, buf + pos, size, !parse_pes, ctx);
- break;
-
- case MPEG_PRIVATE_1_CODE:
- _analyze_private_1_stream (buf + pos, size, ctx);
- break;
- }
-
- pos += size;
- break;
-
- case MPEG_PROGRAM_END_CODE:
- ctx->packet.pem = true;
- pos += 4;
- break;
-
- case MPEG_PICTURE_CODE:
- pos += 3;
- break;
-
- default:
- vcd_debug ("unexpected start code 0x%8.8x", (unsigned int) code);
- pos += 4;
- break;
- }
- }
-
- if (pos != buflen)
- vcd_debug ("pos != buflen (%d != %d)", pos, buflen); /* fixme? */
-
- return buflen;
-}
-
-mpeg_norm_t
-vcd_mpeg_get_norm (const struct vcd_mpeg_stream_vid_info *_info)
-{
- int i;
-
- for (i = 0; norm_table[i].norm != MPEG_NORM_OTHER;i++)
- if (norm_table[i].hsize == _info->hsize
- && norm_table[i].vsize == _info->vsize
- && frame_rates[norm_table[i].frate_idx] == _info->frate)
- break;
-
- return norm_table[i].norm;
-}
-
-enum vcd_mpeg_packet_type
-vcd_mpeg_packet_get_type (const struct vcd_mpeg_packet_info *_info)
-{
- if (_info->video[0]
- || _info->video[1]
- || _info->video[2])
- return PKT_TYPE_VIDEO;
- else if (_info->audio[0]
- || _info->audio[1]
- || _info->audio[2])
- return PKT_TYPE_AUDIO;
- else if (_info->zero)
- return PKT_TYPE_ZERO;
- else if (_info->ogt[0]
- || _info->ogt[1]
- || _info->ogt[2]
- || _info->ogt[3])
- return PKT_TYPE_OGT;
- else if (_info->system_header || _info->padding)
- return PKT_TYPE_EMPTY;
-
- return PKT_TYPE_INVALID;
-}
-
-
-/*
- * Local variables:
- * c-file-style: "gnu"
- * tab-width: 8
- * indent-tabs-mode: nil
- * End:
- */