summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--examples/example_complex.c14
-rw-r--r--examples/example_custom.c8
-rw-r--r--examples/example_simple.c8
-rw-r--r--include/kitchensink/kitplayer.h277
4 files changed, 290 insertions, 17 deletions
diff --git a/examples/example_complex.c b/examples/example_complex.c
index ac136ac..ada613a 100644
--- a/examples/example_complex.c
+++ b/examples/example_complex.c
@@ -72,7 +72,6 @@ int main(int argc, char *argv[]) {
// Audio playback
SDL_AudioSpec wanted_spec, audio_spec;
SDL_AudioDeviceID audio_dev;
- char audiobuf[AUDIOBUFFER_SIZE];
// Get filename to open
if(argc != 2) {
@@ -228,18 +227,25 @@ int main(int argc, char *argv[]) {
// Start playback
Kit_PlayerPlay(player);
- // Get movie area size
+ // Playback temporary data buffers
+ char audiobuf[AUDIOBUFFER_SIZE];
+ SDL_Rect sources[ATLAS_MAX];
+ SDL_Rect targets[ATLAS_MAX];
int mouse_x = 0;
int mouse_y = 0;
int size_w = 0;
int size_h = 0;
int screen_w = 0;
int screen_h = 0;
+ bool fullscreen = false;
+
+ // Get movie area size
SDL_GetWindowSize(window, &screen_w, &screen_h);
find_viewport_size(screen_w, screen_h, pinfo.video.output.width, pinfo.video.output.height, &size_w, &size_h);
SDL_RenderSetLogicalSize(renderer, size_w, size_h);
Kit_SetPlayerScreenSize(player, size_w, size_h);
- bool fullscreen = false;
+
+ // Run until playback is stopped
while(run) {
if(Kit_GetPlayerState(player) == KIT_STOPPED) {
run = false;
@@ -344,8 +350,6 @@ int main(int argc, char *argv[]) {
// Refresh subtitle texture atlas and render subtitle frames from it
// For subtitles, use screen size instead of video size for best quality
- SDL_Rect sources[ATLAS_MAX];
- SDL_Rect targets[ATLAS_MAX];
int got = Kit_GetPlayerSubtitleData(player, subtitle_tex, sources, targets, ATLAS_MAX);
for(int i = 0; i < got; i++) {
SDL_RenderCopy(renderer, subtitle_tex, &sources[i], &targets[i]);
diff --git a/examples/example_custom.c b/examples/example_custom.c
index 507efb1..1d33b0e 100644
--- a/examples/example_custom.c
+++ b/examples/example_custom.c
@@ -40,7 +40,6 @@ int main(int argc, char *argv[]) {
Kit_Player *player = NULL;
SDL_AudioSpec wanted_spec, audio_spec;
SDL_AudioDeviceID audio_dev;
- char audiobuf[AUDIOBUFFER_SIZE];
// Get filename to open
if(argc != 2) {
@@ -153,6 +152,11 @@ int main(int argc, char *argv[]) {
// Start playback
Kit_PlayerPlay(player);
+ // Playback temporary data buffers
+ char audiobuf[AUDIOBUFFER_SIZE];
+ SDL_Rect sources[ATLAS_MAX];
+ SDL_Rect targets[ATLAS_MAX];
+
// Get movie area size
SDL_RenderSetLogicalSize(renderer, pinfo.video.output.width, pinfo.video.output.height);
while(run) {
@@ -203,8 +207,6 @@ int main(int argc, char *argv[]) {
// Refresh subtitle texture atlas and render subtitle frames from it
// For subtitles, use screen size instead of video size for best quality
- SDL_Rect sources[ATLAS_MAX];
- SDL_Rect targets[ATLAS_MAX];
int got = Kit_GetPlayerSubtitleData(player, subtitle_tex, sources, targets, ATLAS_MAX);
for(int i = 0; i < got; i++) {
SDL_RenderCopy(renderer, subtitle_tex, &sources[i], &targets[i]);
diff --git a/examples/example_simple.c b/examples/example_simple.c
index d3b7146..2569fab 100644
--- a/examples/example_simple.c
+++ b/examples/example_simple.c
@@ -23,7 +23,6 @@ int main(int argc, char *argv[]) {
Kit_Player *player = NULL;
SDL_AudioSpec wanted_spec, audio_spec;
SDL_AudioDeviceID audio_dev;
- char audiobuf[AUDIOBUFFER_SIZE];
// Get filename to open
if(argc != 2) {
@@ -130,6 +129,11 @@ int main(int argc, char *argv[]) {
// Start playback
Kit_PlayerPlay(player);
+ // Playback temporary data buffers
+ char audiobuf[AUDIOBUFFER_SIZE];
+ SDL_Rect sources[ATLAS_MAX];
+ SDL_Rect targets[ATLAS_MAX];
+
// Get movie area size
SDL_RenderSetLogicalSize(renderer, pinfo.video.output.width, pinfo.video.output.height);
while(run) {
@@ -180,8 +184,6 @@ int main(int argc, char *argv[]) {
// Refresh subtitle texture atlas and render subtitle frames from it
// For subtitles, use screen size instead of video size for best quality
- SDL_Rect sources[ATLAS_MAX];
- SDL_Rect targets[ATLAS_MAX];
int got = Kit_GetPlayerSubtitleData(player, subtitle_tex, sources, targets, ATLAS_MAX);
for(int i = 0; i < got; i++) {
SDL_RenderCopy(renderer, subtitle_tex, &sources[i], &targets[i]);
diff --git a/include/kitchensink/kitplayer.h b/include/kitchensink/kitplayer.h
index 9d4857b..791851f 100644
--- a/include/kitchensink/kitplayer.h
+++ b/include/kitchensink/kitplayer.h
@@ -1,6 +1,14 @@
#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"
@@ -12,6 +20,9 @@
extern "C" {
#endif
+/**
+ * @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.
@@ -19,6 +30,9 @@ typedef enum Kit_PlayerState {
KIT_CLOSED, ///< Playback is stopped and player is closing.
} Kit_PlayerState;
+/**
+ * @brief Player state container
+ */
typedef struct Kit_Player {
Kit_PlayerState state; ///< Playback state
void *decoders[3]; ///< Decoder contexts
@@ -28,47 +42,298 @@ typedef struct Kit_Player {
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;
- Kit_OutputFormat output;
+ 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 {
- Kit_PlayerStreamInfo video;
- Kit_PlayerStreamInfo audio;
- Kit_PlayerStreamInfo subtitle;
+ Kit_PlayerStreamInfo video; ///< Video stream data
+ Kit_PlayerStreamInfo audio; ///< Audio stream data
+ Kit_PlayerStreamInfo subtitle; ///< Subtitle stream data
} Kit_PlayerInfo;
+/**
+ * @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);
+/**
+ * @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);
-KIT_API int Kit_UpdatePlayer(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