• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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