Просмотр исходного кода

win-dshow: Add LGP timestamp fix

LGP devices are devices that induce anger in any sane developer because
they're prone to bad audio timestamps when using their decoded data
directly.  For that reason, add a hack that smooths the timestamps
within a large threshold to prevent audio skipping.
jp9000 8 лет назад
Родитель
Сommit
32f60d07a3
3 измененных файлов с 48 добавлено и 3 удалено
  1. 31 1
      plugins/win-dshow/ffmpeg-decode.c
  2. 7 1
      plugins/win-dshow/ffmpeg-decode.h
  3. 10 1
      plugins/win-dshow/win-dshow.cpp

+ 31 - 1
plugins/win-dshow/ffmpeg-decode.c

@@ -16,6 +16,8 @@
 ******************************************************************************/
 ******************************************************************************/
 
 
 #include "ffmpeg-decode.h"
 #include "ffmpeg-decode.h"
+#include <util/util_uint128.h>
+#include <util/base.h>
 #include <obs-avc.h>
 #include <obs-avc.h>
 
 
 int ffmpeg_decode_init(struct ffmpeg_decode *decode, enum AVCodecID id)
 int ffmpeg_decode_init(struct ffmpeg_decode *decode, enum AVCodecID id)
@@ -107,8 +109,33 @@ static inline void copy_data(struct ffmpeg_decode *decode, uint8_t *data,
 	memcpy(decode->packet_buffer, data, size);
 	memcpy(decode->packet_buffer, data, size);
 }
 }
 
 
+static void do_idiotic_lgp_audio_packet_realignment(
+		struct ffmpeg_decode *decode, long long *ts)
+{
+	uint64_t new_ts = (uint64_t)*ts;
+	util_uint128_t u128;
+
+	if (!decode->lgp_started) {
+		decode->lgp_start_ts = new_ts;
+		decode->lgp_next_expected_ts = new_ts;
+		decode->lgp_started = true;
+	}
+
+	if (llabs(decode->lgp_next_expected_ts - new_ts) < 3000000ULL) {
+		*ts = (long long)decode->lgp_next_expected_ts;
+	} else {
+		decode->lgp_start_ts = new_ts;
+		decode->lgp_frames_since_start = 0;
+	}
+
+	decode->lgp_frames_since_start += (uint64_t)decode->frame->nb_samples;
+	u128 = util_mul64_64(decode->lgp_frames_since_start, 10000000ULL);
+	decode->lgp_next_expected_ts = decode->lgp_start_ts +
+		util_div128_32(u128, (uint32_t)decode->frame->sample_rate).low;
+}
+
 int ffmpeg_decode_audio(struct ffmpeg_decode *decode,
 int ffmpeg_decode_audio(struct ffmpeg_decode *decode,
-		uint8_t *data, size_t size,
+		uint8_t *data, size_t size, long long *ts,
 		struct obs_source_audio *audio,
 		struct obs_source_audio *audio,
 		bool *got_output)
 		bool *got_output)
 {
 {
@@ -148,6 +175,9 @@ int ffmpeg_decode_audio(struct ffmpeg_decode *decode,
 	if (audio->format == AUDIO_FORMAT_UNKNOWN)
 	if (audio->format == AUDIO_FORMAT_UNKNOWN)
 		return 0;
 		return 0;
 
 
+	if (decode->fix_braindead_lgp_audio_packet_stupidity)
+		do_idiotic_lgp_audio_packet_realignment(decode, ts);
+
 	*got_output = true;
 	*got_output = true;
 	return len;
 	return len;
 }
 }

+ 7 - 1
plugins/win-dshow/ffmpeg-decode.h

@@ -44,13 +44,19 @@ struct ffmpeg_decode {
 
 
 	uint8_t        *packet_buffer;
 	uint8_t        *packet_buffer;
 	size_t         packet_size;
 	size_t         packet_size;
+
+	uint64_t       lgp_start_ts;
+	uint64_t       lgp_frames_since_start;
+	uint64_t       lgp_next_expected_ts;
+	bool           lgp_started;
+	bool           fix_braindead_lgp_audio_packet_stupidity;
 };
 };
 
 
 extern int ffmpeg_decode_init(struct ffmpeg_decode *decode, enum AVCodecID id);
 extern int ffmpeg_decode_init(struct ffmpeg_decode *decode, enum AVCodecID id);
 extern void ffmpeg_decode_free(struct ffmpeg_decode *decode);
 extern void ffmpeg_decode_free(struct ffmpeg_decode *decode);
 
 
 extern int ffmpeg_decode_audio(struct ffmpeg_decode *decode,
 extern int ffmpeg_decode_audio(struct ffmpeg_decode *decode,
-		uint8_t *data, size_t size,
+		uint8_t *data, size_t size, long long *ts,
 		struct obs_source_audio *audio,
 		struct obs_source_audio *audio,
 		bool *got_output);
 		bool *got_output);
 
 

+ 10 - 1
plugins/win-dshow/win-dshow.cpp

@@ -116,6 +116,7 @@ public:
 	inline ~Decoder() {ffmpeg_decode_free(&decode);}
 	inline ~Decoder() {ffmpeg_decode_free(&decode);}
 
 
 	inline operator ffmpeg_decode*() {return &decode;}
 	inline operator ffmpeg_decode*() {return &decode;}
+	inline ffmpeg_decode *operator->() {return &decode;}
 };
 };
 
 
 class CriticalSection {
 class CriticalSection {
@@ -507,10 +508,18 @@ void DShowInput::OnEncodedAudioData(enum AVCodecID id,
 			blog(LOG_WARNING, "Could not initialize audio decoder");
 			blog(LOG_WARNING, "Could not initialize audio decoder");
 			return;
 			return;
 		}
 		}
+
+		if (videoConfig.name.find(L"C875") != std::string::npos ||
+		    videoConfig.name.find(L"C835") != std::string::npos) {
+			audio_decoder->fix_braindead_lgp_audio_packet_stupidity
+				= true;
+			blog(LOG_INFO, "Oh great, an LGP was detected.  "
+					"How wonderful.  I'm just ecstatic.");
+		}
 	}
 	}
 
 
 	bool got_output;
 	bool got_output;
-	int len = ffmpeg_decode_audio(audio_decoder, data, size,
+	int len = ffmpeg_decode_audio(audio_decoder, data, size, &ts,
 			&audio, &got_output);
 			&audio, &got_output);
 	if (len < 0) {
 	if (len < 0) {
 		blog(LOG_WARNING, "Error decoding audio");
 		blog(LOG_WARNING, "Error decoding audio");