Sfoglia il codice sorgente

Merge pull request #6887 from jpark37/priority-parse

libobs: obs-ffmpeg: Update codec priority handling
Jim 3 anni fa
parent
commit
842c04ecee

+ 21 - 24
libobs/obs-avc.c

@@ -51,19 +51,11 @@ const uint8_t *obs_avc_find_startcode(const uint8_t *p, const uint8_t *end)
 	return obs_nal_find_startcode(p, end);
 }
 
-static inline int get_drop_priority(int priority)
-{
-	return priority;
-}
-
 static void serialize_avc_data(struct serializer *s, const uint8_t *data,
 			       size_t size, bool *is_keyframe, int *priority)
 {
-	const uint8_t *nal_start, *nal_end;
-	const uint8_t *end = data + size;
-	int type;
-
-	nal_start = obs_avc_find_startcode(data, end);
+	const uint8_t *const end = data + size;
+	const uint8_t *nal_start = obs_nal_find_startcode(data, end);
 	while (true) {
 		while (nal_start < end && !*(nal_start++))
 			;
@@ -71,18 +63,23 @@ static void serialize_avc_data(struct serializer *s, const uint8_t *data,
 		if (nal_start == end)
 			break;
 
-		type = nal_start[0] & 0x1F;
+		const int type = nal_start[0] & 0x1F;
 
-		if (type == OBS_NAL_SLICE_IDR || type == OBS_NAL_SLICE) {
-			if (is_keyframe)
-				*is_keyframe = (type == OBS_NAL_SLICE_IDR);
-			if (priority)
-				*priority = nal_start[0] >> 5;
+		switch (type) {
+		case OBS_NAL_SLICE:
+			if (*priority < OBS_NAL_PRIORITY_HIGH)
+				*priority = OBS_NAL_PRIORITY_HIGH;
+			break;
+		case OBS_NAL_SLICE_IDR:
+			*is_keyframe = true;
+			*priority = OBS_NAL_PRIORITY_HIGHEST;
 		}
 
-		nal_end = obs_avc_find_startcode(nal_start, end);
-		s_wb32(s, (uint32_t)(nal_end - nal_start));
-		s_write(s, nal_start, nal_end - nal_start);
+		const uint8_t *const nal_end =
+			obs_nal_find_startcode(nal_start, end);
+		const size_t size = nal_end - nal_start;
+		s_wb32(s, (uint32_t)size);
+		s_write(s, nal_start, size);
 		nal_start = nal_end;
 	}
 }
@@ -103,7 +100,7 @@ void obs_parse_avc_packet(struct encoder_packet *avc_packet,
 
 	avc_packet->data = output.bytes.array + sizeof(ref);
 	avc_packet->size = output.bytes.num - sizeof(ref);
-	avc_packet->drop_priority = get_drop_priority(avc_packet->priority);
+	avc_packet->drop_priority = avc_packet->priority;
 }
 
 static inline bool has_start_code(const uint8_t *data)
@@ -121,7 +118,7 @@ static void get_sps_pps(const uint8_t *data, size_t size, const uint8_t **sps,
 	const uint8_t *end = data + size;
 	int type;
 
-	nal_start = obs_avc_find_startcode(data, end);
+	nal_start = obs_nal_find_startcode(data, end);
 	while (true) {
 		while (nal_start < end && !*(nal_start++))
 			;
@@ -129,7 +126,7 @@ static void get_sps_pps(const uint8_t *data, size_t size, const uint8_t **sps,
 		if (nal_start == end)
 			break;
 
-		nal_end = obs_avc_find_startcode(nal_start, end);
+		nal_end = obs_nal_find_startcode(nal_start, end);
 
 		type = nal_start[0] & 0x1F;
 		if (type == OBS_NAL_SPS) {
@@ -195,7 +192,7 @@ void obs_extract_avc_headers(const uint8_t *packet, size_t size,
 	da_init(header);
 	da_init(sei);
 
-	nal_start = obs_avc_find_startcode(packet, end);
+	nal_start = obs_nal_find_startcode(packet, end);
 	nal_end = NULL;
 	while (nal_end != end) {
 		nal_codestart = nal_start;
@@ -208,7 +205,7 @@ void obs_extract_avc_headers(const uint8_t *packet, size_t size,
 
 		const uint8_t type = nal_start[0] & 0x1F;
 
-		nal_end = obs_avc_find_startcode(nal_start, end);
+		nal_end = obs_nal_find_startcode(nal_start, end);
 		if (!nal_end)
 			nal_end = end;
 

+ 1 - 8
libobs/obs-avc.h

@@ -17,7 +17,7 @@
 
 #pragma once
 
-#include "util/c99defs.h"
+#include "obs-nal.h"
 
 #ifdef __cplusplus
 extern "C" {
@@ -39,13 +39,6 @@ enum {
 	OBS_NAL_FILLER = 12,
 };
 
-enum {
-	OBS_NAL_PRIORITY_DISPOSABLE = 0,
-	OBS_NAL_PRIORITY_LOW = 1,
-	OBS_NAL_PRIORITY_HIGH = 2,
-	OBS_NAL_PRIORITY_HIGHEST = 3,
-};
-
 /* Helpers for parsing AVC NAL units.  */
 
 EXPORT bool obs_avc_keyframe(const uint8_t *data, size_t size);

+ 59 - 1
libobs/obs-hevc.c

@@ -17,8 +17,9 @@
 
 #include "obs-hevc.h"
 
+#include "obs.h"
 #include "obs-nal.h"
-#include "util/darray.h"
+#include "util/array-serializer.h"
 
 enum {
 	OBS_HEVC_NAL_TRAIL_N = 0,
@@ -89,6 +90,63 @@ bool obs_hevc_keyframe(const uint8_t *data, size_t size)
 	return false;
 }
 
+static void serialize_hevc_data(struct serializer *s, const uint8_t *data,
+				size_t size, bool *is_keyframe, int *priority)
+{
+	const uint8_t *const end = data + size;
+	const uint8_t *nal_start = obs_nal_find_startcode(data, end);
+	while (true) {
+		while (nal_start < end && !*(nal_start++))
+			;
+
+		if (nal_start == end)
+			break;
+
+		// HEVC contains NAL unit specifier at [6..1] bits of
+		// the byte next to the startcode 0x000001
+		const int type = (nal_start[0] & 0x7F) >> 1;
+
+		// Mark IDR slices as key-frames and set them to highest
+		// priority if needed. Assume other slices are non-key
+		// frames and set their priority as high
+		if (type >= OBS_HEVC_NAL_BLA_W_LP &&
+		    type <= OBS_HEVC_NAL_RSV_IRAP_VCL23) {
+			*is_keyframe = 1;
+			*priority = OBS_NAL_PRIORITY_HIGHEST;
+		} else if (type >= OBS_HEVC_NAL_TRAIL_N &&
+			   type <= OBS_HEVC_NAL_RASL_R) {
+			if (*priority < OBS_NAL_PRIORITY_HIGH)
+				*priority = OBS_NAL_PRIORITY_HIGH;
+		}
+
+		const uint8_t *const nal_end =
+			obs_nal_find_startcode(nal_start, end);
+		const size_t size = nal_end - nal_start;
+		s_wb32(s, (uint32_t)size);
+		s_write(s, nal_start, size);
+		nal_start = nal_end;
+	}
+}
+
+void obs_parse_hevc_packet(struct encoder_packet *hevc_packet,
+			   const struct encoder_packet *src)
+{
+	struct array_output_data output;
+	struct serializer s;
+	long ref = 1;
+
+	array_output_serializer_init(&s, &output);
+	*hevc_packet = *src;
+
+	serialize(&s, &ref, sizeof(ref));
+	serialize_hevc_data(&s, src->data, src->size, &hevc_packet->keyframe,
+			    &hevc_packet->priority);
+
+	hevc_packet->data = output.bytes.array + sizeof(ref);
+	hevc_packet->size = output.bytes.num - sizeof(ref);
+	hevc_packet->drop_priority = hevc_packet->priority;
+}
+
 void obs_extract_hevc_headers(const uint8_t *packet, size_t size,
 			      uint8_t **new_packet_data,
 			      size_t *new_packet_size, uint8_t **header_data,

+ 4 - 0
libobs/obs-hevc.h

@@ -23,7 +23,11 @@
 extern "C" {
 #endif
 
+struct encoder_packet;
+
 EXPORT bool obs_hevc_keyframe(const uint8_t *data, size_t size);
+EXPORT void obs_parse_hevc_packet(struct encoder_packet *hevc_packet,
+				  const struct encoder_packet *src);
 EXPORT void obs_extract_hevc_headers(const uint8_t *packet, size_t size,
 				     uint8_t **new_packet_data,
 				     size_t *new_packet_size,

+ 7 - 0
libobs/obs-nal.h

@@ -23,6 +23,13 @@
 extern "C" {
 #endif
 
+enum {
+	OBS_NAL_PRIORITY_DISPOSABLE = 0,
+	OBS_NAL_PRIORITY_LOW = 1,
+	OBS_NAL_PRIORITY_HIGH = 2,
+	OBS_NAL_PRIORITY_HIGHEST = 3,
+};
+
 EXPORT const uint8_t *obs_nal_find_startcode(const uint8_t *p,
 					     const uint8_t *end);
 

+ 18 - 3
plugins/obs-ffmpeg/obs-ffmpeg-hls-mux.c

@@ -1,4 +1,8 @@
 #include "obs-ffmpeg-mux.h"
+#include <obs-avc.h>
+#ifdef ENABLE_HEVC
+#include <obs-hevc.h>
+#endif
 
 #define do_log(level, format, ...)                      \
 	blog(level, "[ffmpeg hls muxer: '%s'] " format, \
@@ -292,9 +296,20 @@ void ffmpeg_hls_mux_data(void *data, struct encoder_packet *packet)
 	}
 
 	if (packet->type == OBS_ENCODER_VIDEO) {
-		obs_parse_avc_packet(&tmp_packet, packet);
-		packet->drop_priority = tmp_packet.priority;
-		obs_encoder_packet_release(&tmp_packet);
+		const char *const codec =
+			obs_encoder_get_codec(packet->encoder);
+		if (strcmp(codec, "h264") == 0) {
+			obs_parse_avc_packet(&tmp_packet, packet);
+			packet->drop_priority = tmp_packet.priority;
+			obs_encoder_packet_release(&tmp_packet);
+		}
+#ifdef ENABLE_HEVC
+		else if (strcmp(codec, "hevc") == 0) {
+			obs_parse_hevc_packet(&tmp_packet, packet);
+			packet->drop_priority = tmp_packet.priority;
+			obs_encoder_packet_release(&tmp_packet);
+		}
+#endif
 	}
 	obs_encoder_packet_ref(&new_packet, packet);
 

+ 0 - 1
plugins/obs-ffmpeg/obs-ffmpeg-mux.h

@@ -1,6 +1,5 @@
 #pragma once
 
-#include <obs-avc.h>
 #include <obs-module.h>
 #include <obs-hotkey.h>
 #include <util/circlebuf.h>