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_surface_allocator.h"
17 #include <sync_fence.h>
18 #include "media_log.h"
19 #include "media_dfx.h"
20
21 GST_DEBUG_CATEGORY_STATIC(gst_surface_allocator_debug_category);
22 #define GST_CAT_DEFAULT gst_surface_allocator_debug_category
23
24 #define gst_surface_allocator_parent_class parent_class
25 G_DEFINE_TYPE(GstSurfaceAllocator, gst_surface_allocator, GST_TYPE_ALLOCATOR);
26
27 using namespace OHOS;
28 using namespace OHOS::Media;
29
30 enum class VideoScaleType {
31 VIDEO_SCALE_TYPE_FIT,
32 VIDEO_SCALE_TYPE_FIT_CROP,
33 };
34
35 namespace {
36 const std::unordered_map<VideoScaleType, OHOS::ScalingMode> SCALEMODE_MAP = {
37 { VideoScaleType::VIDEO_SCALE_TYPE_FIT, OHOS::SCALING_MODE_SCALE_TO_WINDOW },
38 { VideoScaleType::VIDEO_SCALE_TYPE_FIT_CROP, OHOS::SCALING_MODE_SCALE_CROP},
39 };
40 }
41
gst_surface_allocator_set_surface(GstSurfaceAllocator * allocator,OHOS::sptr<OHOS::Surface> surface)42 gboolean gst_surface_allocator_set_surface(GstSurfaceAllocator *allocator, OHOS::sptr<OHOS::Surface> surface)
43 {
44 if (allocator == nullptr) {
45 GST_ERROR("allocator is nullptr");
46 return FALSE;
47 }
48 if (surface == nullptr) {
49 GST_ERROR("surface is nullptr");
50 return FALSE;
51 }
52 allocator->surface = surface;
53 return TRUE;
54 }
55
gst_surface_allocator_get_scale_type(GstSurfaceAllocParam param)56 static OHOS::ScalingMode gst_surface_allocator_get_scale_type(GstSurfaceAllocParam param)
57 {
58 if (SCALEMODE_MAP.find(static_cast<VideoScaleType>(param.scale_type)) == SCALEMODE_MAP.end()) {
59 return OHOS::SCALING_MODE_SCALE_TO_WINDOW;
60 }
61 return SCALEMODE_MAP.at(static_cast<VideoScaleType>(param.scale_type));
62 }
63
gst_surface_request_buffer(const GstSurfaceAllocator * allocator,GstSurfaceAllocParam param,OHOS::sptr<OHOS::SurfaceBuffer> & buffer)64 static bool gst_surface_request_buffer(const GstSurfaceAllocator *allocator, GstSurfaceAllocParam param,
65 OHOS::sptr<OHOS::SurfaceBuffer> &buffer)
66 {
67 MediaTrace trace("Surface::RequestBuffer");
68 static constexpr int32_t stride_alignment = 8;
69 int32_t wait_time = param.dont_wait ? 0 : INT_MAX; // wait forever or no wait.
70 OHOS::BufferRequestConfig request_config = {
71 param.width, param.height, stride_alignment, param.format,
72 param.usage | BUFFER_USAGE_CPU_READ | BUFFER_USAGE_CPU_WRITE | BUFFER_USAGE_MEM_DMA,
73 wait_time
74 };
75 int32_t release_fence = -1;
76 OHOS::SurfaceError ret = allocator->surface->RequestBuffer(buffer, release_fence, request_config);
77 if (ret != OHOS::SurfaceError::SURFACE_ERROR_OK || buffer == nullptr) {
78 GST_ERROR("there is no more surface buffer");
79 return false;
80 }
81 {
82 MediaTrace mapTrace("Surface::Map");
83 if (buffer->Map() != OHOS::SurfaceError::SURFACE_ERROR_OK) {
84 GST_ERROR("surface buffer Map failed");
85 allocator->surface->CancelBuffer(buffer);
86 return false;
87 }
88 }
89
90 {
91 MediaTrace FenceTrace("Surface::WaitFence");
92 OHOS::sptr<OHOS::SyncFence> autoFence = new(std::nothrow) OHOS::SyncFence(release_fence);
93 if (autoFence != nullptr) {
94 autoFence->Wait(100); // 100ms
95 }
96 }
97
98 {
99 MediaTrace scaleTrace("Surface::SetScalingMode");
100 auto scaleType = gst_surface_allocator_get_scale_type(param);
101 ret = allocator->surface->SetScalingMode(buffer->GetSeqNum(), scaleType);
102 if (ret != OHOS::SurfaceError::SURFACE_ERROR_OK) {
103 GST_ERROR("surface buffer set scaling mode failed");
104 allocator->surface->CancelBuffer(buffer);
105 return false;
106 }
107 }
108 return true;
109 }
110
gst_surface_allocator_alloc(GstSurfaceAllocator * allocator,GstSurfaceAllocParam param)111 GstSurfaceMemory *gst_surface_allocator_alloc(GstSurfaceAllocator *allocator, GstSurfaceAllocParam param)
112 {
113 g_return_val_if_fail(allocator != nullptr && allocator->surface != nullptr, nullptr);
114
115 OHOS::sptr<OHOS::SurfaceBuffer> buffer = nullptr;
116 if (!gst_surface_request_buffer(allocator, param, buffer) || buffer == nullptr) {
117 GST_ERROR("failed to request surface buffer");
118 return nullptr;
119 }
120
121 GstSurfaceMemory *memory = reinterpret_cast<GstSurfaceMemory *>(g_slice_alloc0(sizeof(GstSurfaceMemory)));
122 if (memory == nullptr) {
123 GST_ERROR("alloc GstSurfaceMemory slice failed");
124 allocator->surface->CancelBuffer(buffer);
125 return nullptr;
126 }
127
128 gst_memory_init(GST_MEMORY_CAST(memory), (GstMemoryFlags)0, GST_ALLOCATOR_CAST(allocator), nullptr,
129 buffer->GetSize(), 0, 0, buffer->GetSize());
130
131 memory->buf = buffer;
132 memory->fence = -1;
133 memory->need_render = FALSE;
134 GST_DEBUG("alloc surface buffer for width: %d, height: %d, format: %d, size: %u",
135 param.width, param.height, param.format, buffer->GetSize());
136
137 return memory;
138 }
139
gst_surface_allocator_free(GstAllocator * baseAllocator,GstMemory * baseMemory)140 static void gst_surface_allocator_free(GstAllocator *baseAllocator, GstMemory *baseMemory)
141 {
142 GstSurfaceAllocator *allocator = reinterpret_cast<GstSurfaceAllocator*>(baseAllocator);
143 GstSurfaceMemory *memory = reinterpret_cast<GstSurfaceMemory*>(baseMemory);
144 g_return_if_fail(memory != nullptr && allocator != nullptr && allocator->surface != nullptr);
145
146 GST_DEBUG("free surface buffer for width: %d, height: %d, format: %d, size: %u, need_render: %d, fence: %d",
147 memory->buf->GetWidth(), memory->buf->GetHeight(), memory->buf->GetFormat(), memory->buf->GetSize(),
148 memory->need_render, memory->fence);
149
150 if (!memory->need_render) {
151 OHOS::SurfaceError ret = allocator->surface->CancelBuffer(memory->buf);
152 if (ret != OHOS::SurfaceError::SURFACE_ERROR_OK) {
153 GST_INFO("cancel buffer to surface failed, %d", ret);
154 }
155 }
156
157 memory->buf = nullptr;
158 g_slice_free(GstSurfaceMemory, memory);
159 }
160
gst_surface_allocator_alloc_dummy(GstAllocator * allocator,gsize size,GstAllocationParams * params)161 static GstMemory *gst_surface_allocator_alloc_dummy(GstAllocator *allocator, gsize size, GstAllocationParams *params)
162 {
163 (void)allocator;
164 (void)size;
165 (void)params;
166 return nullptr;
167 }
168
gst_surface_allocator_mem_map(GstMemory * mem,gsize maxsize,GstMapFlags flags)169 static gpointer gst_surface_allocator_mem_map(GstMemory *mem, gsize maxsize, GstMapFlags flags)
170 {
171 (void)maxsize;
172 (void)flags;
173 g_return_val_if_fail(mem != nullptr, nullptr);
174 g_return_val_if_fail(gst_is_surface_memory(mem), nullptr);
175
176 GstSurfaceMemory *sf_mem = reinterpret_cast<GstSurfaceMemory *>(mem);
177 g_return_val_if_fail(sf_mem->buf != nullptr, nullptr);
178
179 return sf_mem->buf->GetVirAddr();
180 }
181
gst_surface_allocator_mem_unmap(GstMemory * mem)182 static void gst_surface_allocator_mem_unmap(GstMemory *mem)
183 {
184 (void)mem;
185 }
186
gst_surface_allocator_init(GstSurfaceAllocator * allocator)187 static void gst_surface_allocator_init(GstSurfaceAllocator *allocator)
188 {
189 GstAllocator *base_allocator = GST_ALLOCATOR_CAST(allocator);
190 g_return_if_fail(base_allocator != nullptr);
191
192 GST_DEBUG_OBJECT(allocator, "init allocator 0x%06" PRIXPTR "", FAKE_POINTER(allocator));
193
194 base_allocator->mem_type = GST_SURFACE_MEMORY_TYPE;
195 base_allocator->mem_map = (GstMemoryMapFunction)gst_surface_allocator_mem_map;
196 base_allocator->mem_unmap = (GstMemoryUnmapFunction)gst_surface_allocator_mem_unmap;
197 }
198
gst_surface_allocator_finalize(GObject * obj)199 static void gst_surface_allocator_finalize(GObject *obj)
200 {
201 GstSurfaceAllocator *allocator = GST_SURFACE_ALLOCATOR_CAST(obj);
202 g_return_if_fail(allocator != nullptr);
203
204 allocator->surface = nullptr;
205 GST_DEBUG_OBJECT(allocator, "finalize allocator 0x%06" PRIXPTR "", FAKE_POINTER(allocator));
206 G_OBJECT_CLASS(parent_class)->finalize(obj);
207 }
208
gst_surface_allocator_class_init(GstSurfaceAllocatorClass * klass)209 static void gst_surface_allocator_class_init(GstSurfaceAllocatorClass *klass)
210 {
211 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
212 g_return_if_fail(gobject_class != nullptr);
213
214 gobject_class->finalize = gst_surface_allocator_finalize;
215
216 GstAllocatorClass *allocatorClass = GST_ALLOCATOR_CLASS(klass);
217 g_return_if_fail(allocatorClass != nullptr);
218
219 allocatorClass->alloc = gst_surface_allocator_alloc_dummy;
220 allocatorClass->free = gst_surface_allocator_free;
221 GST_DEBUG_CATEGORY_INIT(gst_surface_allocator_debug_category, "prosurallocator", 0, "surface allocator");
222 }
223
gst_surface_allocator_new()224 GstSurfaceAllocator *gst_surface_allocator_new()
225 {
226 GstSurfaceAllocator *alloc = GST_SURFACE_ALLOCATOR_CAST(g_object_new(
227 GST_TYPE_SURFACE_ALLOCATOR, "name", "SurfaceAllocator", nullptr));
228 (void)gst_object_ref_sink(alloc);
229
230 return alloc;
231 }
232