GCC Code Coverage Report


Directory: src/gate/
File: src/gate/io/videosources_writer.c
Date: 2026-10-19 17:06:30
Exec Total Coverage
Lines: 0 103 0.0%
Functions: 0 9 0.0%
Branches: 0 32 0.0%

Line Branch Exec Source
1 /* GATE PROJECT LICENSE:
2 +----------------------------------------------------------------------------+
3 | Copyright (c) 2018-2026, Stefan Meislinger <sm@opengate.at> |
4 | All rights reserved. |
5 | |
6 | Redistribution and use in source and binary forms, with or without |
7 | modification, are permitted provided that the following conditions are met:|
8 | |
9 | 1. Redistributions of source code must retain the above copyright notice, |
10 | this list of conditions and the following disclaimer. |
11 | 2. Redistributions in binary form must reproduce the above copyright |
12 | notice, this list of conditions and the following disclaimer in the |
13 | documentation and/or other materials provided with the distribution. |
14 | |
15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"|
16 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
17 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
18 | ARE DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE |
19 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
20 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
21 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
22 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
23 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
24 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF |
25 | THE POSSIBILITY OF SUCH DAMAGE. |
26 +----------------------------------------------------------------------------+
27 */
28 #include "gate/io/videosources.h"
29 #include "gate/results.h"
30 #include "gate/files.h"
31 #include "gate/graphics/pngimages.h"
32 #include "gate/graphics/jpegimages.h"
33
34 typedef struct gate_videowriter_impl_class
35 {
36 GATE_INTERFACE_VTBL(gate_video_writer) const* vtbl;
37
38 gate_atomic_int_t ref_counter;
39 gate_enumint_t filetype;
40 gate_video_format_t format;
41 gate_string_t path;
42 gate_string_t file_prefix;
43 gate_string_t file_extension;
44 gate_filestream_t* stream;
45 gate_timecounter_t start_time;
46 gate_timecounter_t last_frame_time;
47 gate_uint64_t frame_id;
48 } gate_videowriter_impl_t;
49
50 ✗ static char const* videowriter_get_interface_name(void* thisptr)
51 {
52 GATE_UNUSED_ARG(thisptr);
53 ✗ return GATE_INTERFACE_NAME_VIDEO_WRITER;
54 }
55 ✗ static void videowriter_release(void* thisptr)
56 {
57 ✗ gate_videowriter_impl_t* const self = (gate_videowriter_impl_t*)thisptr;
58 ✗ if (gate_atomic_int_dec(&self->ref_counter) == 0)
59 {
60 ✗ if (self->stream)
61 {
62 ✗ gate_object_release(self->stream);
63 }
64 ✗ gate_string_release(&self->path);
65 ✗ gate_string_release(&self->file_prefix);
66 ✗ gate_string_release(&self->file_extension);
67 }
68 ✗ }
69 ✗ static int videowriter_retain(void* thisptr)
70 {
71 ✗ gate_videowriter_impl_t* const self = (gate_videowriter_impl_t*)thisptr;
72 ✗ return gate_atomic_int_inc(&self->ref_counter);
73 }
74
75 ✗ static gate_string_t* generate_next_frame_file_name(gate_videowriter_impl_t* self, gate_string_t* file_name)
76 {
77 ✗ gate_string_t* ret = NULL;
78 ✗ gate_uint64_t frame_id = ++self->frame_id;
79 gate_strbuilder_t builder;
80
81 ✗ gate_strbuilder_create(&builder, gate_string_length(&self->path) + 32);
82 ✗ gate_strbuilder_append_string(&builder, &self->path);
83 ✗ gate_strbuilder_append_string(&builder, &self->file_prefix);
84 ✗ gate_strbuilder_append_cstr(&builder, "__");
85 ✗ gate_strbuilder_append_uint64(&builder, frame_id);
86 ✗ gate_strbuilder_append_cstr(&builder, "-");
87 ✗ gate_strbuilder_append_uint64(&builder, 0);
88 ✗ gate_strbuilder_append_string(&builder, &self->file_extension);
89
90 ✗ ret = gate_strbuilder_to_string(&builder, file_name);
91 ✗ gate_strbuilder_release(&builder);
92 ✗ return ret;
93 }
94
95 ✗ static gate_result_t write_png_frame(gate_videowriter_impl_t* self, gate_video_frame_t const* frame)
96 {
97 ✗ gate_result_t ret = GATE_RESULT_FAILED;
98 ✗ gate_string_t file_path = GATE_STRING_INIT_EMPTY;
99 ✗ gate_filestream_t* stream = NULL;
100
101 do
102 {
103 ✗ if (NULL == generate_next_frame_file_name(self, &file_path))
104 {
105 ✗ ret = GATE_RESULT_OUTOFMEMORY;
106 ✗ break;
107 }
108
109 ✗ ret = gate_file_openstream(&file_path, GATE_STREAM_OPEN_WRITE, &stream);
110 ✗ GATE_BREAK_IF_FAILED(ret);
111
112 ✗ ret = gate_pngimage_save(&frame->image, (gate_stream_t*)stream, 0);
113 } while (0);
114
115 ✗ gate_string_release(&file_path);
116 ✗ if (stream)
117 {
118 ✗ gate_object_release(stream);
119 }
120
121 ✗ return ret;
122 }
123
124 ✗ static gate_result_t write_jpeg_frame(gate_videowriter_impl_t* self, gate_video_frame_t const* frame)
125 {
126 ✗ gate_result_t ret = GATE_RESULT_FAILED;
127 ✗ gate_string_t file_path = GATE_STRING_INIT_EMPTY;
128 ✗ gate_filestream_t* stream = NULL;
129
130 do
131 {
132 ✗ if (NULL == generate_next_frame_file_name(self, &file_path))
133 {
134 ✗ ret = GATE_RESULT_OUTOFMEMORY;
135 ✗ break;
136 }
137
138 ✗ ret = gate_file_openstream(&file_path, GATE_STREAM_OPEN_WRITE, &stream);
139 ✗ GATE_BREAK_IF_FAILED(ret);
140
141 ✗ ret = gate_jpegimage_save(&frame->image, (gate_stream_t*)stream, 0);
142 } while (0);
143
144 ✗ gate_string_release(&file_path);
145 ✗ if (stream)
146 {
147 ✗ gate_object_release(stream);
148 }
149
150 ✗ return ret;
151 }
152
153 ✗ static gate_result_t videowriter_write(void* thisptr, gate_video_frame_t const* frame)
154 {
155 ✗ gate_videowriter_impl_t* const self = (gate_videowriter_impl_t*)thisptr;
156 ✗ switch (self->filetype)
157 {
158 ✗ case GATE_VIDEO_FILEWRITER_TYPE_PNG:
159 {
160 ✗ return write_png_frame(self, frame);
161 }
162 ✗ case GATE_VIDEO_FILEWRITER_TYPE_JPEG:
163 {
164 ✗ return write_jpeg_frame(self, frame);
165 }
166 ✗ default:
167 {
168 ✗ return GATE_RESULT_NOTSUPPORTED;
169 }
170 }
171 }
172
173 ✗ static GATE_INTERFACE_VTBL(gate_video_writer) const* init_videowriter_vtbl()
174 {
175 static GATE_INTERFACE_VTBL(gate_video_writer) global_vtbl;
176 ✗ if (global_vtbl.get_interface_name == NULL)
177 {
178 GATE_INTERFACE_VTBL(gate_video_writer) const local_vtbl =
179 {
180 &videowriter_get_interface_name,
181 &videowriter_release,
182 &videowriter_retain,
183 &videowriter_write
184 };
185 ✗ global_vtbl = local_vtbl;
186 }
187 ✗ return &global_vtbl;
188 }
189
190
191 ✗ gate_result_t gate_video_filewriter_create(
192 gate_enumint_t filetype,
193 gate_string_t const* path,
194 gate_video_format_t const* ptr_format,
195 gate_video_writer_t** ptr_writer)
196 {
197 static gate_string_t const file_ext_png = GATE_STRING_INIT_STATIC(".png");
198 static gate_string_t const file_ext_jpg = GATE_STRING_INIT_STATIC(".jpg");
199 ✗ gate_result_t ret = GATE_RESULT_FAILED;
200 ✗ gate_videowriter_impl_t* impl = NULL;
201 do
202 {
203 ✗ impl = (gate_videowriter_impl_t*)gate_mem_alloc(sizeof(gate_videowriter_impl_t));
204 ✗ if (impl == NULL)
205 {
206 ✗ ret = GATE_RESULT_OUTOFMEMORY;
207 ✗ break;
208 }
209 ✗ gate_mem_clear(impl, sizeof(gate_videowriter_impl_t));
210 ✗ impl->vtbl = init_videowriter_vtbl();
211 ✗ gate_atomic_int_init(&impl->ref_counter, 1);
212
213 ✗ gate_mem_copy(&impl->format, ptr_format, sizeof(impl->format));
214 ✗ impl->filetype = filetype;
215
216 ✗ switch (filetype)
217 {
218 ✗ case GATE_VIDEO_FILEWRITER_TYPE_PNG:
219 {
220 ✗ gate_file_split_path(path, &impl->path, &impl->file_prefix);
221 ✗ gate_string_duplicate(&impl->file_extension, &file_ext_png);
222 ✗ ret = GATE_RESULT_OK;
223 ✗ break;
224 }
225 ✗ case GATE_VIDEO_FILEWRITER_TYPE_JPEG:
226 {
227 ✗ gate_file_split_path(path, &impl->path, &impl->file_prefix);
228 ✗ gate_string_duplicate(&impl->file_extension, &file_ext_jpg);
229 ✗ ret = GATE_RESULT_OK;
230 ✗ break;
231 }
232 ✗ default:
233 {
234 ✗ ret = GATE_RESULT_NOTSUPPORTED;
235 ✗ break;
236 }
237 }
238
239 ✗ GATE_BREAK_IF_FAILED(ret);
240
241 ✗ if (ptr_writer)
242 {
243 ✗ *ptr_writer = (gate_video_writer_t*)impl;
244 ✗ impl = NULL;
245 }
246 ✗ ret = GATE_RESULT_OK;
247 } while (0);
248
249 ✗ if (impl)
250 {
251 ✗ videowriter_release(impl);
252 }
253 ✗ return ret;
254 }
255