Skip to content

Commit fc15de2

Browse files
committed
fix crash with some formats and aspect ratios
1 parent 71dc623 commit fc15de2

File tree

5 files changed

+46
-27
lines changed

5 files changed

+46
-27
lines changed

changelog.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,5 @@
2424
- Fix Events API
2525
- V-flip support
2626
- More error handling
27-
- Performance improvements
27+
- Performance improvements
28+
- Bug fixes

include/recorder.hpp

+1
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ class FFMPEG_API_DLL Recorder {
4545
AVFilterContext* m_vflipCtx = nullptr;
4646

4747
size_t m_frameCount = 0;
48+
size_t m_expectedSize = 0;
4849
bool m_init = false;
4950

5051
geode::Result<> init(const RenderSettings& settings);

mod.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"geode": "4.1.1",
2+
"geode": "4.2.0",
33
"gd": {
44
"win": "*",
55
"android": "*",
@@ -14,7 +14,7 @@
1414
"id": "eclipse.ffmpeg-api",
1515
"name": "FFmpeg API",
1616
"version": "v1.2.0",
17-
"developers": ["Eclipse Team", "maxnu"],
17+
"developers": ["Eclipse Team", "maxnu", "Prevter"],
1818
"description": "Interaction with FFmpeg made easy",
1919
"tags": ["utility", "offline", "developer"],
2020
"links": {

src/audio_mixer.cpp

+3
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,9 @@ BEGIN_FFMPEG_NAMESPACE_V
193193
}
194194
}
195195

196+
if(videoStreamIndex == -1)
197+
return geode::Err("Could not find a valid video stream.");
198+
196199
AVCodecParameters* inputVideoParams = videoFormatContext->streams[videoStreamIndex]->codecpar;
197200
avcodec_parameters_copy(outputVideoStream->codecpar, inputVideoParams);
198201
outputVideoStream->codecpar->codec_tag = 0;

src/recorder.cpp

+38-24
Original file line numberDiff line numberDiff line change
@@ -103,10 +103,11 @@ geode::Result<> Recorder::Impl::init(const RenderSettings& settings) {
103103
return geode::Err("Could not write header: " + utils::getErrorString(ret));
104104

105105
m_frame = av_frame_alloc();
106-
m_frame->format = m_codecContext->pix_fmt;
106+
m_frame->format = (AVPixelFormat)settings.m_pixelFormat;
107107
m_frame->width = m_codecContext->width;
108108
m_frame->height = m_codecContext->height;
109109

110+
//m_frame should always have the pixel format of the settings, if the codec does not support it, it will be converted in writeFrame
110111
if (ret = av_image_alloc(m_frame->data, m_frame->linesize, m_codecContext->width, m_codecContext->height, (AVPixelFormat)settings.m_pixelFormat, 32); ret < 0)
111112
return geode::Err("Could not allocate raw picture buffer: " + utils::getErrorString(ret));
112113

@@ -124,8 +125,6 @@ geode::Result<> Recorder::Impl::init(const RenderSettings& settings) {
124125
m_packet->data = nullptr;
125126
m_packet->size = 0;
126127

127-
int inputPixelFormat = (int)settings.m_pixelFormat;
128-
129128
if(!settings.m_colorspaceFilters.empty() || settings.m_doVerticalFlip) {
130129
m_filterGraph = avfilter_graph_alloc();
131130
if (!m_filterGraph)
@@ -137,7 +136,7 @@ geode::Result<> Recorder::Impl::init(const RenderSettings& settings) {
137136
const AVFilter* vflip = avfilter_get_by_name("vflip");
138137

139138
char args[512];
140-
snprintf(args, sizeof(args),
139+
snprintf(args, sizeof(args),
141140
"video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:pixel_aspect=%d/%d",
142141
m_codecContext->width, m_codecContext->height, m_codecContext->pix_fmt,
143142
m_codecContext->time_base.num, m_codecContext->time_base.den,
@@ -191,17 +190,18 @@ geode::Result<> Recorder::Impl::init(const RenderSettings& settings) {
191190
avfilter_graph_free(&m_filterGraph);
192191
return geode::Err("Could not configure filter graph: " + utils::getErrorString(ret));
193192
}
194-
195-
inputPixelFormat = av_buffersink_get_format(m_buffersinkCtx);
196193
}
197194

198-
m_swsCtx = sws_getContext(m_codecContext->width, m_codecContext->height, (AVPixelFormat)inputPixelFormat, m_codecContext->width,
199-
m_codecContext->height, m_codecContext->pix_fmt, SWS_FAST_BILINEAR, nullptr, nullptr, nullptr);
195+
if((AVPixelFormat)settings.m_pixelFormat != m_codecContext->pix_fmt) {
196+
m_swsCtx = sws_getContext(m_codecContext->width, m_codecContext->height, (AVPixelFormat)settings.m_pixelFormat, m_codecContext->width,
197+
m_codecContext->height, m_codecContext->pix_fmt, SWS_FAST_BILINEAR, nullptr, nullptr, nullptr);
200198

201-
if (!m_swsCtx)
202-
return geode::Err("Could not create sws context.");
199+
if (!m_swsCtx)
200+
return geode::Err("Could not create sws context.");
201+
}
203202

204203
m_frameCount = 0;
204+
m_expectedSize = av_image_get_buffer_size((AVPixelFormat)m_frame->format, m_frame->width, m_frame->height, 1);
205205

206206
m_init = true;
207207

@@ -212,32 +212,45 @@ geode::Result<> Recorder::Impl::writeFrame(const std::vector<uint8_t>& frameData
212212
if (!m_init || !m_frame)
213213
return geode::Err("Recorder is not initialized.");
214214

215-
if(frameData.size() != m_frame->linesize[0] * m_frame->height)
215+
if(frameData.size() != m_expectedSize)
216216
return geode::Err("Frame data size does not match expected dimensions.");
217217

218-
if(m_buffersrcCtx) {
219-
std::memcpy(m_frame->data[0], frameData.data(), frameData.size());
220-
geode::Result<> res = filterFrame(m_frame, m_filteredFrame);
218+
int ret = av_image_fill_arrays(
219+
m_frame->data,
220+
m_frame->linesize,
221+
frameData.data(),
222+
(AVPixelFormat)m_frame->format,
223+
m_frame->width,
224+
m_frame->height,
225+
1
226+
);
221227

222-
if(res.isErr())
223-
return res;
228+
if (ret < 0)
229+
return geode::Err("Failed to fill image arrays: " + utils::getErrorString(ret));
224230

231+
if(m_swsCtx) {
225232
sws_scale(
226-
m_swsCtx, m_filteredFrame->data, m_filteredFrame->linesize, 0, m_filteredFrame->height,
233+
m_swsCtx, m_frame->data, m_frame->linesize, 0, m_frame->height,
227234
m_convertedFrame->data, m_convertedFrame->linesize);
228235
}
229236
else {
230-
const uint8_t* srcData[1] = { frameData.data() };
231-
int srcLinesize[1] = { m_frame->linesize[0] };
237+
av_frame_copy(m_convertedFrame, m_frame);
238+
av_frame_copy_props(m_convertedFrame, m_frame);
239+
}
232240

233-
sws_scale(
234-
m_swsCtx, srcData, m_frame->linesize, 0, m_frame->height,
235-
m_convertedFrame->data, m_convertedFrame->linesize);
241+
if(m_buffersrcCtx) {
242+
geode::Result<> res = filterFrame(m_convertedFrame, m_filteredFrame);
243+
244+
if(res.isErr())
245+
return res;
246+
247+
av_frame_copy(m_convertedFrame, m_filteredFrame);
248+
av_frame_copy_props(m_convertedFrame, m_filteredFrame);
236249
}
237250

238251
m_convertedFrame->pts = m_frameCount++;
239252

240-
int ret = avcodec_send_frame(m_codecContext, m_convertedFrame);
253+
ret = avcodec_send_frame(m_codecContext, m_convertedFrame);
241254
if (ret < 0)
242255
return geode::Err("Error while sending frame: " + utils::getErrorString(ret));
243256

@@ -293,7 +306,8 @@ void Recorder::Impl::stop() {
293306

294307
avcodec_free_context(&m_codecContext);
295308
av_frame_free(&m_frame);
296-
av_frame_free(&m_convertedFrame);
309+
if(m_convertedFrame) //m_convertedFrame could be pointing to m_frame
310+
av_frame_free(&m_convertedFrame);
297311
if (!(m_formatContext->oformat->flags & AVFMT_NOFILE)) {
298312
avio_close(m_formatContext->pb);
299313
}

0 commit comments

Comments
 (0)