浏览代码

libobs: Use reference counting for encoder packets

Prevents reallocation of encoded packet data.

Deprecates:
obs_duplicate_encoder_packet
obs_free_encoder_packet

Replaces those functions with:
obs_encoder_packet_ref
obs_encoder_packet_release
jp9000 9 年之前
父节点
当前提交
7d6e6eee79

+ 42 - 4
libobs/obs-encoder.c

@@ -1035,17 +1035,55 @@ void obs_encoder_remove_output(struct obs_encoder *encoder,
 	pthread_mutex_unlock(&encoder->outputs_mutex);
 }
 
-void obs_duplicate_encoder_packet(struct encoder_packet *dst,
+void obs_encoder_packet_create_instance(struct encoder_packet *dst,
 		const struct encoder_packet *src)
 {
+	long *p_refs;
+
 	*dst = *src;
-	dst->data = bmemdup(src->data, src->size);
+	p_refs = bmalloc(src->size + sizeof(long));
+	dst->data = (void*)(p_refs + 1);
+	*p_refs = 1;
+	memcpy(dst->data, src->data, src->size);
+}
+
+void obs_duplicate_encoder_packet(struct encoder_packet *dst,
+		const struct encoder_packet *src)
+{
+	obs_encoder_packet_create_instance(dst, src);
 }
 
 void obs_free_encoder_packet(struct encoder_packet *packet)
 {
-	bfree(packet->data);
-	memset(packet, 0, sizeof(struct encoder_packet));
+	obs_encoder_packet_release(packet);
+}
+
+void obs_encoder_packet_ref(struct encoder_packet *dst,
+		struct encoder_packet *src)
+{
+	if (!src)
+		return;
+
+	if (src->data) {
+		long *p_refs = ((long*)src->data) - 1;
+		os_atomic_inc_long(p_refs);
+	}
+
+	*dst = *src;
+}
+
+void obs_encoder_packet_release(struct encoder_packet *pkt)
+{
+	if (!pkt)
+		return;
+
+	if (pkt->data) {
+		long *p_refs = ((long*)pkt->data) - 1;
+		if (os_atomic_dec_long(p_refs) == 0)
+			bfree(p_refs);
+	}
+
+	memset(pkt, 0, sizeof(struct encoder_packet));
 }
 
 void obs_encoder_set_preferred_video_format(obs_encoder_t *encoder,

+ 2 - 0
libobs/obs-internal.h

@@ -864,6 +864,8 @@ extern const struct obs_output_info *find_output(const char *id);
 extern void obs_output_remove_encoder(struct obs_output *output,
 		struct obs_encoder *encoder);
 
+extern void obs_encoder_packet_create_instance(struct encoder_packet *dst,
+		const struct encoder_packet *src);
 void obs_output_destroy(obs_output_t *output);
 
 

+ 3 - 3
libobs/obs-output-delay.c

@@ -35,7 +35,7 @@ static inline void push_packet(struct obs_output *output,
 
 	dd.msg = DELAY_MSG_PACKET;
 	dd.ts  = t;
-	obs_duplicate_encoder_packet(&dd.packet, packet);
+	obs_encoder_packet_create_instance(&dd.packet, packet);
 
 	pthread_mutex_lock(&output->delay_mutex);
 	circlebuf_push_back(&output->delay_data, &dd, sizeof(dd));
@@ -48,7 +48,7 @@ static inline void process_delay_data(struct obs_output *output,
 	switch (dd->msg) {
 	case DELAY_MSG_PACKET:
 		if (!delay_active(output) || !delay_capturing(output))
-			obs_free_encoder_packet(&dd->packet);
+			obs_encoder_packet_release(&dd->packet);
 		else
 			output->delay_callback(output, &dd->packet);
 		break;
@@ -68,7 +68,7 @@ void obs_output_cleanup_delay(obs_output_t *output)
 	while (output->delay_data.size) {
 		circlebuf_pop_front(&output->delay_data, &dd, sizeof(dd));
 		if (dd.msg == DELAY_MSG_PACKET) {
-			obs_free_encoder_packet(&dd.packet);
+			obs_encoder_packet_release(&dd.packet);
 		}
 	}
 

+ 6 - 6
libobs/obs-output.c

@@ -157,7 +157,7 @@ fail:
 static inline void free_packets(struct obs_output *output)
 {
 	for (size_t i = 0; i < output->interleaved_packets.num; i++)
-		obs_free_encoder_packet(output->interleaved_packets.array+i);
+		obs_encoder_packet_release(output->interleaved_packets.array+i);
 	da_free(output->interleaved_packets);
 }
 
@@ -957,7 +957,7 @@ static inline void send_interleaved(struct obs_output *output)
 
 	da_erase(output->interleaved_packets, 0);
 	output->info.encoded_packet(output->context.data, &out);
-	obs_free_encoder_packet(&out);
+	obs_encoder_packet_release(&out);
 }
 
 static inline void set_higher_ts(struct obs_output *output,
@@ -1056,7 +1056,7 @@ static void discard_to_idx(struct obs_output *output, size_t idx)
 	for (size_t i = 0; i < idx; i++) {
 		struct encoder_packet *packet =
 			&output->interleaved_packets.array[i];
-		obs_free_encoder_packet(packet);
+		obs_encoder_packet_release(packet);
 	}
 
 	da_erase_range(output->interleaved_packets, 0, idx);
@@ -1304,7 +1304,7 @@ static void interleave_packets(void *data, struct encoder_packet *packet)
 		pthread_mutex_unlock(&output->interleaved_mutex);
 
 		if (output->active_delay_ns)
-			obs_free_encoder_packet(packet);
+			obs_encoder_packet_release(packet);
 		return;
 	}
 
@@ -1313,7 +1313,7 @@ static void interleave_packets(void *data, struct encoder_packet *packet)
 	if (output->active_delay_ns)
 		out = *packet;
 	else
-		obs_duplicate_encoder_packet(&out, packet);
+		obs_encoder_packet_create_instance(&out, packet);
 
 	if (was_started)
 		apply_interleaved_packet_offset(output, &out);
@@ -1356,7 +1356,7 @@ static void default_encoded_callback(void *param, struct encoder_packet *packet)
 	}
 
 	if (output->active_delay_ns)
-		obs_free_encoder_packet(packet);
+		obs_encoder_packet_release(packet);
 }
 
 static void default_raw_video_callback(void *param, struct video_data *frame)

+ 6 - 0
libobs/obs.h

@@ -1651,11 +1651,17 @@ EXPORT const char *obs_encoder_get_id(const obs_encoder_t *encoder);
 EXPORT uint32_t obs_get_encoder_caps(const char *encoder_id);
 
 /** Duplicates an encoder packet */
+DEPRECATED
 EXPORT void obs_duplicate_encoder_packet(struct encoder_packet *dst,
 		const struct encoder_packet *src);
 
+DEPRECATED
 EXPORT void obs_free_encoder_packet(struct encoder_packet *packet);
 
+EXPORT void obs_encoder_packet_ref(struct encoder_packet *dst,
+		struct encoder_packet *src);
+EXPORT void obs_encoder_packet_release(struct encoder_packet *packet);
+
 
 /* ------------------------------------------------------------------------- */
 /* Stream Services */

+ 2 - 2
plugins/obs-outputs/flv-output.c

@@ -100,7 +100,7 @@ static int write_packet(struct flv_output *stream,
 	flv_packet_mux(packet, &data, &size, is_header);
 	fwrite(data, 1, size, stream->file);
 	bfree(data);
-	obs_free_encoder_packet(packet);
+	obs_encoder_packet_release(packet);
 
 	return ret;
 }
@@ -200,7 +200,7 @@ static void flv_output_data(void *data, struct encoder_packet *packet)
 	if (packet->type == OBS_ENCODER_VIDEO) {
 		obs_parse_avc_packet(&parsed_packet, packet);
 		write_packet(stream, &parsed_packet, false);
-		obs_free_encoder_packet(&parsed_packet);
+		obs_encoder_packet_release(&parsed_packet);
 	} else {
 		write_packet(stream, packet, false);
 	}

+ 6 - 6
plugins/obs-outputs/rtmp-stream.c

@@ -134,7 +134,7 @@ static inline void free_packets(struct rtmp_stream *stream)
 	while (stream->packets.size) {
 		struct encoder_packet packet;
 		circlebuf_pop_front(&stream->packets, &packet, sizeof(packet));
-		obs_free_encoder_packet(&packet);
+		obs_encoder_packet_release(&packet);
 	}
 	pthread_mutex_unlock(&stream->packets_mutex);
 }
@@ -375,7 +375,7 @@ static int send_packet(struct rtmp_stream *stream,
 	ret = RTMP_Write(&stream->rtmp, (char*)data, (int)size, (int)idx);
 	bfree(data);
 
-	obs_free_encoder_packet(packet);
+	obs_encoder_packet_release(packet);
 
 	stream->total_bytes_sent += size;
 	return ret;
@@ -414,7 +414,7 @@ static void *send_thread(void *data)
 
 		if (stopping(stream)) {
 			if (can_shutdown_stream(stream, &packet)) {
-				obs_free_encoder_packet(&packet);
+				obs_encoder_packet_release(&packet);
 				break;
 			}
 		}
@@ -844,7 +844,7 @@ static void drop_frames(struct rtmp_stream *stream, const char *name,
 
 		} else {
 			num_frames_dropped++;
-			obs_free_encoder_packet(&packet);
+			obs_encoder_packet_release(&packet);
 		}
 	}
 
@@ -929,7 +929,7 @@ static void rtmp_stream_data(void *data, struct encoder_packet *packet)
 	if (packet->type == OBS_ENCODER_VIDEO)
 		obs_parse_avc_packet(&new_packet, packet);
 	else
-		obs_duplicate_encoder_packet(&new_packet, packet);
+		obs_encoder_packet_ref(&new_packet, packet);
 
 	pthread_mutex_lock(&stream->packets_mutex);
 
@@ -944,7 +944,7 @@ static void rtmp_stream_data(void *data, struct encoder_packet *packet)
 	if (added_packet)
 		os_sem_post(stream->send_sem);
 	else
-		obs_free_encoder_packet(&new_packet);
+		obs_encoder_packet_release(&new_packet);
 }
 
 static void rtmp_stream_defaults(obs_data_t *defaults)