static bool video_frame(struct ff_frame *frame, void *opaque) { struct ffmpeg_source *s = opaque; struct obs_source_frame obs_frame = {0}; uint64_t pts; // Media ended if (frame == NULL) { if (s->is_clear_on_media_end) obs_source_output_video(s->source, NULL); return true; } pts = (uint64_t)(frame->pts * 1000000000.0L); obs_frame.timestamp = pts; obs_frame.width = frame->frame->width; obs_frame.height = frame->frame->height; 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, &obs_frame); else return video_frame_direct(frame, s, &obs_frame); }
static bool set_obs_frame_colorprops(struct ff_frame *frame, struct ffmpeg_source *s, struct obs_source_frame *obs_frame) { enum AVColorSpace frame_cs = av_frame_get_colorspace(frame->frame); enum video_colorspace obs_cs; switch(frame_cs) { case AVCOL_SPC_BT709: obs_cs = VIDEO_CS_709; break; case AVCOL_SPC_SMPTE170M: case AVCOL_SPC_BT470BG: obs_cs = VIDEO_CS_601; break; case AVCOL_SPC_UNSPECIFIED: obs_cs = VIDEO_CS_DEFAULT; break; default: FF_BLOG(LOG_WARNING, "frame using an unsupported colorspace %d", frame_cs); obs_cs = VIDEO_CS_DEFAULT; } enum video_range_type range; obs_frame->format = ffmpeg_to_obs_video_format(frame->frame->format); obs_frame->full_range = frame->frame->color_range == AVCOL_RANGE_JPEG; if (s->range != VIDEO_RANGE_DEFAULT) obs_frame->full_range = s->range == VIDEO_RANGE_FULL; range = obs_frame->full_range ? VIDEO_RANGE_FULL : VIDEO_RANGE_PARTIAL; if (!video_format_get_parameters(obs_cs, range, obs_frame->color_matrix, obs_frame->color_range_min, obs_frame->color_range_max)) { FF_BLOG(LOG_ERROR, "Failed to get video format " "parameters for video format %u", obs_cs); return false; } return true; }