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 "gst_consumer_surface_allocator.h"
17 #include "gst_consumer_surface_memory.h"
18 #include "media_log.h"
19 #include "scope_guard.h"
20 #include "securec.h"
21
22 using namespace OHOS;
23
24 #define GST_CONSUMER_SURFACE_MEMORY_TYPE "ConsumerSurfaceMemory"
25
26 #define gst_consumer_surface_allocator_parent_class parent_class
27
28 GST_DEBUG_CATEGORY_STATIC(gst_consumer_surface_allocator_debug_category);
29 #define GST_CAT_DEFAULT gst_consumer_surface_allocator_debug_category
30
31 struct _GstConsumerSurfaceAllocatorPrivate {
32 sptr<Surface> csurface;
33 };
34
35 G_DEFINE_TYPE_WITH_PRIVATE(GstConsumerSurfaceAllocator, gst_consumer_surface_allocator, GST_TYPE_ALLOCATOR);
36
37 static void gst_consumer_surface_allocator_class_init(GstConsumerSurfaceAllocatorClass *klass);
38 static void gst_consumer_surface_allocator_free(GstAllocator *allocator, GstMemory *mem);
39 static gpointer gst_consumer_surface_allocator_mem_map(GstMemory *mem, gsize maxsize, GstMapFlags flags);
40 static void gst_consumer_surface_allocator_init(GstConsumerSurfaceAllocator *sallocator);
41 static void gst_consumer_surface_allocator_finalize(GObject *obj);
42
gst_is_consumer_surface_memory(GstMemory * mem)43 gboolean gst_is_consumer_surface_memory(GstMemory *mem)
44 {
45 return gst_memory_is_type(mem, GST_CONSUMER_SURFACE_MEMORY_TYPE);
46 }
47
gst_consumer_surface_allocator_alloc(GstAllocator * allocator,gsize size,GstAllocationParams * params)48 static GstMemory *gst_consumer_surface_allocator_alloc(GstAllocator *allocator, gsize size, GstAllocationParams *params)
49 {
50 (void)size;
51 g_return_val_if_fail(params != nullptr, nullptr);
52 g_return_val_if_fail(allocator != nullptr, nullptr);
53 GstConsumerSurfaceAllocator *sallocator = GST_CONSUMER_SURFACE_ALLOCATOR(allocator);
54 g_return_val_if_fail(sallocator != nullptr && sallocator->priv != nullptr, nullptr);
55 g_return_val_if_fail(sallocator->priv->csurface != nullptr, nullptr);
56 GstConsumerSurfaceMemory *mem =
57 reinterpret_cast<GstConsumerSurfaceMemory *>(g_slice_alloc0(sizeof(GstConsumerSurfaceMemory)));
58 g_return_val_if_fail(mem != nullptr, nullptr);
59
60 ON_SCOPE_EXIT(0) { g_slice_free(GstConsumerSurfaceMemory, mem); };
61 // shorten code
62 sptr<Surface> surface = sallocator->priv->csurface;
63 sptr<SurfaceBuffer> surface_buffer = nullptr;
64 gint32 fencefd = -1;
65 gint64 timestamp = 0;
66 gint32 data_size = 0;
67 gboolean end_of_stream = false;
68 int32_t pixel_format = 0;
69 Rect damage = {0, 0, 0, 0};
70 if (surface->AcquireBuffer(surface_buffer, fencefd, timestamp, damage) != SURFACE_ERROR_OK) {
71 GST_WARNING_OBJECT(allocator, "Acquire surface buffer failed");
72 return nullptr;
73 }
74 g_return_val_if_fail(surface_buffer != nullptr, nullptr);
75 ON_SCOPE_EXIT(1) { surface->ReleaseBuffer(surface_buffer, -1); };
76
77 const sptr<OHOS::BufferExtraData>& extraData = surface_buffer->GetExtraData();
78 if (extraData != nullptr) {
79 (void)extraData->ExtraGet("timeStamp", timestamp);
80 (void)extraData->ExtraGet("endOfStream", end_of_stream);
81 (void)extraData->ExtraGet("dataSize", data_size);
82 }
83
84 pixel_format = surface_buffer->GetFormat();
85
86 gsize realsize = surface_buffer->GetSize();
87 g_return_val_if_fail(realsize > 0, nullptr);
88 gst_memory_init(GST_MEMORY_CAST(mem), GST_MEMORY_FLAG_NO_SHARE,
89 allocator, nullptr, realsize, 0, 0, realsize);
90 mem->surface_buffer = surface_buffer;
91 mem->fencefd = fencefd;
92 mem->timestamp = timestamp;
93 mem->data_size = data_size;
94 mem->pixel_format = pixel_format;
95 mem->damage = damage;
96 mem->is_eos_frame = end_of_stream;
97 mem->buffer_handle = surface_buffer->GetBufferHandle();
98 mem->width = static_cast<uint32_t>(surface_buffer->GetWidth());
99 mem->height = static_cast<uint32_t>(surface_buffer->GetHeight());
100 GST_INFO_OBJECT(allocator, "acquire surface buffer");
101
102 CANCEL_SCOPE_EXIT_GUARD(0);
103 CANCEL_SCOPE_EXIT_GUARD(1);
104 return GST_MEMORY_CAST(mem);
105 }
106
gst_consumer_surface_allocator_free(GstAllocator * allocator,GstMemory * mem)107 static void gst_consumer_surface_allocator_free(GstAllocator *allocator, GstMemory *mem)
108 {
109 g_return_if_fail(mem != nullptr && allocator != nullptr);
110 g_return_if_fail(gst_is_consumer_surface_memory(mem));
111 GstConsumerSurfaceAllocator *sallocator = GST_CONSUMER_SURFACE_ALLOCATOR(allocator);
112 g_return_if_fail(sallocator->priv != nullptr && sallocator->priv->csurface != nullptr);
113
114 GstConsumerSurfaceMemory *surfacemem = reinterpret_cast<GstConsumerSurfaceMemory*>(mem);
115 (void)sallocator->priv->csurface->ReleaseBuffer(surfacemem->surface_buffer, surfacemem->fencefd);
116 GST_INFO_OBJECT(allocator, "release surface buffer");
117 surfacemem->surface_buffer = nullptr;
118 g_slice_free(GstConsumerSurfaceMemory, surfacemem);
119 }
120
gst_consumer_surface_allocator_mem_map(GstMemory * mem,gsize maxsize,GstMapFlags flags)121 static gpointer gst_consumer_surface_allocator_mem_map(GstMemory *mem, gsize maxsize, GstMapFlags flags)
122 {
123 (void)maxsize;
124 (void)flags;
125 g_return_val_if_fail(mem != nullptr, nullptr);
126 g_return_val_if_fail(gst_is_consumer_surface_memory(mem), nullptr);
127
128 GstConsumerSurfaceMemory *surfacemem = reinterpret_cast<GstConsumerSurfaceMemory*>(mem);
129 g_return_val_if_fail(surfacemem->surface_buffer != nullptr, nullptr);
130
131 return surfacemem->surface_buffer->GetVirAddr();
132 }
133
gst_consumer_surface_allocator_mem_unmap(GstMemory * mem)134 static void gst_consumer_surface_allocator_mem_unmap(GstMemory *mem)
135 {
136 (void)mem;
137 }
138
gst_consumer_surface_allocator_mem_copy(GstConsumerSurfaceMemory * mem,gssize offset,gssize size)139 static GstMemory *gst_consumer_surface_allocator_mem_copy(GstConsumerSurfaceMemory *mem, gssize offset, gssize size)
140 {
141 g_return_val_if_fail(mem != nullptr && mem->surface_buffer != nullptr, nullptr);
142 g_return_val_if_fail(mem->surface_buffer->GetVirAddr() != nullptr, nullptr);
143
144 gssize realOffset = 0;
145 if (((gint64)mem->parent.offset + offset) > INT32_MAX) {
146 GST_ERROR("invalid offset");
147 return nullptr;
148 } else {
149 realOffset = static_cast<gssize>(mem->parent.offset) + offset;
150 }
151 g_return_val_if_fail(realOffset >= 0, nullptr);
152
153 if (size == -1) {
154 if (((gint64)mem->parent.size - offset) > INT32_MAX) {
155 GST_ERROR("invalid size");
156 return nullptr;
157 } else {
158 size = static_cast<gssize>(mem->parent.size) - offset;
159 }
160 }
161 g_return_val_if_fail(size > 0, nullptr);
162
163 if ((size < INT32_MAX) && ((INT32_MAX - size) <= realOffset)) {
164 GST_ERROR("invalid limit");
165 return nullptr;
166 }
167
168 gsize realLimit = static_cast<gsize>(size) + static_cast<gsize>(realOffset);
169 g_return_val_if_fail(realLimit <= static_cast<gsize>(mem->surface_buffer->GetSize()), nullptr);
170
171 GstMemory *copy = gst_allocator_alloc(nullptr, static_cast<gsize>(size), nullptr);
172 g_return_val_if_fail(copy != nullptr, nullptr);
173
174 GstMapInfo info = GST_MAP_INFO_INIT;
175 if (!gst_memory_map(copy, &info, GST_MAP_WRITE)) {
176 gst_memory_unref(copy);
177 GST_ERROR("map failed");
178 return nullptr;
179 }
180
181 uint8_t *src = static_cast<uint8_t *>(mem->surface_buffer->GetVirAddr()) + realOffset;
182 errno_t rc = memcpy_s(info.data, info.size, src, static_cast<size_t>(size));
183 if (rc != EOK) {
184 GST_ERROR("memcpy failed");
185 gst_memory_unmap(copy, &info);
186 gst_memory_unref(copy);
187 return nullptr;
188 }
189
190 gst_memory_unmap(copy, &info);
191 GST_LOG("copy memory: 0x%06" PRIXPTR " for size: %" G_GSSIZE_FORMAT ", offset: %" G_GSSIZE_FORMAT
192 ", gstmemory: 0x%06" PRIXPTR, FAKE_POINTER(mem), size, offset, FAKE_POINTER(copy));
193
194 return copy;
195 }
196
gst_consumer_surface_allocator_init(GstConsumerSurfaceAllocator * sallocator)197 static void gst_consumer_surface_allocator_init(GstConsumerSurfaceAllocator *sallocator)
198 {
199 GstAllocator *allocator = GST_ALLOCATOR_CAST(sallocator);
200 g_return_if_fail(allocator != nullptr);
201 auto priv = reinterpret_cast<GstConsumerSurfaceAllocatorPrivate *>(
202 gst_consumer_surface_allocator_get_instance_private(sallocator));
203 g_return_if_fail(priv != nullptr);
204 sallocator->priv = priv;
205
206 GST_DEBUG_OBJECT(allocator, "init allocator 0x%06" PRIXPTR "", FAKE_POINTER(allocator));
207
208 allocator->mem_type = GST_CONSUMER_SURFACE_MEMORY_TYPE;
209 allocator->mem_map = (GstMemoryMapFunction)gst_consumer_surface_allocator_mem_map;
210 allocator->mem_unmap = (GstMemoryUnmapFunction)gst_consumer_surface_allocator_mem_unmap;
211 allocator->mem_copy = (GstMemoryCopyFunction)gst_consumer_surface_allocator_mem_copy;
212 }
213
gst_consumer_surface_allocator_finalize(GObject * obj)214 static void gst_consumer_surface_allocator_finalize(GObject *obj)
215 {
216 GstConsumerSurfaceAllocator *allocator = GST_CONSUMER_SURFACE_ALLOCATOR(obj);
217 g_return_if_fail(allocator != nullptr && allocator->priv != nullptr);
218 allocator->priv->csurface = nullptr;
219
220 GST_DEBUG_OBJECT(allocator, "finalize allocator 0x%06" PRIXPTR "", FAKE_POINTER(allocator));
221 G_OBJECT_CLASS(parent_class)->finalize(obj);
222 }
223
gst_consumer_surface_allocator_class_init(GstConsumerSurfaceAllocatorClass * klass)224 static void gst_consumer_surface_allocator_class_init(GstConsumerSurfaceAllocatorClass *klass)
225 {
226 GObjectClass *gobjectClass = G_OBJECT_CLASS(klass);
227 g_return_if_fail(gobjectClass != nullptr);
228 GST_DEBUG_CATEGORY_INIT(gst_consumer_surface_allocator_debug_category, "surfaceallocator", 0, "surface allocator");
229 gobjectClass->finalize = gst_consumer_surface_allocator_finalize;
230
231 GstAllocatorClass *allocatorClass = GST_ALLOCATOR_CLASS(klass);
232 g_return_if_fail(allocatorClass != nullptr);
233
234 allocatorClass->alloc = gst_consumer_surface_allocator_alloc;
235 allocatorClass->free = gst_consumer_surface_allocator_free;
236 }
237
gst_consumer_surface_allocator_set_surface(GstAllocator * allocator,sptr<Surface> & consumerSurface)238 void gst_consumer_surface_allocator_set_surface(GstAllocator *allocator, sptr<Surface> &consumerSurface)
239 {
240 GstConsumerSurfaceAllocator *sallocator = GST_CONSUMER_SURFACE_ALLOCATOR(allocator);
241 g_return_if_fail(sallocator != nullptr && sallocator->priv != nullptr);
242 sallocator->priv->csurface = consumerSurface;
243 }
244
gst_consumer_surface_allocator_new()245 GstAllocator *gst_consumer_surface_allocator_new()
246 {
247 GstAllocator *alloc = GST_ALLOCATOR_CAST(g_object_new(
248 GST_TYPE_CONSUMER_SURFACE_ALLOCATOR, "name", "ConsumerSurface::Allocator", nullptr));
249 (void)gst_object_ref_sink(alloc);
250
251 return alloc;
252 }
253