瀏覽代碼

obs-ffmpeg: Fix race and deprecation warnings

Attempt to simply shutdown sequence to avoid race between vidoe and
write threads. Can no longer join on write thread from write thread.

Also use codecpar instead of deprecated codec member.
jpark37 5 年之前
父節點
當前提交
ffbc3ed923
共有 2 個文件被更改,包括 63 次插入33 次删除
  1. 56 32
      plugins/obs-ffmpeg/obs-ffmpeg-output.c
  2. 7 1
      plugins/obs-ffmpeg/obs-ffmpeg-output.h

+ 56 - 32
plugins/obs-ffmpeg/obs-ffmpeg-output.c

@@ -135,7 +135,7 @@ static bool parse_params(AVCodecContext *context, char **opts)
 
 
 static bool open_video_codec(struct ffmpeg_data *data)
 static bool open_video_codec(struct ffmpeg_data *data)
 {
 {
-	AVCodecContext *context = data->video->codec;
+	AVCodecContext *const context = data->video_ctx;
 	char **opts = strlist_split(data->config.video_settings, ' ', false);
 	char **opts = strlist_split(data->config.video_settings, ' ', false);
 	int ret;
 	int ret;
 
 
@@ -180,6 +180,10 @@ static bool open_video_codec(struct ffmpeg_data *data)
 		return false;
 		return false;
 	}
 	}
 
 
+#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 48, 101)
+	avcodec_parameters_from_context(data->video->codecpar, context);
+#endif
+
 	return true;
 	return true;
 }
 }
 
 
@@ -218,7 +222,11 @@ static bool create_video_stream(struct ffmpeg_data *data)
 	closest_format = avcodec_find_best_pix_fmt_of_list(
 	closest_format = avcodec_find_best_pix_fmt_of_list(
 		data->vcodec->pix_fmts, data->config.format, 0, NULL);
 		data->vcodec->pix_fmts, data->config.format, 0, NULL);
 
 
+#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 48, 101)
+	context = avcodec_alloc_context3(data->vcodec);
+#else
 	context = data->video->codec;
 	context = data->video->codec;
+#endif
 	context->bit_rate = (int64_t)data->config.video_bitrate * 1000;
 	context->bit_rate = (int64_t)data->config.video_bitrate * 1000;
 	context->width = data->config.scale_width;
 	context->width = data->config.scale_width;
 	context->height = data->config.scale_height;
 	context->height = data->config.scale_height;
@@ -234,6 +242,8 @@ static bool create_video_stream(struct ffmpeg_data *data)
 	if (data->output->oformat->flags & AVFMT_GLOBALHEADER)
 	if (data->output->oformat->flags & AVFMT_GLOBALHEADER)
 		context->flags |= CODEC_FLAG_GLOBAL_H;
 		context->flags |= CODEC_FLAG_GLOBAL_H;
 
 
+	data->video_ctx = context;
+
 	if (!open_video_codec(data))
 	if (!open_video_codec(data))
 		return false;
 		return false;
 
 
@@ -250,7 +260,7 @@ static bool create_video_stream(struct ffmpeg_data *data)
 
 
 static bool open_audio_codec(struct ffmpeg_data *data, int idx)
 static bool open_audio_codec(struct ffmpeg_data *data, int idx)
 {
 {
-	AVCodecContext *context = data->audio_streams[idx]->codec;
+	AVCodecContext *const context = data->audio_infos[idx].ctx;
 	char **opts = strlist_split(data->config.audio_settings, ' ', false);
 	char **opts = strlist_split(data->config.audio_settings, ' ', false);
 	int ret;
 	int ret;
 
 
@@ -292,6 +302,11 @@ static bool open_audio_codec(struct ffmpeg_data *data, int idx)
 		return false;
 		return false;
 	}
 	}
 
 
+#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 48, 101)
+	avcodec_parameters_from_context(data->audio_infos[idx].stream->codecpar,
+					context);
+#endif
+
 	return true;
 	return true;
 }
 }
 
 
@@ -311,8 +326,11 @@ static bool create_audio_stream(struct ffmpeg_data *data, int idx)
 			data->config.audio_encoder))
 			data->config.audio_encoder))
 		return false;
 		return false;
 
 
-	data->audio_streams[idx] = stream;
-	context = data->audio_streams[idx]->codec;
+#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 48, 101)
+	context = avcodec_alloc_context3(data->acodec);
+#else
+	context = stream->codec;
+#endif
 	context->bit_rate = (int64_t)data->config.audio_bitrate * 1000;
 	context->bit_rate = (int64_t)data->config.audio_bitrate * 1000;
 	context->time_base = (AVRational){1, aoi.samples_per_sec};
 	context->time_base = (AVRational){1, aoi.samples_per_sec};
 	context->channels = get_audio_channels(aoi.speakers);
 	context->channels = get_audio_channels(aoi.speakers);
@@ -328,7 +346,7 @@ static bool create_audio_stream(struct ffmpeg_data *data, int idx)
 				      ? data->acodec->sample_fmts[0]
 				      ? data->acodec->sample_fmts[0]
 				      : AV_SAMPLE_FMT_FLTP;
 				      : AV_SAMPLE_FMT_FLTP;
 
 
-	data->audio_streams[idx]->time_base = context->time_base;
+	stream->time_base = context->time_base;
 
 
 	data->audio_samplerate = aoi.samples_per_sec;
 	data->audio_samplerate = aoi.samples_per_sec;
 	data->audio_format = convert_ffmpeg_sample_format(context->sample_fmt);
 	data->audio_format = convert_ffmpeg_sample_format(context->sample_fmt);
@@ -338,6 +356,9 @@ static bool create_audio_stream(struct ffmpeg_data *data, int idx)
 	if (data->output->oformat->flags & AVFMT_GLOBALHEADER)
 	if (data->output->oformat->flags & AVFMT_GLOBALHEADER)
 		context->flags |= CODEC_FLAG_GLOBAL_H;
 		context->flags |= CODEC_FLAG_GLOBAL_H;
 
 
+	data->audio_infos[idx].stream = stream;
+	data->audio_infos[idx].ctx = context;
+
 	return open_audio_codec(data, idx);
 	return open_audio_codec(data, idx);
 }
 }
 
 
@@ -351,8 +372,8 @@ static inline bool init_streams(struct ffmpeg_data *data)
 
 
 	if (format->audio_codec != AV_CODEC_ID_NONE &&
 	if (format->audio_codec != AV_CODEC_ID_NONE &&
 	    data->num_audio_streams) {
 	    data->num_audio_streams) {
-		data->audio_streams =
-			calloc(1, data->num_audio_streams * sizeof(void *));
+		data->audio_infos = calloc(data->num_audio_streams,
+					   sizeof(*data->audio_infos));
 		for (int i = 0; i < data->num_audio_streams; i++) {
 		for (int i = 0; i < data->num_audio_streams; i++) {
 			if (!create_audio_stream(data, i))
 			if (!create_audio_stream(data, i))
 				return false;
 				return false;
@@ -402,10 +423,6 @@ static inline bool open_output_file(struct ffmpeg_data *data)
 		}
 		}
 	}
 	}
 
 
-	strncpy(data->output->filename, data->config.url,
-		sizeof(data->output->filename));
-	data->output->filename[sizeof(data->output->filename) - 1] = 0;
-
 	ret = avformat_write_header(data->output, &dict);
 	ret = avformat_write_header(data->output, &dict);
 	if (ret < 0) {
 	if (ret < 0) {
 		ffmpeg_log_error(LOG_WARNING, data, "Error opening '%s': %s",
 		ffmpeg_log_error(LOG_WARNING, data, "Error opening '%s': %s",
@@ -432,7 +449,11 @@ static inline bool open_output_file(struct ffmpeg_data *data)
 
 
 static void close_video(struct ffmpeg_data *data)
 static void close_video(struct ffmpeg_data *data)
 {
 {
+#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 48, 101)
+	avcodec_free_context(&data->video_ctx);
+#else
 	avcodec_close(data->video->codec);
 	avcodec_close(data->video->codec);
+#endif
 	av_frame_unref(data->vframe);
 	av_frame_unref(data->vframe);
 
 
 	// This format for some reason derefs video frame
 	// This format for some reason derefs video frame
@@ -452,8 +473,13 @@ static void close_audio(struct ffmpeg_data *data)
 
 
 		if (data->samples[idx][0])
 		if (data->samples[idx][0])
 			av_freep(&data->samples[idx][0]);
 			av_freep(&data->samples[idx][0]);
-		if (data->audio_streams[idx])
-			avcodec_close(data->audio_streams[idx]->codec);
+		if (data->audio_infos[idx].ctx) {
+#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 48, 101)
+			avcodec_free_context(&data->audio_infos[idx].ctx);
+#else
+			avcodec_close(data->audio_infos[idx].stream->codec);
+#endif
+		}
 		if (data->aframe[idx])
 		if (data->aframe[idx])
 			av_frame_free(&data->aframe[idx]);
 			av_frame_free(&data->aframe[idx]);
 	}
 	}
@@ -466,10 +492,10 @@ void ffmpeg_data_free(struct ffmpeg_data *data)
 
 
 	if (data->video)
 	if (data->video)
 		close_video(data);
 		close_video(data);
-	if (data->audio_streams) {
+	if (data->audio_infos) {
 		close_audio(data);
 		close_audio(data);
-		free(data->audio_streams);
-		data->audio_streams = NULL;
+		free(data->audio_infos);
+		data->audio_infos = NULL;
 	}
 	}
 
 
 	if (data->output) {
 	if (data->output) {
@@ -555,7 +581,7 @@ bool ffmpeg_data_init(struct ffmpeg_data *data, struct ffmpeg_cfg *config)
 	}
 	}
 
 
 	avformat_alloc_output_context2(&data->output, output_format, NULL,
 	avformat_alloc_output_context2(&data->output, output_format, NULL,
-				       NULL);
+				       data->config.url);
 
 
 	if (!data->output) {
 	if (!data->output) {
 		ffmpeg_log_error(LOG_WARNING, data,
 		ffmpeg_log_error(LOG_WARNING, data,
@@ -688,7 +714,7 @@ static void receive_video(void *param, struct video_data *frame)
 	if (!data->video)
 	if (!data->video)
 		return;
 		return;
 
 
-	AVCodecContext *context = data->video->codec;
+	AVCodecContext *context = data->video_ctx;
 	AVPacket packet = {0};
 	AVPacket packet = {0};
 	int ret = 0, got_packet;
 	int ret = 0, got_packet;
 
 
@@ -833,13 +859,13 @@ static void encode_audio(struct ffmpeg_output *output, int idx,
 		return;
 		return;
 
 
 	packet.pts = rescale_ts(packet.pts, context,
 	packet.pts = rescale_ts(packet.pts, context,
-				data->audio_streams[idx]->time_base);
+				data->audio_infos[idx].stream->time_base);
 	packet.dts = rescale_ts(packet.dts, context,
 	packet.dts = rescale_ts(packet.dts, context,
-				data->audio_streams[idx]->time_base);
+				data->audio_infos[idx].stream->time_base);
 	packet.duration =
 	packet.duration =
 		(int)av_rescale_q(packet.duration, context->time_base,
 		(int)av_rescale_q(packet.duration, context->time_base,
-				  data->audio_streams[idx]->time_base);
-	packet.stream_index = data->audio_streams[idx]->index;
+				  data->audio_infos[idx].stream->time_base);
+	packet.stream_index = data->audio_infos[idx].stream->index;
 
 
 	pthread_mutex_lock(&output->write_mutex);
 	pthread_mutex_lock(&output->write_mutex);
 	da_push_back(output->packets, &packet);
 	da_push_back(output->packets, &packet);
@@ -868,7 +894,7 @@ static void receive_audio(void *param, size_t mix_idx, struct audio_data *frame)
 	int track_order;
 	int track_order;
 
 
 	// codec doesn't support audio or none configured
 	// codec doesn't support audio or none configured
-	if (!data->audio_streams)
+	if (!data->audio_infos)
 		return;
 		return;
 
 
 	/* check that the track was selected */
 	/* check that the track was selected */
@@ -878,7 +904,7 @@ static void receive_audio(void *param, size_t mix_idx, struct audio_data *frame)
 	/* get track order (first selected, etc ...) */
 	/* get track order (first selected, etc ...) */
 	track_order = get_track_order(data->audio_tracks, mix_idx);
 	track_order = get_track_order(data->audio_tracks, mix_idx);
 
 
-	AVCodecContext *context = data->audio_streams[track_order]->codec;
+	AVCodecContext *context = data->audio_infos[track_order].ctx;
 
 
 	if (!data->start_timestamp)
 	if (!data->start_timestamp)
 		return;
 		return;
@@ -916,7 +942,7 @@ static uint64_t get_packet_sys_dts(struct ffmpeg_output *output,
 		time_base = data->video->time_base;
 		time_base = data->video->time_base;
 		start_ts = output->video_start_ts;
 		start_ts = output->video_start_ts;
 	} else {
 	} else {
-		time_base = data->audio_streams[0]->time_base;
+		time_base = data->audio_infos[0].stream->time_base;
 		start_ts = output->audio_start_ts;
 		start_ts = output->audio_start_ts;
 	}
 	}
 
 
@@ -949,10 +975,8 @@ static int process_packet(struct ffmpeg_output *output)
 
 
 	if (stopping(output)) {
 	if (stopping(output)) {
 		uint64_t sys_ts = get_packet_sys_dts(output, &packet);
 		uint64_t sys_ts = get_packet_sys_dts(output, &packet);
-		if (sys_ts >= output->stop_ts) {
-			ffmpeg_output_full_stop(output);
+		if (sys_ts >= output->stop_ts)
 			return 0;
 			return 0;
-		}
 	}
 	}
 
 
 	output->total_bytes += packet.size;
 	output->total_bytes += packet.size;
@@ -1159,12 +1183,12 @@ static void ffmpeg_output_stop(void *data, uint64_t ts)
 	struct ffmpeg_output *output = data;
 	struct ffmpeg_output *output = data;
 
 
 	if (output->active) {
 	if (output->active) {
-		if (ts == 0) {
-			ffmpeg_output_full_stop(output);
-		} else {
-			os_atomic_set_bool(&output->stopping, true);
+		if (ts > 0) {
 			output->stop_ts = ts;
 			output->stop_ts = ts;
+			os_atomic_set_bool(&output->stopping, true);
 		}
 		}
+
+		ffmpeg_output_full_stop(output);
 	}
 	}
 }
 }
 
 

+ 7 - 1
plugins/obs-ffmpeg/obs-ffmpeg-output.h

@@ -30,9 +30,15 @@ struct ffmpeg_cfg {
 	int height;
 	int height;
 };
 };
 
 
+struct ffmpeg_audio_info {
+	AVStream *stream;
+	AVCodecContext *ctx;
+};
+
 struct ffmpeg_data {
 struct ffmpeg_data {
 	AVStream *video;
 	AVStream *video;
-	AVStream **audio_streams;
+	AVCodecContext *video_ctx;
+	struct ffmpeg_audio_info *audio_infos;
 	AVCodec *acodec;
 	AVCodec *acodec;
 	AVCodec *vcodec;
 	AVCodec *vcodec;
 	AVFormatContext *output;
 	AVFormatContext *output;