summaryrefslogtreecommitdiffstats
path: root/xbmc/utils/VC1BitstreamParser.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'xbmc/utils/VC1BitstreamParser.cpp')
-rw-r--r--xbmc/utils/VC1BitstreamParser.cpp149
1 files changed, 149 insertions, 0 deletions
diff --git a/xbmc/utils/VC1BitstreamParser.cpp b/xbmc/utils/VC1BitstreamParser.cpp
new file mode 100644
index 0000000..8ac1b6e
--- /dev/null
+++ b/xbmc/utils/VC1BitstreamParser.cpp
@@ -0,0 +1,149 @@
+/*
+ * 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<uint8_t>(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;
+}