summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt2
-rw-r--r--examples/example_complex.c6
-rw-r--r--include/kitchensink/internal/kitdecoder.h5
-rw-r--r--include/kitchensink/internal/subtitle/kitsubtitle.h2
-rw-r--r--src/internal/audio/kitaudio.c82
-rw-r--r--src/internal/kitdecoder.c35
-rw-r--r--src/internal/subtitle/kitsubtitle.c15
-rw-r--r--src/internal/subtitle/renderers/kitsubass.c2
-rw-r--r--src/internal/video/kitvideo.c75
-rw-r--r--src/kitlib.c6
-rw-r--r--src/kitplayer.c11
11 files changed, 205 insertions, 36 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 0922eaa..56d511c 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -14,7 +14,7 @@ add_definitions(
)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall")
-set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -ggdb -Werror -fno-omit-frame-pointer -Wno-deprecated-declarations")
+set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -ggdb -Werror -fno-omit-frame-pointer")
set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} -ggdb -O2 -fno-omit-frame-pointer -DNDEBUG")
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -O2 -DNDEBUG")
set(CMAKE_C_FLAGS_MINSIZEREL "${CMAKE_C_FLAGS_MINSIZEREL} -Os -DNDEBUG")
diff --git a/examples/example_complex.c b/examples/example_complex.c
index aeda110..9f5d8aa 100644
--- a/examples/example_complex.c
+++ b/examples/example_complex.c
@@ -109,7 +109,11 @@ int main(int argc, char *argv[]) {
}
// Allow Kit to use more threads
- Kit_SetHint(KIT_HINT_THREAD_COUNT, SDL_GetCPUCount() <= 8 ? SDL_GetCPUCount() : 8);
+ Kit_SetHint(KIT_HINT_THREAD_COUNT, SDL_GetCPUCount());
+
+ // Lots of buffers for smooth playback (will eat up more memory, too).
+ Kit_SetHint(KIT_HINT_VIDEO_BUFFER_FRAMES, 5);
+ Kit_SetHint(KIT_HINT_AUDIO_BUFFER_FRAMES, 192);
// Open up the sourcefile.
// This can be a local file, network url, ...
diff --git a/include/kitchensink/internal/kitdecoder.h b/include/kitchensink/internal/kitdecoder.h
index 74134b0..17e1e4b 100644
--- a/include/kitchensink/internal/kitdecoder.h
+++ b/include/kitchensink/internal/kitdecoder.h
@@ -21,7 +21,7 @@ enum {
typedef struct Kit_Decoder Kit_Decoder;
-typedef void (*dec_decode_cb)(Kit_Decoder *dec, AVPacket *in_packet);
+typedef int (*dec_decode_cb)(Kit_Decoder *dec, AVPacket *in_packet);
typedef void (*dec_close_cb)(Kit_Decoder *dec);
typedef void (*dec_free_packet_cb)(void *packet);
@@ -61,8 +61,11 @@ KIT_LOCAL bool Kit_CanWriteDecoderInput(Kit_Decoder *dec);
KIT_LOCAL int Kit_WriteDecoderInput(Kit_Decoder *dec, AVPacket *packet);
KIT_LOCAL AVPacket* Kit_ReadDecoderInput(Kit_Decoder *dec);
KIT_LOCAL void Kit_ClearDecoderInput(Kit_Decoder *dec);
+KIT_LOCAL AVPacket* Kit_PeekDecoderInput(Kit_Decoder *dec);
+KIT_LOCAL void Kit_AdvanceDecoderInput(Kit_Decoder *dec);
KIT_LOCAL int Kit_WriteDecoderOutput(Kit_Decoder *dec, void *packet);
+KIT_LOCAL bool Kit_CanWriteDecoderOutput(Kit_Decoder *dec);
KIT_LOCAL void* Kit_PeekDecoderOutput(Kit_Decoder *dec);
KIT_LOCAL void* Kit_ReadDecoderOutput(Kit_Decoder *dec);
KIT_LOCAL void Kit_AdvanceDecoderOutput(Kit_Decoder *dec);
diff --git a/include/kitchensink/internal/subtitle/kitsubtitle.h b/include/kitchensink/internal/subtitle/kitsubtitle.h
index 8bb2a62..09aabec 100644
--- a/include/kitchensink/internal/subtitle/kitsubtitle.h
+++ b/include/kitchensink/internal/subtitle/kitsubtitle.h
@@ -9,7 +9,7 @@
KIT_LOCAL Kit_Decoder* Kit_CreateSubtitleDecoder(
const Kit_Source *src, int stream_index, int video_w, int video_h, int screen_w, int screen_h);
-KIT_LOCAL void Kit_GetSubtitleDecoderTexture(Kit_Decoder *dec, SDL_Texture *texture);
+KIT_LOCAL void Kit_GetSubtitleDecoderTexture(Kit_Decoder *dec, SDL_Texture *texture, double sync_ts);
KIT_LOCAL void Kit_SetSubtitleDecoderSize(Kit_Decoder *dec, int w, int h);
KIT_LOCAL int Kit_GetSubtitleDecoderInfo(
Kit_Decoder *dec, SDL_Texture *texture, SDL_Rect *sources, SDL_Rect *targets, int limit);
diff --git a/src/internal/audio/kitaudio.c b/src/internal/audio/kitaudio.c
index 3a534bb..4bc284d 100644
--- a/src/internal/audio/kitaudio.c
+++ b/src/internal/audio/kitaudio.c
@@ -104,9 +104,13 @@ static void free_out_audio_packet_cb(void *packet) {
free(p);
}
-static void dec_decode_audio_cb(Kit_Decoder *dec, AVPacket *in_packet) {
+#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(57, 48, 101)
+static int dec_decode_audio_cb(Kit_Decoder *dec, AVPacket *in_packet) {
assert(dec != NULL);
- assert(in_packet != NULL);
+
+ if(in_packet == NULL) {
+ return 0;
+ }
Kit_AudioDecoder *audio_dec = dec->userdata;
int frame_finished;
@@ -117,13 +121,13 @@ static void dec_decode_audio_cb(Kit_Decoder *dec, AVPacket *in_packet) {
int dst_bufsize;
double pts;
unsigned char **dst_data;
- Kit_AudioPacket *out_packet;
+ Kit_AudioPacket *out_packet = NULL;
// Decode as long as there is data
while(in_packet->size > 0) {
len = avcodec_decode_audio4(dec->codec_ctx, audio_dec->scratch_frame, &frame_finished, in_packet);
if(len < 0) {
- return;
+ return 0;
}
if(frame_finished) {
@@ -175,7 +179,77 @@ static void dec_decode_audio_cb(Kit_Decoder *dec, AVPacket *in_packet) {
in_packet->size -= len;
in_packet->data += len;
}
+ return 0;
+}
+#else
+static int dec_decode_audio_cb(Kit_Decoder *dec, AVPacket *in_packet) {
+ assert(dec != NULL);
+ assert(in_packet != NULL);
+
+ Kit_AudioDecoder *audio_dec = dec->userdata;
+ int ret;
+ int len;
+ int dst_linesize;
+ int dst_nb_samples;
+ int dst_bufsize;
+ double pts;
+ unsigned char **dst_data;
+ Kit_AudioPacket *out_packet = NULL;
+
+ // Write packet to the decoder for handling.
+ ret = avcodec_send_packet(dec->codec_ctx, in_packet);
+ if(ret < 0) {
+ return 1;
+ }
+
+ // Pull decoded frames out when ready and if we have room in decoder output buffer
+ while(!ret && Kit_CanWriteDecoderOutput(dec)) {
+ ret = avcodec_receive_frame(dec->codec_ctx, audio_dec->scratch_frame);
+ if(!ret) {
+ dst_nb_samples = av_rescale_rnd(
+ audio_dec->scratch_frame->nb_samples,
+ dec->output.samplerate, // Target samplerate
+ dec->codec_ctx->sample_rate, // Source samplerate
+ AV_ROUND_UP);
+
+ av_samples_alloc_array_and_samples(
+ &dst_data,
+ &dst_linesize,
+ dec->output.channels,
+ dst_nb_samples,
+ _FindAVSampleFormat(dec->output.format),
+ 0);
+
+ len = swr_convert(
+ audio_dec->swr,
+ dst_data,
+ audio_dec->scratch_frame->nb_samples,
+ (const unsigned char **)audio_dec->scratch_frame->extended_data,
+ audio_dec->scratch_frame->nb_samples);
+
+ dst_bufsize = av_samples_get_buffer_size(
+ &dst_linesize,
+ dec->output.channels,
+ len,
+ _FindAVSampleFormat(dec->output.format), 1);
+
+ // Get presentation timestamp
+ pts = audio_dec->scratch_frame->best_effort_timestamp;
+ pts *= av_q2d(dec->format_ctx->streams[dec->stream_index]->time_base);
+
+ // Lock, write to audio buffer, unlock
+ out_packet = _CreateAudioPacket(
+ (char*)dst_data[0], (size_t)dst_bufsize, pts);
+ Kit_WriteDecoderOutput(dec, out_packet);
+
+ // Free temps
+ av_freep(&dst_data[0]);
+ av_freep(&dst_data);
+ }
+ }
+ return 0;
}
+#endif
static void dec_close_audio_cb(Kit_Decoder *dec) {
if(dec == NULL) return;
diff --git a/src/internal/kitdecoder.c b/src/internal/kitdecoder.c
index b4a69e6..b1753c1 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 256
+#define BUFFER_IN_SIZE 384
static void free_in_video_packet_cb(void *packet) {
av_packet_free((AVPacket**)&packet);
@@ -156,17 +156,18 @@ int Kit_RunDecoder(Kit_Decoder *dec) {
}
// Then, see if we have incoming data
- in_packet = Kit_ReadDecoderInput(dec);
+ in_packet = Kit_PeekDecoderInput(dec);
if(in_packet == NULL) {
return 0;
}
// Run decoder with incoming packet
- dec->dec_decode(dec, in_packet);
-
- // Free raw packet before returning
- av_packet_free(&in_packet);
- return 1;
+ if(dec->dec_decode(dec, in_packet) == 0) {
+ Kit_AdvanceDecoderInput(dec);
+ av_packet_free(&in_packet);
+ return 1;
+ }
+ return 0;
}
// ---- Information API ----
@@ -228,6 +229,16 @@ AVPacket* Kit_ReadDecoderInput(Kit_Decoder *dec) {
return Kit_ReadBuffer(dec->buffer[KIT_DEC_BUF_IN]);
}
+AVPacket* Kit_PeekDecoderInput(Kit_Decoder *dec) {
+ assert(dec != NULL);
+ return Kit_PeekBuffer(dec->buffer[KIT_DEC_BUF_IN]);
+}
+
+void Kit_AdvanceDecoderInput(Kit_Decoder *dec) {
+ assert(dec != NULL);
+ Kit_AdvanceBuffer(dec->buffer[KIT_DEC_BUF_IN]);
+}
+
void Kit_ClearDecoderInput(Kit_Decoder *dec) {
Kit_ClearBuffer(dec->buffer[KIT_DEC_BUF_IN]);
}
@@ -271,6 +282,16 @@ void* Kit_ReadDecoderOutput(Kit_Decoder *dec) {
return ret;
}
+bool Kit_CanWriteDecoderOutput(Kit_Decoder *dec) {
+ assert(dec != NULL);
+ bool ret = false;
+ if(SDL_LockMutex(dec->output_lock) == 0) {
+ ret = !Kit_IsBufferFull(dec->buffer[KIT_DEC_BUF_OUT]);
+ SDL_UnlockMutex(dec->output_lock);
+ }
+ return ret;
+}
+
void Kit_ForEachDecoderOutput(Kit_Decoder *dec, Kit_ForEachItemCallback cb, void *userdata) {
assert(dec != NULL);
if(SDL_LockMutex(dec->output_lock) == 0) {
diff --git a/src/internal/subtitle/kitsubtitle.c b/src/internal/subtitle/kitsubtitle.c
index 417b338..024179e 100644
--- a/src/internal/subtitle/kitsubtitle.c
+++ b/src/internal/subtitle/kitsubtitle.c
@@ -29,9 +29,12 @@ static void free_out_subtitle_packet_cb(void *packet) {
Kit_FreeSubtitlePacket((Kit_SubtitlePacket*)packet);
}
-static void dec_decode_subtitle_cb(Kit_Decoder *dec, AVPacket *in_packet) {
+static int dec_decode_subtitle_cb(Kit_Decoder *dec, AVPacket *in_packet) {
assert(dec != NULL);
- assert(in_packet != NULL);
+
+ if(in_packet == NULL) {
+ return 0;
+ }
Kit_SubtitleDecoder *subtitle_dec = dec->userdata;
double pts;
@@ -43,7 +46,7 @@ static void dec_decode_subtitle_cb(Kit_Decoder *dec, AVPacket *in_packet) {
if(in_packet->size > 0) {
len = avcodec_decode_subtitle2(dec->codec_ctx, &subtitle_dec->scratch_frame, &frame_finished, in_packet);
if(len < 0) {
- return;
+ return 0;
}
if(frame_finished) {
@@ -70,6 +73,7 @@ static void dec_decode_subtitle_cb(Kit_Decoder *dec, AVPacket *in_packet) {
avsubtitle_free(&subtitle_dec->scratch_frame);
}
}
+ return 0;
}
static void dec_close_subtitle_cb(Kit_Decoder *dec) {
@@ -173,14 +177,11 @@ void Kit_SetSubtitleDecoderSize(Kit_Decoder *dec, int screen_w, int screen_h) {
Kit_SetSubtitleRendererSize(subtitle_dec->renderer, screen_w, screen_h);
}
-void Kit_GetSubtitleDecoderTexture(Kit_Decoder *dec, SDL_Texture *texture) {
+void Kit_GetSubtitleDecoderTexture(Kit_Decoder *dec, SDL_Texture *texture, double sync_ts) {
assert(dec != NULL);
assert(texture != NULL);
Kit_SubtitleDecoder *subtitle_dec = dec->userdata;
- double sync_ts = _GetSystemTime() - dec->clock_sync;
-
- // Tell the renderer to render content to atlas
Kit_GetSubtitleRendererData(subtitle_dec->renderer, subtitle_dec->atlas, texture, sync_ts);
}
diff --git a/src/internal/subtitle/renderers/kitsubass.c b/src/internal/subtitle/renderers/kitsubass.c
index 505d80f..7dfb31b 100644
--- a/src/internal/subtitle/renderers/kitsubass.c
+++ b/src/internal/subtitle/renderers/kitsubass.c
@@ -88,7 +88,7 @@ static int ren_get_ass_data_cb(Kit_SubtitleRenderer *ren, Kit_TextureAtlas *atla
SDL_Surface *dst = NULL;
ASS_Image *src = NULL;
int change = 0;
- unsigned int now = current_pts * 1000;
+ long long now = current_pts * 1000;
if(Kit_LockDecoderOutput(ren->dec) == 0) {
// Tell ASS to render some images
diff --git a/src/internal/video/kitvideo.c b/src/internal/video/kitvideo.c
index 568c178..1f2bed9 100644
--- a/src/internal/video/kitvideo.c
+++ b/src/internal/video/kitvideo.c
@@ -93,21 +93,25 @@ static void free_out_video_packet_cb(void *packet) {
free(p);
}
-static void dec_decode_video_cb(Kit_Decoder *dec, AVPacket *in_packet) {
+#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(57, 48, 101)
+static int dec_decode_video_cb(Kit_Decoder *dec, AVPacket *in_packet) {
assert(dec != NULL);
- assert(in_packet != NULL);
+
+ if(in_packet == NULL) {
+ return 0;
+ }
Kit_VideoDecoder *video_dec = dec->userdata;
- AVFrame *out_frame;
+ AVFrame *out_frame = NULL;
+ Kit_VideoPacket *out_packet = NULL;
int frame_finished;
int len;
double pts;
- Kit_VideoPacket *out_packet;
while(in_packet->size > 0) {
len = avcodec_decode_video2(dec->codec_ctx, video_dec->scratch_frame, &frame_finished, in_packet);
if(len < 0) {
- return;
+ return 0;
}
if(frame_finished) {
@@ -146,7 +150,68 @@ static void dec_decode_video_cb(Kit_Decoder *dec, AVPacket *in_packet) {
in_packet->size -= len;
in_packet->data += len;
}
+
+ return 0;
}
+#else
+static void dec_read_video(Kit_Decoder *dec) {
+ Kit_VideoDecoder *video_dec = dec->userdata;
+ AVFrame *out_frame = NULL;
+ Kit_VideoPacket *out_packet = NULL;
+ double pts;
+ int ret = 0;
+
+ while(!ret && Kit_CanWriteDecoderOutput(dec)) {
+ ret = avcodec_receive_frame(dec->codec_ctx, video_dec->scratch_frame);
+ if(!ret) {
+ out_frame = av_frame_alloc();
+ av_image_alloc(
+ out_frame->data,
+ out_frame->linesize,
+ dec->codec_ctx->width,
+ dec->codec_ctx->height,
+ _FindAVPixelFormat(dec->output.format),
+ 1);
+
+ // Scale from source format to target format, don't touch the size
+ sws_scale(
+ video_dec->sws,
+ (const unsigned char * const *)video_dec->scratch_frame->data,
+ video_dec->scratch_frame->linesize,
+ 0,
+ dec->codec_ctx->height,
+ out_frame->data,
+ out_frame->linesize);
+
+ // Get presentation timestamp
+ pts = video_dec->scratch_frame->best_effort_timestamp;
+ pts *= av_q2d(dec->format_ctx->streams[dec->stream_index]->time_base);
+
+ // Lock, write to audio buffer, unlock
+ out_packet = _CreateVideoPacket(out_frame, pts);
+ Kit_WriteDecoderOutput(dec, out_packet);
+ }
+ }
+}
+
+static int dec_decode_video_cb(Kit_Decoder *dec, AVPacket *in_packet) {
+ assert(dec != NULL);
+ assert(in_packet != NULL);
+
+ // Try to clear the buffer first. We might have too much content in the ffmpeg buffer,
+ /// so we want to clear it of outgoing data if we can.
+ dec_read_video(dec);
+
+ // Write packet to the decoder for handling.
+ if(avcodec_send_packet(dec->codec_ctx, in_packet) < 0) {
+ return 1;
+ }
+
+ // Some input data was put in succesfully, so try again to get frames.
+ dec_read_video(dec);
+ return 0;
+}
+#endif
static void dec_close_video_cb(Kit_Decoder *dec) {
if(dec == NULL) return;
diff --git a/src/kitlib.c b/src/kitlib.c
index 9cfd13e..e823c52 100644
--- a/src/kitlib.c
+++ b/src/kitlib.c
@@ -94,13 +94,13 @@ void Kit_SetHint(Kit_HintType type, int value) {
state->font_hinting = max(min(value, KIT_FONT_HINTING_COUNT), 0);
break;
case KIT_HINT_VIDEO_BUFFER_FRAMES:
- state->video_buf_frames = min(value, 1);
+ state->video_buf_frames = max(value, 1);
break;
case KIT_HINT_AUDIO_BUFFER_FRAMES:
- state->audio_buf_frames = min(value, 1);
+ state->audio_buf_frames = max(value, 1);
break;
case KIT_HINT_SUBTITLE_BUFFER_FRAMES:
- state->subtitle_buf_frames = min(value, 1);
+ state->subtitle_buf_frames = max(value, 1);
break;
}
}
diff --git a/src/kitplayer.c b/src/kitplayer.c
index 0baf57b..f852e48 100644
--- a/src/kitplayer.c
+++ b/src/kitplayer.c
@@ -310,14 +310,15 @@ int Kit_GetPlayerSubtitleData(Kit_Player *player, SDL_Texture *texture, SDL_Rect
assert(targets != NULL);
assert(limit >= 0);
- Kit_Decoder *dec = player->decoders[KIT_SUBTITLE_DEC];
- if(dec == NULL) {
+ Kit_Decoder *sub_dec = player->decoders[KIT_SUBTITLE_DEC];
+ Kit_Decoder *video_dec = player->decoders[KIT_VIDEO_DEC];
+ if(sub_dec == NULL || video_dec == NULL) {
return 0;
}
// If paused, just return the current items
if(player->state == KIT_PAUSED) {
- return Kit_GetSubtitleDecoderInfo(dec, texture, sources, targets, limit);
+ return Kit_GetSubtitleDecoderInfo(sub_dec, texture, sources, targets, limit);
}
// If stopped, do nothing.
@@ -326,8 +327,8 @@ int Kit_GetPlayerSubtitleData(Kit_Player *player, SDL_Texture *texture, SDL_Rect
}
// Refresh texture, then refresh rects and return number of items in the texture.
- Kit_GetSubtitleDecoderTexture(dec, texture);
- return Kit_GetSubtitleDecoderInfo(dec, texture, sources, targets, limit);
+ Kit_GetSubtitleDecoderTexture(sub_dec, texture, video_dec->clock_pos);
+ return Kit_GetSubtitleDecoderInfo(sub_dec, texture, sources, targets, limit);
}
void Kit_GetPlayerInfo(const Kit_Player *player, Kit_PlayerInfo *info) {