1 /*
2 * Copyright (C) 2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "video_capture_sf_es_avc_impl.h"
17 #include "media_log.h"
18 #include "media_errors.h"
19 #include "scope_guard.h"
20 #include "securec.h"
21
22 namespace {
23 constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "VideoCaptureSfEsAvcImpl"};
24 constexpr uint32_t MAX_SURFACE_BUFFER_SIZE = 10 * 1024 * 1024;
25 }
26
27 namespace OHOS {
28 namespace Media {
VideoCaptureSfEsAvcImpl()29 VideoCaptureSfEsAvcImpl::VideoCaptureSfEsAvcImpl()
30 {
31 }
32
~VideoCaptureSfEsAvcImpl()33 VideoCaptureSfEsAvcImpl::~VideoCaptureSfEsAvcImpl()
34 {
35 }
36
AVCDecoderConfiguration(std::vector<uint8_t> & sps,std::vector<uint8_t> & pps)37 GstBuffer *VideoCaptureSfEsAvcImpl::AVCDecoderConfiguration(std::vector<uint8_t> &sps,
38 std::vector<uint8_t> &pps)
39 {
40 // 11 is the length of AVCDecoderConfigurationRecord field except sps and pps
41 uint32_t codecBufferSize = sps.size() + pps.size() + 11;
42 GstBuffer *codec = gst_buffer_new_allocate(nullptr, codecBufferSize, nullptr);
43 CHECK_AND_RETURN_RET_LOG(codec != nullptr, nullptr, "no memory");
44 ON_SCOPE_EXIT(0) {
45 gst_buffer_unref(codec);
46 };
47 GstMapInfo map = GST_MAP_INFO_INIT;
48 CHECK_AND_RETURN_RET_LOG(gst_buffer_map(codec, &map, GST_MAP_READ) == TRUE, nullptr, "gst_buffer_map fail");
49
50 ON_SCOPE_EXIT(1) {
51 gst_buffer_unmap(codec, &map);
52 };
53
54 uint32_t offset = 0;
55 map.data[offset++] = 0x01; // configurationVersion
56 map.data[offset++] = sps[1]; // AVCProfileIndication
57 map.data[offset++] = sps[2]; // profile_compatibility
58 map.data[offset++] = sps[3]; // AVCLevelIndication
59 map.data[offset++] = 0xff; // lengthSizeMinusOne
60
61 map.data[offset++] = 0xe0 | 0x01; // numOfSequenceParameterSets
62 map.data[offset++] = (sps.size() >> 8) & 0xff; // sequenceParameterSetLength high 8 bits
63 map.data[offset++] = sps.size() & 0xff; // sequenceParameterSetLength low 8 bits
64 // sequenceParameterSetNALUnit
65 CHECK_AND_RETURN_RET_LOG(memcpy_s(map.data + offset, codecBufferSize - offset, &sps[0], sps.size()) == EOK,
66 nullptr, "memcpy_s fail");
67 offset += sps.size();
68
69 map.data[offset++] = 0x01; // numOfPictureParameterSets
70 map.data[offset++] = (pps.size() >> 8) & 0xff; // pictureParameterSetLength high 8 bits
71 map.data[offset++] = pps.size() & 0xff; // pictureParameterSetLength low 8 bits
72 // pictureParameterSetNALUnit
73 CHECK_AND_RETURN_RET_LOG(memcpy_s(map.data + offset, codecBufferSize - offset, &pps[0], pps.size()) == EOK,
74 nullptr, "memcpy_s fail");
75 CANCEL_SCOPE_EXIT_GUARD(0);
76
77 return codec;
78 }
79
80
DoGetCodecBuffer()81 std::shared_ptr<EsAvcCodecBuffer> VideoCaptureSfEsAvcImpl::DoGetCodecBuffer()
82 {
83 MEDIA_LOGI("enter DoGetCodecBuffer");
84 CHECK_AND_RETURN_RET_LOG(surfaceBuffer_ != nullptr, nullptr, "surface buffer is nullptr");
85
86 uint32_t bufferSize = static_cast<uint32_t>(dataSize_);
87 CHECK_AND_RETURN_RET_LOG(bufferSize < MAX_SURFACE_BUFFER_SIZE, nullptr, "buffer size too long");
88
89 ON_SCOPE_EXIT(0) { (void)dataConSurface_->ReleaseBuffer(surfaceBuffer_, fence_); };
90
91 gpointer buffer = surfaceBuffer_->GetVirAddr();
92 CHECK_AND_RETURN_RET_LOG(buffer != nullptr, nullptr, "surface buffer address is invalid");
93
94 std::vector<uint8_t> sps;
95 std::vector<uint8_t> pps;
96 std::vector<uint8_t> sei;
97 GetCodecData(reinterpret_cast<const uint8_t *>(buffer), bufferSize, sps, pps, sei);
98 CHECK_AND_RETURN_RET_LOG(nalSize_ > 0 && sps.size() > 0 && pps.size() > 0 && sei.size() > 0,
99 nullptr, "illegal codec buffer");
100
101 GstBuffer *configBuffer = AVCDecoderConfiguration(sps, pps);
102 CHECK_AND_RETURN_RET_LOG(configBuffer != nullptr, nullptr, "AVCDecoderConfiguration failed");
103
104 std::shared_ptr<EsAvcCodecBuffer> codecBuffer = std::make_shared<EsAvcCodecBuffer>();
105 CHECK_AND_RETURN_RET_LOG(codecBuffer != nullptr, nullptr, "no memory");
106 codecBuffer->width = videoWidth_;
107 codecBuffer->height = videoHeight_;
108 codecBuffer->segmentStart = 0;
109 codecBuffer->gstCodecBuffer = configBuffer;
110 codecData_ = (char *)buffer;
111 codecDataSize_ = nalSize_ * 3 + sps.size() + pps.size() + sei.size(); // 3 means sps pps sei common head size
112
113 CANCEL_SCOPE_EXIT_GUARD(0);
114 return codecBuffer;
115 }
116
DoGetFrameBuffer()117 std::shared_ptr<VideoFrameBuffer> VideoCaptureSfEsAvcImpl::DoGetFrameBuffer()
118 {
119 if ((frameSequence_ == 0) && (codecData_ == nullptr)) {
120 GetCodecBuffer();
121 }
122
123 if (frameSequence_ == 0) {
124 return GetIDRFrame();
125 }
126
127 uint32_t bufferSize = static_cast<uint32_t>(dataSize_);
128 CHECK_AND_RETURN_RET_LOG(bufferSize < MAX_SURFACE_BUFFER_SIZE, nullptr, "buffer size too long");
129
130 ON_SCOPE_EXIT(0) { (void)dataConSurface_->ReleaseBuffer(surfaceBuffer_, fence_); };
131
132 gpointer buffer = surfaceBuffer_->GetVirAddr();
133 CHECK_AND_RETURN_RET_LOG(buffer != nullptr, nullptr, "surface buffer address is invalid");
134
135 if (isCodecFrame_ == 1) {
136 buffer = (char *)buffer + codecDataSize_;
137 }
138
139 uint32_t frameSize = bufferSize - nalSize_;
140 // there is two kind of nal head. four byte 0x00000001 or three byte 0x000001
141 // standard es_avc stream should begin with frame size
142 // change the nal head to frame size.
143 if (nalSize_ == 4) { // 0x00000001
144 ((char *)buffer)[0] = (char)((frameSize >> 24) & 0xff);
145 ((char *)buffer)[1] = (char)((frameSize >> 16) & 0xff);
146 ((char *)buffer)[2] = (char)((frameSize >> 8) & 0xff);
147 ((char *)buffer)[3] = (char)(frameSize & 0xff);
148 } else { // 0x000001
149 ((char *)buffer)[0] = (char)((frameSize >> 16) & 0xff);
150 ((char *)buffer)[1] = (char)((frameSize >> 8) & 0xff);
151 ((char *)buffer)[2] = (char)(frameSize & 0xff);
152 }
153
154 GstBuffer *gstBuffer = gst_buffer_new_allocate(nullptr, bufferSize, nullptr);
155 CHECK_AND_RETURN_RET_LOG(gstBuffer != nullptr, nullptr, "no memory");
156
157 ON_SCOPE_EXIT(1) { gst_buffer_unref(gstBuffer); };
158
159 gsize size = gst_buffer_fill(gstBuffer, 0, (char *)buffer, bufferSize);
160 CHECK_AND_RETURN_RET_LOG(size == static_cast<gsize>(bufferSize), nullptr, "unknown error during gst_buffer_fill");
161
162 std::shared_ptr<VideoFrameBuffer> frameBuffer = std::make_shared<VideoFrameBuffer>();
163 frameBuffer->keyFrameFlag = 0;
164 frameBuffer->timeStamp = static_cast<uint64_t>(pts_);
165 frameBuffer->gstBuffer = gstBuffer;
166 frameBuffer->size = static_cast<uint64_t>(bufferSize);
167
168 CANCEL_SCOPE_EXIT_GUARD(1);
169 return frameBuffer;
170 }
171
GetIDRFrame()172 std::shared_ptr<VideoFrameBuffer> VideoCaptureSfEsAvcImpl::GetIDRFrame()
173 {
174 ON_SCOPE_EXIT(0) {
175 (void)dataConSurface_->ReleaseBuffer(surfaceBuffer_, fence_);
176 };
177
178 uint32_t bufferSize = static_cast<uint32_t>(dataSize_) - codecDataSize_;
179 GstBuffer *gstBuffer = gst_buffer_new_allocate(nullptr, bufferSize, nullptr);
180 CHECK_AND_RETURN_RET_LOG(gstBuffer != nullptr, nullptr, "no memory");
181
182 ON_SCOPE_EXIT(1) { gst_buffer_unref(gstBuffer); };
183
184 // there is two kind of nal head. four byte 0x00000001 or three byte 0x000001
185 // standard es_avc stream should begin with frame size
186 // change the nal head to frame size.
187 uint32_t frameSize = bufferSize - nalSize_;
188 if (nalSize_ == 4) { // 0x00000001
189 codecData_[codecDataSize_] = (char)((frameSize >> 24) & 0xff);
190 codecData_[codecDataSize_ + 1] = (char)((frameSize >> 16) & 0xff);
191 codecData_[codecDataSize_ + 2] = (char)((frameSize >> 8) & 0xff);
192 codecData_[codecDataSize_ + 3] = (char)(frameSize & 0xff);
193 } else { // 0x000001
194 codecData_[codecDataSize_] = (char)((frameSize >> 16) & 0xff);
195 codecData_[codecDataSize_ + 1] = (char)((frameSize >> 8) & 0xff);
196 codecData_[codecDataSize_ + 2] = (char)(frameSize & 0xff);
197 }
198
199 gsize size = gst_buffer_fill(gstBuffer, 0, codecData_ + codecDataSize_, bufferSize);
200 CHECK_AND_RETURN_RET_LOG(size == static_cast<gsize>(bufferSize), nullptr, "unknown error during gst_buffer_fill");
201
202 std::shared_ptr<VideoFrameBuffer> frameBuffer = std::make_shared<VideoFrameBuffer>();
203 frameBuffer->keyFrameFlag = 0;
204 frameBuffer->timeStamp = static_cast<uint64_t>(pts_);
205 frameBuffer->gstBuffer = gstBuffer;
206 frameBuffer->size = static_cast<uint64_t>(bufferSize);
207 codecData_ = nullptr;
208 frameSequence_++;
209
210 CANCEL_SCOPE_EXIT_GUARD(1);
211 return frameBuffer;
212 }
213
FindNextNal(const uint8_t * start,const uint8_t * end)214 const uint8_t *VideoCaptureSfEsAvcImpl::FindNextNal(const uint8_t *start, const uint8_t *end)
215 {
216 CHECK_AND_RETURN_RET(start != nullptr && end != nullptr, nullptr);
217 // there is two kind of nal head. four byte 0x00000001 or three byte 0x000001
218 while (start <= end - 3) {
219 if (start[0] == 0x00 && start[1] == 0x00 && start[2] == 0x01) {
220 nalSize_ = 3; // 0x000001 Nal
221 return start;
222 }
223 if (start[0] == 0x00 && start[1] == 0x00 && start[2] == 0x00 && start[3] == 0x01) {
224 nalSize_ = 4; // 0x00000001 Nal
225 return start;
226 }
227 start++;
228 }
229 return end;
230 }
231
GetCodecData(const uint8_t * data,int32_t len,std::vector<uint8_t> & sps,std::vector<uint8_t> & pps,std::vector<uint8_t> & sei)232 void VideoCaptureSfEsAvcImpl::GetCodecData(const uint8_t *data, int32_t len,
233 std::vector<uint8_t> &sps, std::vector<uint8_t> &pps, std::vector<uint8_t> &sei)
234 {
235 CHECK_AND_RETURN(data != nullptr);
236 const uint8_t *end = data + len - 1;
237 const uint8_t *pBegin = data;
238 const uint8_t *pEnd = nullptr;
239 while (pBegin < end) {
240 pBegin = FindNextNal(pBegin, end);
241 if (pBegin == end) {
242 break;
243 }
244 pBegin += nalSize_;
245 pEnd = FindNextNal(pBegin, end);
246 if (((*pBegin) & 0x1F) == 0x07) { // sps
247 sps.assign(pBegin, pBegin + static_cast<int>(pEnd - pBegin));
248 }
249 if (((*pBegin) & 0x1F) == 0x08) { // pps
250 pps.assign(pBegin, pBegin + static_cast<int>(pEnd - pBegin));
251 }
252 if (((*pBegin) & 0x1F) == 0x06) { // sei
253 sei.assign(pBegin, pBegin + static_cast<int>(pEnd - pBegin));
254 }
255 pBegin = pEnd;
256 }
257 }
258 } // namespace Media
259 } // namespace OHOS
260