/* * Copyright (C) 2017-2018 Team Kodi * This file is part of Kodi - https://kodi.tv * * SPDX-License-Identifier: GPL-2.0-or-later * See LICENSES/README.md for more information. */ #include "VC1BitstreamParser.h" #include "BitstreamReader.h" enum { VC1_PROFILE_SIMPLE, VC1_PROFILE_MAIN, VC1_PROFILE_RESERVED, VC1_PROFILE_ADVANCED, VC1_PROFILE_NOPROFILE }; enum { VC1_END_OF_SEQ = 0x0A, VC1_SLICE = 0x0B, VC1_FIELD = 0x0C, VC1_FRAME = 0x0D, VC1_ENTRYPOINT = 0x0E, VC1_SEQUENCE = 0x0F, VC1_SLICE_USER = 0x1B, VC1_FIELD_USER = 0x1C, VC1_FRAME_USER = 0x1D, VC1_ENTRY_POINT_USER = 0x1E, VC1_SEQUENCE_USER = 0x1F }; enum { VC1_FRAME_PROGRESSIVE = 0x0, VC1_FRAME_INTERLACE = 0x10, VC1_FIELD_INTERLACE = 0x11 }; CVC1BitstreamParser::CVC1BitstreamParser() { Reset(); } void CVC1BitstreamParser::Reset() { m_Profile = VC1_PROFILE_NOPROFILE; } bool CVC1BitstreamParser::IsRecoveryPoint(const uint8_t *buf, int buf_size) { return vc1_parse_frame(buf, buf + buf_size, true); }; bool CVC1BitstreamParser::IsIFrame(const uint8_t *buf, int buf_size) { return vc1_parse_frame(buf, buf + buf_size, false); }; bool CVC1BitstreamParser::vc1_parse_frame(const uint8_t *buf, const uint8_t *buf_end, bool sequence_only) { uint32_t state = -1; for (;;) { buf = find_start_code(buf, buf_end, &state); if (buf >= buf_end) break; if (buf[-1] == VC1_SEQUENCE) { if (m_Profile != VC1_PROFILE_NOPROFILE) return false; CBitstreamReader br(buf, buf_end - buf); // Read the profile m_Profile = static_cast(br.ReadBits(2)); if (m_Profile == VC1_PROFILE_ADVANCED) { br.SkipBits(39); m_AdvInterlace = br.ReadBits(1); } else { br.SkipBits(22); m_SimpleSkipBits = 2; if (br.ReadBits(1)) //rangered ++m_SimpleSkipBits; m_MaxBFrames = br.ReadBits(3); br.SkipBits(2); // quantizer if (br.ReadBits(1)) //finterpflag ++m_SimpleSkipBits; } if (sequence_only) return true; } else if (buf[-1] == VC1_FRAME) { CBitstreamReader br(buf, buf_end - buf); if (sequence_only) return false; if (m_Profile == VC1_PROFILE_ADVANCED) { uint8_t fcm; if (m_AdvInterlace) { fcm = br.ReadBits(1); if (fcm) fcm = br.ReadBits(1) + 1; } else fcm = VC1_FRAME_PROGRESSIVE; if (fcm == VC1_FIELD_INTERLACE) { uint8_t pic = br.ReadBits(3); return pic == 0x00 || pic == 0x01; } else { uint8_t pic(0); while (pic < 4 && br.ReadBits(1))++pic; return pic == 2; } return false; } else if (m_Profile != VC1_PROFILE_NOPROFILE) { br.SkipBits(m_SimpleSkipBits); // quantizer uint8_t pic(br.ReadBits(1)); if (m_MaxBFrames) { if (!pic) { pic = br.ReadBits(1); return pic != 0; } else return false; } else return pic != 0; } else break; } } return false; }