xref: /aosp_15_r20/external/deqp/external/vulkancts/modules/vulkan/video/vktDemuxer.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2024 The Khronos Group Inc.
6  * Copyright (c) 2024 Igalia S.L
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  *      http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  */
21 #include "deMemory.h"
22 
23 #include "vktVideoTestUtils.hpp"
24 #include "vktDemuxer.hpp"
25 
26 #include <algorithm>
27 #include <limits>
28 
29 namespace vkt
30 {
31 namespace video
32 {
33 
create(Params && params)34 std::shared_ptr<Demuxer> Demuxer::create(Params &&params)
35 {
36     switch (params.codecOperation)
37     {
38     case vk::VK_VIDEO_CODEC_OPERATION_DECODE_H264_BIT_KHR:
39     case vk::VK_VIDEO_CODEC_OPERATION_DECODE_H265_BIT_KHR:
40     {
41         return std::make_shared<H26XAnnexBDemuxer>(std::move(params));
42     }
43     break;
44     case vk::VK_VIDEO_CODEC_OPERATION_DECODE_AV1_BIT_KHR:
45     {
46         if (params.framing == ElementaryStreamFraming::AV1_ANNEXB)
47             return std::make_shared<AV1AnnexBDemuxer>(std::move(params));
48         else if (params.framing == ElementaryStreamFraming::IVF)
49             return std::make_shared<DuckIVFDemuxer>(std::move(params));
50         else
51             TCU_THROW(InternalError, "unknown elementary stream framing");
52     }
53     break;
54     default:
55         TCU_THROW(InternalError, "Unknown codec operation");
56     }
57 }
58 
Demuxer(Params && params)59 Demuxer::Demuxer(Params &&params) : m_params(std::move(params))
60 {
61 }
62 
H26XAnnexBDemuxer(Params && params)63 H26XAnnexBDemuxer::H26XAnnexBDemuxer(Params &&params) : Demuxer(std::move(params))
64 {
65     readToNextStartCode(nullptr);
66 }
67 
nextPacket()68 std::vector<uint8_t> H26XAnnexBDemuxer::nextPacket()
69 {
70     std::vector<uint8_t> packet;
71     readToNextStartCode(&packet);
72     return packet;
73 }
74 
75 // Very inefficient but simple algorithm, which is fine for the CTS
76 // since it can expect never to have to deal with inputs larger than a
77 // couple of megabytes.  A ~20x time boost would be mapping the
78 // bitstreams into memory and using the std::boyer_moore algorithm to
79 // find the start codes, at the cost of extra complexity handling
80 // corner cases in file mapping and low-memory environments.
readToNextStartCode(std::vector<uint8_t> * payload)81 void H26XAnnexBDemuxer::readToNextStartCode(std::vector<uint8_t> *payload)
82 {
83     int zeroRunCount = 0;
84     auto &reader     = m_params.data;
85     uint8_t byte;
86 
87     if (reader->isEof() || reader->isError())
88         return;
89 
90     if (payload)
91     {
92         // TODO: Fix the sample parser's interface
93         payload->push_back(0x0);
94         payload->push_back(0x0);
95         payload->push_back(0x0);
96         payload->push_back(0x1);
97     }
98 
99     while (true)
100     {
101         byte = reader->readByteChecked("failure looking for H26X start code");
102         if (reader->isEof() || reader->isError())
103             return;
104 
105         if (byte == 0x01 && zeroRunCount >= 3)
106         {
107             return;
108         }
109         else if (byte == 0x00)
110         {
111             zeroRunCount++;
112         }
113         else
114         {
115             while (zeroRunCount > 0)
116             {
117                 zeroRunCount--;
118                 payload->push_back(0x0);
119             }
120             payload->push_back(byte);
121         }
122     }
123 }
124 
DuckIVFDemuxer(Params && params)125 DuckIVFDemuxer::DuckIVFDemuxer(Params &&params) : Demuxer(std::move(params)), m_frameNumber(0)
126 {
127     readHeader();
128 }
129 
130 DE_PACKED(DuckIVFFrameHeader {
131     uint32_t sizeOfFrame;           // bytes 0-3    size of frame in bytes (not including the 12-byte header)
132     uint64_t presentationTimestamp; // bytes 4-11    64-bit presentation timestamp
133 } DuckIVFFrameHeader);
134 
nextPacket()135 std::vector<uint8_t> DuckIVFDemuxer::nextPacket()
136 {
137     auto &reader = m_params.data;
138 
139     DuckIVFFrameHeader frameHdr;
140     reader->readChecked((uint8_t *)&frameHdr, sizeof(DuckIVFFrameHeader), "error reading Duck IVF frame header");
141 
142     std::vector<uint8_t> packet(frameHdr.sizeOfFrame);
143     reader->readChecked(packet.data(), frameHdr.sizeOfFrame, "error reading Duck IVF frame");
144 
145     m_frameNumber++;
146 
147     DE_ASSERT(packet.size() > 0);
148 
149     return packet;
150 }
151 
readHeader()152 void DuckIVFDemuxer::readHeader()
153 {
154     auto &reader = m_params.data;
155 
156     DE_ASSERT(!reader->isError() && !reader->isEof());
157 
158     reader->readChecked((uint8_t *)&m_hdr, sizeof(DuckIVFDemuxer::Header), "invalid Duck IVF header");
159 
160     static uint8_t kDuckIVFSignature[4] = {'D', 'K', 'I', 'F'};
161     if (deMemCmp(&m_hdr.signature, kDuckIVFSignature, sizeof(kDuckIVFSignature)) != 0)
162         TCU_THROW(InternalError, "invalid Duck IVF signature");
163 
164     m_numFrames = m_hdr.framesInFile;
165 }
166 
AV1AnnexBDemuxer(Params && params)167 AV1AnnexBDemuxer::AV1AnnexBDemuxer(Params &&params) : Demuxer(std::move(params))
168 {
169 }
170 
nextPacket()171 std::vector<uint8_t> AV1AnnexBDemuxer::nextPacket()
172 {
173     std::vector<uint8_t> packet;
174     auto &reader = m_params.data;
175 
176     DE_ASSERT(!reader->isError());
177     if (reader->isEof())
178         return packet;
179 
180     if (m_remainingBytesInTemporalUnit == 0)
181     {
182         uint32_t tuUlebSize            = 0;
183         uint32_t tuSize                = getUleb128(&tuUlebSize);
184         m_remainingBytesInTemporalUnit = tuSize;
185     }
186 
187     uint32_t frameUlebSize = 0;
188     uint32_t frameSize     = getUleb128(&frameUlebSize);
189 
190     packet.resize(frameSize);
191     reader->read(packet);
192 
193     DE_ASSERT((frameSize + frameUlebSize) <= m_remainingBytesInTemporalUnit);
194     m_remainingBytesInTemporalUnit -= (frameSize + frameUlebSize);
195 
196     m_frameNumber++;
197 
198     return packet;
199 }
200 
getUleb128(uint32_t * numBytes)201 uint32_t AV1AnnexBDemuxer::getUleb128(uint32_t *numBytes)
202 {
203     auto &in           = m_params.data;
204     uint64_t val       = 0;
205     uint32_t i         = 0;
206     uint32_t more      = 0;
207     uint32_t bytesRead = 0;
208 
209     do
210     {
211         const int v = in->readByteChecked("error reading uleb128 value");
212         more        = v & 0x80;
213         val |= ((uint64_t)(v & 0x7F)) << i;
214         bytesRead += 1;
215         i += 7;
216     } while (more && i < 56);
217 
218     if (val > std::numeric_limits<uint32_t>::max() || more)
219         return 0;
220 
221     if (numBytes)
222         *numBytes = bytesRead;
223 
224     return (uint32_t)val;
225 }
226 
227 } // namespace video
228 } // namespace vkt
229