@@ -39,33 +39,26 @@ const AVCodec* getCodecByName(const std::string& name) {
39
39
return nullptr ;
40
40
}
41
41
42
- geode::Result<> Recorder::init (const RenderSettings& settings) {
43
- m_impl = std::make_unique<Impl>();
44
-
45
- int ret = avformat_alloc_output_context2 (&m_impl->m_formatContext , NULL , NULL , settings.m_outputFile .string ().c_str ());
46
- const auto m_formatContext = m_impl->m_formatContext ;
42
+ geode::Result<> Recorder::Impl::init (const RenderSettings& settings) {
43
+ int ret = avformat_alloc_output_context2 (&m_formatContext, NULL , NULL , settings.m_outputFile .string ().c_str ());
47
44
if (!m_formatContext)
48
45
return geode::Err (" Could not create output context: " + utils::getErrorString (ret));
49
46
50
- m_impl->m_codec = getCodecByName (settings.m_codec );
51
- const auto m_codec = m_impl->m_codec ;
47
+ m_codec = getCodecByName (settings.m_codec );
52
48
if (!m_codec)
53
49
return geode::Err (" Could not find encoder." );
54
50
55
- m_impl->m_videoStream = avformat_new_stream (m_formatContext, m_codec);
56
- const auto m_videoStream = m_impl->m_videoStream ;
51
+ m_videoStream = avformat_new_stream (m_formatContext, m_codec);
57
52
if (!m_videoStream)
58
53
return geode::Err (" Could not create video stream." );
59
54
60
- m_impl->m_codecContext = avcodec_alloc_context3 (m_codec);
61
- const auto m_codecContext = m_impl->m_codecContext ;
55
+ m_codecContext = avcodec_alloc_context3 (m_codec);
62
56
if (!m_codecContext)
63
57
return geode::Err (" Could not allocate video codec context." );
64
58
65
- if (settings.m_hardwareAccelerationType != HardwareAccelerationType::NONE && (ret = av_hwdevice_ctx_create (&m_impl-> m_hwDevice , (AVHWDeviceType)settings.m_hardwareAccelerationType , NULL , NULL , 0 )); ret < 0 )
59
+ if (settings.m_hardwareAccelerationType != HardwareAccelerationType::NONE && (ret = av_hwdevice_ctx_create (&m_hwDevice, (AVHWDeviceType)settings.m_hardwareAccelerationType , NULL , NULL , 0 )); ret < 0 )
66
60
return geode::Err (" Could not create hardware device context: " + utils::getErrorString (ret));
67
61
68
- const auto m_hwDevice = m_impl->m_hwDevice ;
69
62
m_codecContext->hw_device_ctx = m_hwDevice ? av_buffer_ref (m_hwDevice) : nullptr ;
70
63
m_codecContext->codec_id = m_codec->id ;
71
64
m_codecContext->bit_rate = settings.m_bitrate ;
@@ -109,35 +102,33 @@ geode::Result<> Recorder::init(const RenderSettings& settings) {
109
102
if (ret = avformat_write_header (m_formatContext, nullptr ); ret < 0 )
110
103
return geode::Err (" Could not write header: " + utils::getErrorString (ret));
111
104
112
- m_impl->m_frame = av_frame_alloc ();
113
- const auto m_frame = m_impl->m_frame ;
105
+ m_frame = av_frame_alloc ();
114
106
m_frame->format = m_codecContext->pix_fmt ;
115
107
m_frame->width = m_codecContext->width ;
116
108
m_frame->height = m_codecContext->height ;
117
109
118
110
if (ret = av_image_alloc (m_frame->data , m_frame->linesize , m_codecContext->width , m_codecContext->height , (AVPixelFormat)settings.m_pixelFormat , 32 ); ret < 0 )
119
111
return geode::Err (" Could not allocate raw picture buffer: " + utils::getErrorString (ret));
120
112
121
- m_impl->m_convertedFrame = av_frame_alloc ();
122
- const auto m_convertedFrame = m_impl->m_convertedFrame ;
113
+ m_convertedFrame = av_frame_alloc ();
123
114
m_convertedFrame->format = m_codecContext->pix_fmt ;
124
115
m_convertedFrame->width = m_codecContext->width ;
125
116
m_convertedFrame->height = m_codecContext->height ;
126
117
if (ret = av_image_alloc (m_convertedFrame->data , m_convertedFrame->linesize , m_convertedFrame->width , m_convertedFrame->height , m_codecContext->pix_fmt , 32 ); ret < 0 )
127
118
return geode::Err (" Could not allocate raw picture buffer: " + utils::getErrorString (ret));
128
119
129
- m_impl-> m_filteredFrame = av_frame_alloc ();
120
+ m_filteredFrame = av_frame_alloc ();
130
121
131
- m_impl-> m_packet = av_packet_alloc ();
122
+ m_packet = av_packet_alloc ();
132
123
133
- m_impl-> m_packet ->data = nullptr ;
134
- m_impl-> m_packet ->size = 0 ;
124
+ m_packet->data = nullptr ;
125
+ m_packet->size = 0 ;
135
126
136
127
int inputPixelFormat = (int )settings.m_pixelFormat ;
137
128
138
129
if (!settings.m_colorspaceFilters .empty () || settings.m_doVerticalFlip ) {
139
- m_impl-> m_filterGraph = avfilter_graph_alloc ();
140
- if (!m_impl-> m_filterGraph )
130
+ m_filterGraph = avfilter_graph_alloc ();
131
+ if (!m_filterGraph)
141
132
return geode::Err (" Could not allocate filter graph." );
142
133
143
134
const AVFilter* buffersrc = avfilter_get_by_name (" buffer" );
@@ -151,112 +142,100 @@ geode::Result<> Recorder::init(const RenderSettings& settings) {
151
142
m_codecContext->width , m_codecContext->height , m_codecContext->pix_fmt ,
152
143
m_codecContext->time_base .num , m_codecContext->time_base .den ,
153
144
m_codecContext->sample_aspect_ratio .num , m_codecContext->sample_aspect_ratio .den );
154
- const auto m_filterGraph = m_impl->m_filterGraph ;
155
145
156
- if (ret = avfilter_graph_create_filter (&m_impl-> m_buffersrcCtx , buffersrc, " in" , args, nullptr , m_filterGraph); ret < 0 ) {
157
- avfilter_graph_free (&m_impl-> m_filterGraph );
146
+ if (ret = avfilter_graph_create_filter (&m_buffersrcCtx, buffersrc, " in" , args, nullptr , m_filterGraph); ret < 0 ) {
147
+ avfilter_graph_free (&m_filterGraph);
158
148
return geode::Err (" Could not create input for filter graph: " + utils::getErrorString (ret));
159
149
}
160
150
161
- if (ret = avfilter_graph_create_filter (&m_impl-> m_buffersinkCtx , buffersink, " out" , nullptr , nullptr , m_filterGraph); ret < 0 ) {
162
- avfilter_graph_free (&m_impl-> m_filterGraph );
151
+ if (ret = avfilter_graph_create_filter (&m_buffersinkCtx, buffersink, " out" , nullptr , nullptr , m_filterGraph); ret < 0 ) {
152
+ avfilter_graph_free (&m_filterGraph);
163
153
return geode::Err (" Could not create output for filter graph: " + utils::getErrorString (ret));
164
154
}
165
155
166
156
if (!settings.m_colorspaceFilters .empty ()) {
167
- if (ret = avfilter_graph_create_filter (&m_impl-> m_colorspaceCtx , colorspace, " colorspace" , settings.m_colorspaceFilters .c_str (), nullptr , m_filterGraph); ret < 0 ) {
168
- avfilter_graph_free (&m_impl-> m_filterGraph );
157
+ if (ret = avfilter_graph_create_filter (&m_colorspaceCtx, colorspace, " colorspace" , settings.m_colorspaceFilters .c_str (), nullptr , m_filterGraph); ret < 0 ) {
158
+ avfilter_graph_free (&m_filterGraph);
169
159
return geode::Err (" Could not create colorspace for filter graph: " + utils::getErrorString (ret));
170
160
}
171
161
172
- if (ret = avfilter_link (m_impl-> m_buffersrcCtx , 0 , m_impl-> m_colorspaceCtx , 0 ); ret < 0 ) {
173
- avfilter_graph_free (&m_impl-> m_filterGraph );
162
+ if (ret = avfilter_link (m_buffersrcCtx, 0 , m_colorspaceCtx, 0 ); ret < 0 ) {
163
+ avfilter_graph_free (&m_filterGraph);
174
164
return geode::Err (" Could not link filters: " + utils::getErrorString (ret));
175
165
}
176
166
177
- if (ret = avfilter_link (m_impl-> m_colorspaceCtx , 0 , m_impl-> m_buffersinkCtx , 0 ); ret < 0 ) {
178
- avfilter_graph_free (&m_impl-> m_filterGraph );
167
+ if (ret = avfilter_link (m_colorspaceCtx, 0 , m_buffersinkCtx, 0 ); ret < 0 ) {
168
+ avfilter_graph_free (&m_filterGraph);
179
169
return geode::Err (" Could not link filters: " + utils::getErrorString (ret));
180
170
}
181
171
}
182
172
183
173
if (settings.m_doVerticalFlip ) {
184
- if (ret = avfilter_graph_create_filter (&m_impl-> m_vflipCtx , vflip, " vflip" , nullptr , nullptr , m_filterGraph); ret < 0 ) {
185
- avfilter_graph_free (&m_impl-> m_filterGraph );
174
+ if (ret = avfilter_graph_create_filter (&m_vflipCtx, vflip, " vflip" , nullptr , nullptr , m_filterGraph); ret < 0 ) {
175
+ avfilter_graph_free (&m_filterGraph);
186
176
return geode::Err (" Could not create vflip for filter graph: " + utils::getErrorString (ret));
187
177
}
188
178
189
- if (ret = avfilter_link (m_impl-> m_buffersrcCtx , 0 , m_impl-> m_vflipCtx , 0 ); ret < 0 ) {
190
- avfilter_graph_free (&m_impl-> m_filterGraph );
179
+ if (ret = avfilter_link (m_buffersrcCtx, 0 , m_vflipCtx, 0 ); ret < 0 ) {
180
+ avfilter_graph_free (&m_filterGraph);
191
181
return geode::Err (" Could not link filters: " + utils::getErrorString (ret));
192
182
}
193
183
194
- if (ret = avfilter_link (m_impl-> m_vflipCtx , 0 , m_impl-> m_buffersinkCtx , 0 ); ret < 0 ) {
195
- avfilter_graph_free (&m_impl-> m_filterGraph );
184
+ if (ret = avfilter_link (m_vflipCtx, 0 , m_buffersinkCtx, 0 ); ret < 0 ) {
185
+ avfilter_graph_free (&m_filterGraph);
196
186
return geode::Err (" Could not link filters: " + utils::getErrorString (ret));
197
187
}
198
188
}
199
189
200
190
if (ret = avfilter_graph_config (m_filterGraph, nullptr ); ret < 0 ) {
201
- avfilter_graph_free (&m_impl-> m_filterGraph );
191
+ avfilter_graph_free (&m_filterGraph);
202
192
return geode::Err (" Could not configure filter graph: " + utils::getErrorString (ret));
203
193
}
204
194
205
- inputPixelFormat = av_buffersink_get_format (m_impl-> m_buffersinkCtx );
195
+ inputPixelFormat = av_buffersink_get_format (m_buffersinkCtx);
206
196
}
207
197
208
- m_impl-> m_swsCtx = sws_getContext (m_codecContext->width , m_codecContext->height , (AVPixelFormat)inputPixelFormat, m_codecContext->width ,
198
+ m_swsCtx = sws_getContext (m_codecContext->width , m_codecContext->height , (AVPixelFormat)inputPixelFormat, m_codecContext->width ,
209
199
m_codecContext->height , m_codecContext->pix_fmt , SWS_FAST_BILINEAR, nullptr , nullptr , nullptr );
210
200
211
- if (!m_impl-> m_swsCtx )
201
+ if (!m_swsCtx)
212
202
return geode::Err (" Could not create sws context." );
213
203
214
- m_impl-> m_frameCount = 0 ;
204
+ m_frameCount = 0 ;
215
205
216
- m_impl-> m_init = true ;
206
+ m_init = true ;
217
207
218
208
return geode::Ok ();
219
209
}
220
210
221
- geode::Result<> Recorder::writeFrame (const std::vector<uint8_t >& frameData) {
222
- if (!m_impl-> m_init || !m_impl-> m_frame )
211
+ geode::Result<> Recorder::Impl:: writeFrame (const std::vector<uint8_t >& frameData) {
212
+ if (!m_init || !m_frame)
223
213
return geode::Err (" Recorder is not initialized." );
224
214
225
- const auto m_frame = m_impl->m_frame ;
226
-
227
215
if (frameData.size () != m_frame->linesize [0 ] * m_frame->height )
228
216
return geode::Err (" Frame data size does not match expected dimensions." );
229
217
230
- if (m_impl->m_buffersrcCtx ) {
231
- const auto m_filteredFrame = m_impl->m_filteredFrame ;
232
-
218
+ if (m_buffersrcCtx) {
233
219
std::memcpy (m_frame->data [0 ], frameData.data (), frameData.size ());
234
220
geode::Result<> res = filterFrame (m_frame, m_filteredFrame);
235
221
236
222
if (res.isErr ())
237
223
return res;
238
224
239
- const auto m_convertedFrame = m_impl->m_convertedFrame ;
240
-
241
225
sws_scale (
242
- m_impl-> m_swsCtx , m_filteredFrame->data , m_filteredFrame->linesize , 0 , m_filteredFrame->height ,
226
+ m_swsCtx, m_filteredFrame->data , m_filteredFrame->linesize , 0 , m_filteredFrame->height ,
243
227
m_convertedFrame->data , m_convertedFrame->linesize );
244
228
}
245
229
else {
246
230
const uint8_t * srcData[1 ] = { frameData.data () };
247
- const auto m_convertedFrame = m_impl-> m_convertedFrame ;
231
+ int srcLinesize[ 1 ] = { m_frame-> linesize [ 0 ] } ;
248
232
249
233
sws_scale (
250
- m_impl-> m_swsCtx , srcData, m_frame->linesize , 0 , m_frame->height ,
234
+ m_swsCtx, srcData, m_frame->linesize , 0 , m_frame->height ,
251
235
m_convertedFrame->data , m_convertedFrame->linesize );
252
236
}
253
237
254
- const auto m_convertedFrame = m_impl->m_convertedFrame ;
255
- const auto m_packet = m_impl->m_packet ;
256
- const auto m_codecContext = m_impl->m_codecContext ;
257
- const auto m_videoStream = m_impl->m_videoStream ;
258
-
259
- m_convertedFrame->pts = m_impl->m_frameCount ++;
238
+ m_convertedFrame->pts = m_frameCount++;
260
239
261
240
int ret = avcodec_send_frame (m_codecContext, m_convertedFrame);
262
241
if (ret < 0 )
@@ -272,64 +251,64 @@ geode::Result<> Recorder::writeFrame(const std::vector<uint8_t>& frameData) {
272
251
av_packet_rescale_ts (m_packet, m_codecContext->time_base , m_videoStream->time_base );
273
252
m_packet->stream_index = m_videoStream->index ;
274
253
275
- av_interleaved_write_frame (m_impl-> m_formatContext , m_packet);
254
+ av_interleaved_write_frame (m_formatContext, m_packet);
276
255
av_packet_unref (m_packet);
277
256
}
278
257
279
- av_frame_unref (m_impl-> m_filteredFrame );
258
+ av_frame_unref (m_filteredFrame);
280
259
281
260
return geode::Ok ();
282
261
}
283
262
284
- geode::Result<> Recorder::filterFrame (AVFrame* inputFrame, AVFrame* outputFrame) {
263
+ geode::Result<> Recorder::Impl:: filterFrame (AVFrame* inputFrame, AVFrame* outputFrame) {
285
264
int ret = 0 ;
286
- if (ret = av_buffersrc_add_frame (m_impl-> m_buffersrcCtx , inputFrame); ret < 0 ) {
287
- avfilter_graph_free (&m_impl-> m_filterGraph );
265
+ if (ret = av_buffersrc_add_frame (m_buffersrcCtx, inputFrame); ret < 0 ) {
266
+ avfilter_graph_free (&m_filterGraph);
288
267
return geode::Err (" Could not feed frame to filter graph: " + utils::getErrorString (ret));
289
268
}
290
269
291
- if (ret = av_buffersink_get_frame (m_impl-> m_buffersinkCtx , outputFrame); ret < 0 ) {
270
+ if (ret = av_buffersink_get_frame (m_buffersinkCtx, outputFrame); ret < 0 ) {
292
271
av_frame_unref (outputFrame);
293
272
return geode::Err (" Could not retrieve frame from filter graph: " + utils::getErrorString (ret));
294
273
}
295
274
296
275
return geode::Ok ();
297
276
}
298
277
299
- void Recorder::stop () {
300
- if (!m_impl-> m_init )
278
+ void Recorder::Impl:: stop () {
279
+ if (!m_init)
301
280
return ;
302
281
303
- m_impl-> m_init = false ;
282
+ m_init = false ;
304
283
305
- avcodec_send_frame (m_impl-> m_codecContext , nullptr );
306
- while (avcodec_receive_packet (m_impl-> m_codecContext , m_impl-> m_packet ) == 0 ) {
307
- av_packet_rescale_ts (m_impl-> m_packet , m_impl-> m_codecContext ->time_base , m_impl-> m_videoStream ->time_base );
308
- m_impl-> m_packet ->stream_index = m_impl-> m_videoStream ->index ;
309
- av_interleaved_write_frame (m_impl-> m_formatContext , m_impl-> m_packet );
310
- av_packet_unref (m_impl-> m_packet );
284
+ avcodec_send_frame (m_codecContext, nullptr );
285
+ while (avcodec_receive_packet (m_codecContext, m_packet) == 0 ) {
286
+ av_packet_rescale_ts (m_packet, m_codecContext->time_base , m_videoStream->time_base );
287
+ m_packet->stream_index = m_videoStream->index ;
288
+ av_interleaved_write_frame (m_formatContext, m_packet);
289
+ av_packet_unref (m_packet);
311
290
}
312
291
313
- av_write_trailer (m_impl-> m_formatContext );
292
+ av_write_trailer (m_formatContext);
314
293
315
- avcodec_free_context (&m_impl-> m_codecContext );
316
- av_frame_free (&m_impl-> m_frame );
317
- av_frame_free (&m_impl-> m_convertedFrame );
318
- if (!(m_impl-> m_formatContext ->oformat ->flags & AVFMT_NOFILE)) {
319
- avio_close (m_impl-> m_formatContext ->pb );
294
+ avcodec_free_context (&m_codecContext);
295
+ av_frame_free (&m_frame);
296
+ av_frame_free (&m_convertedFrame);
297
+ if (!(m_formatContext->oformat ->flags & AVFMT_NOFILE)) {
298
+ avio_close (m_formatContext->pb );
320
299
}
321
- avformat_free_context (m_impl-> m_formatContext );
300
+ avformat_free_context (m_formatContext);
322
301
323
- if (m_impl-> m_filterGraph ) {
324
- avfilter_graph_free (&m_impl-> m_filterGraph );
325
- av_frame_free (&m_impl-> m_filteredFrame );
302
+ if (m_filterGraph) {
303
+ avfilter_graph_free (&m_filterGraph);
304
+ av_frame_free (&m_filteredFrame);
326
305
}
327
306
328
- if (m_impl-> m_hwDevice ) {
329
- av_buffer_unref (&m_impl-> m_hwDevice );
307
+ if (m_hwDevice) {
308
+ av_buffer_unref (&m_hwDevice);
330
309
}
331
310
332
- av_packet_free (&m_impl-> m_packet );
311
+ av_packet_free (&m_packet);
333
312
}
334
313
335
314
END_FFMPEG_NAMESPACE_V
0 commit comments