diff options
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"; |