summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--examples/example_audio.c6
-rw-r--r--examples/example_video.c94
-rw-r--r--include/kitchensink/kitchensink.h1
-rw-r--r--include/kitchensink/kitplayer.h95
-rw-r--r--include/kitchensink/kitsource.h32
-rw-r--r--include/kitchensink/kitutils.h18
-rw-r--r--src/kitbuffer.c5
-rw-r--r--src/kitchensink.c4
-rw-r--r--src/kitplayer.c444
-rw-r--r--src/kitsource.c6
-rw-r--r--src/kitutils.c73
11 files changed, 532 insertions, 246 deletions
diff --git a/examples/example_audio.c b/examples/example_audio.c
index 7066951..1701017 100644
--- a/examples/example_audio.c
+++ b/examples/example_audio.c
@@ -51,7 +51,11 @@ int main(int argc, char *argv[]) {
return 1;
}
- Kit_Init(KIT_INIT_FORMATS|KIT_INIT_NETWORK);
+ err = Kit_Init(KIT_INIT_FORMATS|KIT_INIT_NETWORK);
+ if(err != 0) {
+ fprintf(stderr, "Unable to initialize Kitchensink: %s", Kit_GetError());
+ return 1;
+ }
// Open up the sourcefile.
src = Kit_CreateSourceFromUrl(filename);
diff --git a/examples/example_video.c b/examples/example_video.c
index 4a405cd..f469b6a 100644
--- a/examples/example_video.c
+++ b/examples/example_video.c
@@ -12,58 +12,6 @@
#define AUDIOBUFFER_SIZE (16384)
-const char *stream_types[] = {
- "KIT_STREAMTYPE_UNKNOWN",
- "KIT_STREAMTYPE_VIDEO",
- "KIT_STREAMTYPE_AUDIO",
- "KIT_STREAMTYPE_DATA",
- "KIT_STREAMTYPE_SUBTITLE",
- "KIT_STREAMTYPE_ATTACHMENT"
-};
-
-const char* get_tex_type(unsigned int type) {
- switch(type) {
- case SDL_PIXELFORMAT_UNKNOWN: return "SDL_PIXELFORMAT_UNKNOWN";
- case SDL_PIXELFORMAT_INDEX1LSB: return "SDL_PIXELFORMAT_INDEX1LSB";
- case SDL_PIXELFORMAT_INDEX1MSB: return "SDL_PIXELFORMAT_INDEX1MSB";
- case SDL_PIXELFORMAT_INDEX4LSB: return "SDL_PIXELFORMAT_INDEX4LSB";
- case SDL_PIXELFORMAT_INDEX4MSB: return "SDL_PIXELFORMAT_INDEX4MSB";
- case SDL_PIXELFORMAT_INDEX8: return "SDL_PIXELFORMAT_INDEX8";
- case SDL_PIXELFORMAT_RGB332: return "SDL_PIXELFORMAT_RGB332";
- case SDL_PIXELFORMAT_RGB444: return "SDL_PIXELFORMAT_RGB444";
- case SDL_PIXELFORMAT_RGB555: return "SDL_PIXELFORMAT_RGB555";
- case SDL_PIXELFORMAT_BGR555: return "SDL_PIXELFORMAT_BGR555";
- case SDL_PIXELFORMAT_ARGB4444: return "SDL_PIXELFORMAT_ARGB4444";
- case SDL_PIXELFORMAT_RGBA4444: return "SDL_PIXELFORMAT_RGBA4444";
- case SDL_PIXELFORMAT_ABGR4444: return "SDL_PIXELFORMAT_ABGR4444";
- case SDL_PIXELFORMAT_BGRA4444: return "SDL_PIXELFORMAT_BGRA4444";
- case SDL_PIXELFORMAT_ARGB1555: return "SDL_PIXELFORMAT_ARGB1555";
- case SDL_PIXELFORMAT_RGBA5551: return "SDL_PIXELFORMAT_RGBA5551";
- case SDL_PIXELFORMAT_ABGR1555: return "SDL_PIXELFORMAT_ABGR1555";
- case SDL_PIXELFORMAT_BGRA5551: return "SDL_PIXELFORMAT_BGRA5551";
- case SDL_PIXELFORMAT_RGB565: return "SDL_PIXELFORMAT_RGB565";
- case SDL_PIXELFORMAT_BGR565: return "SDL_PIXELFORMAT_BGR565";
- case SDL_PIXELFORMAT_RGB24: return "SDL_PIXELFORMAT_RGB24";
- case SDL_PIXELFORMAT_BGR24: return "SDL_PIXELFORMAT_BGR24";
- case SDL_PIXELFORMAT_RGB888: return "SDL_PIXELFORMAT_RGB888";
- case SDL_PIXELFORMAT_RGBX8888: return "SDL_PIXELFORMAT_RGBX8888";
- case SDL_PIXELFORMAT_BGR888: return "SDL_PIXELFORMAT_BGR888";
- case SDL_PIXELFORMAT_BGRX8888: return "SDL_PIXELFORMAT_BGRX8888";
- case SDL_PIXELFORMAT_ARGB8888: return "SDL_PIXELFORMAT_ARGB8888";
- case SDL_PIXELFORMAT_RGBA8888: return "SDL_PIXELFORMAT_RGBA8888";
- case SDL_PIXELFORMAT_ABGR8888: return "SDL_PIXELFORMAT_ABGR8888";
- case SDL_PIXELFORMAT_BGRA8888: return "SDL_PIXELFORMAT_BGRA8888";
- case SDL_PIXELFORMAT_ARGB2101010: return "SDL_PIXELFORMAT_ARGB2101010";
- case SDL_PIXELFORMAT_YV12: return "SDL_PIXELFORMAT_YV12";
- case SDL_PIXELFORMAT_IYUV: return "SDL_PIXELFORMAT_IYUV";
- case SDL_PIXELFORMAT_YUY2: return "SDL_PIXELFORMAT_YUY2";
- case SDL_PIXELFORMAT_UYVY: return "SDL_PIXELFORMAT_UYVY";
- case SDL_PIXELFORMAT_YVYU: return "SDL_PIXELFORMAT_YVYU";
- default:
- return "unknown";
- }
-}
-
int main(int argc, char *argv[]) {
int err = 0, ret = 0;
const char* filename = NULL;
@@ -94,16 +42,34 @@ int main(int argc, char *argv[]) {
// Init SDL
err = SDL_Init(SDL_INIT_VIDEO|SDL_INIT_AUDIO);
+ if(err != 0) {
+ fprintf(stderr, "Unable to initialize SDL2!\n");
+ return 1;
+ }
+
+ // Create a resizable window.
window = SDL_CreateWindow("Example Player", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 1280, 720, SDL_WINDOW_RESIZABLE);
+ if(window == NULL) {
+ fprintf(stderr, "Unable to create a new window!\n");
+ return 1;
+ }
+
+ // Create an accelerated renderer. Enable vsync, so we don't need to play around with SDL_Delay.
renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED|SDL_RENDERER_PRESENTVSYNC);
- Kit_Init(KIT_INIT_FORMATS|KIT_INIT_NETWORK);
+ if(window == NULL) {
+ fprintf(stderr, "Unable to create a renderer!\n");
+ return 1;
+ }
- if(err != 0 || window == NULL || renderer == NULL) {
- fprintf(stderr, "Unable to initialize SDL!\n");
+ // Initialize Kitchensink with network support and all formats.
+ err = Kit_Init(KIT_INIT_FORMATS|KIT_INIT_NETWORK);
+ if(err != 0) {
+ fprintf(stderr, "Unable to initialize Kitchensink: %s", Kit_GetError());
return 1;
}
// Open up the sourcefile.
+ // This can be a local file, network url, ...
src = Kit_CreateSourceFromUrl(filename);
if(src == NULL) {
fprintf(stderr, "Unable to load file '%s': %s\n", filename, Kit_GetError());
@@ -119,7 +85,7 @@ int main(int argc, char *argv[]) {
fprintf(stderr, "Unable to fetch stream #%d information: %s.\n", i, Kit_GetError());
return 1;
}
- fprintf(stderr, " * Stream #%d: %s\n", i, stream_types[sinfo.type]);
+ fprintf(stderr, " * Stream #%d: %s\n", i, Kit_GetKitStreamTypeString(sinfo.type));
}
// Create the player
@@ -151,6 +117,7 @@ int main(int argc, char *argv[]) {
pinfo.vcodec_name,
pinfo.video.width,
pinfo.video.height);
+ fprintf(stderr, "Duration: %f seconds\n", Kit_GetPlayerDuration(player));
// Init audio
SDL_memset(&wanted_spec, 0, sizeof(wanted_spec));
@@ -160,8 +127,11 @@ int main(int argc, char *argv[]) {
audio_dev = SDL_OpenAudioDevice(NULL, 0, &wanted_spec, &audio_spec, 0);
SDL_PauseAudioDevice(audio_dev, 0);
+ // 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));
+
// Initialize texture
- fprintf(stderr, "Texture type: %s\n", get_tex_type(pinfo.video.format));
SDL_Texture *tex = SDL_CreateTexture(
renderer,
pinfo.video.format,
@@ -203,6 +173,16 @@ int main(int argc, char *argv[]) {
if(event.key.keysym.sym == SDLK_e) {
Kit_PlayerStop(player);
}
+ if(event.key.keysym.sym == SDLK_RIGHT) {
+ if(Kit_PlayerSeek(player, 10.0) != 0) {
+ fprintf(stderr, "%s\n", Kit_GetError());
+ }
+ }
+ if(event.key.keysym.sym == SDLK_LEFT) {
+ if(Kit_PlayerSeek(player, -10.0) != 0) {
+ fprintf(stderr, "%s\n", Kit_GetError());
+ }
+ }
break;
case SDL_QUIT:
run = false;
diff --git a/include/kitchensink/kitchensink.h b/include/kitchensink/kitchensink.h
index 3120db7..0d40442 100644
--- a/include/kitchensink/kitchensink.h
+++ b/include/kitchensink/kitchensink.h
@@ -4,6 +4,7 @@
#include "kitchensink/kiterror.h"
#include "kitchensink/kitsource.h"
#include "kitchensink/kitplayer.h"
+#include "kitchensink/kitutils.h"
#include "kitchensink/kitconfig.h"
#ifdef __cplusplus
diff --git a/include/kitchensink/kitplayer.h b/include/kitchensink/kitplayer.h
index 4d99e26..a0f97ad 100644
--- a/include/kitchensink/kitplayer.h
+++ b/include/kitchensink/kitplayer.h
@@ -17,55 +17,70 @@ extern "C" {
#define KIT_CODECNAMEMAX 128
typedef enum Kit_PlayerState {
- KIT_STOPPED = 0,
- KIT_PLAYING,
- KIT_PAUSED,
- KIT_CLOSED
+ 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_PlayerState;
typedef struct Kit_AudioFormat {
- bool is_enabled; // Is stream enabled
- unsigned int format;
- bool is_signed;
- int bytes;
- int samplerate;
- int channels;
+ bool is_enabled; ///< Is stream enabled
+ unsigned int format; ///< SDL Audio Format
+ bool is_signed; ///< Signedness
+ int bytes; ///< Bytes per sample per channel
+ int samplerate; ///< Sampling rate
+ int channels; ///< Channels
} Kit_AudioFormat;
typedef struct Kit_VideoFormat {
- bool is_enabled; // Is stream enabled
- unsigned int format;
- int width;
- int height;
+ bool is_enabled; ///<Is stream enabled
+ unsigned int format; ///< SDL Pixel Format
+ int width; ///< Width in pixels
+ int height; ///< Height in pixels
} Kit_VideoFormat;
typedef struct Kit_Player {
- Kit_PlayerState state;
- Kit_VideoFormat vformat;
- Kit_AudioFormat aformat;
- double clock_sync; // Clock sync point
- double pause_start; // Timestamp of pause beginning
- SDL_Thread *dec_thread;
- SDL_mutex *vmutex;
- SDL_mutex *amutex;
- void *abuffer;
- void *vbuffer;
- void *vcodec_ctx;
- void *acodec_ctx;
- void *tmp_vframe;
- void *tmp_aframe;
- void *swr;
- void *sws;
- const Kit_Source *src;
+ // Local state
+ Kit_PlayerState state; ///< Playback state
+ Kit_VideoFormat vformat; ///< Video format information
+ Kit_AudioFormat aformat; ///< Audio format information
+
+ // Synchronization
+ double clock_sync; ///< Clock sync point
+ double pause_start; ///< Timestamp of pause beginning
+ double vclock_pos; ///< Video stream last pts
+
+ // Threading
+ SDL_Thread *dec_thread; ///< Decoder thread
+ SDL_mutex *vmutex; ///< Video stream buffer lock
+ SDL_mutex *amutex; ///< Audio stream buffer lock
+ SDL_mutex *cmutex; ///< Control stream buffer lock
+
+ // Buffers
+ void *abuffer; ///<Audio stream buffer
+ void *vbuffer; ///< Video stream buffer
+ void *cbuffer; ///< Control stream buffer
+
+ // FFmpeg internal state
+ void *vcodec_ctx; ///< FFmpeg: Video codec context
+ void *acodec_ctx; ///< FFmpeg: Audio codec context
+ void *tmp_vframe; ///< FFmpeg: Preallocated temporary video frame
+ void *tmp_aframe; ///< FFmpeg: Preallocated temporary audio frame
+ void *swr; ///< FFmpeg: Audio resampler
+ void *sws; ///< FFmpeg: Video converter
+
+ // Other
+ uint8_t seek_flag;
+ const Kit_Source *src; ///< Reference to Audio/Video source
} Kit_Player;
typedef struct Kit_PlayerInfo {
- char acodec[KIT_CODECMAX];
- char acodec_name[KIT_CODECNAMEMAX];
- char vcodec[KIT_CODECMAX];
- char vcodec_name[KIT_CODECNAMEMAX];
- Kit_VideoFormat video;
- Kit_AudioFormat audio;
+ char acodec[KIT_CODECMAX]; ///< Audio codec short name, eg "ogg", "mp3"
+ char acodec_name[KIT_CODECNAMEMAX]; ///< Audio codec long, more descriptive name
+ char vcodec[KIT_CODECMAX]; ///< Video codec short name, eg. "x264"
+ char vcodec_name[KIT_CODECNAMEMAX]; ///< Video codec long, more descriptive name
+ Kit_VideoFormat video; ///< Video format information
+ Kit_AudioFormat audio; ///< Audio format information
} Kit_PlayerInfo;
KIT_API Kit_Player* Kit_CreatePlayer(const Kit_Source *src);
@@ -73,7 +88,7 @@ KIT_API void Kit_ClosePlayer(Kit_Player *player);
KIT_API int Kit_UpdatePlayer(Kit_Player *player);
KIT_API int Kit_RefreshTexture(Kit_Player *player, SDL_Texture *texture);
-KIT_API int Kit_GetAudioData(Kit_Player *player, unsigned char *buffer, size_t length, size_t cur_buf_len);
+KIT_API int Kit_GetAudioData(Kit_Player *player, unsigned char *buffer, int length, int cur_buf_len);
KIT_API void Kit_GetPlayerInfo(const Kit_Player *player, Kit_PlayerInfo *info);
KIT_API Kit_PlayerState Kit_GetPlayerState(const Kit_Player *player);
@@ -81,6 +96,10 @@ KIT_API void Kit_PlayerPlay(Kit_Player *player);
KIT_API void Kit_PlayerStop(Kit_Player *player);
KIT_API void Kit_PlayerPause(Kit_Player *player);
+KIT_API int Kit_PlayerSeek(Kit_Player *player, double time);
+KIT_API double Kit_GetPlayerDuration(const Kit_Player *player);
+KIT_API double Kit_GetPlayerPosition(const Kit_Player *player);
+
#ifdef __cplusplus
}
#endif
diff --git a/include/kitchensink/kitsource.h b/include/kitchensink/kitsource.h
index 43b9d2b..aef9764 100644
--- a/include/kitchensink/kitsource.h
+++ b/include/kitchensink/kitsource.h
@@ -10,24 +10,24 @@ extern "C" {
#define KIT_CODECNAMESIZE 32
#define KIT_CODECLONGNAMESIZE 128
-typedef enum Kit_streamtype {
- KIT_STREAMTYPE_UNKNOWN,
- KIT_STREAMTYPE_VIDEO,
- KIT_STREAMTYPE_AUDIO,
- KIT_STREAMTYPE_DATA,
- KIT_STREAMTYPE_SUBTITLE,
- KIT_STREAMTYPE_ATTACHMENT
-} Kit_streamtype;
+typedef enum Kit_StreamType {
+ KIT_STREAMTYPE_UNKNOWN, ///< Unknown stream type
+ KIT_STREAMTYPE_VIDEO, ///< Video stream
+ KIT_STREAMTYPE_AUDIO, ///< Audio stream
+ KIT_STREAMTYPE_DATA, ///< Data stream
+ KIT_STREAMTYPE_SUBTITLE, ///< Subtitle streawm
+ KIT_STREAMTYPE_ATTACHMENT ///< Attachment stream (images, etc)
+} Kit_StreamType;
typedef struct Kit_Source {
- int astream_idx;
- int vstream_idx;
- void *format_ctx;
+ int astream_idx; ///< Audiostream index
+ int vstream_idx; ///< Videostream index
+ void *format_ctx; ///< FFmpeg: Videostream format context
} Kit_Source;
typedef struct Kit_Stream {
- int index;
- Kit_streamtype type;
+ int index; ///< Stream index
+ Kit_StreamType type; ///< Stream type
} Kit_StreamInfo;
KIT_API Kit_Source* Kit_CreateSourceFromUrl(const char *path);
@@ -35,9 +35,9 @@ KIT_API void Kit_CloseSource(Kit_Source *src);
KIT_API int Kit_GetSourceStreamInfo(const Kit_Source *src, Kit_StreamInfo *info, int index);
KIT_API int Kit_GetSourceStreamCount(const Kit_Source *src);
-KIT_API int Kit_GetBestSourceStream(const Kit_Source *src, const Kit_streamtype type);
-KIT_API int Kit_SetSourceStream(Kit_Source *src, const Kit_streamtype type, int index);
-KIT_API int Kit_GetSourceStream(const Kit_Source *src, const Kit_streamtype type);
+KIT_API int Kit_GetBestSourceStream(const Kit_Source *src, const Kit_StreamType type);
+KIT_API int Kit_SetSourceStream(Kit_Source *src, const Kit_StreamType type, int index);
+KIT_API int Kit_GetSourceStream(const Kit_Source *src, const Kit_StreamType type);
#ifdef __cplusplus
}
diff --git a/include/kitchensink/kitutils.h b/include/kitchensink/kitutils.h
new file mode 100644
index 0000000..af3307c
--- /dev/null
+++ b/include/kitchensink/kitutils.h
@@ -0,0 +1,18 @@
+#ifndef KITUTILS_H
+#define KITUTILS_H
+
+#include "kitchensink/kitconfig.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+KIT_API const char* Kit_GetSDLAudioFormatString(unsigned int type);
+KIT_API const char* Kit_GetSDLPixelFormatString(unsigned int type);
+KIT_API const char* Kit_GetKitStreamTypeString(unsigned int type);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // KITUTILS_H
diff --git a/src/kitbuffer.c b/src/kitbuffer.c
index 06b0321..b19a24c 100644
--- a/src/kitbuffer.c
+++ b/src/kitbuffer.c
@@ -61,6 +61,7 @@ int Kit_WriteBuffer(Kit_Buffer *buffer, void *ptr) {
}
int Kit_IsBufferFull(const Kit_Buffer *buffer) {
- assert(buffer != NULL);
- return (buffer->write_p - buffer->read_p >= buffer->size);
+ int len = buffer->write_p - buffer->read_p;
+ int k = (len >= buffer->size);
+ return k;
}
diff --git a/src/kitchensink.c b/src/kitchensink.c
index eb8deb1..afbfdac 100644
--- a/src/kitchensink.c
+++ b/src/kitchensink.c
@@ -5,6 +5,10 @@
static unsigned int _init_flags = 0;
int Kit_Init(unsigned int flags) {
+ if(_init_flags != 0) {
+ Kit_SetError("Kitchensink is already initialized.");
+ return 1;
+ }
if(flags & KIT_INIT_NETWORK) {
avformat_network_init();
}
diff --git a/src/kitplayer.c b/src/kitplayer.c
index d4e23fc..f022e1e 100644
--- a/src/kitplayer.c
+++ b/src/kitplayer.c
@@ -17,6 +17,8 @@
#include <string.h>
#include <assert.h>
#include <math.h>
+#define __STDC_FORMAT_MACROS
+#include <inttypes.h>
// Threshold is in seconds
#define VIDEO_SYNC_THRESHOLD 0.01
@@ -25,6 +27,12 @@
// Buffersizes
#define KIT_VBUFFERSIZE 3
#define KIT_ABUFFERSIZE 64
+#define KIT_CBUFFERSIZE 8
+
+typedef enum Kit_ControlPacketType {
+ KIT_CONTROL_SEEK,
+ KIT_CONTROL_FLUSH
+} Kit_ControlPacketType;
typedef struct Kit_VideoPacket {
double pts;
@@ -37,6 +45,11 @@ typedef struct Kit_AudioPacket {
Kit_RingBuffer *rb;
} Kit_AudioPacket;
+typedef struct Kit_ControlPacket {
+ Kit_ControlPacketType type;
+ double value1;
+} Kit_ControlPacket;
+
static int _InitCodecs(Kit_Player *player, const Kit_Source *src) {
assert(player != NULL);
assert(src != NULL);
@@ -212,6 +225,40 @@ static Kit_AudioPacket* _CreateAudioPacket(const char* data, size_t len, double
return p;
}
+static void _FreeControlPacket(Kit_ControlPacket *packet) {
+ free(packet);
+}
+
+static Kit_ControlPacket* _CreateControlPacket(Kit_ControlPacketType type, double value1) {
+ Kit_ControlPacket *p = calloc(1, sizeof(Kit_ControlPacket));
+ p->type = type;
+ p->value1 = value1;
+ return p;
+}
+
+static void _FlushVideoBuffer(Kit_Player *player) {
+ Kit_VideoPacket *vp;
+ while((vp = Kit_ReadBuffer(player->vbuffer)) != NULL) {
+ _FreeVideoPacket(vp);
+ }
+ fflush(stderr);
+}
+
+static void _FlushAudioBuffer(Kit_Player *player) {
+ Kit_AudioPacket *ap;
+ while((ap = Kit_ReadBuffer(player->abuffer)) != NULL) {
+ _FreeAudioPacket(ap);
+ }
+ fflush(stderr);
+}
+
+static void _FlushControlBuffer(Kit_Player *player) {
+ Kit_ControlPacket *cp;
+ while((cp = Kit_ReadBuffer(player->cbuffer)) != NULL) {
+ _FreeControlPacket(cp);
+ }
+}
+
static double _GetSystemTime() {
return (double)av_gettime() / 1000000.0;
}
@@ -253,6 +300,13 @@ static void _HandleVideoPacket(Kit_Player *player, AVPacket *packet) {
pts *= av_q2d(fmt_ctx->streams[player->src->vstream_idx]->time_base);
}
+ // Just seeked, set sync clock & pos.
+ if(player->seek_flag == 1) {
+ player->vclock_pos = pts;
+ player->clock_sync = _GetSystemTime() - pts;
+ player->seek_flag = 0;
+ }
+
// Lock, write to audio buffer, unlock
Kit_VideoPacket *vpacket = _CreateVideoPacket(oframe, pts);
if(SDL_LockMutex(player->vmutex) == 0) {
@@ -317,6 +371,13 @@ static void _HandleAudioPacket(Kit_Player *player, AVPacket *packet) {
pts *= av_q2d(fmt_ctx->streams[player->src->astream_idx]->time_base);
}
+ // Just seeked, set sync clock & pos.
+ if(player->seek_flag == 1) {
+ player->vclock_pos = pts;
+ player->clock_sync = _GetSystemTime() - pts;
+ player->seek_flag = 0;
+ }
+
// Lock, write to audio buffer, unlock
Kit_AudioPacket *apacket = _CreateAudioPacket((char*)dst_data[0], (size_t)dst_bufsize, pts);
if(SDL_LockMutex(player->amutex) == 0) {
@@ -330,47 +391,110 @@ static void _HandleAudioPacket(Kit_Player *player, AVPacket *packet) {
}
}
+static void _HandlePacket(Kit_Player *player, AVPacket *packet) {
+ // Check if this is a packet we need to handle and pass it on
+ if(player->vcodec_ctx != NULL && packet->stream_index == player->src->vstream_idx) {
+ _HandleVideoPacket(player, packet);
+ }
+ if(player->acodec_ctx != NULL && packet->stream_index == player->src->astream_idx) {
+ _HandleAudioPacket(player, packet);
+ }
+}
+
+static void _HandleFlushCommand(Kit_Player *player, Kit_ControlPacket *packet) {
+ if(SDL_LockMutex(player->amutex) == 0) {
+ _FlushAudioBuffer(player);
+ SDL_UnlockMutex(player->amutex);
+ }
+ if(SDL_LockMutex(player->vmutex) == 0) {
+ _FlushVideoBuffer(player);
+ SDL_UnlockMutex(player->vmutex);
+ }
+}
+
+static void _HandleSeekCommand(Kit_Player *player, Kit_ControlPacket *packet) {
+ AVFormatContext *fmt_ctx = (AVFormatContext *)player->src->format_ctx;
+
+ // Find and limit absolute position
+ double seek = packet->value1;
+ double duration = Kit_GetPlayerDuration(player);
+ if(player->vclock_pos + seek <= 0) {
+ seek = -player->vclock_pos;
+ }
+ if(player->vclock_pos + seek >= duration) {
+ seek = duration - player->vclock_pos;
+ }
+ double absolute_pos = player->vclock_pos + seek;
+ int64_t seek_target = absolute_pos * AV_TIME_BASE;
+
+ // Seek to timestamp.
+ avformat_seek_file(fmt_ctx, -1, INT64_MIN, seek_target, INT64_MAX, 0);
+ if(player->vcodec_ctx != NULL)
+ avcodec_flush_buffers(player->vcodec_ctx);
+ if(player->acodec_ctx != NULL)
+ avcodec_flush_buffers(player->acodec_ctx);
+
+ // On first packet, set clock and current position
+ player->seek_flag = 1;
+}
+
+static void _HandleControlPacket(Kit_Player *player, Kit_ControlPacket *packet) {
+ switch(packet->type) {
+ case KIT_CONTROL_FLUSH:
+ _HandleFlushCommand(player, packet);
+ break;
+ case KIT_CONTROL_SEEK:
+ _HandleSeekCommand(player, packet);
+ break;
+ }
+}
+
// 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 was an error or stream end
static int _UpdatePlayer(Kit_Player *player) {
assert(player != NULL);
- int ret;
+ AVFormatContext *format_ctx = (AVFormatContext*)player->src->format_ctx;
+
+ // Handle control queue
+ if(SDL_LockMutex(player->cmutex) == 0) {
+ Kit_ControlPacket *cpacket;
+ while((cpacket = (Kit_ControlPacket*)Kit_ReadBuffer(player->cbuffer)) != NULL) {
+ _HandleControlPacket(player, cpacket);
+ _FreeControlPacket(cpacket);
+ }
+ SDL_UnlockMutex(player->cmutex);
+ }
// If either buffer is full, just stop here for now.
- if(player->vcodec_ctx != NULL && SDL_LockMutex(player->vmutex) == 0) {
- ret = Kit_IsBufferFull(player->vbuffer);
- SDL_UnlockMutex(player->vmutex);
- if(ret) {
- return 0;
+ // 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(player->vcodec_ctx != NULL) {
+ if(SDL_LockMutex(player->vmutex) == 0) {
+ int ret = Kit_IsBufferFull(player->vbuffer);
+ SDL_UnlockMutex(player->vmutex);
+ if(ret == 1) {
+ return 0;
+ }
}
}
- if(player->acodec_ctx != NULL && SDL_LockMutex(player->amutex) == 0) {
- ret = Kit_IsBufferFull(player->abuffer);
- SDL_UnlockMutex(player->amutex);
- if(ret) {
- return 0;
+ if(player->acodec_ctx != NULL) {
+ if(SDL_LockMutex(player->amutex) == 0) {
+ int ret = Kit_IsBufferFull(player->abuffer);
+ SDL_UnlockMutex(player->amutex);
+ if(ret == 1) {
+ return 0;
+ }
}
}
- AVPacket packet;
- AVFormatContext *format_ctx = (AVFormatContext*)player->src->format_ctx;
-
// Attempt to read frame. Just return here if it fails.
+ AVPacket packet;
if(av_read_frame(format_ctx, &packet) < 0) {
return 1;
}
-
- // Check if this is a packet we need to handle and pass it on
- if(player->vcodec_ctx != NULL && packet.stream_index == player->src->vstream_idx) {
- _HandleVideoPacket(player, &packet);
- }
- if(player->acodec_ctx != NULL && packet.stream_index == player->src->astream_idx) {
- _HandleAudioPacket(player, &packet);
- }
-
- // Free packet and that's that
+ _HandlePacket(player, &packet);
av_free_packet(&packet);
return -1;
}
@@ -399,7 +523,7 @@ static int _DecoderThread(void *ptr) {
continue;
}
- // Get more data from demuxer, decode.
+ // Get more data from demuxer, decode. Wait a bit if there's no more work for now.
ret = _UpdatePlayer(player);
if(ret == 1) {
player->state = KIT_STOPPED;
@@ -407,6 +531,8 @@ static int _DecoderThread(void *ptr) {
SDL_Delay(1);
}
}
+
+ // Just idle while waiting for work.
SDL_Delay(10);
}
@@ -500,6 +626,12 @@ Kit_Player* Kit_CreatePlayer(const Kit_Source *src) {
}
}
+ player->cbuffer = Kit_CreateBuffer(KIT_CBUFFERSIZE);
+ if(player->cbuffer == NULL) {
+ Kit_SetError("Unable to initialize control ringbuffer");
+ goto error;
+ }
+
player->vmutex = SDL_CreateMutex();
if(player->vmutex == NULL) {
Kit_SetError("Unable to allocate video mutex");
@@ -512,6 +644,12 @@ Kit_Player* Kit_CreatePlayer(const Kit_Source *src) {
goto error;
}
+ player->cmutex = SDL_CreateMutex();
+ if(player->cmutex == NULL) {
+ Kit_SetError("Unable to allocate control buffer mutex");
+ goto error;
+ }
+
player->dec_thread = SDL_CreateThread(_DecoderThread, "Kit Decoder Thread", player);
if(player->dec_thread == NULL) {
Kit_SetError("Unable to create a decoder thread: %s", SDL_GetError());
@@ -527,6 +665,9 @@ error:
if(player->vmutex != NULL) {
SDL_DestroyMutex(player->vmutex);
}
+ if(player->cmutex != NULL) {
+ SDL_DestroyMutex(player->cmutex);
+ }
if(player->tmp_aframe != NULL) {
av_frame_free((AVFrame**)&player->tmp_aframe);
}
@@ -539,6 +680,9 @@ error:
if(player->abuffer != NULL) {
Kit_DestroyBuffer((Kit_Buffer*)player->abuffer);
}
+ if(player->cbuffer != NULL) {
+ Kit_DestroyBuffer((Kit_Buffer*)player->cbuffer);
+ }
if(player->sws != NULL) {
sws_freeContext((struct SwsContext *)player->sws);
}
@@ -559,6 +703,7 @@ void Kit_ClosePlayer(Kit_Player *player) {
SDL_WaitThread(player->dec_thread, NULL);
SDL_DestroyMutex(player->vmutex);
SDL_DestroyMutex(player->amutex);
+ SDL_DestroyMutex(player->cmutex);
// Free up the ffmpeg context
if(player->sws != NULL) {
@@ -579,20 +724,20 @@ void Kit_ClosePlayer(Kit_Player *player) {
avcodec_free_context((AVCodecContext**)&player->vcodec_ctx);
// Free local audio buffers
+ if(player->cbuffer != NULL) {
+ _FlushControlBuffer(player);
+ Kit_DestroyBuffer((Kit_Buffer*)player->cbuffer);
+ }
+
+ // Free local audio buffers
if(player->abuffer != NULL) {
- Kit_AudioPacket *ap;
- while((ap = Kit_ReadBuffer(player->abuffer)) != NULL) {
- _FreeAudioPacket(ap);
- }
+ _FlushAudioBuffer(player);
Kit_DestroyBuffer((Kit_Buffer*)player->abuffer);
}
// Free local video buffers
if(player->vbuffer != NULL) {
- Kit_VideoPacket *vp;
- while((vp = Kit_ReadBuffer(player->vbuffer)) != NULL) {
- _FreeVideoPacket(vp);
- }
+ _FlushVideoBuffer(player);
Kit_DestroyBuffer((Kit_Buffer*)player->vbuffer);
}
@@ -622,24 +767,21 @@ int Kit_RefreshTexture(Kit_Player *player, SDL_Texture *texture) {
Kit_VideoPacket *n_packet = NULL;
if(SDL_LockMutex(player->vmutex) == 0) {
packet = (Kit_VideoPacket*)Kit_PeekBuffer((Kit_Buffer*)player->vbuffer);
- SDL_UnlockMutex(player->vmutex);
- } else {
- return 1;
- }
- if(packet == NULL) {
- return 0;
- }
+ if(packet == NULL) {
+ SDL_UnlockMutex(player->vmutex);
+ return 0;
+ }
- // Print some data
- double cur_video_ts = _GetSystemTime() - player->clock_sync;
+ // Print some data
+ double cur_video_ts = _GetSystemTime() - player->clock_sync;
- // Check if we want the packet
- if(packet->pts > cur_video_ts + VIDEO_SYNC_THRESHOLD) {
- // Video is ahead, don't show yet.
- return 0;
- } else if(packet->pts < cur_video_ts - VIDEO_SYNC_THRESHOLD) {
- // Video is lagging, skip until we find a good PTS to continue from.
- if(SDL_LockMutex(player->vmutex) == 0) {
+ // Check if we want the packet
+ if(packet->pts > cur_video_ts + VIDEO_SYNC_THRESHOLD) {
+ // Video is ahead, don't show yet.
+ SDL_UnlockMutex(player->vmutex);
+ return 0;
+ } else if(packet->pts < cur_video_ts - VIDEO_SYNC_THRESHOLD) {
+ // Video is lagging, skip until we find a good PTS to continue from.
while(packet != NULL) {
Kit_AdvanceBuffer((Kit_Buffer*)player->vbuffer);
n_packet = (Kit_VideoPacket*)Kit_PeekBuffer((Kit_Buffer*)player->vbuffer);
@@ -652,45 +794,52 @@ int Kit_RefreshTexture(Kit_Player *player, SDL_Texture *texture) {
break;
}
}
- SDL_UnlockMutex(player->vmutex);
}
- }
- // Advance buffer one frame forwards
- if(SDL_LockMutex(player->vmutex) == 0) {
+ // Advance buffer one frame forwards
Kit_AdvanceBuffer((Kit_Buffer*)player->vbuffer);
+ player->vclock_pos = packet->pts;
+
+ // Update textures as required. Handle UYV frames separately.
+ if(player->vformat.format == SDL_PIXELFORMAT_YV12
+ || player->vformat.format == SDL_PIXELFORMAT_IYUV)
+ {
+ SDL_UpdateYUVTexture(
+ texture, NULL,
+ packet->frame->data[0], packet->frame->linesize[0],
+ packet->frame->data[1], packet->frame->linesize[1],
+ packet->frame->data[2], packet->frame->linesize[2]);
+ }
+ else {
+ SDL_UpdateTexture(
+ texture, NULL,
+ packet->frame->data[0],
+ packet->frame->linesize[0]);
+ }
+
+ _FreeVideoPacket(packet);
SDL_UnlockMutex(player->vmutex);
+ } else {
+ Kit_SetError("Unable to lock video buffer mutex");
+ return 1;
}
- // Update textures as required. Handle UYV frames separately.
- if(player->vformat.format == SDL_PIXELFORMAT_YV12
- || player->vformat.format == SDL_PIXELFORMAT_IYUV)
- {
- SDL_UpdateYUVTexture(
- texture, NULL,
- packet->frame->data[0], packet->frame->linesize[0],
- packet->frame->data[1], packet->frame->linesize[1],
- packet->frame->data[2], packet->frame->linesize[2]);
- }
- else {
- SDL_UpdateTexture(
- texture, NULL,
- packet->frame->data[0],
- packet->frame->linesize[0]);
- }
-
- // Free the packet
- _FreeVideoPacket(packet);
return 0;
}
-int Kit_GetAudioData(Kit_Player *player, unsigned char *buffer, size_t length, size_t cur_buf_len) {
+int Kit_GetAudioData(Kit_Player *player, unsigned char *buffer, int length, int cur_buf_len) {
assert(player != NULL);
+ // If there is no audio stream, don't bother.
if(player->src->astream_idx == -1) {
return 0;
}
+ // If asked for nothing, don't return anything either :P
+ if(length == 0) {
+ return 0;
+ }
+
assert(buffer != NULL);
// If paused or stopped, do nothing
@@ -701,76 +850,75 @@ int Kit_GetAudioData(Kit_Player *player, unsigned char *buffer, size_t length, s
return 0;
}
- // If asked for nothing, don't return anything either :P
- if(length == 0) {
- return 0;
- }
-
// Read a packet from buffer, if one exists. Stop here if not.
+ int ret = 0;
Kit_AudioPacket *packet = NULL;
Kit_AudioPacket *n_packet = NULL;
if(SDL_LockMutex(player->amutex) == 0) {
packet = (Kit_AudioPacket*)Kit_PeekBuffer((Kit_Buffer*)player->abuffer);
- SDL_UnlockMutex(player->amutex);
- } else {
- return 1;
- }
- if(packet == NULL) {
- return 0;
- }
-
- int bytes_per_sample = player->aformat.bytes * player->aformat.channels;
- double bps = bytes_per_sample * player->aformat.samplerate;
- double cur_audio_ts = _GetSystemTime() - player->clock_sync + ((double)cur_buf_len / bps);
- double diff = cur_audio_ts - packet->pts;
- int diff_samples = diff * player->aformat.samplerate;
-
- if(packet->pts > cur_audio_ts + AUDIO_SYNC_THRESHOLD) {
- // Audio is ahead, fill buffer with some silence
+ if(packet == NULL) {
+ SDL_UnlockMutex(player->amutex);
+ return 0;
+ }
- int max_diff_samples = length / bytes_per_sample;
- int max_samples = (max_diff_samples < diff_samples) ? max_diff_samples : diff_samples;
+ int bytes_per_sample = player->aformat.bytes * player->aformat.channels;
+ double bps = bytes_per_sample * player->aformat.samplerate;
+ double cur_audio_ts = _GetSystemTime() - player->clock_sync + ((double)cur_buf_len / bps);
+ double diff = cur_audio_ts - packet->pts;
+ int diff_samples = fabs(diff) * player->aformat.samplerate;
+
+ if(packet->pts > cur_audio_ts + AUDIO_SYNC_THRESHOLD) {
+ // Audio is ahead, fill buffer with some silence
+ int max_diff_samples = length / bytes_per_sample;
+ int max_samples = (max_diff_samples < diff_samples) ? max_diff_samples : diff_samples;
+
+ av_samples_set_silence(
+ &buffer,
+ 0, // Offset
+ max_samples,
+ player->aformat.channels,
+ _FindAVSampleFormat(player->aformat.format));
- av_samples_set_silence(
- &buffer,
- 0, // Offset
- max_samples,
- player->aformat.channels,
- _FindAVSampleFormat(player->aformat.format));
+ int diff_bytes = max_samples * bytes_per_sample;
- int diff_bytes = max_samples * bytes_per_sample;
- buffer += diff_bytes;
- length -= diff_bytes;
+ SDL_UnlockMutex(player->amutex);
+ return diff_bytes;
- } else if(packet->pts < cur_audio_ts - AUDIO_SYNC_THRESHOLD) {
- // Audio is lagging, skip until good pts is found
+ } else if(packet->pts < cur_audio_ts - AUDIO_SYNC_THRESHOLD) {
+ // Audio is lagging, skip until good pts is found
- while(1) {
- Kit_AdvanceBuffer((Kit_Buffer*)player->abuffer);
- n_packet = (Kit_AudioPacket*)Kit_PeekBuffer((Kit_Buffer*)player->abuffer);
- if(n_packet != NULL) {
- packet = n_packet;
- } else {
- break;
- }
- if(packet->pts > cur_audio_ts - AUDIO_SYNC_THRESHOLD) {
- break;
+ while(1) {
+ Kit_AdvanceBuffer((Kit_Buffer*)player->abuffer);
+ n_packet = (Kit_AudioPacket*)Kit_PeekBuffer((Kit_Buffer*)player->abuffer);
+ if(n_packet != NULL) {
+ packet = n_packet;
+ } else {
+ break;
+ }
+ if(packet->pts > cur_audio_ts - AUDIO_SYNC_THRESHOLD) {
+ break;
+ }
}
}
- }
- int ret = Kit_ReadRingBuffer(packet->rb, (char*)buffer, length);
- if(Kit_GetRingBufferLength(packet->rb) == 0) {
- if(SDL_LockMutex(player->amutex) == 0) {
+ if(length > 0) {
+ ret += Kit_ReadRingBuffer(packet->rb, (char*)buffer, length);
+ }
+
+ if(Kit_GetRingBufferLength(packet->rb) == 0) {
Kit_AdvanceBuffer((Kit_Buffer*)player->abuffer);
- SDL_UnlockMutex(player->amutex);
+ _FreeAudioPacket(packet);
+ } else {
+ double adjust = (double)ret / bps;
+ packet->pts += adjust;
}
+
+ SDL_UnlockMutex(player->amutex);
} else {
- double adjust = (double)ret / bps;
- packet->pts += adjust;
+ Kit_SetError("Unable to lock audio buffer mutex");
+ ret = 1;
}
- _FreeAudioPacket(packet);
return ret;
}
@@ -796,11 +944,15 @@ void Kit_GetPlayerInfo(const Kit_Player *player, Kit_PlayerInfo *info) {
}
}
-KIT_API Kit_PlayerState Kit_GetPlayerState(const Kit_Player *player) {
+Kit_PlayerState Kit_GetPlayerState(const Kit_Player *player) {
+ assert(player != NULL);
+
return player->state;
}
-KIT_API void Kit_PlayerPlay(Kit_Player *player) {
+void Kit_PlayerPlay(Kit_Player *player) {
+ assert(player != NULL);
+
if(player->state == KIT_PLAYING) {
return;
}
@@ -813,17 +965,51 @@ KIT_API void Kit_PlayerPlay(Kit_Player *player) {
player->state = KIT_PLAYING;
}
-KIT_API void Kit_PlayerStop(Kit_Player *player) {
+void Kit_PlayerStop(Kit_Player *player) {
+ assert(player != NULL);
+
if(player->state == KIT_STOPPED) {
return;
}
player->state = KIT_STOPPED;
}
-KIT_API void Kit_PlayerPause(Kit_Player *player) {
+void Kit_PlayerPause(Kit_Player *player) {
+ assert(player != NULL);
+
if(player->state != KIT_PLAYING) {
return;
}
player->pause_start = _GetSystemTime();
player->state = KIT_PAUSED;
}
+
+int Kit_PlayerSeek(Kit_Player *player, double m_time) {
+ assert(player != NULL);
+
+ // Send packets to control stream
+ if(SDL_LockMutex(player->cmutex) == 0) {
+ // Flush audio and video buffers, then set seek, then unlock control queue mutex.
+ Kit_WriteBuffer((Kit_Buffer*)player->cbuffer, _CreateControlPacket(KIT_CONTROL_FLUSH, 0));
+ Kit_WriteBuffer((Kit_Buffer*)player->cbuffer, _CreateControlPacket(KIT_CONTROL_SEEK, m_time));
+ SDL_UnlockMutex(player->cmutex);
+ } else {
+ Kit_SetError("Unable to lock control queue mutex");
+ return 1;
+ }
+
+ return 0;
+}
+
+double Kit_GetPlayerDuration(const Kit_Player *player) {
+ assert(player != NULL);
+
+ AVFormatContext *fmt_ctx = (AVFormatContext *)player->src->format_ctx;
+ return (fmt_ctx->duration / AV_TIME_BASE);
+}
+
+double Kit_GetPlayerPosition(const Kit_Player *player) {
+ assert(player != NULL);
+
+ return player->vclock_pos;
+}
diff --git a/src/kitsource.c b/src/kitsource.c
index b79207e..9a7b739 100644
--- a/src/kitsource.c
+++ b/src/kitsource.c
@@ -74,7 +74,7 @@ int Kit_GetSourceStreamInfo(const Kit_Source *src, Kit_StreamInfo *info, int ind
return 0;
}
-int Kit_GetBestSourceStream(const Kit_Source *src, const Kit_streamtype type) {
+int Kit_GetBestSourceStream(const Kit_Source *src, const Kit_StreamType type) {
assert(src != NULL);
int avmedia_type = 0;
switch(type) {
@@ -93,7 +93,7 @@ int Kit_GetBestSourceStream(const Kit_Source *src, const Kit_streamtype type) {
return ret;
}
-int Kit_SetSourceStream(Kit_Source *src, const Kit_streamtype type, int index) {
+int Kit_SetSourceStream(Kit_Source *src, const Kit_StreamType type, int index) {
assert(src != NULL);
switch(type) {
case KIT_STREAMTYPE_AUDIO: src->astream_idx = index; break;
@@ -105,7 +105,7 @@ int Kit_SetSourceStream(Kit_Source *src, const Kit_streamtype type, int index) {
return 0;
}
-int Kit_GetSourceStream(const Kit_Source *src, const Kit_streamtype type) {
+int Kit_GetSourceStream(const Kit_Source *src, const Kit_StreamType type) {
assert(src != NULL);
switch(type) {
case KIT_STREAMTYPE_AUDIO: return src->astream_idx;
diff --git a/src/kitutils.c b/src/kitutils.c
new file mode 100644
index 0000000..b618c07
--- /dev/null
+++ b/src/kitutils.c
@@ -0,0 +1,73 @@
+#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";
+ case AUDIO_U8: return "AUDIO_U8";
+ case AUDIO_S16: return "AUDIO_S16";
+ case AUDIO_U16: return "AUDIO_U16";
+ case AUDIO_S32: return "AUDIO_S32";
+ case AUDIO_F32: return "AUDIO_F32";
+ default:
+ return NULL;
+ }
+}
+
+const char* Kit_GetSDLPixelFormatString(unsigned int type) {
+ switch(type) {
+ case SDL_PIXELFORMAT_UNKNOWN: return "SDL_PIXELFORMAT_UNKNOWN";
+ case SDL_PIXELFORMAT_INDEX1LSB: return "SDL_PIXELFORMAT_INDEX1LSB";
+ case SDL_PIXELFORMAT_INDEX1MSB: return "SDL_PIXELFORMAT_INDEX1MSB";
+ case SDL_PIXELFORMAT_INDEX4LSB: return "SDL_PIXELFORMAT_INDEX4LSB";
+ case SDL_PIXELFORMAT_INDEX4MSB: return "SDL_PIXELFORMAT_INDEX4MSB";
+ case SDL_PIXELFORMAT_INDEX8: return "SDL_PIXELFORMAT_INDEX8";
+ case SDL_PIXELFORMAT_RGB332: return "SDL_PIXELFORMAT_RGB332";
+ case SDL_PIXELFORMAT_RGB444: return "SDL_PIXELFORMAT_RGB444";
+ case SDL_PIXELFORMAT_RGB555: return "SDL_PIXELFORMAT_RGB555";
+ case SDL_PIXELFORMAT_BGR555: return "SDL_PIXELFORMAT_BGR555";
+ case SDL_PIXELFORMAT_ARGB4444: return "SDL_PIXELFORMAT_ARGB4444";
+ case SDL_PIXELFORMAT_RGBA4444: return "SDL_PIXELFORMAT_RGBA4444";
+ case SDL_PIXELFORMAT_ABGR4444: return "SDL_PIXELFORMAT_ABGR4444";
+ case SDL_PIXELFORMAT_BGRA4444: return "SDL_PIXELFORMAT_BGRA4444";
+ case SDL_PIXELFORMAT_ARGB1555: return "SDL_PIXELFORMAT_ARGB1555";
+ case SDL_PIXELFORMAT_RGBA5551: return "SDL_PIXELFORMAT_RGBA5551";
+ case SDL_PIXELFORMAT_ABGR1555: return "SDL_PIXELFORMAT_ABGR1555";
+ case SDL_PIXELFORMAT_BGRA5551: return "SDL_PIXELFORMAT_BGRA5551";
+ case SDL_PIXELFORMAT_RGB565: return "SDL_PIXELFORMAT_RGB565";
+ case SDL_PIXELFORMAT_BGR565: return "SDL_PIXELFORMAT_BGR565";
+ case SDL_PIXELFORMAT_RGB24: return "SDL_PIXELFORMAT_RGB24";
+ case SDL_PIXELFORMAT_BGR24: return "SDL_PIXELFORMAT_BGR24";
+ case SDL_PIXELFORMAT_RGB888: return "SDL_PIXELFORMAT_RGB888";
+ case SDL_PIXELFORMAT_RGBX8888: return "SDL_PIXELFORMAT_RGBX8888";
+ case SDL_PIXELFORMAT_BGR888: return "SDL_PIXELFORMAT_BGR888";
+ case SDL_PIXELFORMAT_BGRX8888: return "SDL_PIXELFORMAT_BGRX8888";
+ case SDL_PIXELFORMAT_ARGB8888: return "SDL_PIXELFORMAT_ARGB8888";
+ case SDL_PIXELFORMAT_RGBA8888: return "SDL_PIXELFORMAT_RGBA8888";
+ case SDL_PIXELFORMAT_ABGR8888: return "SDL_PIXELFORMAT_ABGR8888";
+ case SDL_PIXELFORMAT_BGRA8888: return "SDL_PIXELFORMAT_BGRA8888";
+ case SDL_PIXELFORMAT_ARGB2101010: return "SDL_PIXELFORMAT_ARGB2101010";
+ case SDL_PIXELFORMAT_YV12: return "SDL_PIXELFORMAT_YV12";
+ case SDL_PIXELFORMAT_IYUV: return "SDL_PIXELFORMAT_IYUV";
+ case SDL_PIXELFORMAT_YUY2: return "SDL_PIXELFORMAT_YUY2";
+ case SDL_PIXELFORMAT_UYVY: return "SDL_PIXELFORMAT_UYVY";
+ case SDL_PIXELFORMAT_YVYU: return "SDL_PIXELFORMAT_YVYU";
+ default:
+ return NULL;
+ }
+}
+
+const char* Kit_GetKitStreamTypeString(unsigned int type) {
+ switch(type) {
+ case KIT_STREAMTYPE_UNKNOWN: return "KIT_STREAMTYPE_UNKNOWN";
+ case KIT_STREAMTYPE_VIDEO: return "KIT_STREAMTYPE_VIDEO";
+ case KIT_STREAMTYPE_AUDIO: return "KIT_STREAMTYPE_AUDIO";
+ case KIT_STREAMTYPE_DATA: return "KIT_STREAMTYPE_DATA";
+ case KIT_STREAMTYPE_SUBTITLE: return "KIT_STREAMTYPE_SUBTITLE";
+ case KIT_STREAMTYPE_ATTACHMENT: return "KIT_STREAMTYPE_ATTACHMENT";
+ default:
+ return NULL;
+ }
+}