GCC Code Coverage Report


Directory: src/gate/
File: src/gate/io/videosources_writer.c
Date: 2025-09-14 13:10:38
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 return GATE_INTERFACE_NAME_VIDEO_WRITER;
53 }
54 static void videowriter_release(void* thisptr)
55 {
56 gate_videowriter_impl_t* const self = (gate_videowriter_impl_t*)thisptr;
57 if (gate_atomic_int_dec(&self->ref_counter) == 0)
58 {
59 if (self->stream)
60 {
61 gate_object_release(self->stream);
62 }
63 gate_string_release(&self->path);
64 gate_string_release(&self->file_prefix);
65 gate_string_release(&self->file_extension);
66 }
67 }
68 static int videowriter_retain(void* thisptr)
69 {
70 gate_videowriter_impl_t* const self = (gate_videowriter_impl_t*)thisptr;
71 return gate_atomic_int_inc(&self->ref_counter);
72 }
73
74 static gate_string_t* generate_next_frame_file_name(gate_videowriter_impl_t* self, gate_string_t* file_name)
75 {
76 gate_string_t* ret = NULL;
77 gate_uint64_t frame_id = ++self->frame_id;
78 gate_strbuilder_t builder;
79
80 gate_strbuilder_create(&builder, gate_string_length(&self->path) + 32);
81 gate_strbuilder_append_string(&builder, &self->path);
82 gate_strbuilder_append_string(&builder, &self->file_prefix);
83 gate_strbuilder_append_cstr(&builder, "__");
84 gate_strbuilder_append_uint64(&builder, frame_id);
85 gate_strbuilder_append_cstr(&builder, "-");
86 gate_strbuilder_append_uint64(&builder, 0);
87 gate_strbuilder_append_string(&builder, &self->file_extension);
88
89 ret = gate_strbuilder_to_string(&builder, file_name);
90 gate_strbuilder_release(&builder);
91 return ret;
92 }
93
94 static gate_result_t write_png_frame(gate_videowriter_impl_t* self, gate_video_frame_t const* frame)
95 {
96 gate_result_t ret = GATE_RESULT_FAILED;
97 gate_string_t file_path = GATE_STRING_INIT_EMPTY;
98 gate_filestream_t* stream = NULL;
99
100 do
101 {
102 if (NULL == generate_next_frame_file_name(self, &file_path))
103 {
104 ret = GATE_RESULT_OUTOFMEMORY;
105 break;
106 }
107
108 ret = gate_file_openstream(&file_path, GATE_STREAM_OPEN_WRITE, &stream);
109 GATE_BREAK_IF_FAILED(ret);
110
111 ret = gate_pngimage_save(&frame->image, (gate_stream_t*)stream, 0);
112 } while (0);
113
114 gate_string_release(&file_path);
115 if (stream)
116 {
117 gate_object_release(stream);
118 }
119
120 return ret;
121 }
122
123 static gate_result_t write_jpeg_frame(gate_videowriter_impl_t* self, gate_video_frame_t const* frame)
124 {
125 gate_result_t ret = GATE_RESULT_FAILED;
126 gate_string_t file_path = GATE_STRING_INIT_EMPTY;
127 gate_filestream_t* stream = NULL;
128
129 do
130 {
131 if (NULL == generate_next_frame_file_name(self, &file_path))
132 {
133 ret = GATE_RESULT_OUTOFMEMORY;
134 break;
135 }
136
137 ret = gate_file_openstream(&file_path, GATE_STREAM_OPEN_WRITE, &stream);
138 GATE_BREAK_IF_FAILED(ret);
139
140 ret = gate_jpegimage_save(&frame->image, (gate_stream_t*)stream, 0);
141 } while (0);
142
143 gate_string_release(&file_path);
144 if (stream)
145 {
146 gate_object_release(stream);
147 }
148
149 return ret;
150 }
151
152 static gate_result_t videowriter_write(void* thisptr, gate_video_frame_t const* frame)
153 {
154 gate_videowriter_impl_t* const self = (gate_videowriter_impl_t*)thisptr;
155 switch (self->filetype)
156 {
157 case GATE_VIDEO_FILEWRITER_TYPE_PNG:
158 {
159 return write_png_frame(self, frame);
160 }
161 case GATE_VIDEO_FILEWRITER_TYPE_JPEG:
162 {
163 return write_jpeg_frame(self, frame);
164 }
165 default:
166 {
167 return GATE_RESULT_NOTSUPPORTED;
168 }
169 }
170 }
171
172 static GATE_INTERFACE_VTBL(gate_video_writer) const* init_videowriter_vtbl()
173 {
174 static GATE_INTERFACE_VTBL(gate_video_writer) global_vtbl;
175 if (global_vtbl.get_interface_name == NULL)
176 {
177 GATE_INTERFACE_VTBL(gate_video_writer) const local_vtbl =
178 {
179 &videowriter_get_interface_name,
180 &videowriter_release,
181 &videowriter_retain,
182 &videowriter_write
183 };
184 global_vtbl = local_vtbl;
185 }
186 return &global_vtbl;
187 }
188
189
190 gate_result_t gate_video_filewriter_create(
191 gate_enumint_t filetype,
192 gate_string_t const* path,
193 gate_video_format_t const* ptr_format,
194 gate_video_writer_t** ptr_writer)
195 {
196 static gate_string_t const file_ext_png = GATE_STRING_INIT_STATIC(".png");
197 static gate_string_t const file_ext_jpg = GATE_STRING_INIT_STATIC(".jpg");
198 gate_result_t ret = GATE_RESULT_FAILED;
199 gate_videowriter_impl_t* impl = NULL;
200 do
201 {
202 impl = (gate_videowriter_impl_t*)gate_mem_alloc(sizeof(gate_videowriter_impl_t));
203 if (impl == NULL)
204 {
205 ret = GATE_RESULT_OUTOFMEMORY;
206 break;
207 }
208 gate_mem_clear(impl, sizeof(gate_videowriter_impl_t));
209 impl->vtbl = init_videowriter_vtbl();
210 gate_atomic_int_init(&impl->ref_counter, 1);
211
212 gate_mem_copy(&impl->format, ptr_format, sizeof(impl->format));
213 impl->filetype = filetype;
214
215 switch (filetype)
216 {
217 case GATE_VIDEO_FILEWRITER_TYPE_PNG:
218 {
219 gate_file_split_path(path, &impl->path, &impl->file_prefix);
220 gate_string_duplicate(&impl->file_extension, &file_ext_png);
221 ret = GATE_RESULT_OK;
222 break;
223 }
224 case GATE_VIDEO_FILEWRITER_TYPE_JPEG:
225 {
226 gate_file_split_path(path, &impl->path, &impl->file_prefix);
227 gate_string_duplicate(&impl->file_extension, &file_ext_jpg);
228 ret = GATE_RESULT_OK;
229 break;
230 }
231 default:
232 {
233 ret = GATE_RESULT_NOTSUPPORTED;
234 break;
235 }
236 }
237
238 GATE_BREAK_IF_FAILED(ret);
239
240 if (ptr_writer)
241 {
242 *ptr_writer = (gate_video_writer_t*)impl;
243 impl = NULL;
244 }
245 ret = GATE_RESULT_OK;
246 } while (0);
247
248 if (impl)
249 {
250 videowriter_release(impl);
251 }
252 return ret;
253 }
254