• 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 "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