diff options
Diffstat (limited to 'include')
25 files changed, 1068 insertions, 138 deletions
diff --git a/include/kitchensink/internal/audio/kitaudio.h b/include/kitchensink/internal/audio/kitaudio.h new file mode 100644 index 0000000..e42770b --- /dev/null +++ b/include/kitchensink/internal/audio/kitaudio.h @@ -0,0 +1,11 @@ +#ifndef KITAUDIO_H
+#define KITAUDIO_H
+
+#include "kitchensink/kitconfig.h"
+#include "kitchensink/kitsource.h"
+#include "kitchensink/internal/kitdecoder.h"
+
+KIT_LOCAL Kit_Decoder* Kit_CreateAudioDecoder(const Kit_Source *src, int stream_index);
+KIT_LOCAL int Kit_GetAudioDecoderData(Kit_Decoder *dec, unsigned char *buf, int len);
+
+#endif // KITAUDIO_H
diff --git a/include/kitchensink/internal/kitdecoder.h b/include/kitchensink/internal/kitdecoder.h new file mode 100644 index 0000000..ef3edb7 --- /dev/null +++ b/include/kitchensink/internal/kitdecoder.h @@ -0,0 +1,75 @@ +#ifndef KITDECODER_H
+#define KITDECODER_H
+
+#include <stdbool.h>
+
+#include <SDL_mutex.h>
+#include <libavcodec/avcodec.h>
+#include <libavformat/avformat.h>
+
+#include "kitchensink/kitformat.h"
+#include "kitchensink/kitcodec.h"
+#include "kitchensink/kitconfig.h"
+#include "kitchensink/kitsource.h"
+#include "kitchensink/internal/utils/kitbuffer.h"
+
+enum {
+ KIT_DEC_BUF_IN = 0,
+ KIT_DEC_BUF_OUT,
+ KIT_DEC_BUF_COUNT
+};
+
+typedef struct Kit_Decoder Kit_Decoder;
+
+typedef void (*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);
+
+KIT_LOCAL struct Kit_Decoder {
+ int stream_index; ///< Source stream index for the current stream
+ double clock_sync; ///< Sync source for current stream
+ double clock_pos; ///< Current pts for the stream
+ Kit_OutputFormat output; ///< Output format for the decoder
+
+ AVCodecContext *codec_ctx; ///< FFMpeg internal: Codec context
+ AVFormatContext *format_ctx; ///< FFMpeg internal: Format context (owner: Kit_Source)
+
+ SDL_mutex *output_lock; ///< Threading lock for output buffer
+ Kit_Buffer *buffer[2]; ///< Buffers for incoming and decoded packets
+
+ void *userdata; ///< Decoder specific information (Audio, video, subtitle context)
+ dec_decode_cb dec_decode; ///< Decoder decoding function callback
+ dec_close_cb dec_close; ///< Decoder close function callback
+};
+
+KIT_LOCAL Kit_Decoder* Kit_CreateDecoder(const Kit_Source *src, int stream_index,
+ int out_b_size, dec_free_packet_cb free_out_cb,
+ int thread_count);
+KIT_LOCAL void Kit_CloseDecoder(Kit_Decoder *dec);
+
+KIT_LOCAL int Kit_GetDecoderStreamIndex(const Kit_Decoder *dec);
+KIT_LOCAL int Kit_GetDecoderCodecInfo(const Kit_Decoder *dec, Kit_Codec *codec);
+KIT_LOCAL int Kit_GetDecoderOutputFormat(const Kit_Decoder *dec, Kit_OutputFormat *output);
+
+KIT_LOCAL void Kit_SetDecoderClockSync(Kit_Decoder *dec, double sync);
+KIT_LOCAL void Kit_ChangeDecoderClockSync(Kit_Decoder *dec, double sync);
+
+KIT_LOCAL int Kit_RunDecoder(Kit_Decoder *dec);
+KIT_LOCAL void Kit_ClearDecoderBuffers(Kit_Decoder *dec);
+
+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 int Kit_WriteDecoderOutput(Kit_Decoder *dec, void *packet);
+KIT_LOCAL void* Kit_PeekDecoderOutput(Kit_Decoder *dec);
+KIT_LOCAL void* Kit_ReadDecoderOutput(Kit_Decoder *dec);
+KIT_LOCAL void Kit_AdvanceDecoderOutput(Kit_Decoder *dec);
+KIT_LOCAL void Kit_ForEachDecoderOutput(Kit_Decoder *dec, Kit_ForEachItemCallback foreach_cb, void *userdata);
+KIT_LOCAL int Kit_LockDecoderOutput(Kit_Decoder *dec);
+KIT_LOCAL void Kit_UnlockDecoderOutput(Kit_Decoder *dec);
+KIT_LOCAL void Kit_ClearDecoderOutput(Kit_Decoder *dec);
+
+
+#endif // KITDECODER_H
diff --git a/include/kitchensink/internal/kitlibstate.h b/include/kitchensink/internal/kitlibstate.h index e16a5c9..b92cebb 100644 --- a/include/kitchensink/internal/kitlibstate.h +++ b/include/kitchensink/internal/kitlibstate.h @@ -1,12 +1,18 @@ #ifndef KITLIBSTATE_H #define KITLIBSTATE_H -#include <ass/ass.h> +#include "kitchensink/internal/libass.h" #include "kitchensink/kitconfig.h" typedef struct Kit_LibraryState { unsigned int init_flags; + unsigned int thread_count; + unsigned int font_hinting; + unsigned int video_buf_frames; + unsigned int audio_buf_frames; + unsigned int subtitle_buf_frames; ASS_Library *libass_handle; + void *ass_so_handle; } Kit_LibraryState; KIT_LOCAL Kit_LibraryState* Kit_GetLibraryState(); 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/libass.h b/include/kitchensink/internal/libass.h new file mode 100644 index 0000000..0f91d95 --- /dev/null +++ b/include/kitchensink/internal/libass.h @@ -0,0 +1,66 @@ +#ifndef KITLIBASS_H
+#define KITLIBASS_H
+
+#ifndef USE_DYNAMIC_LIBASS
+
+#include <ass/ass.h>
+
+#else // USE_DYNAMIC_LIBASS
+
+#include <stdint.h>
+#include <stdarg.h>
+
+#include "kitchensink/kitconfig.h"
+
+typedef struct ass_library ASS_Library;
+typedef struct ass_renderer ASS_Renderer;
+typedef struct ass_track ASS_Track;
+
+typedef struct ass_image {
+ int w, h;
+ int stride;
+ unsigned char *bitmap;
+ uint32_t color;
+ int dst_x, dst_y;
+ struct ass_image *next;
+ enum {
+ IMAGE_TYPE_CHARACTER,
+ IMAGE_TYPE_OUTLINE,
+ IMAGE_TYPE_SHADOW
+ } type;
+} ASS_Image;
+
+typedef enum {
+ ASS_HINTING_NONE = 0,
+ ASS_HINTING_LIGHT,
+ ASS_HINTING_NORMAL,
+ ASS_HINTING_NATIVE
+} ASS_Hinting;
+
+KIT_LOCAL ASS_Library* (*ass_library_init)(void);
+KIT_LOCAL void (*ass_library_done)(ASS_Library *priv);
+KIT_LOCAL void (*ass_process_codec_private)(ASS_Track *track, char *data, int size);
+KIT_LOCAL void (*ass_set_message_cb)(ASS_Library *priv, void (*msg_cb)(int level, const char *fmt, va_list args, void *data), void *data);
+KIT_LOCAL ASS_Renderer* (*ass_renderer_init)(ASS_Library *);
+KIT_LOCAL void (*ass_renderer_done)(ASS_Renderer *priv);
+KIT_LOCAL void (*ass_set_frame_size)(ASS_Renderer *priv, int w, int h);
+KIT_LOCAL void (*ass_set_hinting)(ASS_Renderer *priv, ASS_Hinting ht);
+KIT_LOCAL void (*ass_set_fonts)(ASS_Renderer *priv, const char *default_font, const char *default_family, int dfp, const char *config, int update);
+KIT_LOCAL ASS_Image* (*ass_render_frame)(ASS_Renderer *priv, ASS_Track *track, long long now, int *detect_change);
+KIT_LOCAL ASS_Track* (*ass_new_track)(ASS_Library *);
+KIT_LOCAL void (*ass_free_track)(ASS_Track *track);
+KIT_LOCAL void (*ass_process_data)(ASS_Track *track, char *data, int size);
+KIT_LOCAL void (*ass_process_chunk)(ASS_Track *track, char *data, int size, long long timecode, long long duration);
+KIT_LOCAL void (*ass_add_font)(ASS_Library *library, char *name, char *data, int data_size);
+KIT_LOCAL void (*ass_set_storage_size)(ASS_Renderer *priv, int w, int h);
+
+KIT_LOCAL int load_libass(void *handle);
+
+#endif // USE_DYNAMIC_LIBASS
+
+// For compatibility
+#ifndef ASS_FONTPROVIDER_AUTODETECT
+#define ASS_FONTPROVIDER_AUTODETECT 1
+#endif
+
+#endif // KITLIBASS_H
diff --git a/include/kitchensink/internal/subtitle/kitatlas.h b/include/kitchensink/internal/subtitle/kitatlas.h new file mode 100644 index 0000000..d9207c1 --- /dev/null +++ b/include/kitchensink/internal/subtitle/kitatlas.h @@ -0,0 +1,40 @@ +#ifndef KITATLAS_H
+#define KITATLAS_H
+
+#include <stdbool.h>
+#include <SDL_rect.h>
+#include <SDL_render.h>
+
+#include "kitchensink/kitconfig.h"
+
+typedef struct Kit_TextureAtlasItem {
+ int cur_shelf; //< Current shelf number in cache
+ int cur_slot; //< Current slot on shelf in cache
+ SDL_Rect source; //< Source coordinates on cache surface
+ SDL_Rect target; //< Target coordinates on output surface
+} Kit_TextureAtlasItem;
+
+typedef struct Kit_Shelf {
+ uint16_t width;
+ uint16_t height;
+ uint16_t count;
+} Kit_Shelf;
+
+typedef struct Kit_TextureAtlas {
+ int cur_items; //< Current items count
+ int max_items; //< Maximum items count
+ int max_shelves; //< Maximum shelf count
+ int w; //< Current atlas width
+ int h; //< Current atlas height
+ Kit_TextureAtlasItem *items; //< Cached items
+ Kit_Shelf *shelves; //< Atlas shelves
+} Kit_TextureAtlas;
+
+KIT_LOCAL Kit_TextureAtlas* Kit_CreateAtlas();
+KIT_LOCAL void Kit_FreeAtlas(Kit_TextureAtlas *atlas);
+KIT_LOCAL void Kit_ClearAtlasContent(Kit_TextureAtlas *atlas);
+KIT_LOCAL void Kit_CheckAtlasTextureSize(Kit_TextureAtlas *atlas, SDL_Texture *texture);
+KIT_LOCAL int Kit_GetAtlasItems(const Kit_TextureAtlas *atlas, SDL_Rect *sources, SDL_Rect *targets, int limit);
+KIT_LOCAL int Kit_AddAtlasItem(Kit_TextureAtlas *atlas, SDL_Texture *texture, SDL_Surface *surface, const SDL_Rect *target);
+
+#endif // KITATLAS_H
diff --git a/include/kitchensink/internal/subtitle/kitsubtitle.h b/include/kitchensink/internal/subtitle/kitsubtitle.h new file mode 100644 index 0000000..8bb2a62 --- /dev/null +++ b/include/kitchensink/internal/subtitle/kitsubtitle.h @@ -0,0 +1,17 @@ +#ifndef KITSUBTITLE_H
+#define KITSUBTITLE_H
+
+#include <SDL_render.h>
+
+#include "kitchensink/kitconfig.h"
+#include "kitchensink/kitsource.h"
+#include "kitchensink/internal/kitdecoder.h"
+
+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_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);
+
+#endif // KITSUBTITLE_H
diff --git a/include/kitchensink/internal/subtitle/kitsubtitlepacket.h b/include/kitchensink/internal/subtitle/kitsubtitlepacket.h new file mode 100644 index 0000000..c560c74 --- /dev/null +++ b/include/kitchensink/internal/subtitle/kitsubtitlepacket.h @@ -0,0 +1,22 @@ +#ifndef KITSUBTITLEPACKET_H
+#define KITSUBTITLEPACKET_H
+
+#include <stdbool.h>
+#include <SDL_surface.h>
+
+#include "kitchensink/kitconfig.h"
+
+typedef struct Kit_SubtitlePacket {
+ double pts_start;
+ double pts_end;
+ int x;
+ int y;
+ bool clear;
+ SDL_Surface *surface;
+} Kit_SubtitlePacket;
+
+KIT_LOCAL Kit_SubtitlePacket* Kit_CreateSubtitlePacket(
+ bool clear, double pts_start, double pts_end, int pos_x, int pos_y, SDL_Surface *surface);
+KIT_LOCAL void Kit_FreeSubtitlePacket(Kit_SubtitlePacket *packet);
+
+#endif // KITSUBTITLEPACKET_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..6dff50c --- /dev/null +++ b/include/kitchensink/internal/subtitle/renderers/kitsubass.h @@ -0,0 +1,11 @@ +#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(
+ Kit_Decoder *dec, int video_w, int video_h, int screen_w, int screen_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..883fde3 --- /dev/null +++ b/include/kitchensink/internal/subtitle/renderers/kitsubimage.h @@ -0,0 +1,11 @@ +#ifndef KITSUBIMAGE_H
+#define KITSUBIMAGE_H
+
+#include "kitchensink/kitconfig.h"
+#include "kitchensink/internal/kitdecoder.h"
+#include "kitchensink/internal/subtitle/renderers/kitsubrenderer.h"
+
+KIT_LOCAL Kit_SubtitleRenderer* Kit_CreateImageSubtitleRenderer(
+ Kit_Decoder *dec, int video_w, int video_h, int screen_w, int screen_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..3c37b00 --- /dev/null +++ b/include/kitchensink/internal/subtitle/renderers/kitsubrenderer.h @@ -0,0 +1,32 @@ +#ifndef KITSUBRENDERER_H
+#define KITSUBRENDERER_H
+
+#include <SDL_render.h>
+
+#include "kitchensink/kitsource.h"
+
+typedef struct Kit_SubtitleRenderer Kit_SubtitleRenderer;
+typedef struct Kit_TextureAtlas Kit_TextureAtlas;
+typedef struct Kit_Decoder Kit_Decoder;
+
+typedef void (*ren_render_cb)(Kit_SubtitleRenderer *ren, void *src, double start_pts, double end_pts);
+typedef int (*ren_get_data_cb)(Kit_SubtitleRenderer *ren, Kit_TextureAtlas *atlas, SDL_Texture *texture, double current_pts);
+typedef void (*ren_set_size_cb)(Kit_SubtitleRenderer *ren, int w, int h);
+typedef void (*ren_close_cb)(Kit_SubtitleRenderer *ren);
+
+struct Kit_SubtitleRenderer {
+ Kit_Decoder *dec;
+ void *userdata;
+ ren_render_cb ren_render; ///< Subtitle rendering function callback
+ ren_get_data_cb ren_get_data; ///< Subtitle data getter function callback
+ ren_set_size_cb ren_set_size; ///< Screen size setter function callback
+ ren_close_cb ren_close; ///< Subtitle renderer close function callback
+};
+
+KIT_LOCAL Kit_SubtitleRenderer* Kit_CreateSubtitleRenderer(Kit_Decoder *dec);
+KIT_LOCAL void Kit_RunSubtitleRenderer(Kit_SubtitleRenderer *ren, void *src, double start_pts, double end_pts);
+KIT_LOCAL int Kit_GetSubtitleRendererData(Kit_SubtitleRenderer *ren, Kit_TextureAtlas *atlas, SDL_Texture *texture, double current_pts);
+KIT_LOCAL void Kit_SetSubtitleRendererSize(Kit_SubtitleRenderer *ren, int w, int h);
+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..67d93c3 100644 --- a/include/kitchensink/internal/kitbuffer.h +++ b/include/kitchensink/internal/utils/kitbuffer.h @@ -6,6 +6,7 @@ typedef struct Kit_Buffer Kit_Buffer; typedef void (*Kit_BufferFreeCallback)(void*); +typedef void (*Kit_ForEachItemCallback)(void*, void *userdata); struct Kit_Buffer { unsigned int read_p; @@ -23,6 +24,7 @@ KIT_LOCAL void* Kit_ReadBuffer(Kit_Buffer *buffer); KIT_LOCAL void* Kit_PeekBuffer(const Kit_Buffer *buffer); KIT_LOCAL void Kit_AdvanceBuffer(Kit_Buffer *buffer); KIT_LOCAL int Kit_WriteBuffer(Kit_Buffer *buffer, void *ptr); +KIT_LOCAL void Kit_ForEachItemInBuffer(const Kit_Buffer *buffer, Kit_ForEachItemCallback cb, void *userdata); KIT_LOCAL int Kit_IsBufferFull(const Kit_Buffer *buffer); #endif // KITBUFFER_H diff --git a/include/kitchensink/internal/utils/kithelpers.h b/include/kitchensink/internal/utils/kithelpers.h new file mode 100644 index 0000000..5b94a7a --- /dev/null +++ b/include/kitchensink/internal/utils/kithelpers.h @@ -0,0 +1,11 @@ +#ifndef KITHELPERS_H
+#define KITHELPERS_H
+
+#include <stdbool.h>
+#include <libavformat/avformat.h>
+#include "kitchensink/kitconfig.h"
+
+KIT_LOCAL double _GetSystemTime();
+KIT_LOCAL bool attachment_is_font(AVStream *stream);
+
+#endif // KITHELPERS_H
diff --git a/include/kitchensink/internal/utils/kitlog.h b/include/kitchensink/internal/utils/kitlog.h new file mode 100644 index 0000000..d298592 --- /dev/null +++ b/include/kitchensink/internal/utils/kitlog.h @@ -0,0 +1,11 @@ +#ifndef KITLOG_H
+#define KITLOG_H
+
+#ifdef NDEBUG
+#define LOG(...)
+#else
+#include <stdio.h>
+#define LOG(...) fprintf(stderr, __VA_ARGS__); fflush(stderr)
+#endif
+
+#endif // KITLOG_H
diff --git a/include/kitchensink/internal/kitringbuffer.h b/include/kitchensink/internal/utils/kitringbuffer.h index 2f67520..153dfd4 100644 --- a/include/kitchensink/internal/kitringbuffer.h +++ b/include/kitchensink/internal/utils/kitringbuffer.h @@ -6,7 +6,8 @@ typedef struct Kit_RingBuffer { int size; int len; - int wpos, rpos; + int wpos; + int rpos; char* data; } Kit_RingBuffer; diff --git a/include/kitchensink/internal/video/kitvideo.h b/include/kitchensink/internal/video/kitvideo.h new file mode 100644 index 0000000..5c072ef --- /dev/null +++ b/include/kitchensink/internal/video/kitvideo.h @@ -0,0 +1,13 @@ +#ifndef KITVIDEO_H
+#define KITVIDEO_H
+
+#include <SDL_render.h>
+
+#include "kitchensink/kitconfig.h"
+#include "kitchensink/kitsource.h"
+#include "kitchensink/internal/kitdecoder.h"
+
+KIT_LOCAL Kit_Decoder* Kit_CreateVideoDecoder(const Kit_Source *src, int stream_index);
+KIT_LOCAL int Kit_GetVideoDecoderData(Kit_Decoder *dec, SDL_Texture *texture);
+
+#endif // KITVIDEO_H
diff --git a/include/kitchensink/kitchensink.h b/include/kitchensink/kitchensink.h index be318a5..7fc08e6 100644 --- a/include/kitchensink/kitchensink.h +++ b/include/kitchensink/kitchensink.h @@ -1,8 +1,18 @@ #ifndef KITCHENSINK_H #define KITCHENSINK_H +/** + * @brief Header aggregator + * + * @file kitchensink.h + * @author Tuomas Virtanen + * @date 2018-06-27 + */ + #include "kitchensink/kitlib.h" #include "kitchensink/kiterror.h" +#include "kitchensink/kitformat.h" +#include "kitchensink/kitcodec.h" #include "kitchensink/kitsource.h" #include "kitchensink/kitplayer.h" #include "kitchensink/kitutils.h" diff --git a/include/kitchensink/kitcodec.h b/include/kitchensink/kitcodec.h new file mode 100644 index 0000000..589f84d --- /dev/null +++ b/include/kitchensink/kitcodec.h @@ -0,0 +1,32 @@ +#ifndef KITCODEC_H
+#define KITCODEC_H
+
+/**
+ * @brief Codec type
+ *
+ * @file kitcodec.h
+ * @author Tuomas Virtanen
+ * @date 2018-06-25
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define KIT_CODEC_NAME_MAX 8
+#define KIT_CODEC_DESC_MAX 48
+
+/**
+ * @brief Contains information about the used codec for playback
+ */
+typedef struct Kit_Codec {
+ unsigned int threads; ///< Currently enabled threads (For all decoders)
+ char name[KIT_CODEC_NAME_MAX]; ///< Codec short name, eg. "ogg" or "webm"
+ char description[KIT_CODEC_DESC_MAX]; ///< Codec longer, more descriptive name
+} Kit_Codec;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // KITCODEC_H
diff --git a/include/kitchensink/kitconfig.h b/include/kitchensink/kitconfig.h index e8b2d01..8eda779 100644 --- a/include/kitchensink/kitconfig.h +++ b/include/kitchensink/kitconfig.h @@ -1,6 +1,14 @@ #ifndef KITCONFIG_H #define KITCONFIG_H +/** + * @brief Public API configurations + * + * @file kitconfig.h + * @author Tuomas Virtanen + * @date 2018-06-25 + */ + #if defined _WIN32 || defined __CYGWIN__ #define KIT_DLL_IMPORT __declspec(dllimport) #define KIT_DLL_EXPORT __declspec(dllexport) diff --git a/include/kitchensink/kiterror.h b/include/kitchensink/kiterror.h index 824ea8c..e6c2acd 100644 --- a/include/kitchensink/kiterror.h +++ b/include/kitchensink/kiterror.h @@ -1,14 +1,38 @@ #ifndef KITERROR_H #define KITERROR_H +/** + * @brief Error handling functions + * + * @file kiterror.h + * @author Tuomas Virtanen + * @date 2018-06-25 + */ + #include "kitchensink/kitconfig.h" #ifdef __cplusplus extern "C" { #endif +/** + * @brief Returns the latest error. This is set by SDL_kitchensink library functions on error. + * + * @return Error message or NULL + */ KIT_API const char* Kit_GetError(); + +/** + * @brief Sets the error message. This should really only be used by the library. + * + * @param fmt Message format + * @param ... Message arguments + */ KIT_API void Kit_SetError(const char* fmt, ...); + +/** + * @brief Clears latest error message. After this, Kit_GetError() will return NULL. + */ KIT_API void Kit_ClearError(); #ifdef __cplusplus diff --git a/include/kitchensink/kitformat.h b/include/kitchensink/kitformat.h new file mode 100644 index 0000000..3e8df91 --- /dev/null +++ b/include/kitchensink/kitformat.h @@ -0,0 +1,33 @@ +#ifndef KITFORMAT_H
+#define KITFORMAT_H
+
+/**
+ * @brief Audio/video output format type
+ *
+ * @file kitformat.h
+ * @author Tuomas Virtanen
+ * @date 2018-06-25
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief Contains information about the data format coming out from the player
+ */
+typedef struct Kit_OutputFormat {
+ unsigned int format; ///< SDL Format (SDL_PixelFormat if video/subtitle, SDL_AudioFormat if audio)
+ int is_signed; ///< Signedness, 1 = signed, 0 = unsigned (if audio)
+ int bytes; ///< Bytes per sample per channel (if audio)
+ int samplerate; ///< Sampling rate (if audio)
+ int channels; ///< Channels (if audio)
+ int width; ///< Width in pixels (if video)
+ int height; ///< Height in pixels (if video)
+} Kit_OutputFormat;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // KITFORMAT_H
diff --git a/include/kitchensink/kitlib.h b/include/kitchensink/kitlib.h index 9a827be..a5fe913 100644 --- a/include/kitchensink/kitlib.h +++ b/include/kitchensink/kitlib.h @@ -1,29 +1,118 @@ #ifndef KITLIB_H #define KITLIB_H -#include "kitchensink/kiterror.h" -#include "kitchensink/kitsource.h" -#include "kitchensink/kitplayer.h" -#include "kitchensink/kitutils.h" +/** + * @brief Library initialization and deinitialization functionality + * + * @file kitlib.h + * @author Tuomas Virtanen + * @date 2018-06-25 + */ + #include "kitchensink/kitconfig.h" #ifdef __cplusplus extern "C" { #endif +/** + * @brief Font hinting options. Used as values for Kit_SetHint(KIT_HINT_FONT_HINTING, ...). + */ +enum { + KIT_FONT_HINTING_NONE = 0, ///< No hinting. This is recommended option + KIT_FONT_HINTING_LIGHT, ///< Light hinting. Use this if you need hinting + KIT_FONT_HINTING_NORMAL, ///< Not recommended, please see libass docs for details + KIT_FONT_HINTING_NATIVE, ///< Not recommended, please see libass docs for details + KIT_FONT_HINTING_COUNT +}; + +/** + * @brief SDL_kitchensink library version container + */ typedef struct Kit_Version { - unsigned char major; - unsigned char minor; - unsigned char patch; + unsigned char major; ///< Major version number, raising this signifies API breakage + unsigned char minor; ///< Minor version number, small/internal changes + unsigned char patch; ///< Patch version number, bugfixes etc. } Kit_Version; +/** + * @brief Library hint types. Used as keys for Kit_SetHint(). + * + * Note that all of these must be set *before* player initialization for them to take effect! + */ +typedef enum Kit_HintType { + KIT_HINT_FONT_HINTING, ///< Set font hinting mode (currently used for libass) + KIT_HINT_THREAD_COUNT, ///< Set thread count for ffmpeg (1 by default) + KIT_HINT_VIDEO_BUFFER_FRAMES, ///< Video output buffer frames (3 by default) + KIT_HINT_AUDIO_BUFFER_FRAMES, ///< Audio output buffers (64 by default) + KIT_HINT_SUBTITLE_BUFFER_FRAMES ///< Subtitle output buffers (64 by default, used by image subtitles) +} Kit_HintType; + +/** + * @brief Library initialization options, please see Kit_Init() + * + */ enum { - KIT_INIT_FORMATS = 0x1, - KIT_INIT_NETWORK = 0x2, + KIT_INIT_NETWORK = 0x1, ///< Initialise ffmpeg network support + KIT_INIT_ASS = 0x2 ///< Initialize libass support (library must be linked statically or loadable dynamically) }; +/** + * @brief Initialize SDL_kitchensink library. + * + * This MUST be run before doing anything. After you are done using the library, you should use Kit_Quit() to + * deinitialize everything. Otherwise there might be resource leaks. + * + * Following flags can be used to initialize subsystems: + * - `KIT_INIT_NETWORK` for ffmpeg network support (playback from the internet, for example) + * - `KIT_INIT_ASS` for libass subtitles (text and ass/ssa subtitle support) + * + * Note that if this function fails, the failure reason should be available via Kit_GetError(). + * + * For example: + * ``` + * if(Kit_Init(KIT_INIT_NETWORK|KIT_INIT_ASS) != 0) { + * fprintf(stderr, "Error: %s\n", Kit_GetError()); + * return 1; + * } + * ``` + * + * @param flags Library initialization flags + * @return Returns 0 on success, 1 on failure. + */ KIT_API int Kit_Init(unsigned int flags); + +/** + * @brief Deinitializes SDL_kitchensink + * + * Note that any calls to library functions after this will cause undefined behaviour! + */ KIT_API void Kit_Quit(); + +/** + * @brief Sets a librarywide hint + * + * This can be used to set hints on how the library should behave. See Kit_HintType + * for all the options. + * + * @param type Hint type (refer to Kit_HintType for options) + * @param value Value for the hint + */ +KIT_API void Kit_SetHint(Kit_HintType type, int value); + +/** + * @brief Gets a previously set or default hint value + * + * @param type Hint type (refer to Kit_HintType for options) + * @return Hint value + */ +KIT_API int Kit_GetHint(Kit_HintType type); + +/** + * @brief Can be used to fetch the version of the linked SDL_kitchensink library + * + * @param version Allocated Kit_Version + */ KIT_API void Kit_GetVersion(Kit_Version *version); #ifdef __cplusplus diff --git a/include/kitchensink/kitplayer.h b/include/kitchensink/kitplayer.h index b9ea1c7..1c73020 100644 --- a/include/kitchensink/kitplayer.h +++ b/include/kitchensink/kitplayer.h @@ -1,124 +1,339 @@ #ifndef KITPLAYER_H #define KITPLAYER_H +/** + * @brief Video/audio player functions + * + * @file kitplayer.h + * @author Tuomas Virtanen + * @date 2018-06-27 + */ + #include "kitchensink/kitsource.h" #include "kitchensink/kitconfig.h" +#include "kitchensink/kitformat.h" +#include "kitchensink/kitcodec.h" -#include <SDL2/SDL_render.h> -#include <SDL2/SDL_thread.h> -#include <SDL2/SDL_surface.h> - -#include <stdbool.h> +#include <SDL_render.h> #ifdef __cplusplus extern "C" { #endif -#define KIT_CODECMAX 16 -#define KIT_CODECNAMEMAX 128 - +/** + * @brief Playback states + */ 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_AudioFormat { - int stream_idx; ///< Stream index - 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 { - int stream_idx; ///< Stream index - 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_SubtitleFormat { - int stream_idx; ///< Stream index - bool is_enabled; ///< Is stream enabled -} Kit_SubtitleFormat; - +/** + * @brief Player state container + */ typedef struct Kit_Player { - // Local state - Kit_PlayerState state; ///< Playback state - Kit_VideoFormat vformat; ///< Video format information - Kit_AudioFormat aformat; ///< Audio format information - Kit_SubtitleFormat sformat; ///< Subtitle 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 *smutex; ///< Subtitle stream buffer lock - SDL_mutex *cmutex; ///< Control stream buffer lock - - // Buffers - void *abuffer; ///< Audio stream buffer - void *vbuffer; ///< Video stream buffer - void *sbuffer; ///< Subtitle 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 *scodec_ctx; ///< FFmpeg: Subtitle codec context - void *tmp_vframe; ///< FFmpeg: Preallocated temporary video frame - void *tmp_aframe; ///< FFmpeg: Preallocated temporary audio frame - void *tmp_sframe; ///< FFmpeg: Preallocated temporary subtitle frame - void *swr; ///< FFmpeg: Audio resampler - void *sws; ///< FFmpeg: Video converter - - // libass - void *ass_renderer; - void *ass_track; - - // Other - uint8_t seek_flag; - const Kit_Source *src; ///< Reference to Audio/Video source + Kit_PlayerState state; ///< Playback state + void *decoders[3]; ///< Decoder contexts + void *dec_thread; ///< Decoder thread + void *dec_lock; ///< Decoder lock + const Kit_Source *src; ///< Reference to Audio/Video source + double pause_started; ///< Temporary flag for handling pauses } Kit_Player; +/** + * @brief Contains data about a stream selected for playback + */ +typedef struct Kit_PlayerStreamInfo { + Kit_Codec codec; ///< Decoder codec information + Kit_OutputFormat output; ///< Information about the output format +} Kit_PlayerStreamInfo; + +/** + * @brief Contains information about the streams selected for playback + * + */ typedef struct Kit_PlayerInfo { - 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 - char scodec[KIT_CODECMAX]; ///< Subtitle codec short name, eg. "ass" - char scodec_name[KIT_CODECNAMEMAX]; ///< Subtitle codec long, more descriptive name - Kit_VideoFormat video; ///< Video format information - Kit_AudioFormat audio; ///< Audio format information - Kit_SubtitleFormat subtitle; ///< Subtitle format information + Kit_PlayerStreamInfo video; ///< Video stream data + Kit_PlayerStreamInfo audio; ///< Audio stream data + Kit_PlayerStreamInfo subtitle; ///< Subtitle stream data } Kit_PlayerInfo; -KIT_API Kit_Player* Kit_CreatePlayer(const Kit_Source *src); +/** + * @brief Creates a new player from a source. + * + * Creates a new player from the given source. The source must be previously succesfully + * initialized by calling either Kit_CreateSourceFromUrl() or Kit_CreateSourceFromCustom(), + * and it must not be used by any other player. Source must stay valid during the whole + * playback (as in, don't close it while stuff is playing). + * + * Screen width and height are used for subtitle positioning, scaling and rendering resolution. + * Ideally this should be precisely the size of your screen surface (in pixels). + * Higher resolution leads to higher resolution text rendering. This MUST be set precisely + * if you plan to use font hinting! If you don't care or don't have subtitles at all, + * set both to video surface size or 0. + * + * For streams, either video and/or audio stream MUST be set! Either set the stream indexes manually, + * or pick them automatically by using Kit_GetBestSourceStream(). + * + * On success, this will return an initialized Kit_Player which can later be freed by Kit_ClosePlayer(). + * On error, NULL is returned and a more detailed error is availably via Kit_GetError(). + * + * For example: + * ``` + * Kit_Player *player = Kit_CreatePlayer( + * src, + * Kit_GetBestSourceStream(src, KIT_STREAMTYPE_VIDEO), + * Kit_GetBestSourceStream(src, KIT_STREAMTYPE_AUDIO), + * Kit_GetBestSourceStream(src, KIT_STREAMTYPE_SUBTITLE), + * 1280, 720); + * if(player == NULL) { + * fprintf(stderr, "Unable to create player: %s\n", Kit_GetError()); + * return 1; + * } + * ``` + * + * @param src Valid video/audio source + * @param video_stream_index Video stream index or -1 if not wanted + * @param audio_stream_index Audio stream index or -1 if not wanted + * @param subtitle_stream_index Subtitle stream index or -1 if not wanted + * @param screen_w Screen width in pixels + * @param screen_h Screen height in pixels + * @return Ínitialized Kit_Player or NULL + */ +KIT_API Kit_Player* Kit_CreatePlayer(const Kit_Source *src, + int video_stream_index, + int audio_stream_index, + int subtitle_stream_index, + int screen_w, + int screen_h); + +/** + * @brief Close previously initialized player + * + * Closes a previously initialized Kit_Player instance. Note that this does NOT free + * the linked Kit_Source -- you must free it manually. + * + * @param player Player instance + */ 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); +/** + * @brief Sets the current screen size in pixels + * + * Call this to change the subtitle font rendering resolution if eg. your + * video window size changes. + * + * This does nothing if subtitles are not in use or if subtitles are bitmaps. + * + * @param player Player instance + * @param w New width in pixels + * @param h New height in pixels + */ +KIT_API void Kit_SetPlayerScreenSize(Kit_Player *player, int w, int h); + +/** + * @brief Gets the current video stream index + * + * Returns the current video stream index or -1 if one is not selected. + * + * @param player Player instance + * @return Video stream index or -1 + */ +KIT_API int Kit_GetPlayerVideoStream(const Kit_Player *player); + +/** + * @brief Gets the current audio stream index + * + * Returns the current audio stream index or -1 if one is not selected. + * + * @param player Player instance + * @return Audio stream index or -1 + */ +KIT_API int Kit_GetPlayerAudioStream(const Kit_Player *player); + +/** + * @brief Gets the current subtitle stream index + * + * Returns the current subtitle stream index or -1 if one is not selected. + * + * @param player Player instance + * @return Subtitle stream index or -1 + */ +KIT_API int Kit_GetPlayerSubtitleStream(const Kit_Player *player); + +/** + * @brief Fetches a new video frame from the player + * + * Note that the output texture must be previously allocated and valid. + * + * It is important to select the correct texture format and size. If you pick a different + * texture format or size from what the decoder outputs, then the decoder will attempt to convert + * the frames to fit the texture. This will slow down the decoder a *lot* however, so if possible, + * pick the texture format from what Kit_GetPlayerInfo() outputs. + * + * Access flag for the texture *MUST* always be SDL_TEXTUREACCESS_STATIC! Anything else will lead to + * undefined behaviour. + * + * This function will do nothing if player playback has not been started. + * + * @param player Player instance + * @param texture A previously allocated texture + * @return 0 on success, 1 on error + */ +KIT_API int Kit_GetPlayerVideoData(Kit_Player *player, SDL_Texture *texture); + +/** + * @brief Fetches subtitle data from the player + * + * Output texture will be used as a texture atlas for the subtitle fragments. + * + * Note that the output texture must be previously allocated and valid. Make sure to have large + * enough a texture for the rendering resolution you picked! If your rendering resolution if 4k, + * then make sure to have texture sized 4096x4096 etc. This gives the texture room to handle the + * worst case subtitle textures. If your resolutions is too small, this function will return + * value -1. At that point you can replace your current texture with a bigger one on the fly. + * + * Note that the texture format for the atlas texture *MUST* be SDL_PIXELFORMAT_RGBA32 and + * the access flag *MUST* be set to SDL_TEXTUREACCESS_STATIC for correct rendering. + * Using any other format will lead to undefined behaviour. Also, make sure to set scaling quality + * to 0 or "nearest" before creating the texture -- otherwise you get artifacts + * (see SDL_HINT_RENDER_SCALE_QUALITY). + * + * This function will do nothing if player playback has not been started. + * + * For example: + * ``` + * SDL_Rect sources[256]; + * SDL_Rect targets[256]; + * int got = Kit_GetPlayerSubtitleData(player, subtitle_tex, sources, targets, 256); + * for(int i = 0; i < got; i++) { + * SDL_RenderCopy(renderer, subtitle_tex, &sources[i], &targets[i]); + * } + * ``` + * + * @param player Player instance + * @param texture A previously allocated texture + * @param sources List of source rectangles to copy fropm + * @param targets List of target rectangles to render + * @param limit Defines the maximum size of your rectangle lists + * @return Number of sources or <0 on error + */ +KIT_API int Kit_GetPlayerSubtitleData(Kit_Player *player, + SDL_Texture *texture, + SDL_Rect *sources, + SDL_Rect *targets, + int limit); + +/** + * @brief Fetches audio data from the player + * + * Note that the output buffer must be previously allocated. + * + * Outputted audio data will be precisely what is described by the output format struct given + * by Kit_GetPlayerInfo(). + * + * This function will attemt to read the maximum allowed amount of data allowed by the length + * argument. It is possible however that there is not enough data available, at which point + * this function will read less and return value may differ from maximum allowed value. + * Return value 0 should be taken as a hint that there is nothing available. + * + * This function will do nothing if player playback has not been started. + * + * @param player Player instance + * @param buffer Buffer to read into + * @param length Maximum length of the buffer + * @return Amount of data that was read, <0 on error. + */ +KIT_API int Kit_GetPlayerAudioData(Kit_Player *player, unsigned char *buffer, int length); + +/** + * @brief Fetches information about the currently selected streams + * + * This function should be used to fetch codec information and output format data from the player + * before creating textures and setting up audio outputs. + * + * @param player Player instance + * @param info A previously allocated Kit_PlayerInfo instance + */ KIT_API void Kit_GetPlayerInfo(const Kit_Player *player, Kit_PlayerInfo *info); +/** + * @brief Returns the current state of the player + * + * @param player Player instance + * @return Current state of the player, see Kit_PlayerState + */ KIT_API Kit_PlayerState Kit_GetPlayerState(const Kit_Player *player); + +/** + * @brief Starts playback + * + * State shifts: + * - If player is already playing, will do nothing. + * - If player is paused, will resume playback. + * - If player is stopped, will begin playback (and background decoding). + * + * @param player Player instance + */ KIT_API void Kit_PlayerPlay(Kit_Player *player); + +/** + * @brief Stops playback + * + * State shifts: + * - If player is already stopped, will do nothing. + * - If player is paused, will stop playback. + * - If player is started, will stop playback (and background decoding). + * + * @param player Player instance + */ KIT_API void Kit_PlayerStop(Kit_Player *player); + +/** + * @brief Pauses playback + * + * State shifts: + * - If player is already paused, will do nothing. + * - If player is stopped, will do nothing. + * - If player is started, will pause playback (and background decoding). + * + * @param player Player instance + */ KIT_API void Kit_PlayerPause(Kit_Player *player); +/** + * @brief Seek to timestamp + * + * Rewinds or forwards video/audio playback to the given timestamp (in seconds). + * + * This may not work for network or custom sources! + * + * @param player Player instance + * @param time Timestamp to seek to in seconds + * @return 0 on success, 1 on failure. + */ KIT_API int Kit_PlayerSeek(Kit_Player *player, double time); + +/** + * @brief Get the duration of the source + * + * Returns the duration of the source in seconds + * + * @param player Player instance + * @return Duration + */ KIT_API double Kit_GetPlayerDuration(const Kit_Player *player); + +/** + * @brief Get the current position of the playback + * + * Returns the position of the playback in seconds + * + * @param player Player instance + * @return Position + */ KIT_API double Kit_GetPlayerPosition(const Kit_Player *player); #ifdef __cplusplus diff --git a/include/kitchensink/kitsource.h b/include/kitchensink/kitsource.h index ed1711f..9b744ca 100644 --- a/include/kitchensink/kitsource.h +++ b/include/kitchensink/kitsource.h @@ -1,15 +1,27 @@ #ifndef KITSOURCE_H #define KITSOURCE_H +/** + * @brief Video/Audio source file handling + * + * @file kitsource.h + * @author Tuomas Virtanen + * @date 2018-06-27 + */ + +#include <inttypes.h> +#include <SDL_rwops.h> #include "kitchensink/kitconfig.h" #ifdef __cplusplus extern "C" { #endif -#define KIT_CODECNAMESIZE 32 -#define KIT_CODECLONGNAMESIZE 128 - +/** + * @brief Type of the stream. + * + * This is used by Kit_SourceStreamInfo and Kit_GetSourceStreamInfo(). + */ typedef enum Kit_StreamType { KIT_STREAMTYPE_UNKNOWN, ///< Unknown stream type KIT_STREAMTYPE_VIDEO, ///< Video stream @@ -19,26 +31,202 @@ typedef enum Kit_StreamType { KIT_STREAMTYPE_ATTACHMENT ///< Attachment stream (images, etc) } Kit_StreamType; +/** + * @brief Audio/video source. + * + * Should be created using Kit_CreateSourceFromUrl() or Kit_CreateSourceFromCustom(), and + * closed with Kit_CloseSource(). + * + * Source must exist for the whole duration of using a player. You must take care of closing the source + * yourself after you are done with it! + */ typedef struct Kit_Source { - int astream_idx; ///< Audio stream index - int vstream_idx; ///< Video stream index - int sstream_idx; ///< Subtitle stream index void *format_ctx; ///< FFmpeg: Videostream format context + void *avio_ctx; ///< FFmpeg: AVIO context } Kit_Source; -typedef struct Kit_Stream { +/** + * @brief Information for a source stream. + * + * Fetch information by using Kit_GetSourceStreamInfo(). + */ +typedef struct Kit_SourceStreamInfo { int index; ///< Stream index Kit_StreamType type; ///< Stream type -} Kit_StreamInfo; +} Kit_SourceStreamInfo; + +/** + * @brief Callback function type for reading data stream + * + * Used by Kit_CreateSourceFromCustom() for reading data from user defined source. + * + * A custom reader function must accept three arguments: + * - userdata, this is the same data as set as last argument for Kit_CreateSourceFromCustom + * - buf, a buffer the data must be copied into + * - size, how much data you are expected to provide at maximum. + * + * The function must return the amount of bytes copied to the buffer or <0 on error. + * + * Note that this callback is passed directly to ffmpeg avio, so please refer to ffmpeg documentation + * for any further details. + */ +typedef int (*Kit_ReadCallback)(void *userdata, uint8_t *buf, int size); + +/** + * @brief Callback function type for seeking data strema + * + * Used by Kit_CreateSourceFromCustom() for seeking a user defined source. + * + * A custom seeking function must accept three arguments: + * - userdata, this is the same data as set as last argument for Kit_CreateSourceFromCustom + * - offset, an seeking offset in bytes + * - whence, reference position for the offset. + * + * Whence parameter can be one of the standard fseek values or optionally AVSEEK_SIZE. + * - SEEK_SET: Reference position is beginning of file + * - SEEK_CUR: Reference position is the current position of the file pointer + * - SEEK_END: Reference position is the end of the file + * - AVSEEK_SIZE: Optional. Does not seek, instead finds the size of the source file. + * - AVSEEK_FORCE: Optional. Suggests that seeking should be done at any cost. May be passed alongside + * any of the SEEK_* flags, eg. SEEK_SET|AVSEEK_FORCE. + * + * The function must return the position (in bytes) we seeked to or <0 on error or on unsupported operation. + * + * Note that this callback is passed directly to ffmpeg avio, so please refer to ffmpeg documentation + * for any further details. + */ +typedef int64_t (*Kit_SeekCallback)(void *userdata, int64_t offset, int whence); + +/** + * @brief Create a new source from a given url + * + * This can be used to load video/audio from a file or network resource. If you wish to + * use network resources, make sure the library has been initialized using KIT_INIT_NETWORK flag. + * + * This function will return an initialized Kit_Source on success. Note that you need to manually + * free the source when it's no longer needed by calling Kit_CloseSource(). + * + * On failure, this function will return NULL, and further error data is available via Kit_GetError(). + * + * For example: + * ``` + * if(Kit_CreateSourceFromUrl(filename) == NULL) { + * fprintf(stderr, "Error: %s\n", Kit_GetError()); + * return 1; + * } + * ``` + * + * @param url File path or URL to a video/audio resource + * @return Returns an initialized Kit_Source* on success or NULL on failure + */ +KIT_API Kit_Source* Kit_CreateSourceFromUrl(const char *url); -KIT_API Kit_Source* Kit_CreateSourceFromUrl(const char *path); +/** + * @brief Create a new source from custom data + * + * This can be used to load data from any resource via the given read and seek functions. + * + * This function will return an initialized Kit_Source on success. Note that you need to manually + * free the source when it's no longer needed by calling Kit_CloseSource(). + * + * On failure, this function will return NULL, and further error data is available via Kit_GetError(). + * + * For example: + * ``` + * if(Kit_CreateSourceFromCustom(read_fn, seek_fn, fp) == NULL) { + * fprintf(stderr, "Error: %s\n", Kit_GetError()); + * return 1; + * } + * ``` + * + * @param read_cb Read function callback + * @param seek_cb Seek function callback + * @param userdata Any data (or NULL). Will be passed to read_cb and/or seek_cb functions as-is. + * @return Returns an initialized Kit_Source* on success or NULL on failure + */ +KIT_API Kit_Source* Kit_CreateSourceFromCustom(Kit_ReadCallback read_cb, Kit_SeekCallback seek_cb, void *userdata); + +/** + * @brief Create a new source from SDL RWops struct + * + * Can be used to read data from SDL compatible sources. + * + * This function will return an initialized Kit_Source on success. Note that you need to manually + * free the source when it's no longer needed by calling Kit_CloseSource(). + * + * On failure, this function will return NULL, and further error data is available via Kit_GetError(). + * + * Note that the RWops struct must exist during the whole lifetime of the source, and you must take + * care of freeing the rwops after it's no longer needed. + * + * For example: + * ``` + * SDL_RWops *rw = SDL_RWFromFile("myvideo.mkv", "rb"); + * if(Kit_CreateSourceFromRW(rw) == NULL) { + * fprintf(stderr, "Error: %s\n", Kit_GetError()); + * return 1; + * } + * ``` + * + * @param rw_ops Initialized RWOps + * @return KIT_API* Kit_CreateSourceFromRW + */ +KIT_API Kit_Source* Kit_CreateSourceFromRW(SDL_RWops *rw_ops); + +/** + * @brief Closes a previously initialized source + * + * Closes a Kit_Source that was previously created by Kit_CreateSourceFromUrl() or Kit_CreateSourceFromCustom() + * and frees up all memory and resources used by it. Using the source for anything after this will + * lead to undefined behaviour. + * + * Passing NULL as argument is valid, and will do nothing. + * + * @param src Previously initialized Kit_Source to close + */ KIT_API void Kit_CloseSource(Kit_Source *src); -KIT_API int Kit_GetSourceStreamInfo(const Kit_Source *src, Kit_StreamInfo *info, int index); +/** + * @brief Fetches stream information for a given stream index + * + * Sets fields for given Kit_SourceStreamInfo with information about the stream. + * + * For example: + * ``` + * Kit_SourceStreamInfo stream; + * if(Kit_GetSourceStreamInfo(source, &stream, 0) == 1) { + * fprintf(stderr, "Error: %s\n", Kit_GetError()); + * return 1; + * } + * fprintf(stderr, "Stream type: %s\n", Kit_GetKitStreamTypeString(stream.type)) + * ``` + * + * @param src Source to query from + * @param info A previously allocated Kit_SourceStreamInfo to fill out + * @param index Stream index (starting from 0) + * @return 0 on success, 1 on error. + */ +KIT_API int Kit_GetSourceStreamInfo(const Kit_Source *src, Kit_SourceStreamInfo *info, int index); + +/** + * @brief Gets the amount of streams in source + * + * @param src Source to query from + * @return Number of streams in the source + */ KIT_API int Kit_GetSourceStreamCount(const Kit_Source *src); + +/** + * @brief Gets the best stream index for a given stream type. + * + * Find the best stream index for a given stream type, if one exists. If there is no + * stream for the wanted type, will return -1. + * + * @param src Source to query from + * @param type Stream type + * @return Index number on success (>=0), -1 on error. + */ 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 index af3307c..af0e14b 100644 --- a/include/kitchensink/kitutils.h +++ b/include/kitchensink/kitutils.h @@ -1,14 +1,42 @@ #ifndef KITUTILS_H #define KITUTILS_H +/** + * @brief Helpful utilities + * + * @file kitutils.h + * @author Tuomas Virtanen + * @date 2018-06-25 + */ + #include "kitchensink/kitconfig.h" #ifdef __cplusplus extern "C" { #endif +/** + * @brief Returns a descriptive string for SDL audio format types + * + * @param type SDL_AudioFormat + * @return Format string, eg. "AUDIO_S8". + */ KIT_API const char* Kit_GetSDLAudioFormatString(unsigned int type); + +/** + * @brief Returns a descriptive string for SDL pixel format types + * + * @param type SDL_PixelFormat + * @return Format string, eg. "SDL_PIXELFORMAT_YV12" + */ KIT_API const char* Kit_GetSDLPixelFormatString(unsigned int type); + +/** + * @brief Returns a descriptibe string for Kitchensink stream types + * + * @param type Kit_StreamType + * @return Format string, eg. "KIT_STREAMTYPE_VIDEO" + */ KIT_API const char* Kit_GetKitStreamTypeString(unsigned int type); #ifdef __cplusplus |