diff options
Diffstat (limited to 'src/input/vcd/libvcd/mpeg.c')
-rw-r--r-- | src/input/vcd/libvcd/mpeg.c | 1177 |
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: - */ |