diff options
-rw-r--r-- | include/kitchensink/internal/audio/kitaudio.h | 1 | ||||
-rw-r--r-- | include/kitchensink/internal/video/kitvideo.h | 1 | ||||
-rw-r--r-- | src/internal/audio/kitaudio.c | 8 | ||||
-rw-r--r-- | src/internal/video/kitvideo.c | 8 | ||||
-rw-r--r-- | src/kitplayer.c | 102 |
5 files changed, 89 insertions, 31 deletions
diff --git a/include/kitchensink/internal/audio/kitaudio.h b/include/kitchensink/internal/audio/kitaudio.h index e42770b..c3db420 100644 --- a/include/kitchensink/internal/audio/kitaudio.h +++ b/include/kitchensink/internal/audio/kitaudio.h @@ -7,5 +7,6 @@ KIT_LOCAL Kit_Decoder* Kit_CreateAudioDecoder(const Kit_Source *src, int stream_index);
KIT_LOCAL int Kit_GetAudioDecoderData(Kit_Decoder *dec, unsigned char *buf, int len);
+KIT_LOCAL double Kit_GetAudioDecoderPTS(Kit_Decoder *dec);
#endif // KITAUDIO_H
diff --git a/include/kitchensink/internal/video/kitvideo.h b/include/kitchensink/internal/video/kitvideo.h index 5c072ef..b393347 100644 --- a/include/kitchensink/internal/video/kitvideo.h +++ b/include/kitchensink/internal/video/kitvideo.h @@ -9,5 +9,6 @@ KIT_LOCAL Kit_Decoder* Kit_CreateVideoDecoder(const Kit_Source *src, int stream_index);
KIT_LOCAL int Kit_GetVideoDecoderData(Kit_Decoder *dec, SDL_Texture *texture);
+KIT_LOCAL double Kit_GetVideoDecoderPTS(Kit_Decoder *dec);
#endif // KITVIDEO_H
diff --git a/src/internal/audio/kitaudio.c b/src/internal/audio/kitaudio.c index b1a0fdc..e399ff2 100644 --- a/src/internal/audio/kitaudio.c +++ b/src/internal/audio/kitaudio.c @@ -264,6 +264,14 @@ exit_0: return NULL;
}
+double Kit_GetAudioDecoderPTS(Kit_Decoder *dec) {
+ Kit_AudioPacket *packet = Kit_PeekDecoderOutput(dec);
+ if(packet == NULL) {
+ return -1.0;
+ }
+ return packet->pts;
+}
+
int Kit_GetAudioDecoderData(Kit_Decoder *dec, unsigned char *buf, int len) {
assert(dec != NULL);
diff --git a/src/internal/video/kitvideo.c b/src/internal/video/kitvideo.c index 79994bd..350d3c5 100644 --- a/src/internal/video/kitvideo.c +++ b/src/internal/video/kitvideo.c @@ -236,6 +236,14 @@ exit_0: return NULL;
}
+double Kit_GetVideoDecoderPTS(Kit_Decoder *dec) {
+ Kit_VideoPacket *packet = Kit_PeekDecoderOutput(dec);
+ if(packet == NULL) {
+ return -1.0;
+ }
+ return packet->pts;
+}
+
int Kit_GetVideoDecoderData(Kit_Decoder *dec, SDL_Texture *texture) {
assert(dec != NULL);
assert(texture != NULL);
diff --git a/src/kitplayer.c b/src/kitplayer.c index 5220945..eaa89e9 100644 --- a/src/kitplayer.c +++ b/src/kitplayer.c @@ -73,26 +73,32 @@ static bool _IsOutputEmpty(const Kit_Player *player) { static int _RunDecoder(Kit_Player *player) { int got; - int ret = 0; + bool has_room = true; - if(SDL_LockMutex(player->dec_lock) != 0) { - return ret; - } + do { + while((got = _DemuxStream(player)) == -1); + if(got == 1 && _IsOutputEmpty(player)) { + return 1; + } - while((got = _DemuxStream(player)) == -1); - if(got == 1 && _IsOutputEmpty(player)) { - ret = 1; - goto exit; - } + for(int i = 0; i < KIT_DEC_COUNT; i++) { + while(Kit_RunDecoder(player->decoders[i]) == 1); + } - // Run decoders for a bit - for(int i = 0; i < KIT_DEC_COUNT; i++) { - while(Kit_RunDecoder(player->decoders[i]) == 1); - } + // If there is no room in any decoder input, just stop here since it likely means that + // at least some decoder output is full. + for(int i = 0; i < KIT_DEC_COUNT; i++) { + Kit_Decoder *dec = player->decoders[i]; + if(dec == NULL) + continue; + if(!Kit_CanWriteDecoderInput(dec)) { + has_room = false; + break; + } + } + } while(has_room); -exit: - SDL_UnlockMutex(player->dec_lock); - return ret; + return 0; } static int _DecoderThread(void *ptr) { @@ -109,18 +115,26 @@ static int _DecoderThread(void *ptr) { is_playing = true; } while(is_running && is_playing) { - if(player->state == KIT_CLOSED) { - is_running = false; - continue; - } - if(player->state == KIT_STOPPED) { - is_playing = false; - continue; - } - if(_RunDecoder(player) == 1) { - player->state = KIT_STOPPED; - continue; + // Grab the decoder lock, and run demuxer & decoders for a bit. + if(SDL_LockMutex(player->dec_lock) == 0) { + if(player->state == KIT_CLOSED) { + is_running = false; + goto end_block; + } + if(player->state == KIT_STOPPED) { + is_playing = false; + goto end_block; + } + if(_RunDecoder(player) == 1) { + player->state = KIT_STOPPED; + goto end_block; + } + +end_block: + SDL_UnlockMutex(player->dec_lock); } + + // Delay to make sure this thread does not hog all cpu SDL_Delay(2); } @@ -361,6 +375,7 @@ void Kit_PlayerPlay(Kit_Player *player) { player->state = KIT_PLAYING; break; case KIT_STOPPED: + _RunDecoder(player); // Fill some buffers before starting playback _SetClockSync(player); player->state = KIT_PLAYING; break; @@ -379,6 +394,9 @@ void Kit_PlayerStop(Kit_Player *player) { case KIT_PLAYING: case KIT_PAUSED: player->state = KIT_STOPPED; + for(int i = 0; i < KIT_DEC_COUNT; i++) { + Kit_ClearDecoderBuffers(player->decoders[i]); + } break; } SDL_UnlockMutex(player->dec_lock); @@ -414,15 +432,37 @@ int Kit_PlayerSeek(Kit_Player *player, double seek_set) { if(seek_set < position) { flags |= AVSEEK_FLAG_BACKWARD; } - if(avformat_seek_file(format_ctx, -1, 0, seek_target, seek_target, flags) < 0) { + + // First, tell ffmpeg to seek stream. If not capable, stop here. + // Failure here probably means that stream is unseekable someway, eg. streamed media + if(avformat_seek_file(format_ctx, -1, 0, seek_target, INT_MAX, flags) < 0) { Kit_SetError("Unable to seek source"); SDL_UnlockMutex(player->dec_lock); return 1; + } + + // Clean old buffers and try to fill them with new data + for(int i = 0; i < KIT_DEC_COUNT; i++) { + Kit_ClearDecoderBuffers(player->decoders[i]); + } + _RunDecoder(player); + + // Try to get a precise seek position from the next audio/video frame + // (depending on which one is used to sync) + double precise_pts = -1.0F; + if(player->decoders[KIT_VIDEO_DEC] != NULL) { + precise_pts = Kit_GetVideoDecoderPTS(player->decoders[KIT_VIDEO_DEC]); + } + else if(player->decoders[KIT_AUDIO_DEC] != NULL) { + precise_pts = Kit_GetAudioDecoderPTS(player->decoders[KIT_AUDIO_DEC]); + } + + // If we got a legit looking value, set it as seek value. Otherwise use + // the seek value we requested. + if(precise_pts >= 0) { + _ChangeClockSync(player, position - precise_pts); } else { _ChangeClockSync(player, position - seek_set); - for(int i = 0; i < KIT_DEC_COUNT; i++) { - Kit_ClearDecoderBuffers(player->decoders[i]); - } } // That's it. Unlock and continue. |