xref: /aosp_15_r20/external/v4l2_codec2/common/EncodeHelpers.cpp (revision 0ec5a0ec62797f775085659156625e7f1bdb369f)
1*0ec5a0ecSAndroid Build Coastguard Worker // Copyright 2020 The Chromium Authors. All rights reserved.
2*0ec5a0ecSAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*0ec5a0ecSAndroid Build Coastguard Worker // found in the LICENSE file.
4*0ec5a0ecSAndroid Build Coastguard Worker 
5*0ec5a0ecSAndroid Build Coastguard Worker //#define LOG_NDEBUG 0
6*0ec5a0ecSAndroid Build Coastguard Worker #define LOG_TAG "EncodeHelpers"
7*0ec5a0ecSAndroid Build Coastguard Worker 
8*0ec5a0ecSAndroid Build Coastguard Worker #include <v4l2_codec2/common/EncodeHelpers.h>
9*0ec5a0ecSAndroid Build Coastguard Worker 
10*0ec5a0ecSAndroid Build Coastguard Worker #include <linux/v4l2-controls.h>
11*0ec5a0ecSAndroid Build Coastguard Worker 
12*0ec5a0ecSAndroid Build Coastguard Worker #include <C2AllocatorGralloc.h>
13*0ec5a0ecSAndroid Build Coastguard Worker #include <cutils/native_handle.h>
14*0ec5a0ecSAndroid Build Coastguard Worker #include <ui/GraphicBuffer.h>
15*0ec5a0ecSAndroid Build Coastguard Worker #include <utils/Log.h>
16*0ec5a0ecSAndroid Build Coastguard Worker 
17*0ec5a0ecSAndroid Build Coastguard Worker #include <v4l2_codec2/common/H264NalParser.h>
18*0ec5a0ecSAndroid Build Coastguard Worker 
19*0ec5a0ecSAndroid Build Coastguard Worker namespace android {
20*0ec5a0ecSAndroid Build Coastguard Worker 
21*0ec5a0ecSAndroid Build Coastguard Worker namespace {
22*0ec5a0ecSAndroid Build Coastguard Worker 
23*0ec5a0ecSAndroid Build Coastguard Worker // Android frameworks needs 4 bytes start code.
24*0ec5a0ecSAndroid Build Coastguard Worker constexpr uint8_t kH264StartCode[] = {0x00, 0x00, 0x00, 0x01};
25*0ec5a0ecSAndroid Build Coastguard Worker constexpr size_t kH264StartCodeSize = 4;
26*0ec5a0ecSAndroid Build Coastguard Worker 
27*0ec5a0ecSAndroid Build Coastguard Worker // Copy an H.264 NAL unit with size |srcSize| (without a start code) into a buffer with size
28*0ec5a0ecSAndroid Build Coastguard Worker // |dstSize|. An H.264 start code is prepended to the NAL unit. After copying |dst| is adjusted to
29*0ec5a0ecSAndroid Build Coastguard Worker // point to the address immediately following the copied data, and the |dstSize| is updated to
30*0ec5a0ecSAndroid Build Coastguard Worker // reflect the remaining destination buffer size.
copyNALUPrependingStartCode(const uint8_t * src,size_t srcSize,uint8_t ** dst,size_t * dstSize)31*0ec5a0ecSAndroid Build Coastguard Worker bool copyNALUPrependingStartCode(const uint8_t* src, size_t srcSize, uint8_t** dst,
32*0ec5a0ecSAndroid Build Coastguard Worker                                  size_t* dstSize) {
33*0ec5a0ecSAndroid Build Coastguard Worker     size_t naluSize = srcSize + kH264StartCodeSize;
34*0ec5a0ecSAndroid Build Coastguard Worker     if (naluSize > *dstSize) {
35*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Couldn't copy NAL unit, not enough space in destination buffer");
36*0ec5a0ecSAndroid Build Coastguard Worker         return false;
37*0ec5a0ecSAndroid Build Coastguard Worker     }
38*0ec5a0ecSAndroid Build Coastguard Worker     memcpy(*dst, kH264StartCode, kH264StartCodeSize);
39*0ec5a0ecSAndroid Build Coastguard Worker     memcpy(*dst + kH264StartCodeSize, src, srcSize);
40*0ec5a0ecSAndroid Build Coastguard Worker     *dst += naluSize;
41*0ec5a0ecSAndroid Build Coastguard Worker     *dstSize -= naluSize;
42*0ec5a0ecSAndroid Build Coastguard Worker     return true;
43*0ec5a0ecSAndroid Build Coastguard Worker }
44*0ec5a0ecSAndroid Build Coastguard Worker 
45*0ec5a0ecSAndroid Build Coastguard Worker }  // namespace
46*0ec5a0ecSAndroid Build Coastguard Worker 
c2LevelToV4L2Level(C2Config::level_t level)47*0ec5a0ecSAndroid Build Coastguard Worker uint8_t c2LevelToV4L2Level(C2Config::level_t level) {
48*0ec5a0ecSAndroid Build Coastguard Worker     switch (level) {
49*0ec5a0ecSAndroid Build Coastguard Worker     case C2Config::LEVEL_AVC_1:
50*0ec5a0ecSAndroid Build Coastguard Worker         return V4L2_MPEG_VIDEO_H264_LEVEL_1_0;
51*0ec5a0ecSAndroid Build Coastguard Worker     case C2Config::LEVEL_AVC_1B:
52*0ec5a0ecSAndroid Build Coastguard Worker         return V4L2_MPEG_VIDEO_H264_LEVEL_1B;
53*0ec5a0ecSAndroid Build Coastguard Worker     case C2Config::LEVEL_AVC_1_1:
54*0ec5a0ecSAndroid Build Coastguard Worker         return V4L2_MPEG_VIDEO_H264_LEVEL_1_1;
55*0ec5a0ecSAndroid Build Coastguard Worker     case C2Config::LEVEL_AVC_1_2:
56*0ec5a0ecSAndroid Build Coastguard Worker         return V4L2_MPEG_VIDEO_H264_LEVEL_1_2;
57*0ec5a0ecSAndroid Build Coastguard Worker     case C2Config::LEVEL_AVC_1_3:
58*0ec5a0ecSAndroid Build Coastguard Worker         return V4L2_MPEG_VIDEO_H264_LEVEL_1_3;
59*0ec5a0ecSAndroid Build Coastguard Worker     case C2Config::LEVEL_AVC_2:
60*0ec5a0ecSAndroid Build Coastguard Worker         return V4L2_MPEG_VIDEO_H264_LEVEL_2_0;
61*0ec5a0ecSAndroid Build Coastguard Worker     case C2Config::LEVEL_AVC_2_1:
62*0ec5a0ecSAndroid Build Coastguard Worker         return V4L2_MPEG_VIDEO_H264_LEVEL_2_1;
63*0ec5a0ecSAndroid Build Coastguard Worker     case C2Config::LEVEL_AVC_2_2:
64*0ec5a0ecSAndroid Build Coastguard Worker         return V4L2_MPEG_VIDEO_H264_LEVEL_2_2;
65*0ec5a0ecSAndroid Build Coastguard Worker     case C2Config::LEVEL_AVC_3:
66*0ec5a0ecSAndroid Build Coastguard Worker         return V4L2_MPEG_VIDEO_H264_LEVEL_3_0;
67*0ec5a0ecSAndroid Build Coastguard Worker     case C2Config::LEVEL_AVC_3_1:
68*0ec5a0ecSAndroid Build Coastguard Worker         return V4L2_MPEG_VIDEO_H264_LEVEL_3_1;
69*0ec5a0ecSAndroid Build Coastguard Worker     case C2Config::LEVEL_AVC_3_2:
70*0ec5a0ecSAndroid Build Coastguard Worker         return V4L2_MPEG_VIDEO_H264_LEVEL_3_2;
71*0ec5a0ecSAndroid Build Coastguard Worker     case C2Config::LEVEL_AVC_4:
72*0ec5a0ecSAndroid Build Coastguard Worker         return V4L2_MPEG_VIDEO_H264_LEVEL_4_0;
73*0ec5a0ecSAndroid Build Coastguard Worker     case C2Config::LEVEL_AVC_4_1:
74*0ec5a0ecSAndroid Build Coastguard Worker         return V4L2_MPEG_VIDEO_H264_LEVEL_4_1;
75*0ec5a0ecSAndroid Build Coastguard Worker     case C2Config::LEVEL_AVC_4_2:
76*0ec5a0ecSAndroid Build Coastguard Worker         return V4L2_MPEG_VIDEO_H264_LEVEL_4_2;
77*0ec5a0ecSAndroid Build Coastguard Worker     case C2Config::LEVEL_AVC_5:
78*0ec5a0ecSAndroid Build Coastguard Worker         return V4L2_MPEG_VIDEO_H264_LEVEL_5_0;
79*0ec5a0ecSAndroid Build Coastguard Worker     case C2Config::LEVEL_AVC_5_1:
80*0ec5a0ecSAndroid Build Coastguard Worker         return V4L2_MPEG_VIDEO_H264_LEVEL_5_1;
81*0ec5a0ecSAndroid Build Coastguard Worker     default:
82*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Unrecognizable C2 level (value = 0x%x)...", level);
83*0ec5a0ecSAndroid Build Coastguard Worker         return 0;
84*0ec5a0ecSAndroid Build Coastguard Worker     }
85*0ec5a0ecSAndroid Build Coastguard Worker }
86*0ec5a0ecSAndroid Build Coastguard Worker 
getGraphicBlockInfo(const C2ConstGraphicBlock & block)87*0ec5a0ecSAndroid Build Coastguard Worker android_ycbcr getGraphicBlockInfo(const C2ConstGraphicBlock& block) {
88*0ec5a0ecSAndroid Build Coastguard Worker     uint32_t width, height, format, stride, igbp_slot, generation;
89*0ec5a0ecSAndroid Build Coastguard Worker     uint64_t usage, igbp_id;
90*0ec5a0ecSAndroid Build Coastguard Worker     android::_UnwrapNativeCodec2GrallocMetadata(block.handle(), &width, &height, &format, &usage,
91*0ec5a0ecSAndroid Build Coastguard Worker                                                 &stride, &generation, &igbp_id, &igbp_slot);
92*0ec5a0ecSAndroid Build Coastguard Worker     native_handle_t* grallocHandle = android::UnwrapNativeCodec2GrallocHandle(block.handle());
93*0ec5a0ecSAndroid Build Coastguard Worker     sp<GraphicBuffer> buf = new GraphicBuffer(grallocHandle, GraphicBuffer::CLONE_HANDLE, width,
94*0ec5a0ecSAndroid Build Coastguard Worker                                               height, format, 1, usage, stride);
95*0ec5a0ecSAndroid Build Coastguard Worker     native_handle_delete(grallocHandle);
96*0ec5a0ecSAndroid Build Coastguard Worker 
97*0ec5a0ecSAndroid Build Coastguard Worker     // Pass SW flag so that ARCVM returns the guest buffer dimensions instead
98*0ec5a0ecSAndroid Build Coastguard Worker     // of the host buffer dimensions. This means we will have to convert the
99*0ec5a0ecSAndroid Build Coastguard Worker     // return value from ptrs to buffer offsets ourselves.
100*0ec5a0ecSAndroid Build Coastguard Worker     android_ycbcr ycbcr = {};
101*0ec5a0ecSAndroid Build Coastguard Worker     int32_t status = buf->lockYCbCr(GRALLOC_USAGE_SW_READ_OFTEN, &ycbcr);
102*0ec5a0ecSAndroid Build Coastguard Worker     if (status != OK) ALOGE("lockYCbCr is failed: %d", (int)status);
103*0ec5a0ecSAndroid Build Coastguard Worker     buf->unlock();
104*0ec5a0ecSAndroid Build Coastguard Worker 
105*0ec5a0ecSAndroid Build Coastguard Worker     uintptr_t y = reinterpret_cast<uintptr_t>(ycbcr.y);
106*0ec5a0ecSAndroid Build Coastguard Worker     ycbcr.y = nullptr;
107*0ec5a0ecSAndroid Build Coastguard Worker     ycbcr.cb = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(ycbcr.cb) - y);
108*0ec5a0ecSAndroid Build Coastguard Worker     ycbcr.cr = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(ycbcr.cr) - y);
109*0ec5a0ecSAndroid Build Coastguard Worker 
110*0ec5a0ecSAndroid Build Coastguard Worker     return ycbcr;
111*0ec5a0ecSAndroid Build Coastguard Worker }
112*0ec5a0ecSAndroid Build Coastguard Worker 
extractSPSPPS(const uint8_t * data,size_t length,std::vector<uint8_t> * sps,std::vector<uint8_t> * pps)113*0ec5a0ecSAndroid Build Coastguard Worker bool extractSPSPPS(const uint8_t* data, size_t length, std::vector<uint8_t>* sps,
114*0ec5a0ecSAndroid Build Coastguard Worker                    std::vector<uint8_t>* pps) {
115*0ec5a0ecSAndroid Build Coastguard Worker     bool foundSPS = false;
116*0ec5a0ecSAndroid Build Coastguard Worker     bool foundPPS = false;
117*0ec5a0ecSAndroid Build Coastguard Worker     H264NalParser parser(data, length);
118*0ec5a0ecSAndroid Build Coastguard Worker     while (!(foundSPS && foundPPS) && parser.locateNextNal()) {
119*0ec5a0ecSAndroid Build Coastguard Worker         switch (parser.type()) {
120*0ec5a0ecSAndroid Build Coastguard Worker         case H264NalParser::kSPSType:
121*0ec5a0ecSAndroid Build Coastguard Worker             sps->resize(parser.length());
122*0ec5a0ecSAndroid Build Coastguard Worker             memcpy(sps->data(), parser.data(), parser.length());
123*0ec5a0ecSAndroid Build Coastguard Worker             foundSPS = true;
124*0ec5a0ecSAndroid Build Coastguard Worker             break;
125*0ec5a0ecSAndroid Build Coastguard Worker         case H264NalParser::kPPSType:
126*0ec5a0ecSAndroid Build Coastguard Worker             pps->resize(parser.length());
127*0ec5a0ecSAndroid Build Coastguard Worker             memcpy(pps->data(), parser.data(), parser.length());
128*0ec5a0ecSAndroid Build Coastguard Worker             foundPPS = true;
129*0ec5a0ecSAndroid Build Coastguard Worker             break;
130*0ec5a0ecSAndroid Build Coastguard Worker         }
131*0ec5a0ecSAndroid Build Coastguard Worker     }
132*0ec5a0ecSAndroid Build Coastguard Worker     return foundSPS && foundPPS;
133*0ec5a0ecSAndroid Build Coastguard Worker }
134*0ec5a0ecSAndroid Build Coastguard Worker 
extractCSDInfo(std::unique_ptr<C2StreamInitDataInfo::output> * const csd,const uint8_t * data,size_t length)135*0ec5a0ecSAndroid Build Coastguard Worker bool extractCSDInfo(std::unique_ptr<C2StreamInitDataInfo::output>* const csd, const uint8_t* data,
136*0ec5a0ecSAndroid Build Coastguard Worker                     size_t length) {
137*0ec5a0ecSAndroid Build Coastguard Worker     csd->reset();
138*0ec5a0ecSAndroid Build Coastguard Worker 
139*0ec5a0ecSAndroid Build Coastguard Worker     std::vector<uint8_t> sps;
140*0ec5a0ecSAndroid Build Coastguard Worker     std::vector<uint8_t> pps;
141*0ec5a0ecSAndroid Build Coastguard Worker     if (!extractSPSPPS(data, length, &sps, &pps)) {
142*0ec5a0ecSAndroid Build Coastguard Worker         return false;
143*0ec5a0ecSAndroid Build Coastguard Worker     }
144*0ec5a0ecSAndroid Build Coastguard Worker 
145*0ec5a0ecSAndroid Build Coastguard Worker     size_t configDataLength = sps.size() + pps.size() + (2u * kH264StartCodeSize);
146*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("Extracted codec config data: length=%zu", configDataLength);
147*0ec5a0ecSAndroid Build Coastguard Worker 
148*0ec5a0ecSAndroid Build Coastguard Worker     *csd = C2StreamInitDataInfo::output::AllocUnique(configDataLength, 0u);
149*0ec5a0ecSAndroid Build Coastguard Worker     uint8_t* csdBuffer = (*csd)->m.value;
150*0ec5a0ecSAndroid Build Coastguard Worker     return copyNALUPrependingStartCode(sps.data(), sps.size(), &csdBuffer, &configDataLength) &&
151*0ec5a0ecSAndroid Build Coastguard Worker            copyNALUPrependingStartCode(pps.data(), pps.size(), &csdBuffer, &configDataLength);
152*0ec5a0ecSAndroid Build Coastguard Worker }
153*0ec5a0ecSAndroid Build Coastguard Worker 
prependSPSPPSToIDR(const uint8_t * src,size_t srcSize,uint8_t * dst,size_t dstSize,std::vector<uint8_t> * sps,std::vector<uint8_t> * pps)154*0ec5a0ecSAndroid Build Coastguard Worker size_t prependSPSPPSToIDR(const uint8_t* src, size_t srcSize, uint8_t* dst, size_t dstSize,
155*0ec5a0ecSAndroid Build Coastguard Worker                           std::vector<uint8_t>* sps, std::vector<uint8_t>* pps) {
156*0ec5a0ecSAndroid Build Coastguard Worker     bool foundStreamParams = false;
157*0ec5a0ecSAndroid Build Coastguard Worker     size_t remainingDstSize = dstSize;
158*0ec5a0ecSAndroid Build Coastguard Worker     H264NalParser parser(src, srcSize);
159*0ec5a0ecSAndroid Build Coastguard Worker     while (parser.locateNextNal()) {
160*0ec5a0ecSAndroid Build Coastguard Worker         switch (parser.type()) {
161*0ec5a0ecSAndroid Build Coastguard Worker         case H264NalParser::kSPSType:
162*0ec5a0ecSAndroid Build Coastguard Worker             // SPS found, copy to cache.
163*0ec5a0ecSAndroid Build Coastguard Worker             ALOGV("Found SPS (length %zu)", parser.length());
164*0ec5a0ecSAndroid Build Coastguard Worker             sps->resize(parser.length());
165*0ec5a0ecSAndroid Build Coastguard Worker             memcpy(sps->data(), parser.data(), parser.length());
166*0ec5a0ecSAndroid Build Coastguard Worker             foundStreamParams = true;
167*0ec5a0ecSAndroid Build Coastguard Worker             break;
168*0ec5a0ecSAndroid Build Coastguard Worker         case H264NalParser::kPPSType:
169*0ec5a0ecSAndroid Build Coastguard Worker             // PPS found, copy to cache.
170*0ec5a0ecSAndroid Build Coastguard Worker             ALOGV("Found PPS (length %zu)", parser.length());
171*0ec5a0ecSAndroid Build Coastguard Worker             pps->resize(parser.length());
172*0ec5a0ecSAndroid Build Coastguard Worker             memcpy(pps->data(), parser.data(), parser.length());
173*0ec5a0ecSAndroid Build Coastguard Worker             foundStreamParams = true;
174*0ec5a0ecSAndroid Build Coastguard Worker             break;
175*0ec5a0ecSAndroid Build Coastguard Worker         case H264NalParser::kIDRType:
176*0ec5a0ecSAndroid Build Coastguard Worker             ALOGV("Found IDR (length %zu)", parser.length());
177*0ec5a0ecSAndroid Build Coastguard Worker             if (foundStreamParams) {
178*0ec5a0ecSAndroid Build Coastguard Worker                 ALOGV("Not injecting SPS and PPS before IDR, already present");
179*0ec5a0ecSAndroid Build Coastguard Worker                 break;
180*0ec5a0ecSAndroid Build Coastguard Worker             }
181*0ec5a0ecSAndroid Build Coastguard Worker 
182*0ec5a0ecSAndroid Build Coastguard Worker             // Prepend the cached SPS and PPS to the IDR NAL unit.
183*0ec5a0ecSAndroid Build Coastguard Worker             if (sps->empty() || pps->empty()) {
184*0ec5a0ecSAndroid Build Coastguard Worker                 ALOGE("No cached SPS or PPS NAL unit available to inject before IDR");
185*0ec5a0ecSAndroid Build Coastguard Worker                 return 0;
186*0ec5a0ecSAndroid Build Coastguard Worker             }
187*0ec5a0ecSAndroid Build Coastguard Worker             if (!copyNALUPrependingStartCode(sps->data(), sps->size(), &dst, &remainingDstSize)) {
188*0ec5a0ecSAndroid Build Coastguard Worker                 ALOGE("Not enough space to inject SPS NAL unit before IDR");
189*0ec5a0ecSAndroid Build Coastguard Worker                 return 0;
190*0ec5a0ecSAndroid Build Coastguard Worker             }
191*0ec5a0ecSAndroid Build Coastguard Worker             if (!copyNALUPrependingStartCode(pps->data(), pps->size(), &dst, &remainingDstSize)) {
192*0ec5a0ecSAndroid Build Coastguard Worker                 ALOGE("Not enough space to inject PPS NAL unit before IDR");
193*0ec5a0ecSAndroid Build Coastguard Worker                 return 0;
194*0ec5a0ecSAndroid Build Coastguard Worker             }
195*0ec5a0ecSAndroid Build Coastguard Worker 
196*0ec5a0ecSAndroid Build Coastguard Worker             ALOGV("Stream header injected before IDR");
197*0ec5a0ecSAndroid Build Coastguard Worker             break;
198*0ec5a0ecSAndroid Build Coastguard Worker         }
199*0ec5a0ecSAndroid Build Coastguard Worker 
200*0ec5a0ecSAndroid Build Coastguard Worker         // Copy the NAL unit to the new output buffer.
201*0ec5a0ecSAndroid Build Coastguard Worker         if (!copyNALUPrependingStartCode(parser.data(), parser.length(), &dst, &remainingDstSize)) {
202*0ec5a0ecSAndroid Build Coastguard Worker             ALOGE("NAL unit does not fit in the provided output buffer");
203*0ec5a0ecSAndroid Build Coastguard Worker             return 0;
204*0ec5a0ecSAndroid Build Coastguard Worker         }
205*0ec5a0ecSAndroid Build Coastguard Worker     }
206*0ec5a0ecSAndroid Build Coastguard Worker 
207*0ec5a0ecSAndroid Build Coastguard Worker     return dstSize - remainingDstSize;
208*0ec5a0ecSAndroid Build Coastguard Worker }
209*0ec5a0ecSAndroid Build Coastguard Worker 
210*0ec5a0ecSAndroid Build Coastguard Worker }  // namespace android
211