GCC Code Coverage Report


Directory: src/gate/
File: src/gate/io/videosources_writer.c
Date: 2025-12-12 23:40:09
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-2025, 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