📄 mpeg.c
字号:
} 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;}intvcd_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_typevcd_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: */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -