summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--examples/example_audio.c7
-rw-r--r--examples/example_video.c28
-rw-r--r--include/kitchensink/internal/audio/kitaudio.h (renamed from include/kitchensink/internal/kitaudio.h)0
-rw-r--r--include/kitchensink/internal/kitdecoder.h4
-rw-r--r--include/kitchensink/internal/kitlist.h26
-rw-r--r--include/kitchensink/internal/subtitle/kitsubtitle.h (renamed from include/kitchensink/internal/kitsubtitle.h)2
-rw-r--r--include/kitchensink/internal/subtitle/renderers/kitsubass.h10
-rw-r--r--include/kitchensink/internal/subtitle/renderers/kitsubimage.h6
-rw-r--r--include/kitchensink/internal/subtitle/renderers/kitsubrenderer.h22
-rw-r--r--include/kitchensink/internal/utils/kitbuffer.h (renamed from include/kitchensink/internal/kitbuffer.h)0
-rw-r--r--include/kitchensink/internal/utils/kithelpers.h (renamed from include/kitchensink/internal/kithelpers.h)0
-rw-r--r--include/kitchensink/internal/utils/kitlog.h (renamed from include/kitchensink/internal/kitlog.h)0
-rw-r--r--include/kitchensink/internal/utils/kitringbuffer.h (renamed from include/kitchensink/internal/kitringbuffer.h)0
-rw-r--r--include/kitchensink/internal/video/kitvideo.h (renamed from include/kitchensink/internal/kitvideo.h)0
-rw-r--r--include/kitchensink/kitformats.h1
-rw-r--r--include/kitchensink/kitlib.h4
-rw-r--r--include/kitchensink/kitplayer.h10
-rw-r--r--src/internal/audio/kitaudio.c (renamed from src/internal/kitaudio.c)45
-rw-r--r--src/internal/kitdecoder.c26
-rw-r--r--src/internal/kitlist.c79
-rw-r--r--src/internal/kitsubtitle.c445
-rw-r--r--src/internal/subtitle/kitsubtitle.c209
-rw-r--r--src/internal/subtitle/renderers/kitsubass.c188
-rw-r--r--src/internal/subtitle/renderers/kitsubimage.c51
-rw-r--r--src/internal/subtitle/renderers/kitsubrenderer.c32
-rw-r--r--src/internal/utils/kitbuffer.c (renamed from src/internal/kitbuffer.c)4
-rw-r--r--src/internal/utils/kithelpers.c (renamed from src/internal/kithelpers.c)2
-rw-r--r--src/internal/utils/kitringbuffer.c (renamed from src/internal/kitringbuffer.c)6
-rw-r--r--src/internal/video/kitvideo.c (renamed from src/internal/kitvideo.c)54
-rw-r--r--src/kiterror.c4
-rw-r--r--src/kitlib.c53
-rw-r--r--src/kitplayer.c81
-rw-r--r--src/kitsource.c10
-rw-r--r--src/kitutils.c4
34 files changed, 721 insertions, 692 deletions
diff --git a/examples/example_audio.c b/examples/example_audio.c
index 9780c26..92a1397 100644
--- a/examples/example_audio.c
+++ b/examples/example_audio.c
@@ -10,7 +10,7 @@
* It is for example use only!
*/
-#define AUDIOBUFFER_SIZE (16384)
+#define AUDIOBUFFER_SIZE (32768)
const char *stream_types[] = {
"KIT_STREAMTYPE_UNKNOWN",
@@ -51,7 +51,7 @@ int main(int argc, char *argv[]) {
return 1;
}
- err = Kit_Init(KIT_INIT_FORMATS|KIT_INIT_NETWORK);
+ err = Kit_Init(KIT_INIT_NETWORK);
if(err != 0) {
fprintf(stderr, "Unable to initialize Kitchensink: %s", Kit_GetError());
return 1;
@@ -129,12 +129,11 @@ int main(int argc, char *argv[]) {
// Refresh audio
ret = SDL_GetQueuedAudioSize(audio_dev);
if(ret < AUDIOBUFFER_SIZE) {
- ret = Kit_GetAudioData(player, (unsigned char*)audiobuf, AUDIOBUFFER_SIZE, 0);
+ ret = Kit_GetAudioData(player, (unsigned char*)audiobuf, AUDIOBUFFER_SIZE);
if(ret > 0) {
SDL_LockAudio();
SDL_QueueAudio(audio_dev, audiobuf, ret);
SDL_UnlockAudio();
- SDL_PauseAudioDevice(audio_dev, 0);
}
}
diff --git a/examples/example_video.c b/examples/example_video.c
index 15186fe..01f44b8 100644
--- a/examples/example_video.c
+++ b/examples/example_video.c
@@ -10,7 +10,7 @@
* It is for example use only!
*/
-#define AUDIOBUFFER_SIZE (32768)
+#define AUDIOBUFFER_SIZE (1024 * 64)
void render_gui(SDL_Renderer *renderer, double percent) {
@@ -106,7 +106,7 @@ int main(int argc, char *argv[]) {
SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear");
// Initialize Kitchensink with network support and all formats.
- err = Kit_Init(KIT_INIT_FORMATS|KIT_INIT_NETWORK);
+ err = Kit_Init(KIT_INIT_NETWORK|KIT_INIT_ASS);
if(err != 0) {
fprintf(stderr, "Unable to initialize Kitchensink: %s", Kit_GetError());
return 1;
@@ -181,6 +181,8 @@ int main(int argc, char *argv[]) {
// Print some format info
fprintf(stderr, "Texture type: %s\n", Kit_GetSDLPixelFormatString(pinfo.video.format));
fprintf(stderr, "Audio format: %s\n", Kit_GetSDLAudioFormatString(pinfo.audio.format));
+ fprintf(stderr, "Subtitle format: %s\n", Kit_GetSDLPixelFormatString(pinfo.subtitle.format));
+ fflush(stderr);
// Initialize textures
SDL_Texture *video_tex = SDL_CreateTexture(
@@ -193,8 +195,19 @@ int main(int argc, char *argv[]) {
fprintf(stderr, "Error while attempting to create a video texture\n");
return 1;
}
+ SDL_Texture *subtitle_tex = SDL_CreateTexture(
+ renderer,
+ pinfo.subtitle.format,
+ SDL_TEXTUREACCESS_STATIC,
+ pinfo.video.width,
+ pinfo.video.height);
+ if(subtitle_tex == NULL) {
+ fprintf(stderr, "Error while attempting to create a subtitle texture\n");
+ return 1;
+ }
- fflush(stderr);
+ // Make sure subtitle texture is in correct blendmode
+ SDL_SetTextureBlendMode(subtitle_tex, SDL_BLENDMODE_BLEND);
// Set logical size for the renderer. This way when we scale, we keep aspect ratio.
SDL_RenderSetLogicalSize(renderer, pinfo.video.width, pinfo.video.height);
@@ -276,7 +289,10 @@ int main(int argc, char *argv[]) {
SDL_LockAudio();
while(need > 0) {
- ret = Kit_GetAudioData(player, (unsigned char*)audiobuf, AUDIOBUFFER_SIZE, (size_t)SDL_GetQueuedAudioSize(audio_dev));
+ ret = Kit_GetAudioData(
+ player,
+ (unsigned char*)audiobuf,
+ AUDIOBUFFER_SIZE);
need -= ret;
if(ret > 0) {
SDL_QueueAudio(audio_dev, audiobuf, ret);
@@ -295,7 +311,8 @@ int main(int argc, char *argv[]) {
// Refresh videotexture and render it
Kit_GetVideoData(player, video_tex);
SDL_RenderCopy(renderer, video_tex, NULL, NULL);
- Kit_GetSubtitleData(player, renderer);
+ Kit_GetSubtitleData(player, subtitle_tex);
+ SDL_RenderCopy(renderer, subtitle_tex, NULL, NULL);
// Render GUI
if(gui_enabled) {
@@ -307,6 +324,7 @@ int main(int argc, char *argv[]) {
SDL_RenderPresent(renderer);
}
+ SDL_DestroyTexture(subtitle_tex);
SDL_DestroyTexture(video_tex);
SDL_CloseAudioDevice(audio_dev);
diff --git a/include/kitchensink/internal/kitaudio.h b/include/kitchensink/internal/audio/kitaudio.h
index ac6753b..ac6753b 100644
--- a/include/kitchensink/internal/kitaudio.h
+++ b/include/kitchensink/internal/audio/kitaudio.h
diff --git a/include/kitchensink/internal/kitdecoder.h b/include/kitchensink/internal/kitdecoder.h
index 191113b..5d494e8 100644
--- a/include/kitchensink/internal/kitdecoder.h
+++ b/include/kitchensink/internal/kitdecoder.h
@@ -9,7 +9,7 @@
#include "kitchensink/kitconfig.h"
#include "kitchensink/kitsource.h"
-#include "kitchensink/internal/kitbuffer.h"
+#include "kitchensink/internal/utils/kitbuffer.h"
#define KIT_DEC_IN 0
#define KIT_DEC_OUT 1
@@ -48,6 +48,8 @@ KIT_LOCAL void* Kit_PeekDecoderOutput(Kit_Decoder *dec);
KIT_LOCAL void Kit_AdvanceDecoderOutput(Kit_Decoder *dec);
KIT_LOCAL void Kit_ClearDecoderBuffers(Kit_Decoder *dec);
KIT_LOCAL int Kit_RunDecoder(Kit_Decoder *dec);
+KIT_LOCAL void Kit_ClearDecoderInput(Kit_Decoder *dec);
+KIT_LOCAL void Kit_ClearDecoderOutput(Kit_Decoder *dec);
KIT_LOCAL void Kit_CloseDecoder(Kit_Decoder *dec);
#endif // KITDECODER_H
diff --git a/include/kitchensink/internal/kitlist.h b/include/kitchensink/internal/kitlist.h
deleted file mode 100644
index 85e3e3f..0000000
--- a/include/kitchensink/internal/kitlist.h
+++ /dev/null
@@ -1,26 +0,0 @@
-#ifndef KITLIST_H
-#define KITLIST_H
-
-#include "kitchensink/kitconfig.h"
-
-typedef struct Kit_List Kit_List;
-
-typedef void (*Kit_ListFreeCallback)(void*);
-
-struct Kit_List {
- unsigned int size;
- unsigned int length;
- Kit_ListFreeCallback free_cb;
- void **data;
-};
-
-KIT_LOCAL Kit_List* Kit_CreateList(unsigned int size, Kit_ListFreeCallback free_cb);
-KIT_LOCAL void Kit_DestroyList(Kit_List *list);
-
-KIT_LOCAL void Kit_ClearList(Kit_List *list);
-KIT_LOCAL void Kit_RemoveFromList(Kit_List *list, unsigned int iterator);
-KIT_LOCAL void* Kit_IterateList(const Kit_List *list, unsigned int *iterator);
-KIT_LOCAL int Kit_WriteList(Kit_List *list, void *ptr);
-KIT_LOCAL int Kit_GetListLength(const Kit_List *list);
-
-#endif // KITLIST_H
diff --git a/include/kitchensink/internal/kitsubtitle.h b/include/kitchensink/internal/subtitle/kitsubtitle.h
index 5296aef..51de9b9 100644
--- a/include/kitchensink/internal/kitsubtitle.h
+++ b/include/kitchensink/internal/subtitle/kitsubtitle.h
@@ -9,6 +9,6 @@
#include "kitchensink/internal/kitdecoder.h"
KIT_LOCAL Kit_Decoder* Kit_CreateSubtitleDecoder(const Kit_Source *src, Kit_SubtitleFormat *format, int w, int h);
-KIT_LOCAL int Kit_GetSubtitleDecoderData(Kit_Decoder *dec, SDL_Renderer *renderer);
+KIT_LOCAL int Kit_GetSubtitleDecoderData(Kit_Decoder *dec, SDL_Texture *texture);
#endif // KITSUBTITLE_H
diff --git a/include/kitchensink/internal/subtitle/renderers/kitsubass.h b/include/kitchensink/internal/subtitle/renderers/kitsubass.h
new file mode 100644
index 0000000..39df3ac
--- /dev/null
+++ b/include/kitchensink/internal/subtitle/renderers/kitsubass.h
@@ -0,0 +1,10 @@
+#ifndef KITSUBASS_H
+#define KITSUBASS_H
+
+#include "kitchensink/kitconfig.h"
+#include "kitchensink/internal/kitdecoder.h"
+#include "kitchensink/internal/subtitle/renderers/kitsubrenderer.h"
+
+KIT_LOCAL Kit_SubtitleRenderer* Kit_CreateASSSubtitleRenderer(const Kit_Decoder *dec, int w, int h);
+
+#endif // KITSUBASS_H
diff --git a/include/kitchensink/internal/subtitle/renderers/kitsubimage.h b/include/kitchensink/internal/subtitle/renderers/kitsubimage.h
new file mode 100644
index 0000000..d26b67e
--- /dev/null
+++ b/include/kitchensink/internal/subtitle/renderers/kitsubimage.h
@@ -0,0 +1,6 @@
+#ifndef KITSUBIMAGE_H
+#define KITSUBIMAGE_H
+
+
+
+#endif // KITSUBIMAGE_H
diff --git a/include/kitchensink/internal/subtitle/renderers/kitsubrenderer.h b/include/kitchensink/internal/subtitle/renderers/kitsubrenderer.h
new file mode 100644
index 0000000..b24161a
--- /dev/null
+++ b/include/kitchensink/internal/subtitle/renderers/kitsubrenderer.h
@@ -0,0 +1,22 @@
+#ifndef KITSUBRENDERER_H
+#define KITSUBRENDERER_H
+
+#include "kitchensink/kitsource.h"
+#include "kitchensink/kitformats.h"
+
+typedef struct Kit_SubtitleRenderer Kit_SubtitleRenderer;
+
+typedef int (*ren_render_cb)(Kit_SubtitleRenderer *ren, void *src, double start_pts, void *surface);
+typedef void (*ren_close_cb)(Kit_SubtitleRenderer *ren);
+
+struct Kit_SubtitleRenderer {
+ void *userdata;
+ ren_render_cb ren_render; ///< Subtitle rendering function callback
+ ren_close_cb ren_close; ///< Subtitle renderer close function callback
+};
+
+KIT_LOCAL Kit_SubtitleRenderer* Kit_CreateSubtitleRenderer();
+KIT_LOCAL int Kit_RunSubtitleRenderer(Kit_SubtitleRenderer *ren, void *src, double start_pts, void *surface);
+KIT_LOCAL void Kit_CloseSubtitleRenderer(Kit_SubtitleRenderer *ren);
+
+#endif // KITSUBRENDERER_H
diff --git a/include/kitchensink/internal/kitbuffer.h b/include/kitchensink/internal/utils/kitbuffer.h
index 4d0f8cc..4d0f8cc 100644
--- a/include/kitchensink/internal/kitbuffer.h
+++ b/include/kitchensink/internal/utils/kitbuffer.h
diff --git a/include/kitchensink/internal/kithelpers.h b/include/kitchensink/internal/utils/kithelpers.h
index 5b94a7a..5b94a7a 100644
--- a/include/kitchensink/internal/kithelpers.h
+++ b/include/kitchensink/internal/utils/kithelpers.h
diff --git a/include/kitchensink/internal/kitlog.h b/include/kitchensink/internal/utils/kitlog.h
index 1a56e53..1a56e53 100644
--- a/include/kitchensink/internal/kitlog.h
+++ b/include/kitchensink/internal/utils/kitlog.h
diff --git a/include/kitchensink/internal/kitringbuffer.h b/include/kitchensink/internal/utils/kitringbuffer.h
index 2f67520..2f67520 100644
--- a/include/kitchensink/internal/kitringbuffer.h
+++ b/include/kitchensink/internal/utils/kitringbuffer.h
diff --git a/include/kitchensink/internal/kitvideo.h b/include/kitchensink/internal/video/kitvideo.h
index 5a5624f..5a5624f 100644
--- a/include/kitchensink/internal/kitvideo.h
+++ b/include/kitchensink/internal/video/kitvideo.h
diff --git a/include/kitchensink/kitformats.h b/include/kitchensink/kitformats.h
index a1cc61e..129047b 100644
--- a/include/kitchensink/kitformats.h
+++ b/include/kitchensink/kitformats.h
@@ -24,6 +24,7 @@ typedef struct Kit_VideoFormat {
typedef struct Kit_SubtitleFormat {
int stream_index; ///< Stream index
bool is_enabled; ///< Is stream enabled
+ unsigned int format; ///< SDL Pixel Format
} Kit_SubtitleFormat;
#endif // KITFORMATS_H
diff --git a/include/kitchensink/kitlib.h b/include/kitchensink/kitlib.h
index 9a827be..d8c3bb9 100644
--- a/include/kitchensink/kitlib.h
+++ b/include/kitchensink/kitlib.h
@@ -18,8 +18,8 @@ typedef struct Kit_Version {
} Kit_Version;
enum {
- KIT_INIT_FORMATS = 0x1,
- KIT_INIT_NETWORK = 0x2,
+ KIT_INIT_NETWORK = 0x1,
+ KIT_INIT_ASS = 0x2
};
KIT_API int Kit_Init(unsigned int flags);
diff --git a/include/kitchensink/kitplayer.h b/include/kitchensink/kitplayer.h
index a33828b..a5c93a2 100644
--- a/include/kitchensink/kitplayer.h
+++ b/include/kitchensink/kitplayer.h
@@ -21,9 +21,9 @@ extern "C" {
typedef enum Kit_PlayerState {
KIT_STOPPED = 0, ///< Playback stopped or has not started yet.
- KIT_PLAYING, ///< Playback started & player is actively decoding.
- KIT_PAUSED, ///< Playback paused; player is actively decoding but no new data is given out.
- KIT_CLOSED ///< Playback is stopped and player is closing.
+ KIT_PLAYING, ///< Playback started & player is actively decoding.
+ KIT_PAUSED, ///< Playback paused; player is actively decoding but no new data is given out.
+ KIT_CLOSED ///< Playback is stopped and player is closing.
} Kit_PlayerState;
typedef struct Kit_Player {
@@ -57,8 +57,8 @@ KIT_API void Kit_ClosePlayer(Kit_Player *player);
KIT_API int Kit_UpdatePlayer(Kit_Player *player);
KIT_API int Kit_GetVideoData(Kit_Player *player, SDL_Texture *texture);
-KIT_API int Kit_GetSubtitleData(Kit_Player *player, SDL_Renderer *renderer);
-KIT_API int Kit_GetAudioData(Kit_Player *player, unsigned char *buffer, int length, int cur_buf_len);
+KIT_API int Kit_GetSubtitleData(Kit_Player *player, SDL_Texture *texture);
+KIT_API int Kit_GetAudioData(Kit_Player *player, unsigned char *buffer, int length);
KIT_API void Kit_GetPlayerInfo(const Kit_Player *player, Kit_PlayerInfo *info);
KIT_API Kit_PlayerState Kit_GetPlayerState(const Kit_Player *player);
diff --git a/src/internal/kitaudio.c b/src/internal/audio/kitaudio.c
index 4e67b74..447a74d 100644
--- a/src/internal/kitaudio.c
+++ b/src/internal/audio/kitaudio.c
@@ -8,13 +8,13 @@
#include <SDL2/SDL.h>
#include "kitchensink/kiterror.h"
-#include "kitchensink/internal/kithelpers.h"
-#include "kitchensink/internal/kitbuffer.h"
-#include "kitchensink/internal/kitaudio.h"
-#include "kitchensink/internal/kitringbuffer.h"
-#include "kitchensink/internal/kitlog.h"
+#include "kitchensink/internal/utils/kithelpers.h"
+#include "kitchensink/internal/utils/kitbuffer.h"
+#include "kitchensink/internal/audio/kitaudio.h"
+#include "kitchensink/internal/utils/kitringbuffer.h"
+#include "kitchensink/internal/utils/kitlog.h"
-#define KIT_AUDIO_OUT_SIZE 16
+#define KIT_AUDIO_OUT_SIZE 64
#define AUDIO_SYNC_THRESHOLD 0.05
typedef struct Kit_AudioDecoder {
@@ -58,6 +58,25 @@ int64_t _FindAVChannelLayout(int channels) {
}
}
+void _FindChannelLayout(uint64_t channel_layout, int *channels) {
+ switch(channel_layout) {
+ case AV_CH_LAYOUT_MONO:
+ *channels = 1;
+ break;
+ case AV_CH_LAYOUT_STEREO:
+ *channels = 2;
+ break;
+ case AV_CH_LAYOUT_QUAD:
+ *channels = 4;
+ break;
+ case AV_CH_LAYOUT_5POINT1:
+ *channels = 6;
+ break;
+ default:
+ *channels = 2;
+ }
+}
+
void _FindAudioFormat(enum AVSampleFormat fmt, int *bytes, bool *is_signed, unsigned int *format) {
switch(fmt) {
case AV_SAMPLE_FMT_U8:
@@ -135,12 +154,9 @@ static int dec_decode_audio_cb(Kit_Decoder *dec, AVPacket *in_packet) {
len2,
_FindAVSampleFormat(audio_dec->format->format), 1);
- // Get pts for the packet
- double pts = 0;
- if(in_packet->pts != AV_NOPTS_VALUE) {
- pts = av_frame_get_best_effort_timestamp(audio_dec->scratch_frame);
- pts *= av_q2d(dec->format_ctx->streams[dec->stream_index]->time_base);
- }
+ // Get presentation timestamp
+ double pts = av_frame_get_best_effort_timestamp(audio_dec->scratch_frame);
+ pts *= av_q2d(dec->format_ctx->streams[dec->stream_index]->time_base);
// Lock, write to audio buffer, unlock
Kit_AudioPacket *out_packet = _CreateAudioPacket(
@@ -191,9 +207,9 @@ Kit_Decoder* Kit_CreateAudioDecoder(const Kit_Source *src, Kit_AudioFormat *form
// Find formats
format->samplerate = dec->codec_ctx->sample_rate;
- format->channels = dec->codec_ctx->channels > 2 ? 2 : dec->codec_ctx->channels;
format->is_enabled = true;
format->stream_index = src->audio_stream_index;
+ _FindChannelLayout(dec->codec_ctx->channel_layout, &format->channels);
_FindAudioFormat(dec->codec_ctx->sample_fmt, &format->bytes, &format->is_signed, &format->format);
// ... then allocate the audio decoder
@@ -289,11 +305,12 @@ int Kit_GetAudioDecoderData(Kit_Decoder *dec, unsigned char *buf, int len) {
// 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;
}
- dec->clock_pos = packet->pts;
return ret;
}
diff --git a/src/internal/kitdecoder.c b/src/internal/kitdecoder.c
index df78559..2d6891b 100644
--- a/src/internal/kitdecoder.c
+++ b/src/internal/kitdecoder.c
@@ -6,7 +6,7 @@
#include "kitchensink/internal/kitdecoder.h"
#include "kitchensink/kiterror.h"
-#define BUFFER_IN_SIZE 32
+#define BUFFER_IN_SIZE 128
static void free_in_video_packet_cb(void *packet) {
av_packet_free((AVPacket**)&packet);
@@ -143,6 +143,20 @@ int Kit_WriteDecoderOutput(Kit_Decoder *dec, void *packet) {
return ret;
}
+void Kit_ClearDecoderOutput(Kit_Decoder *dec) {
+ if(SDL_LockMutex(dec->lock[KIT_DEC_OUT]) == 0) {
+ Kit_ClearBuffer(dec->buffer[KIT_DEC_OUT]);
+ SDL_UnlockMutex(dec->lock[KIT_DEC_OUT]);
+ }
+}
+
+void Kit_ClearDecoderInput(Kit_Decoder *dec) {
+ if(SDL_LockMutex(dec->lock[KIT_DEC_IN]) == 0) {
+ Kit_ClearBuffer(dec->buffer[KIT_DEC_IN]);
+ SDL_UnlockMutex(dec->lock[KIT_DEC_IN]);
+ }
+}
+
void* Kit_PeekDecoderOutput(Kit_Decoder *dec) {
assert(dec != NULL);
void *ret = NULL;
@@ -163,14 +177,8 @@ void Kit_AdvanceDecoderOutput(Kit_Decoder *dec) {
void Kit_ClearDecoderBuffers(Kit_Decoder *dec) {
if(dec == NULL) return;
- if(SDL_LockMutex(dec->lock[KIT_DEC_IN]) == 0) {
- Kit_ClearBuffer(dec->buffer[KIT_DEC_IN]);
- SDL_UnlockMutex(dec->lock[KIT_DEC_IN]);
- }
- if(SDL_LockMutex(dec->lock[KIT_DEC_OUT]) == 0) {
- Kit_ClearBuffer(dec->buffer[KIT_DEC_OUT]);
- SDL_UnlockMutex(dec->lock[KIT_DEC_OUT]);
- }
+ Kit_ClearDecoderInput(dec);
+ Kit_ClearDecoderOutput(dec);
avcodec_flush_buffers(dec->codec_ctx);
}
diff --git a/src/internal/kitlist.c b/src/internal/kitlist.c
deleted file mode 100644
index b6d861c..0000000
--- a/src/internal/kitlist.c
+++ /dev/null
@@ -1,79 +0,0 @@
-#include "kitchensink/internal/kitlist.h"
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <assert.h>
-
-Kit_List* Kit_CreateList(unsigned int size, Kit_ListFreeCallback free_cb) {
- Kit_List *m = calloc(1, sizeof(Kit_List));
- if(m == NULL) {
- return NULL;
- }
- m->size = size;
- m->free_cb = free_cb;
- m->data = calloc(size, sizeof(void*));
- if(m->data == NULL) {
- free(m);
- return NULL;
- }
- return m;
-}
-
-void Kit_DestroyList(Kit_List *list) {
- if(list == NULL) return;
- Kit_ClearList(list);
- free(list->data);
- free(list);
-}
-
-void Kit_ClearList(Kit_List *list) {
- assert(list != NULL);
- for(unsigned int i = 0; i < list->size; i++) {
- if(list->data[i] != NULL) {
- list->free_cb(list->data[i]);
- list->data[i] = NULL;
- }
- }
- list->length = 0;
-}
-
-void Kit_RemoveFromList(Kit_List *list, unsigned int iterator) {
- assert(list != NULL);
- list->free_cb(list->data[iterator-1]);
- list->data[iterator-1] = NULL;
- list->length--;
-}
-
-void* Kit_IterateList(const Kit_List *list, unsigned int *iterator) {
- assert(list != NULL);
- assert(iterator != NULL);
- while((*iterator) < list->size) {
- void *ptr = list->data[(*iterator)];
- *iterator += 1;
- if(ptr != NULL) {
- return ptr;
- }
- }
- return NULL;
-}
-
-int Kit_WriteList(Kit_List *list, void *ptr) {
- assert(list != NULL);
- assert(ptr != NULL);
- if(list->length >= list->size) {
- return 1;
- }
- for(unsigned int i = 0; i < list->size; i++) {
- if(list->data[i] == NULL) {
- list->data[i] = ptr;
- list->length++;
- return 0;
- }
- }
- return 1;
-}
-
-int Kit_GetListLength(const Kit_List *list) {
- assert(list != NULL);
- return list->length;
-}
diff --git a/src/internal/kitsubtitle.c b/src/internal/kitsubtitle.c
deleted file mode 100644
index 09e2afa..0000000
--- a/src/internal/kitsubtitle.c
+++ /dev/null
@@ -1,445 +0,0 @@
-#include <assert.h>
-
-#include <SDL2/SDL.h>
-#include <ass/ass.h>
-#include <libavformat/avformat.h>
-
-#include "kitchensink/kiterror.h"
-#include "kitchensink/internal/kitlibstate.h"
-#include "kitchensink/internal/kitsubtitle.h"
-#include "kitchensink/internal/kitlist.h"
-#include "kitchensink/internal/kithelpers.h"
-
-// For compatibility
-#ifndef ASS_FONTPROVIDER_AUTODETECT
-#define ASS_FONTPROVIDER_AUTODETECT 1
-#endif
-
-#define KIT_SUBTITLE_OUT_SIZE 512
-
-typedef struct Kit_SubtitleDecoder {
- Kit_SubtitleFormat *format;
- ASS_Renderer *ass_renderer;
- ASS_Track *ass_track;
-} Kit_SubtitleDecoder;
-
-typedef struct Kit_SubtitlePacket {
- double pts_start;
- double pts_end;
- SDL_Rect *rect;
- SDL_Surface *surface;
- SDL_Texture *texture;
-} Kit_SubtitlePacket;
-
-/*
-static Kit_SubtitlePacket* _CreateSubtitlePacket(double pts_start, double pts_end, SDL_Rect *rect, SDL_Surface *surface) {
- Kit_SubtitlePacket *p = calloc(1, sizeof(Kit_SubtitlePacket));
- p->pts_start = pts_start;
- p->pts_end = pts_end;
- p->surface = surface;
- p->rect = rect;
- p->texture = NULL; // Cached texture
- return p;
-}
-
-
-void _HandleBitmapSubtitle(Kit_SubtitlePacket** spackets, int *n, Kit_Player *player, double pts, AVSubtitle *sub, AVSubtitleRect *rect) {
- if(rect->nb_colors == 256) {
- // Paletted image based subtitles. Convert and set palette.
- SDL_Surface *s = SDL_CreateRGBSurfaceFrom(
- rect->data[0],
- rect->w, rect->h, 8,
- rect->linesize[0],
- 0, 0, 0, 0);
-
- SDL_SetPaletteColors(s->format->palette, (SDL_Color*)rect->data[1], 0, 256);
-
- Uint32 rmask, gmask, bmask, amask;
- #if SDL_BYTEORDER == SDL_BIG_ENDIAN
- rmask = 0xff000000;
- gmask = 0x00ff0000;
- bmask = 0x0000ff00;
- amask = 0x000000ff;
- #else
- rmask = 0x000000ff;
- gmask = 0x0000ff00;
- bmask = 0x00ff0000;
- amask = 0xff000000;
- #endif
- SDL_Surface *tmp = SDL_CreateRGBSurface(
- 0, rect->w, rect->h, 32,
- rmask, gmask, bmask, amask);
- SDL_BlitSurface(s, NULL, tmp, NULL);
- SDL_FreeSurface(s);
-
- SDL_Rect *dst_rect = malloc(sizeof(SDL_Rect));
- dst_rect->x = rect->x;
- dst_rect->y = rect->y;
- dst_rect->w = rect->w;
- dst_rect->h = rect->h;
-
- double start = pts + (sub->start_display_time / 1000.0f);
- double end = -1;
- if(sub->end_display_time < UINT_MAX) {
- end = pts + (sub->end_display_time / 1000.0f);
- }
-
- spackets[(*n)++] = _CreateSubtitlePacket(start, end, dst_rect, tmp);
- }
-}
-
-static void _ProcessAssSubtitleRect(Kit_Player *player, AVSubtitleRect *rect) {
- ass_process_data((ASS_Track*)player->ass_track, rect->ass, strlen(rect->ass));
-}
-
-static void _ProcessAssImage(SDL_Surface *surface, const ASS_Image *img) {
- int x, y;
- // libass headers claim img->color is RGBA, but the alpha is 0.
- unsigned char r = ((img->color) >> 24) & 0xFF;
- unsigned char g = ((img->color) >> 16) & 0xFF;
- unsigned char b = ((img->color) >> 8) & 0xFF;
- unsigned char *src = img->bitmap;
- unsigned char *dst = (unsigned char*)surface->pixels;
-
- for(y = 0; y < img->h; y++) {
- for(x = 0; x < img->w; x++) {
- dst[x * 4 + 0] = r;
- dst[x * 4 + 1] = g;
- dst[x * 4 + 2] = b;
- dst[x * 4 + 3] = src[x];
- }
- src += img->stride;
- dst += surface->pitch;
- }
-}
-
-static void _HandleAssSubtitle(Kit_SubtitlePacket** spackets, int *n, Kit_Player *player, double pts, AVSubtitle *sub) {
- double start = pts + (sub->start_display_time / 1000.0f);
- double end = pts + (sub->end_display_time / 1000.0f);
-
- // Process current chunk of data
- unsigned int now = start * 1000;
- int change = 0;
- ASS_Image *images = ass_render_frame((ASS_Renderer*)player->ass_renderer, (ASS_Track*)player->ass_track, now, &change);
-
- // Convert to SDL_Surfaces
- if(change > 0) {
- ASS_Image *now = images;
- if(now != NULL) {
- do {
- Uint32 rmask, gmask, bmask, amask;
- #if SDL_BYTEORDER == SDL_BIG_ENDIAN
- rmask = 0xff000000;
- gmask = 0x00ff0000;
- bmask = 0x0000ff00;
- amask = 0x000000ff;
- #else
- rmask = 0x000000ff;
- gmask = 0x0000ff00;
- bmask = 0x00ff0000;
- amask = 0xff000000;
- #endif
- SDL_Surface *tmp = SDL_CreateRGBSurface(
- 0, now->w, now->h, 32,
- rmask, gmask, bmask, amask);
-
- _ProcessAssImage(tmp, now);
-
- SDL_Rect *dst_rect = malloc(sizeof(SDL_Rect));
- dst_rect->x = now->dst_x;
- dst_rect->y = now->dst_y;
- dst_rect->w = now->w;
- dst_rect->h = now->h;
-
- spackets[(*n)++] = _CreateSubtitlePacket(start, end, dst_rect, tmp);
- } while((now = now->next) != NULL);
- }
- }
-}
-
-void _HandleSubtitlePacket(Kit_Player *player, AVPacket *packet) {
- assert(player != NULL);
- assert(packet != NULL);
-
- int frame_finished;
- int len;
- AVCodecContext *scodec_ctx = (AVCodecContext*)player->scodec_ctx;
- AVFormatContext *fmt_ctx = (AVFormatContext *)player->src->format_ctx;
- Kit_SubtitlePacket *tmp = NULL;
- unsigned int it;
- AVSubtitle sub;
- memset(&sub, 0, sizeof(AVSubtitle));
-
- if(packet->size > 0) {
- len = avcodec_decode_subtitle2(scodec_ctx, &sub, &frame_finished, packet);
- if(len < 0) {
- return;
- }
-
- if(frame_finished) {
- // Get pts
- double pts = 0;
- if(packet->pts != AV_NOPTS_VALUE) {
- pts = packet->pts;
- pts *= av_q2d(fmt_ctx->streams[player->src->sstream_idx]->time_base);
- }
-
- // Convert subtitles to SDL_Surface and create a packet
- Kit_SubtitlePacket *spackets[KIT_SBUFFERSIZE];
- memset(spackets, 0, sizeof(Kit_SubtitlePacket*) * KIT_SBUFFERSIZE);
-
- int n = 0;
- bool has_ass = false;
- for(int r = 0; r < sub.num_rects; r++) {
- switch(sub.rects[r]->type) {
- case SUBTITLE_BITMAP:
- _HandleBitmapSubtitle(spackets, &n, player, pts, &sub, sub.rects[r]);
- break;
- case SUBTITLE_ASS:
- _ProcessAssSubtitleRect(player, sub.rects[r]);
- has_ass = true;
- break;
- case SUBTITLE_TEXT:
- break;
- case SUBTITLE_NONE:
- break;
- }
- }
-
- // Process libass content
- if(has_ass) {
- _HandleAssSubtitle(spackets, &n, player, pts, &sub);
- }
-
- // Lock, write to subtitle buffer, unlock
- if(SDL_LockMutex(player->smutex) == 0) {
- if(has_ass) {
- Kit_ClearList((Kit_List*)player->sbuffer);
- } else {
- // Clear out old subtitles that should only be valid until next (this) subtitle
- it = 0;
- while((tmp = Kit_IterateList((Kit_List*)player->sbuffer, &it)) != NULL) {
- if(tmp->pts_end < 0) {
- Kit_RemoveFromList((Kit_List*)player->sbuffer, it);
- }
- }
- }
-
- // Add new subtitle
- for(int i = 0; i < KIT_SBUFFERSIZE; i++) {
- Kit_SubtitlePacket *spacket = spackets[i];
- if(spacket != NULL) {
- if(Kit_WriteList((Kit_List*)player->sbuffer, spacket) == 0) {
- spackets[i] = NULL;
- }
- }
- }
-
- // Unlock subtitle buffer
- SDL_UnlockMutex(player->smutex);
- }
-
- // Couldn't write packet, free memory
- for(int i = 0; i < KIT_SBUFFERSIZE; i++) {
- if(spackets[i] != NULL) {
- _FreeSubtitlePacket(spackets[i]);
- }
- }
- }
- }
-}
-*/
-
-static void free_out_subtitle_packet_cb(void *packet) {
- Kit_SubtitlePacket *p = packet;
- SDL_FreeSurface(p->surface);
- if(p->texture) {
- SDL_DestroyTexture(p->texture);
- }
- free(p->rect);
- free(p);
-}
-
-static int dec_decode_subtitle_cb(Kit_Decoder *dec, AVPacket *in_packet) {
- assert(dec != NULL);
- assert(in_packet != NULL);
-
- int frame_finished;
- int len;
-
- AVSubtitle sub;
- memset(&sub, 0, sizeof(AVSubtitle));
-
- if(in_packet->size > 0) {
- len = avcodec_decode_subtitle2(dec->codec_ctx, &sub, &frame_finished, in_packet);
- if(len < 0) {
- return 1;
- }
-
- if(frame_finished) {
- // Get pts
- double pts = 0;
- if(in_packet->dts != AV_NOPTS_VALUE) {
- pts = in_packet->pts;
- pts *= av_q2d(dec->format_ctx->streams[dec->stream_index]->time_base);
- }
-
-
- // TODO: Implement more stuff
- }
- }
-
- return 1;
-}
-
-static void dec_close_subtitle_cb(Kit_Decoder *dec) {
- if(dec == NULL) return;
-
- Kit_SubtitleDecoder *subtitle_dec = dec->userdata;
- /*
- if(subtitle_dec->ass_track != NULL) {
- ass_free_track(subtitle_dec->ass_track);
- }
- if(subtitle_dec->ass_renderer != NULL) {
- ass_renderer_done(subtitle_dec->ass_renderer);
- }*/
- free(subtitle_dec);
-}
-
-Kit_Decoder* Kit_CreateSubtitleDecoder(const Kit_Source *src, Kit_SubtitleFormat *format, int w, int h) {
- assert(src != NULL);
- assert(format != NULL);
- if(src->subtitle_stream_index < 0) {
- return NULL;
- }
-
- // First the generic decoder component ...
- Kit_Decoder *dec = Kit_CreateDecoder(
- src, src->subtitle_stream_index,
- KIT_SUBTITLE_OUT_SIZE,
- free_out_subtitle_packet_cb);
- if(dec == NULL) {
- goto exit_0;
- }
-
- // Find formats
- format->is_enabled = true;
- format->stream_index = src->subtitle_stream_index;
-
- // ... then allocate the subtitle decoder
- Kit_SubtitleDecoder *subtitle_dec = calloc(1, sizeof(Kit_SubtitleDecoder));
- if(subtitle_dec == NULL) {
- goto exit_1;
- }
-
- /*
- // Initialize libass renderer
- Kit_LibraryState *state = Kit_GetLibraryState();
- subtitle_dec->ass_renderer = ass_renderer_init(state->libass_handle);
- if(subtitle_dec->ass_renderer == NULL) {
- Kit_SetError("Unable to initialize libass renderer");
- goto exit_2;
- }
-
- // Read fonts from attachment streams and give them to libass
- AVFormatContext *format_ctx = src->format_ctx;
- for (int j = 0; j < format_ctx->nb_streams; j++) {
- AVStream *st = format_ctx->streams[j];
- if(st->codec->codec_type == AVMEDIA_TYPE_ATTACHMENT && attachment_is_font(st)) {
- const AVDictionaryEntry *tag = av_dict_get(
- st->metadata,
- "filename",
- NULL,
- AV_DICT_MATCH_CASE);
- if(tag) {
- ass_add_font(
- state->libass_handle,
- tag->value,
- (char*)st->codec->extradata,
- st->codec->extradata_size);
- }
- }
- }
-
- // Init libass fonts and window frame size
- ass_set_fonts(
- subtitle_dec->ass_renderer,
- NULL, "sans-serif",
- ASS_FONTPROVIDER_AUTODETECT,
- NULL, 1);
- ass_set_frame_size(subtitle_dec->ass_renderer, w, h);
- ass_set_hinting(subtitle_dec->ass_renderer, ASS_HINTING_NONE);
-
- // Initialize libass track
- subtitle_dec->ass_track = ass_new_track(state->libass_handle);
- if(subtitle_dec->ass_track == NULL) {
- Kit_SetError("Unable to initialize libass track");
- goto exit_3;
- }
-
- // Set up libass track headers (ffmpeg provides these)
- if(dec->codec_ctx->subtitle_header) {
- ass_process_codec_private(
- subtitle_dec->ass_track,
- (char*)dec->codec_ctx->subtitle_header,
- dec->codec_ctx->subtitle_header_size);
- }*/
-
- // Set callbacks and userdata, and we're go
- subtitle_dec->format = format;
- dec->dec_decode = dec_decode_subtitle_cb;
- dec->dec_close = dec_close_subtitle_cb;
- dec->userdata = subtitle_dec;
- return dec;
-
-//exit_3:
- //ass_renderer_done(subtitle_dec->ass_renderer);
-//exit_2:
- //free(subtitle_dec);
-exit_1:
- Kit_CloseDecoder(dec);
-exit_0:
- return NULL;
-}
-
-int Kit_GetSubtitleDecoderData(Kit_Decoder *dec, SDL_Renderer *renderer) {
- assert(dec != NULL);
- assert(renderer != NULL);
-
-
-/*
- unsigned int it;
- Kit_SubtitlePacket *packet = NULL;
-
- // Current sync timestamp
- double cur_subtitle_ts = _GetSystemTime() - player->clock_sync;
-
- // Read a packet from buffer, if one exists. Stop here if not.
- if(SDL_LockMutex(player->smutex) == 0) {
- // Check if refresh is required and remove old subtitles
- it = 0;
- while((packet = Kit_IterateList((Kit_List*)player->sbuffer, &it)) != NULL) {
- if(packet->pts_end >= 0 && packet->pts_end < cur_subtitle_ts) {
- Kit_RemoveFromList((Kit_List*)player->sbuffer, it);
- }
- }
-
- // Render subtitle bitmaps
- it = 0;
- while((packet = Kit_IterateList((Kit_List*)player->sbuffer, &it)) != NULL) {
- if(packet->texture == NULL) {
- packet->texture = SDL_CreateTextureFromSurface(renderer, packet->surface);
- SDL_SetTextureBlendMode(packet->texture, SDL_BLENDMODE_BLEND);
- }
- SDL_RenderCopy(renderer, packet->texture, NULL, packet->rect);
- }
-
- // Unlock subtitle buffer mutex.
- SDL_UnlockMutex(player->smutex);
- } else {
- Kit_SetError("Unable to lock subtitle buffer mutex");
- return 0;
- }
-*/
- return 0;
-}
diff --git a/src/internal/subtitle/kitsubtitle.c b/src/internal/subtitle/kitsubtitle.c
new file mode 100644
index 0000000..d960044
--- /dev/null
+++ b/src/internal/subtitle/kitsubtitle.c
@@ -0,0 +1,209 @@
+#include <assert.h>
+
+#include <SDL2/SDL.h>
+#include <libavformat/avformat.h>
+
+#include "kitchensink/internal/utils/kitlog.h"
+
+#include "kitchensink/kiterror.h"
+#include "kitchensink/internal/kitlibstate.h"
+#include "kitchensink/internal/subtitle/kitsubtitle.h"
+#include "kitchensink/internal/subtitle/renderers/kitsubimage.h"
+#include "kitchensink/internal/subtitle/renderers/kitsubass.h"
+#include "kitchensink/internal/subtitle/renderers/kitsubrenderer.h"
+#include "kitchensink/internal/utils/kithelpers.h"
+
+
+#define KIT_SUBTITLE_OUT_SIZE 32
+
+typedef struct Kit_SubtitleDecoder {
+ Kit_SubtitleFormat *format;
+ Kit_SubtitleRenderer *renderer;
+ AVSubtitle scratch_frame;
+ int w;
+ int h;
+ int output_state;
+} Kit_SubtitleDecoder;
+
+typedef struct Kit_SubtitlePacket {
+ double pts_start;
+ double pts_end;
+ SDL_Surface *surface;
+} Kit_SubtitlePacket;
+
+
+static Kit_SubtitlePacket* _CreateSubtitlePacket(double pts_start, double pts_end, SDL_Surface *surface) {
+ Kit_SubtitlePacket *p = calloc(1, sizeof(Kit_SubtitlePacket));
+ p->pts_start = pts_start;
+ p->pts_end = pts_end;
+ p->surface = surface;
+ return p;
+}
+
+static void free_out_subtitle_packet_cb(void *packet) {
+ Kit_SubtitlePacket *p = packet;
+ SDL_FreeSurface(p->surface);
+ free(p);
+}
+
+static int dec_decode_subtitle_cb(Kit_Decoder *dec, AVPacket *in_packet) {
+ assert(dec != NULL);
+ assert(in_packet != NULL);
+
+ Kit_SubtitleDecoder *subtitle_dec = dec->userdata;
+ int frame_finished;
+ int len;
+
+ if(in_packet->size > 0) {
+ len = avcodec_decode_subtitle2(dec->codec_ctx, &subtitle_dec->scratch_frame, &frame_finished, in_packet);
+ if(len < 0) {
+ return 1;
+ }
+
+ if(frame_finished) {
+ // Start and end presentation timestamps for subtitle frame
+ double pts = 0;
+ if(in_packet->pts != AV_NOPTS_VALUE) {
+ pts = in_packet->pts;
+ pts *= av_q2d(dec->format_ctx->streams[dec->stream_index]->time_base);
+ }
+ double start = pts + (subtitle_dec->scratch_frame.start_display_time / 1000.0f);
+ double end = pts + (subtitle_dec->scratch_frame.end_display_time / 1000.0f);
+
+ // Surface to render on
+ SDL_Surface *surface = SDL_CreateRGBSurfaceWithFormat(
+ 0, subtitle_dec->w, subtitle_dec->h, 32, SDL_PIXELFORMAT_RGBA32);
+ memset(surface->pixels, 0, surface->pitch * surface->h);
+
+ // Create a packet. This should be filled by renderer.
+ Kit_SubtitlePacket *out_packet = _CreateSubtitlePacket(start, end, surface);
+ int ret = Kit_RunSubtitleRenderer(
+ subtitle_dec->renderer, &subtitle_dec->scratch_frame, start, surface);
+ if(ret == -1) {
+ // Renderer failed, free packet.
+ free_out_subtitle_packet_cb(out_packet);
+ } else {
+ Kit_WriteDecoderOutput(dec, out_packet);
+ }
+
+ // Free subtitle since it has now been handled
+ avsubtitle_free(&subtitle_dec->scratch_frame);
+ }
+ }
+
+ return 1;
+}
+
+static void dec_close_subtitle_cb(Kit_Decoder *dec) {
+ if(dec == NULL) return;
+ Kit_SubtitleDecoder *subtitle_dec = dec->userdata;
+ Kit_CloseSubtitleRenderer(subtitle_dec->renderer);
+ free(subtitle_dec);
+}
+
+Kit_Decoder* Kit_CreateSubtitleDecoder(const Kit_Source *src, Kit_SubtitleFormat *format, int w, int h) {
+ assert(src != NULL);
+ assert(format != NULL);
+ if(src->subtitle_stream_index < 0) {
+ return NULL;
+ }
+
+ // First the generic decoder component
+ Kit_Decoder *dec = Kit_CreateDecoder(
+ src, src->subtitle_stream_index,
+ KIT_SUBTITLE_OUT_SIZE,
+ free_out_subtitle_packet_cb);
+ if(dec == NULL) {
+ goto exit_0;
+ }
+
+ // Set format. Note that is_enabled may be changed below ...
+ format->is_enabled = true;
+ format->stream_index = src->subtitle_stream_index;
+ format->format = SDL_PIXELFORMAT_RGBA32; // Always this
+
+ // ... then allocate the subtitle decoder
+ Kit_SubtitleDecoder *subtitle_dec = calloc(1, sizeof(Kit_SubtitleDecoder));
+ if(subtitle_dec == NULL) {
+ goto exit_1;
+ }
+
+ // For subtitles, we need a renderer for the stream. Pick one based on codec ID.
+ Kit_SubtitleRenderer *ren = NULL;
+ switch(dec->codec_ctx->codec_id) {
+ case AV_CODEC_ID_SSA:
+ case AV_CODEC_ID_ASS:
+ ren = Kit_CreateASSSubtitleRenderer(dec, w, h);
+ break;
+ case AV_CODEC_ID_DVD_SUBTITLE:
+ case AV_CODEC_ID_DVB_SUBTITLE:
+ case AV_CODEC_ID_HDMV_PGS_SUBTITLE:
+ case AV_CODEC_ID_XSUB:
+ format->is_enabled = false;
+ break;
+ default:
+ format->is_enabled = false;
+ break;
+ }
+ if(ren == NULL) {
+ goto exit_2;
+ }
+
+ // Set callbacks and userdata, and we're go
+ subtitle_dec->format = format;
+ subtitle_dec->renderer = ren;
+ subtitle_dec->w = w;
+ subtitle_dec->h = h;
+ dec->dec_decode = dec_decode_subtitle_cb;
+ dec->dec_close = dec_close_subtitle_cb;
+ dec->userdata = subtitle_dec;
+ return dec;
+
+exit_2:
+ free(subtitle_dec);
+exit_1:
+ Kit_CloseDecoder(dec);
+exit_0:
+ return NULL;
+}
+
+int Kit_GetSubtitleDecoderData(Kit_Decoder *dec, SDL_Texture *texture) {
+ assert(dec != NULL);
+ assert(texture != NULL);
+
+ double sync_ts = _GetSystemTime() - dec->clock_sync;
+ char *clear_scr;
+
+ Kit_SubtitleDecoder *subtitle_dec = dec->userdata;
+ Kit_SubtitlePacket *packet = Kit_PeekDecoderOutput(dec);
+ if(packet == NULL) {
+ goto exit_0;
+ }
+ if(packet->pts_start > sync_ts) {
+ goto exit_0;
+ }
+ if(packet->pts_end < sync_ts) {
+ goto exit_1;
+ }
+
+ // Update the texture with our subtitle frame
+ SDL_UpdateTexture(
+ texture, NULL,
+ packet->surface->pixels,
+ packet->surface->pitch);
+
+ dec->clock_pos = sync_ts;
+ return 0;
+
+ // All done.
+exit_1:
+ Kit_AdvanceDecoderOutput(dec);
+ free_out_subtitle_packet_cb(packet);
+exit_0:
+ // Clear subtitle frame
+ clear_scr = calloc(1, subtitle_dec->h * subtitle_dec->w * 4);
+ SDL_UpdateTexture(texture, NULL, clear_scr, subtitle_dec->w * 4);
+ free(clear_scr);
+
+ return 0;
+}
diff --git a/src/internal/subtitle/renderers/kitsubass.c b/src/internal/subtitle/renderers/kitsubass.c
new file mode 100644
index 0000000..d0c5a80
--- /dev/null
+++ b/src/internal/subtitle/renderers/kitsubass.c
@@ -0,0 +1,188 @@
+#include <assert.h>
+#include <stdlib.h>
+
+#include <ass/ass.h>
+#include <SDL2/SDL_Surface.h>
+
+#include "kitchensink/kiterror.h"
+#include "kitchensink/internal/kitlibstate.h"
+#include "kitchensink/internal/utils/kithelpers.h"
+#include "kitchensink/internal/subtitle/renderers/kitsubass.h"
+
+// For compatibility
+#ifndef ASS_FONTPROVIDER_AUTODETECT
+#define ASS_FONTPROVIDER_AUTODETECT 1
+#endif
+
+typedef struct Kit_ASSSubtitleRenderer {
+ ASS_Renderer *renderer;
+ ASS_Track *track;
+} Kit_ASSSubtitleRenderer;
+
+static void _ProcessAssImage(SDL_Surface *surface, const ASS_Image *img) {
+ unsigned char r = ((img->color) >> 24) & 0xFF;
+ unsigned char g = ((img->color) >> 16) & 0xFF;
+ unsigned char b = ((img->color) >> 8) & 0xFF;
+ unsigned char a = (img->color) & 0xFF;
+ unsigned char *src = img->bitmap;
+ unsigned char *dst = surface->pixels;
+ unsigned int an, ao, x, y, x_off;
+ dst += img->dst_y * surface->pitch;
+
+ for(y = 0; y < img->h; y++) {
+ for(x = 0; x < img->w; x++) {
+ x_off = (img->dst_x + x) * 4;
+ an = ((255 - a) * src[x]) >> 8; // New alpha
+ ao = dst[x_off + 3]; // Original alpha
+ if(ao == 0) {
+ dst[x_off + 0] = r;
+ dst[x_off + 1] = g;
+ dst[x_off + 2] = b;
+ dst[x_off + 3] = an;
+ } else {
+ dst[x_off + 3] = 255 - (255 - dst[x_off + 3]) * (255 - an) / 255;
+ if(dst[x_off + 3] != 0) {
+ dst[x_off + 0] = (dst[x_off + 0] * ao * (255-an) / 255 + r * an ) / dst[x_off + 3];
+ dst[x_off + 1] = (dst[x_off + 1] * ao * (255-an) / 255 + g * an ) / dst[x_off + 3];
+ dst[x_off + 2] = (dst[x_off + 2] * ao * (255-an) / 255 + b * an ) / dst[x_off + 3];
+ }
+ }
+ }
+ src += img->stride;
+ dst += surface->pitch;
+ }
+}
+
+static int ren_render_ass_cb(Kit_SubtitleRenderer *ren, void *src, double start_pts, void *dst) {
+ assert(ren != NULL);
+ assert(src != NULL);
+ assert(dst != NULL);
+
+ Kit_ASSSubtitleRenderer *ass_ren = ren->userdata;
+ AVSubtitle *sub = src;
+ SDL_Surface *surface = dst;
+ unsigned int now = start_pts * 1000;
+ int change = 0;
+
+ // Read incoming subtitle packets to libASS
+ for(int r = 0; r < sub->num_rects; r++) {
+ if(sub->rects[r]->ass == NULL)
+ continue;
+ ass_process_data(ass_ren->track, sub->rects[r]->ass, strlen(sub->rects[r]->ass));
+ }
+
+ // Ask libass to render frames. If there are no changes since last render, stop here.
+ ASS_Image *image = ass_render_frame(ass_ren->renderer, ass_ren->track, now, &change);
+ if(change <= 0) {
+ return -1;
+ }
+
+ for(; image; image = image->next) {
+ if(image->w == 0 || image->h == 0)
+ continue;
+ _ProcessAssImage(surface, image);
+ }
+
+ // We tell subtitle handler to clear output before adding this frame.
+ return 0;
+}
+
+static void ren_close_ass_cb(Kit_SubtitleRenderer *ren) {
+ if(ren == NULL) return;
+
+ Kit_ASSSubtitleRenderer *ass_ren = ren->userdata;
+ ass_renderer_done(ass_ren->renderer);
+ free(ass_ren);
+}
+
+Kit_SubtitleRenderer* Kit_CreateASSSubtitleRenderer(const Kit_Decoder *dec, int w, int h) {
+ assert(dec != NULL);
+ assert(w >= 0);
+ assert(h >= 0);
+
+ // Make sure that libass library has been initialized + get handle
+ Kit_LibraryState *state = Kit_GetLibraryState();
+ if(state->libass_handle == NULL) {
+ Kit_SetError("Libass library has not been initialized");
+ return NULL;
+ }
+
+ // First allocate the generic decoder component
+ Kit_SubtitleRenderer *ren = Kit_CreateSubtitleRenderer();
+ if(ren == NULL) {
+ goto exit_0;
+ }
+
+ // Next, allocate ASS subtitle renderer context.
+ Kit_ASSSubtitleRenderer *ass_ren = calloc(1, sizeof(Kit_ASSSubtitleRenderer));
+ if(ass_ren == NULL) {
+ goto exit_1;
+ }
+
+ // Initialize libass renderer
+ ASS_Renderer *ass_renderer = ass_renderer_init(state->libass_handle);
+ if(ass_renderer == NULL) {
+ Kit_SetError("Unable to initialize libass renderer");
+ goto exit_2;
+ }
+
+ // Read fonts from attachment streams and give them to libass
+ for(int j = 0; j < dec->format_ctx->nb_streams; j++) {
+ AVStream *st = dec->format_ctx->streams[j];
+ if(st->codec->codec_type == AVMEDIA_TYPE_ATTACHMENT && attachment_is_font(st)) {
+ const AVDictionaryEntry *tag = av_dict_get(
+ st->metadata,
+ "filename",
+ NULL,
+ AV_DICT_MATCH_CASE);
+ if(tag) {
+ ass_add_font(
+ state->libass_handle,
+ tag->value,
+ (char*)st->codec->extradata,
+ st->codec->extradata_size);
+ }
+ }
+ }
+
+ // Init libass fonts and window frame size
+ ass_set_fonts(
+ ass_renderer,
+ NULL, "sans-serif",
+ ASS_FONTPROVIDER_AUTODETECT,
+ NULL, 1);
+ ass_set_frame_size(ass_renderer, w, h);
+ ass_set_hinting(ass_renderer, ASS_HINTING_NONE);
+
+ // Initialize libass track
+ ASS_Track *ass_track = ass_new_track(state->libass_handle);
+ if(ass_track == NULL) {
+ Kit_SetError("Unable to initialize libass track");
+ goto exit_3;
+ }
+
+ // Set up libass track headers (ffmpeg provides these)
+ if(dec->codec_ctx->subtitle_header) {
+ ass_process_codec_private(
+ ass_track,
+ (char*)dec->codec_ctx->subtitle_header,
+ dec->codec_ctx->subtitle_header_size);
+ }
+
+ // Set callbacks and userdata, and we're go
+ ass_ren->renderer = ass_renderer;
+ ass_ren->track = ass_track;
+ ren->ren_render = ren_render_ass_cb;
+ ren->ren_close = ren_close_ass_cb;
+ ren->userdata = ass_ren;
+ return ren;
+
+exit_3:
+ ass_renderer_done(ass_renderer);
+exit_2:
+ free(ass_ren);
+exit_1:
+ Kit_CloseSubtitleRenderer(ren);
+exit_0:
+ return NULL;
+}
diff --git a/src/internal/subtitle/renderers/kitsubimage.c b/src/internal/subtitle/renderers/kitsubimage.c
new file mode 100644
index 0000000..15a7432
--- /dev/null
+++ b/src/internal/subtitle/renderers/kitsubimage.c
@@ -0,0 +1,51 @@
+#include "kitchensink/internal/subtitle/renderers/kitsubimage.h"
+
+int filler() { return 0; }
+
+/*
+void _HandleBitmapSubtitle(Kit_SubtitlePacket** spackets, int *n, Kit_Player *player, double pts, AVSubtitle *sub, AVSubtitleRect *rect) {
+ if(rect->nb_colors == 256) {
+ // Paletted image based subtitles. Convert and set palette.
+ SDL_Surface *s = SDL_CreateRGBSurfaceFrom(
+ rect->data[0],
+ rect->w, rect->h, 8,
+ rect->linesize[0],
+ 0, 0, 0, 0);
+
+ SDL_SetPaletteColors(s->format->palette, (SDL_Color*)rect->data[1], 0, 256);
+
+ Uint32 rmask, gmask, bmask, amask;
+ #if SDL_BYTEORDER == SDL_BIG_ENDIAN
+ rmask = 0xff000000;
+ gmask = 0x00ff0000;
+ bmask = 0x0000ff00;
+ amask = 0x000000ff;
+ #else
+ rmask = 0x000000ff;
+ gmask = 0x0000ff00;
+ bmask = 0x00ff0000;
+ amask = 0xff000000;
+ #endif
+ SDL_Surface *tmp = SDL_CreateRGBSurface(
+ 0, rect->w, rect->h, 32,
+ rmask, gmask, bmask, amask);
+ SDL_BlitSurface(s, NULL, tmp, NULL);
+ SDL_FreeSurface(s);
+
+ SDL_Rect *dst_rect = malloc(sizeof(SDL_Rect));
+ dst_rect->x = rect->x;
+ dst_rect->y = rect->y;
+ dst_rect->w = rect->w;
+ dst_rect->h = rect->h;
+
+ double start = pts + (sub->start_display_time / 1000.0f);
+ double end = -1;
+ if(sub->end_display_time < UINT_MAX) {
+ end = pts + (sub->end_display_time / 1000.0f);
+ }
+
+ spackets[(*n)++] = _CreateSubtitlePacket(start, end, dst_rect, tmp);
+ }
+}
+
+*/ \ No newline at end of file
diff --git a/src/internal/subtitle/renderers/kitsubrenderer.c b/src/internal/subtitle/renderers/kitsubrenderer.c
new file mode 100644
index 0000000..f7f95a7
--- /dev/null
+++ b/src/internal/subtitle/renderers/kitsubrenderer.c
@@ -0,0 +1,32 @@
+#include <stdlib.h>
+#include <assert.h>
+
+#include "kitchensink/kiterror.h"
+#include "kitchensink/internal/subtitle/renderers/kitsubrenderer.h"
+
+
+Kit_SubtitleRenderer* Kit_CreateSubtitleRenderer() {
+ // Allocate renderer and make sure allocation was a success
+ Kit_SubtitleRenderer *ren = calloc(1, sizeof(Kit_SubtitleRenderer));
+ if(ren == NULL) {
+ Kit_SetError("Unable to allocate kit subtitle renderer");
+ return NULL;
+ }
+ return ren;
+}
+
+int Kit_RunSubtitleRenderer(Kit_SubtitleRenderer *ren, void *src, double start_pts, void *surface) {
+ if(ren == NULL)
+ return 1;
+ if(ren->ren_render != NULL)
+ return ren->ren_render(ren, src, start_pts, surface);
+ return 1;
+}
+
+void Kit_CloseSubtitleRenderer(Kit_SubtitleRenderer *ren) {
+ if(ren == NULL)
+ return;
+ if(ren->ren_close != NULL)
+ ren->ren_close(ren);
+ free(ren);
+}
diff --git a/src/internal/kitbuffer.c b/src/internal/utils/kitbuffer.c
index 5c492ea..f43d9ba 100644
--- a/src/internal/kitbuffer.c
+++ b/src/internal/utils/kitbuffer.c
@@ -1,8 +1,8 @@
-#include "kitchensink/internal/kitbuffer.h"
-
#include <stdlib.h>
#include <assert.h>
+#include "kitchensink/internal/utils/kitbuffer.h"
+
Kit_Buffer* Kit_CreateBuffer(unsigned int size, Kit_BufferFreeCallback free_cb) {
Kit_Buffer *b = calloc(1, sizeof(Kit_Buffer));
if(b == NULL) {
diff --git a/src/internal/kithelpers.c b/src/internal/utils/kithelpers.c
index 25759be..c68f1c7 100644
--- a/src/internal/kithelpers.c
+++ b/src/internal/utils/kithelpers.c
@@ -1,7 +1,7 @@
#include <libavutil/time.h>
#include <libavutil/avstring.h>
-#include "kitchensink/internal/kithelpers.h"
+#include "kitchensink/internal/utils/kithelpers.h"
static const char * const font_mime[] = {
"application/x-font-ttf",
diff --git a/src/internal/kitringbuffer.c b/src/internal/utils/kitringbuffer.c
index 1711d52..70fd24f 100644
--- a/src/internal/kitringbuffer.c
+++ b/src/internal/utils/kitringbuffer.c
@@ -1,17 +1,17 @@
/*
* Ringbuffer
*
- * Copyright (c) 2016, Tuomas Virtanen
+ * Copyright (c) 2017, Tuomas Virtanen
* license: MIT; see LICENSE for details.
*/
-#include "kitchensink/internal/kitringbuffer.h"
-
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <assert.h>
+#include "kitchensink/internal/utils/kitringbuffer.h"
+
/**
* Creates a new ringbuffer with the given size.
* @param size Size for the new ringbuffer
diff --git a/src/internal/kitvideo.c b/src/internal/video/kitvideo.c
index 079d650..ef0d568 100644
--- a/src/internal/kitvideo.c
+++ b/src/internal/video/kitvideo.c
@@ -6,13 +6,13 @@
#include "kitchensink/kiterror.h"
#include "kitchensink/internal/kitdecoder.h"
-#include "kitchensink/internal/kithelpers.h"
-#include "kitchensink/internal/kitbuffer.h"
-#include "kitchensink/internal/kitvideo.h"
-#include "kitchensink/internal/kitlog.h"
+#include "kitchensink/internal/utils/kithelpers.h"
+#include "kitchensink/internal/utils/kitbuffer.h"
+#include "kitchensink/internal/video/kitvideo.h"
+#include "kitchensink/internal/utils/kitlog.h"
-#define KIT_VIDEO_OUT_SIZE 1
-#define VIDEO_SYNC_THRESHOLD 0.01
+#define KIT_VIDEO_OUT_SIZE 2
+#define KIT_VIDEO_SYNC_THRESHOLD 0.01
typedef struct Kit_VideoDecoder {
Kit_VideoFormat *format;
@@ -50,7 +50,7 @@ static void _FindPixelFormat(enum AVPixelFormat fmt, unsigned int *out_fmt) {
*out_fmt = SDL_PIXELFORMAT_UYVY;
break;
default:
- *out_fmt = SDL_PIXELFORMAT_ABGR8888;
+ *out_fmt = SDL_PIXELFORMAT_RGBA32;
break;
}
}
@@ -61,8 +61,8 @@ static enum AVPixelFormat _FindAVPixelFormat(unsigned int fmt) {
case SDL_PIXELFORMAT_YV12: return AV_PIX_FMT_YUV420P;
case SDL_PIXELFORMAT_YUY2: return AV_PIX_FMT_YUYV422;
case SDL_PIXELFORMAT_UYVY: return AV_PIX_FMT_UYVY422;
- case SDL_PIXELFORMAT_ARGB8888: return AV_PIX_FMT_BGRA;
- case SDL_PIXELFORMAT_ABGR8888: return AV_PIX_FMT_RGBA;
+ case SDL_PIXELFORMAT_ARGB32: return AV_PIX_FMT_BGRA;
+ case SDL_PIXELFORMAT_RGBA32: return AV_PIX_FMT_RGBA;
default:
return AV_PIX_FMT_NONE;
}
@@ -81,6 +81,7 @@ static int dec_decode_video_cb(Kit_Decoder *dec, AVPacket *in_packet) {
Kit_VideoDecoder *video_dec = dec->userdata;
int frame_finished;
+
while(in_packet->size > 0) {
int len = avcodec_decode_video2(dec->codec_ctx, video_dec->scratch_frame, &frame_finished, in_packet);
@@ -92,12 +93,12 @@ static int dec_decode_video_cb(Kit_Decoder *dec, AVPacket *in_packet) {
// Target frame
AVFrame *out_frame = av_frame_alloc();
av_image_alloc(
- out_frame->data,
- out_frame->linesize,
- dec->codec_ctx->width,
- dec->codec_ctx->height,
- _FindAVPixelFormat(video_dec->format->format),
- 1);
+ out_frame->data,
+ out_frame->linesize,
+ dec->codec_ctx->width,
+ dec->codec_ctx->height,
+ _FindAVPixelFormat(video_dec->format->format),
+ 1);
// Scale from source format to target format, don't touch the size
sws_scale(
@@ -109,12 +110,9 @@ static int dec_decode_video_cb(Kit_Decoder *dec, AVPacket *in_packet) {
out_frame->data,
out_frame->linesize);
- // Get pts
- double pts = 0;
- if(in_packet->pts != AV_NOPTS_VALUE) {
- pts = av_frame_get_best_effort_timestamp(video_dec->scratch_frame);
- pts *= av_q2d(dec->format_ctx->streams[dec->stream_index]->time_base);
- }
+ // Get presentation timestamp
+ double pts = av_frame_get_best_effort_timestamp(video_dec->scratch_frame);
+ pts *= av_q2d(dec->format_ctx->streams[dec->stream_index]->time_base);
// Lock, write to audio buffer, unlock
Kit_VideoPacket *out_packet = _CreateVideoPacket(out_frame, pts);
@@ -177,7 +175,7 @@ Kit_Decoder* Kit_CreateVideoDecoder(const Kit_Source *src, Kit_VideoFormat *form
goto exit_2;
}
- // Create scaler
+ // Create scaler for handling format changes
video_dec->sws = sws_getContext(
dec->codec_ctx->width, // Source w
dec->codec_ctx->height, // Source h
@@ -185,9 +183,8 @@ Kit_Decoder* Kit_CreateVideoDecoder(const Kit_Source *src, Kit_VideoFormat *form
dec->codec_ctx->width, // Target w
dec->codec_ctx->height, // Target h
_FindAVPixelFormat(format->format), // Target fmt
- SWS_BICUBIC,
+ SWS_BILINEAR,
NULL, NULL, NULL);
-
if(video_dec->sws == NULL) {
Kit_SetError("Unable to initialize video converter context");
goto exit_3;
@@ -212,6 +209,7 @@ exit_0:
int Kit_GetVideoDecoderData(Kit_Decoder *dec, SDL_Texture *texture) {
assert(dec != NULL);
+ assert(texture != NULL);
Kit_VideoPacket *packet = Kit_PeekDecoderOutput(dec);
if(packet == NULL) {
@@ -222,10 +220,10 @@ int Kit_GetVideoDecoderData(Kit_Decoder *dec, SDL_Texture *texture) {
double sync_ts = _GetSystemTime() - dec->clock_sync;
// Check if we want the packet
- if(packet->pts > sync_ts + VIDEO_SYNC_THRESHOLD) {
+ if(packet->pts > sync_ts + KIT_VIDEO_SYNC_THRESHOLD) {
// Video is ahead, don't show yet.
return 0;
- } else if(packet->pts < sync_ts - VIDEO_SYNC_THRESHOLD) {
+ } else if(packet->pts < sync_ts - KIT_VIDEO_SYNC_THRESHOLD) {
// Video is lagging, skip until we find a good PTS to continue from.
while(packet != NULL) {
Kit_AdvanceDecoderOutput(dec);
@@ -236,7 +234,7 @@ int Kit_GetVideoDecoderData(Kit_Decoder *dec, SDL_Texture *texture) {
} else {
dec->clock_pos = packet->pts;
}
- if(packet->pts > sync_ts - VIDEO_SYNC_THRESHOLD) {
+ if(packet->pts > sync_ts - KIT_VIDEO_SYNC_THRESHOLD) {
break;
}
}
@@ -268,8 +266,8 @@ int Kit_GetVideoDecoderData(Kit_Decoder *dec, SDL_Texture *texture) {
// Advance buffer, and free the decoded frame.
Kit_AdvanceDecoderOutput(dec);
- free_out_video_packet_cb(packet);
dec->clock_pos = packet->pts;
+ free_out_video_packet_cb(packet);
return 0;
}
diff --git a/src/kiterror.c b/src/kiterror.c
index 2c87414..9ed0081 100644
--- a/src/kiterror.c
+++ b/src/kiterror.c
@@ -1,11 +1,11 @@
-#include "kitchensink/kitchensink.h"
-
#include <stdlib.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdbool.h>
#include <assert.h>
+#include "kitchensink/kitchensink.h"
+
#define KIT_ERRBUFSIZE 1024
static char _error_available = false;
diff --git a/src/kitlib.c b/src/kitlib.c
index 9ce1e27..2a2307b 100644
--- a/src/kitlib.c
+++ b/src/kitlib.c
@@ -1,11 +1,33 @@
+#include <assert.h>
+
+#include <libavformat/avformat.h>
+
#include "kitchensink/kitchensink.h"
#include "kitchensink/internal/kitlibstate.h"
-#include <libavformat/avformat.h>
+
+#ifdef USE_ASS
#include <ass/ass.h>
-#include <assert.h>
-// No-op
-void _libass_msg_callback(int level, const char *fmt, va_list va, void *data) {}
+static void _libass_msg_callback(int level, const char *fmt, va_list va, void *data) {}
+
+int Kit_InitASS(Kit_LibraryState *state) {
+ state->libass_handle = ass_library_init();
+ ass_set_message_cb(state->libass_handle, _libass_msg_callback, NULL);
+ return 0;
+}
+
+void Kit_CloseASS(Kit_LibraryState *state) {
+ ass_library_done(state->libass_handle);
+ state->libass_handle = NULL;
+}
+
+#else
+
+int Kit_InitASS(Kit_LibraryState *state) { return 1; }
+void Kit_CloseASS(Kit_LibraryState *state) {}
+
+#endif
+
int Kit_Init(unsigned int flags) {
Kit_LibraryState *state = Kit_GetLibraryState();
@@ -14,21 +36,17 @@ int Kit_Init(unsigned int flags) {
Kit_SetError("Kitchensink is already initialized.");
return 1;
}
+ av_register_all();
+
if(flags & KIT_INIT_NETWORK) {
avformat_network_init();
+ state->init_flags |= KIT_INIT_NETWORK;
}
- if(flags & KIT_INIT_FORMATS) {
- av_register_all();
+ if(flags & KIT_INIT_ASS) {
+ if(Kit_InitASS(state) == 0) {
+ state->init_flags |= KIT_INIT_ASS;
+ }
}
-
- state->init_flags = flags;
-
- // Init libass
- //state->libass_handle = ass_library_init();
-
- // Make libass message spam go away
- //ass_set_message_cb(state->libass_handle, _libass_msg_callback, NULL);
-
return 0;
}
@@ -38,9 +56,10 @@ void Kit_Quit() {
if(state->init_flags & KIT_INIT_NETWORK) {
avformat_network_deinit();
}
+ if(state->init_flags & KIT_INIT_ASS) {
+ Kit_CloseASS(state);
+ }
state->init_flags = 0;
-
- //ass_library_done(state->libass_handle);
}
void Kit_GetVersion(Kit_Version *version) {
diff --git a/src/kitplayer.c b/src/kitplayer.c
index 809a5e2..fceb233 100644
--- a/src/kitplayer.c
+++ b/src/kitplayer.c
@@ -1,39 +1,37 @@
+#include <assert.h>
+
+#include <SDL2/SDL.h>
+
#include "kitchensink/kitplayer.h"
#include "kitchensink/kiterror.h"
-#include "kitchensink/internal/kitlist.h"
#include "kitchensink/internal/kitlibstate.h"
-#include "kitchensink/internal/kitvideo.h"
-#include "kitchensink/internal/kitaudio.h"
-#include "kitchensink/internal/kitsubtitle.h"
-#include "kitchensink/internal/kithelpers.h"
-#include "kitchensink/internal/kitlog.h"
-
-#include <SDL2/SDL.h>
-#include <assert.h>
+#include "kitchensink/internal/video/kitvideo.h"
+#include "kitchensink/internal/audio/kitaudio.h"
+#include "kitchensink/internal/subtitle/kitsubtitle.h"
+#include "kitchensink/internal/utils/kithelpers.h"
+#include "kitchensink/internal/utils/kitlog.h"
// Return 0 if stream is good but nothing else to do for now
-// Return -1 if there is still work to be done
+// Return -1 if there may still work to be done
// Return 1 if there was an error or stream end
static int _DemuxStream(const Kit_Player *player) {
assert(player != NULL);
- Kit_Decoder *video_dec = player->video_dec;
- Kit_Decoder *audio_dec = player->audio_dec;
- //Kit_Decoder *subtitle_dec = player->subtitle_dec;
AVFormatContext *format_ctx = player->src->format_ctx;
+ Kit_Decoder *decoders[] = {
+ player->video_dec,
+ player->audio_dec,
+ player->subtitle_dec
+ };
- // If either buffer is full, just stop here for now.
+ // If any buffer is full, just stop here for now.
// Since we don't know what kind of data is going to come out of av_read_frame, we really
// want to make sure we are prepared for everything :)
- if(video_dec != NULL) {
- if(!Kit_CanWriteDecoderInput(video_dec)) {
- return 0;
- }
- }
- if(audio_dec != NULL) {
- if(!Kit_CanWriteDecoderInput(audio_dec)) {
+ for(int i = 0; i < 3; i++) {
+ if(decoders[i] == NULL)
+ continue;
+ if(!Kit_CanWriteDecoderInput(decoders[i]))
return 0;
- }
}
// Attempt to read frame. Just return here if it fails.
@@ -44,16 +42,18 @@ static int _DemuxStream(const Kit_Player *player) {
}
// Check if this is a packet we need to handle and pass it on
- if(video_dec != NULL && packet->stream_index == video_dec->stream_index) {
- Kit_WriteDecoderInput(video_dec, packet);
- }
- else if(audio_dec != NULL && packet->stream_index == audio_dec->stream_index) {
- Kit_WriteDecoderInput(audio_dec, packet);
- }
- else {
- av_packet_free(&packet);
+ for(int i = 0; i < 3; i++) {
+ if(decoders[i] == NULL)
+ continue;
+ if(decoders[i]->stream_index == packet->stream_index) {
+ Kit_WriteDecoderInput(decoders[i], packet);
+ return -1;
+ }
}
+ // We only get here if packet was not written to a decoder. IF that is the case,
+ // disregard and free the packet.
+ av_packet_free(&packet);
return -1;
}
@@ -92,7 +92,8 @@ static int _DecoderThread(void *ptr) {
// Run decoders for a bit
while(Kit_RunDecoder(player->video_dec) == 1);
while(Kit_RunDecoder(player->audio_dec) == 1);
-
+ while(Kit_RunDecoder(player->subtitle_dec) == 1);
+
// Free decoder thread lock.
SDL_UnlockMutex(player->dec_lock);
}
@@ -139,14 +140,14 @@ Kit_Player* Kit_CreatePlayer(const Kit_Source *src) {
// Decoder thread lock
player->dec_lock = SDL_CreateMutex();
if(player->dec_lock == NULL) {
- Kit_SetError("Unable to create a decoder thread: %s", SDL_GetError());
+ Kit_SetError("Unable to create a decoder thread lock mutex: %s", SDL_GetError());
goto error;
}
// Decoder thread
player->dec_thread = SDL_CreateThread(_DecoderThread, "Kit Decoder Thread", player);
if(player->dec_thread == NULL) {
- Kit_SetError("Unable to create a decoder thread lock mutex: %s", SDL_GetError());
+ Kit_SetError("Unable to create a decoder thread: %s", SDL_GetError());
goto error;
}
@@ -161,7 +162,7 @@ error:
void Kit_ClosePlayer(Kit_Player *player) {
if(player == NULL) return;
- // Kill the decoder thread and lock mutex
+ // Kill the decoder thread and mutex
player->state = KIT_CLOSED;
SDL_WaitThread(player->dec_thread, NULL);
SDL_DestroyMutex(player->dec_lock);
@@ -192,7 +193,7 @@ int Kit_GetVideoData(Kit_Player *player, SDL_Texture *texture) {
return Kit_GetVideoDecoderData(player->video_dec, texture);
}
-int Kit_GetAudioData(Kit_Player *player, unsigned char *buffer, int length, int cur_buf_len) {
+int Kit_GetAudioData(Kit_Player *player, unsigned char *buffer, int length) {
assert(player != NULL);
assert(buffer != NULL);
if(player->audio_dec == NULL) {
@@ -215,7 +216,7 @@ int Kit_GetAudioData(Kit_Player *player, unsigned char *buffer, int length, int
return Kit_GetAudioDecoderData(player->audio_dec, buffer, length);
}
-int Kit_GetSubtitleData(Kit_Player *player, SDL_Renderer *renderer) {
+int Kit_GetSubtitleData(Kit_Player *player, SDL_Texture *texture) {
assert(player != NULL);
if(player->subtitle_dec == NULL) {
return 0;
@@ -229,9 +230,7 @@ int Kit_GetSubtitleData(Kit_Player *player, SDL_Renderer *renderer) {
return 0;
}
-
-
- return 0;
+ return Kit_GetSubtitleDecoderData(player->subtitle_dec, texture);
}
void Kit_GetPlayerInfo(const Kit_Player *player, Kit_PlayerInfo *info) {
@@ -345,15 +344,15 @@ int Kit_PlayerSeek(Kit_Player *player, double seek_set) {
// Set source to timestamp
AVFormatContext *format_ctx = player->src->format_ctx;
seek_target = seek_set * AV_TIME_BASE;
- if(avformat_seek_file(format_ctx, -1, INT64_MIN, seek_target, seek_target, 0) < 0) {
+ if(avformat_seek_file(format_ctx, -1, seek_target, seek_target, seek_target, AVSEEK_FLAG_ANY) < 0) {
Kit_SetError("Unable to seek source");
+ SDL_UnlockMutex(player->dec_lock);
return 1;
} else {
_ChangeClockSync(player, position - seek_set);
Kit_ClearDecoderBuffers(player->video_dec);
Kit_ClearDecoderBuffers(player->audio_dec);
Kit_ClearDecoderBuffers(player->subtitle_dec);
- while(_DemuxStream(player) == -1);
}
// That's it. Unlock and continue.
diff --git a/src/kitsource.c b/src/kitsource.c
index c9c8f4c..9e47dcc 100644
--- a/src/kitsource.c
+++ b/src/kitsource.c
@@ -1,13 +1,13 @@
-#include "kitchensink/kitsource.h"
-#include "kitchensink/kiterror.h"
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavutil/opt.h>
-#include <stdlib.h>
-#include <string.h>
-#include <assert.h>
+#include "kitchensink/kitsource.h"
+#include "kitchensink/kiterror.h"
Kit_Source* Kit_CreateSourceFromUrl(const char *url) {
assert(url != NULL);
diff --git a/src/kitutils.c b/src/kitutils.c
index b618c07..1c62ddc 100644
--- a/src/kitutils.c
+++ b/src/kitutils.c
@@ -1,8 +1,8 @@
+#include <SDL2/SDL.h>
+
#include "kitchensink/kitutils.h"
#include "kitchensink/kitsource.h"
-#include <SDL2/SDL.h>
-
const char* Kit_GetSDLAudioFormatString(unsigned int type) {
switch(type) {
case AUDIO_S8: return "AUDIO_S8";