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:
John Bradley
2015-03-10 12:53:17 -05:00
parent b3fddc9f53
commit e13bb8f479

View File

@@ -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);
}