summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTuomas Virtanen <katajakasa@gmail.com>2018-09-30 12:28:46 +0300
committerTuomas Virtanen <katajakasa@gmail.com>2018-09-30 12:28:46 +0300
commit650c1d1cf65b3ac58ac1436d5bca5f64e06118e1 (patch)
treefdc39ecf80a899b824603e1a2e4f5593c36a3394
parenta42322398d09b97433557d9e1f7686042b9beba5 (diff)
Improve playback of videos in low performance scenarios
-rw-r--r--include/kitchensink/internal/kitdecoder.h1
-rw-r--r--include/kitchensink/internal/utils/kitbuffer.h1
-rw-r--r--src/internal/audio/kitaudio.c52
-rw-r--r--src/internal/kitdecoder.c12
-rw-r--r--src/internal/utils/kitbuffer.c4
-rw-r--r--src/internal/video/kitvideo.c40
6 files changed, 55 insertions, 55 deletions
diff --git a/include/kitchensink/internal/kitdecoder.h b/include/kitchensink/internal/kitdecoder.h
index ef3edb7..74134b0 100644
--- a/include/kitchensink/internal/kitdecoder.h
+++ b/include/kitchensink/internal/kitdecoder.h
@@ -70,6 +70,7 @@ KIT_LOCAL void Kit_ForEachDecoderOutput(Kit_Decoder *dec, Kit_ForEachItemCallbac
KIT_LOCAL int Kit_LockDecoderOutput(Kit_Decoder *dec);
KIT_LOCAL void Kit_UnlockDecoderOutput(Kit_Decoder *dec);
KIT_LOCAL void Kit_ClearDecoderOutput(Kit_Decoder *dec);
+KIT_LOCAL unsigned int Kit_GetDecoderOutputLength(Kit_Decoder *dec);
#endif // KITDECODER_H
diff --git a/include/kitchensink/internal/utils/kitbuffer.h b/include/kitchensink/internal/utils/kitbuffer.h
index 67d93c3..95d75b5 100644
--- a/include/kitchensink/internal/utils/kitbuffer.h
+++ b/include/kitchensink/internal/utils/kitbuffer.h
@@ -19,6 +19,7 @@ struct Kit_Buffer {
KIT_LOCAL Kit_Buffer* Kit_CreateBuffer(unsigned int size, Kit_BufferFreeCallback free_cb);
KIT_LOCAL void Kit_DestroyBuffer(Kit_Buffer *buffer);
+KIT_LOCAL unsigned int Kit_GetBufferLength(const Kit_Buffer *buffer);
KIT_LOCAL void Kit_ClearBuffer(Kit_Buffer *buffer);
KIT_LOCAL void* Kit_ReadBuffer(Kit_Buffer *buffer);
KIT_LOCAL void* Kit_PeekBuffer(const Kit_Buffer *buffer);
diff --git a/src/internal/audio/kitaudio.c b/src/internal/audio/kitaudio.c
index e0302ee..eed1c97 100644
--- a/src/internal/audio/kitaudio.c
+++ b/src/internal/audio/kitaudio.c
@@ -276,39 +276,30 @@ int Kit_GetAudioDecoderData(Kit_Decoder *dec, unsigned char *buf, int len) {
assert(dec != NULL);
Kit_AudioPacket *next_packet = NULL;
- Kit_AudioPacket *packet = Kit_PeekDecoderOutput(dec);
+ Kit_AudioPacket *packet = NULL;
+ int ret = 0;
+ int bytes_per_sample = 0;
+ double bytes_per_second = 0;
+ double sync_ts = 0;
+
+ // First, peek the next packet. Make sure we have something to read.
+ packet = next_packet = Kit_PeekDecoderOutput(dec);
if(packet == NULL) {
return 0;
}
- int ret = 0;
- int bytes_per_sample = dec->output.bytes * dec->output.channels;
- double bytes_per_second = bytes_per_sample * dec->output.samplerate;
- double sync_ts = _GetSystemTime() - dec->clock_sync;
-
+ // If packet should not yet be played, stop here and wait.
+ // If packet should have already been played, skip it and try to find a better packet.
+ // For audio, it is possible that we cannot find good packet. Then just don't read anything.
+ sync_ts = _GetSystemTime() - dec->clock_sync;
if(packet->pts > sync_ts + KIT_AUDIO_SYNC_THRESHOLD) {
return 0;
- } else if(packet->pts < sync_ts - KIT_AUDIO_SYNC_THRESHOLD) {
- // Audio is lagging, skip until good pts is found
+ }
+ while(packet != NULL && packet->pts < sync_ts - KIT_AUDIO_SYNC_THRESHOLD) {
Kit_AdvanceDecoderOutput(dec);
- while(1) {
- next_packet = Kit_ReadDecoderOutput(dec);
-
- // If next packet is valid, remove this one and jump to next.
- if(next_packet != NULL) {
- Kit_AdvanceDecoderOutput(dec);
- free_out_audio_packet_cb(packet);
- packet = next_packet;
- }
-
- dec->clock_pos = packet->pts;
- if(packet->pts > sync_ts - KIT_AUDIO_SYNC_THRESHOLD) {
- break;
- }
- }
+ free_out_audio_packet_cb(packet);
+ packet = Kit_PeekDecoderOutput(dec);
}
-
- // If we have no viable packet, just skip
if(packet == NULL) {
return 0;
}
@@ -316,18 +307,19 @@ int Kit_GetAudioDecoderData(Kit_Decoder *dec, unsigned char *buf, int len) {
// Read data from packet ringbuffer
if(len > 0) {
ret = Kit_ReadRingBuffer(packet->rb, (char*)buf, len);
+ if(ret) {
+ bytes_per_sample = dec->output.bytes * dec->output.channels;
+ bytes_per_second = bytes_per_sample * dec->output.samplerate;
+ packet->pts += ((double)ret) / bytes_per_second;
+ }
}
+ dec->clock_pos = packet->pts;
// If ringbuffer is cleared, kill packet and advance buffer.
// Otherwise forward the pts value for the current packet.
if(Kit_GetRingBufferLength(packet->rb) == 0) {
Kit_AdvanceDecoderOutput(dec);
- dec->clock_pos = packet->pts;
free_out_audio_packet_cb(packet);
- } else {
- packet->pts += ((double)ret) / bytes_per_second;
- dec->clock_pos = packet->pts;
}
-
return ret;
}
diff --git a/src/internal/kitdecoder.c b/src/internal/kitdecoder.c
index 14d2e7c..ec95621 100644
--- a/src/internal/kitdecoder.c
+++ b/src/internal/kitdecoder.c
@@ -75,7 +75,7 @@ Kit_Decoder* Kit_CreateDecoder(const Kit_Source *src, int stream_index,
// Set thread count
codec_ctx->thread_count = thread_count;
- codec_ctx->thread_type = FF_THREAD_SLICE;
+ codec_ctx->thread_type = FF_THREAD_SLICE|FF_THREAD_FRAME;
// This is required for ass_process_chunk() support
if(LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 25, 100)) {
@@ -287,6 +287,16 @@ void Kit_AdvanceDecoderOutput(Kit_Decoder *dec) {
}
}
+unsigned int Kit_GetDecoderOutputLength(Kit_Decoder *dec) {
+ assert(dec != NULL);
+ unsigned int len;
+ if(SDL_LockMutex(dec->output_lock) == 0) {
+ len = Kit_GetBufferLength(dec->buffer[KIT_DEC_BUF_OUT]);
+ SDL_UnlockMutex(dec->output_lock);
+ }
+ return len;
+}
+
void Kit_ClearDecoderBuffers(Kit_Decoder *dec) {
if(dec == NULL) return;
Kit_ClearDecoderInput(dec);
diff --git a/src/internal/utils/kitbuffer.c b/src/internal/utils/kitbuffer.c
index 0133154..60ca831 100644
--- a/src/internal/utils/kitbuffer.c
+++ b/src/internal/utils/kitbuffer.c
@@ -18,6 +18,10 @@ Kit_Buffer* Kit_CreateBuffer(unsigned int size, Kit_BufferFreeCallback free_cb)
return b;
}
+unsigned int Kit_GetBufferLength(const Kit_Buffer *buffer) {
+ return buffer->write_p - buffer->read_p;
+}
+
void Kit_DestroyBuffer(Kit_Buffer *buffer) {
if(buffer == NULL) return;
Kit_ClearBuffer(buffer);
diff --git a/src/internal/video/kitvideo.c b/src/internal/video/kitvideo.c
index cde5226..7fb3c30 100644
--- a/src/internal/video/kitvideo.c
+++ b/src/internal/video/kitvideo.c
@@ -249,38 +249,30 @@ int Kit_GetVideoDecoderData(Kit_Decoder *dec, SDL_Texture *texture) {
assert(texture != NULL);
Kit_VideoPacket *next_packet = NULL;
- Kit_VideoPacket *packet = Kit_PeekDecoderOutput(dec);
+ Kit_VideoPacket *packet = NULL;
+ double sync_ts = 0;
+ unsigned int limit_rounds = 0;
+
+ // First, peek the next packet. Make sure we have something to read.
+ packet = next_packet = Kit_PeekDecoderOutput(dec);
if(packet == NULL) {
return 0;
}
- double sync_ts = _GetSystemTime() - dec->clock_sync;
-
- // Check if we want the packet
+ // If packet should not yet be played, stop here and wait.
+ // If packet should have already been played, skip it and try to find a better packet.
+ // For video, we *try* to return a frame, even if we are out of sync. It is better than
+ // not showing anything.
+ sync_ts = _GetSystemTime() - dec->clock_sync;
if(packet->pts > sync_ts + KIT_VIDEO_SYNC_THRESHOLD) {
- // Video is ahead, don't show yet.
return 0;
- } else if(packet->pts < sync_ts - KIT_VIDEO_SYNC_THRESHOLD) {
- // Video is lagging, skip until we find a good PTS to continue from.
+ }
+ limit_rounds = Kit_GetDecoderOutputLength(dec);
+ while(packet != NULL && packet->pts < sync_ts - KIT_VIDEO_SYNC_THRESHOLD && --limit_rounds) {
Kit_AdvanceDecoderOutput(dec);
- while(packet != NULL) {
- next_packet = Kit_PeekDecoderOutput(dec);
-
- // If next packet is valid, remove this one and jump to next.
- if(next_packet != NULL) {
- Kit_AdvanceDecoderOutput(dec);
- free_out_video_packet_cb(packet);
- packet = next_packet;
- }
-
- dec->clock_pos = packet->pts;
- if(packet->pts > sync_ts - KIT_VIDEO_SYNC_THRESHOLD) {
- break;
- }
- }
+ free_out_video_packet_cb(packet);
+ packet = Kit_PeekDecoderOutput(dec);
}
-
- // If we have no viable packet, just skip
if(packet == NULL) {
return 0;
}