obs-ffmpeg: Cache swscale context during frame callback
Some codecs don't report the correct dimensions until the first frame is rendered.
This commit is contained in:
@@ -104,12 +104,31 @@ static bool set_obs_frame_colorprops(struct ff_frame *frame,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool update_sws_context(struct ffmpeg_source *source, AVFrame *frame)
|
||||
{
|
||||
source->sws_ctx = sws_getCachedContext(
|
||||
source->sws_ctx,
|
||||
frame->width,
|
||||
frame->height,
|
||||
frame->format,
|
||||
frame->width,
|
||||
frame->height,
|
||||
AV_PIX_FMT_BGRA,
|
||||
SWS_BILINEAR,
|
||||
NULL, NULL, NULL);
|
||||
|
||||
return source->sws_ctx != NULL;
|
||||
}
|
||||
|
||||
static bool video_frame_scale(struct ff_frame *frame,
|
||||
struct ffmpeg_source *s, struct obs_source_frame *obs_frame)
|
||||
{
|
||||
int linesize = frame->frame->width * 4;
|
||||
uint8_t *picture_data =
|
||||
malloc(linesize * frame->frame->height);
|
||||
|
||||
update_sws_context(s, frame->frame);
|
||||
|
||||
sws_scale(
|
||||
s->sws_ctx,
|
||||
(uint8_t const *const *)frame->frame->data,
|
||||
@@ -176,7 +195,10 @@ static bool video_frame(struct ff_frame *frame, void *opaque)
|
||||
obs_frame.width = frame->frame->width;
|
||||
obs_frame.height = frame->frame->height;
|
||||
|
||||
if (s->sws_ctx != NULL)
|
||||
enum video_format format =
|
||||
ffmpeg_to_obs_video_format(frame->frame->format);
|
||||
|
||||
if (s->is_forcing_scale || format == VIDEO_FORMAT_NONE)
|
||||
return video_frame_scale(frame, s, &obs_frame);
|
||||
else if (s->is_hw_decoding)
|
||||
return video_frame_hwaccel(frame, s->source, &obs_frame);
|
||||
@@ -211,33 +233,6 @@ static bool audio_frame(struct ff_frame *frame, void *opaque)
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool video_format(AVCodecContext *codec_context, void *opaque)
|
||||
{
|
||||
struct ffmpeg_source *s = opaque;
|
||||
if (s->sws_ctx)
|
||||
sws_freeContext(s->sws_ctx);
|
||||
|
||||
enum video_format obs_video_format =
|
||||
ffmpeg_to_obs_video_format(codec_context->pix_fmt);
|
||||
|
||||
if (obs_video_format == VIDEO_FORMAT_NONE || s->is_forcing_scale) {
|
||||
s->sws_ctx = sws_getContext(
|
||||
codec_context->width,
|
||||
codec_context->height,
|
||||
codec_context->pix_fmt,
|
||||
codec_context->width,
|
||||
codec_context->height,
|
||||
AV_PIX_FMT_BGRA,
|
||||
SWS_BILINEAR,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL
|
||||
);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool is_local_file_modified(obs_properties_t *props,
|
||||
obs_property_t *prop, obs_data_t *settings)
|
||||
{
|
||||
@@ -347,11 +342,6 @@ static void ffmpeg_source_update(void *data, obs_data_t *settings)
|
||||
if (s->demuxer != NULL)
|
||||
ff_demuxer_free(s->demuxer);
|
||||
|
||||
if (s->sws_ctx != NULL) {
|
||||
sws_freeContext(s->sws_ctx);
|
||||
s->sws_ctx = NULL;
|
||||
}
|
||||
|
||||
s->demuxer = ff_demuxer_init();
|
||||
s->demuxer->options.is_hw_decoding = s->is_hw_decoding;
|
||||
s->demuxer->options.is_looping = is_looping;
|
||||
@@ -376,7 +366,7 @@ static void ffmpeg_source_update(void *data, obs_data_t *settings)
|
||||
}
|
||||
|
||||
ff_demuxer_set_callbacks(&s->demuxer->video_callbacks,
|
||||
video_frame, video_format,
|
||||
video_frame, NULL,
|
||||
NULL, NULL, NULL, s);
|
||||
|
||||
ff_demuxer_set_callbacks(&s->demuxer->audio_callbacks,
|
||||
@@ -408,6 +398,11 @@ static void ffmpeg_source_destroy(void *data)
|
||||
struct ffmpeg_source *s = data;
|
||||
|
||||
ff_demuxer_free(s->demuxer);
|
||||
|
||||
if (s->sws_ctx != NULL) {
|
||||
sws_freeContext(s->sws_ctx);
|
||||
}
|
||||
|
||||
bfree(s);
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user