diff options
author | Tuomas Virtanen <katajakasa@gmail.com> | 2016-01-04 04:33:59 +0200 |
---|---|---|
committer | Tuomas Virtanen <katajakasa@gmail.com> | 2016-01-04 04:33:59 +0200 |
commit | 537ca31915603d7ed47ab4374a74058e340125c7 (patch) | |
tree | b3c19e8dae778385021ea08be596022d952ccab5 /src |
Initial commit; Not done yet though, needs more work.
Diffstat (limited to 'src')
-rw-r--r-- | src/kitchensink.c | 26 | ||||
-rw-r--r-- | src/kiterror.c | 30 | ||||
-rw-r--r-- | src/kitplayer.c | 2 | ||||
-rw-r--r-- | src/kitsource.c | 219 |
4 files changed, 277 insertions, 0 deletions
diff --git a/src/kitchensink.c b/src/kitchensink.c new file mode 100644 index 0000000..c2b526f --- /dev/null +++ b/src/kitchensink.c @@ -0,0 +1,26 @@ +#include "kitchensink/kitchensink.h" +#include <libavformat/avformat.h> + +static Uint32 _init_flags = 0; + +int Kit_Init(Uint32 flags) { + if(flags & KIT_INIT_NETWORK) + avformat_network_init(); + if(flags & KIT_INIT_FORMATS) + av_register_all(); + _init_flags = flags; + return 0; +} + +void Kit_Quit() { + if(_init_flags & KIT_INIT_NETWORK) { + avformat_network_deinit(); + } + _init_flags = 0; +} + +void Kit_GetVersion(Kit_Version *version) { + version->major = KIT_VERSION_MAJOR; + version->minor = KIT_VERSION_MINOR; + version->patch = KIT_VERSION_PATCH; +} diff --git a/src/kiterror.c b/src/kiterror.c new file mode 100644 index 0000000..948fda9 --- /dev/null +++ b/src/kiterror.c @@ -0,0 +1,30 @@ +#include "kitchensink/kitchensink.h" + +#include <stdarg.h> +#include <stdbool.h> + +#define KIT_ERRBUFSIZE 1024 + +static char _error_available = false; +static char _error_message[KIT_ERRBUFSIZE] = "\0"; + +const char* Kit_GetError() { + if(_error_available) { + _error_available = false; + return _error_message; + } + return NULL; +} + +void Kit_SetError(const char* fmt, ...) { + va_list args; + va_start(args, fmt); + vsnprintf(_error_message, KIT_ERRBUFSIZE, (char*)fmt, args); + va_end(args); + _error_available = true; +} + +void Kit_ClearError() { + _error_message[0] = 0; + _error_available = false; +} diff --git a/src/kitplayer.c b/src/kitplayer.c new file mode 100644 index 0000000..704317f --- /dev/null +++ b/src/kitplayer.c @@ -0,0 +1,2 @@ +#include <kitchensink/kitplayer.h> + diff --git a/src/kitsource.c b/src/kitsource.c new file mode 100644 index 0000000..c947ea1 --- /dev/null +++ b/src/kitsource.c @@ -0,0 +1,219 @@ +#include "kitchensink/kitsource.h" +#include "kitchensink/kiterror.h" + +#include <libavcodec/avcodec.h> +#include <libavformat/avformat.h> + +#include <stdlib.h> +#include <string.h> + +Kit_Source* Kit_CreateSourceFromUrl(const char *url) { + AVFormatContext *format_ctx = NULL; + + if(url == NULL) { + Kit_SetError("Source URL must not be NULL"); + return NULL; + } + + // Attempt to open source + if(avformat_open_input(&format_ctx, url, NULL, NULL) < 0) { + Kit_SetError("Unable to open source Url"); + goto exit_0; + } + + // Fetch stream information. This may potentially take a while. + if(avformat_find_stream_info(format_ctx, NULL) < 0) { + Kit_SetError("Unable to fetch source information"); + goto exit_1; + } + + // Find best streams for defaults + int best_astream_idx = av_find_best_stream(format_ctx, AVMEDIA_TYPE_AUDIO, -1, -1, NULL, 0); + int best_vstream_idx = av_find_best_stream(format_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0); + + // Allocate and return a new source + // TODO: Check allocation errors + Kit_Source *out = calloc(1, sizeof(Kit_Source)); + out->format_ctx = format_ctx; + out->astream_idx = best_astream_idx; + out->vstream_idx = best_vstream_idx; + return out; + +exit_1: + avformat_close_input(&format_ctx); +exit_0: + return NULL; +} + +int Kit_InitSourceCodecs(Kit_Source *src) { + AVCodecContext *acodec_ctx = NULL; + AVCodecContext *vcodec_ctx = NULL; + AVCodec *acodec = NULL; + AVCodec *vcodec = NULL; + + if(src == NULL) { + Kit_SetError("Source must not be NULL"); + return 1; + } + if(src->acodec_ctx || src->vcodec_ctx) { + Kit_SetError("Source codecs already initialized"); + return 1; + } + + // Make sure indexes seem correct + AVFormatContext *format_ctx = (AVFormatContext *)src->format_ctx; + if(src->astream_idx < 0 || src->astream_idx >= format_ctx->nb_streams) { + Kit_SetError("Invalid audio stream index"); + return 1; + } + if(src->vstream_idx < 0 || src->vstream_idx >= format_ctx->nb_streams) { + Kit_SetError("Invalid video stream index"); + return 1; + } + + // Find video decoder + vcodec = avcodec_find_decoder(format_ctx->streams[src->vstream_idx]->codec->codec_id); + if(!vcodec) { + Kit_SetError("No suitable video decoder found"); + goto exit_0; + } + + // Copy the original video codec context + vcodec_ctx = avcodec_alloc_context3(vcodec); + if(avcodec_copy_context(vcodec_ctx, format_ctx->streams[src->vstream_idx]->codec) != 0) { + Kit_SetError("Unable to copy video codec context"); + goto exit_0; + } + + // Create a video decoder context + if(avcodec_open2(vcodec_ctx, vcodec, NULL) < 0) { + Kit_SetError("Unable to allocate video codec context"); + goto exit_1; + } + + // Find audio decoder + acodec = avcodec_find_decoder(format_ctx->streams[src->astream_idx]->codec->codec_id); + if(!acodec) { + Kit_SetError("No suitable audio decoder found"); + goto exit_2; + } + + // Copy the original audio codec context + acodec_ctx = avcodec_alloc_context3(acodec); + if(avcodec_copy_context(acodec_ctx, format_ctx->streams[src->astream_idx]->codec) != 0) { + Kit_SetError("Unable to copy audio codec context"); + goto exit_2; + } + + // Create an audio decoder context + if(avcodec_open2(acodec_ctx, acodec, NULL) < 0) { + Kit_SetError("Unable to allocate audio codec context"); + goto exit_3; + } + + src->acodec = acodec; + src->vcodec = vcodec; + src->acodec_ctx = acodec_ctx; + src->vcodec_ctx = vcodec_ctx; + return 0; + +exit_3: + avcodec_free_context(&acodec_ctx); +exit_2: + avcodec_close(vcodec_ctx); +exit_1: + avcodec_free_context(&vcodec_ctx); +exit_0: + return 1; +} + +void Kit_CloseSource(Kit_Source *src) { + if(src == NULL) return; + avcodec_close((AVCodecContext*)src->acodec_ctx); + avcodec_close((AVCodecContext*)src->vcodec_ctx); + avcodec_free_context((AVCodecContext**)&src->acodec_ctx); + avcodec_free_context((AVCodecContext**)&src->vcodec_ctx); + avformat_close_input((AVFormatContext **)&src->format_ctx); + free(src); +} + +int Kit_GetSourceStreamInfo(const Kit_Source *src, Kit_StreamInfo *info, int index) { + if(src == NULL) { + Kit_SetError("Source must not be NULL"); + return 1; + } + AVFormatContext *format_ctx = (AVFormatContext *)src->format_ctx; + if(index < 0 || index >= format_ctx->nb_streams) { + Kit_SetError("Invalid stream index"); + return 1; + } + + AVStream *stream = format_ctx->streams[index]; + switch(stream->codec->codec_type) { + case AVMEDIA_TYPE_UNKNOWN: info->type = KIT_STREAMTYPE_UNKNOWN; break; + case AVMEDIA_TYPE_DATA: info->type = KIT_STREAMTYPE_DATA; break; + case AVMEDIA_TYPE_VIDEO: info->type = KIT_STREAMTYPE_VIDEO; break; + case AVMEDIA_TYPE_AUDIO: info->type = KIT_STREAMTYPE_AUDIO; break; + case AVMEDIA_TYPE_SUBTITLE: info->type = KIT_STREAMTYPE_SUBTITLE; break; + case AVMEDIA_TYPE_ATTACHMENT: info->type = KIT_STREAMTYPE_ATTACHMENT; break; + default: + Kit_SetError("Unknown native stream type"); + return 1; + } + + info->index = index; + info->width = stream->codec->width; + info->height = stream->codec->height; + return 0; +} + +int Kit_GetBestSourceStream(const Kit_Source *src, const Kit_streamtype type) { + if(src == NULL) { + Kit_SetError("Source must not be NULL"); + return -1; + } + int avmedia_type = 0; + switch(type) { + case KIT_STREAMTYPE_VIDEO: avmedia_type = AVMEDIA_TYPE_VIDEO; break; + case KIT_STREAMTYPE_AUDIO: avmedia_type = AVMEDIA_TYPE_AUDIO; break; + default: return -1; + } + return av_find_best_stream((AVFormatContext *)src->format_ctx, avmedia_type, -1, -1, NULL, 0); +} + +int Kit_SetSourceStream(Kit_Source *src, const Kit_streamtype type, int index) { + if(src == NULL) { + Kit_SetError("Source must not be NULL"); + return 1; + } + switch(type) { + case KIT_STREAMTYPE_AUDIO: src->astream_idx = index; break; + case KIT_STREAMTYPE_VIDEO: src->vstream_idx = index; break; + default: + Kit_SetError("Invalid stream type"); + return 1; + } + return 0; +} + +int Kit_GetSourceStream(const Kit_Source *src, const Kit_streamtype type) { + if(src == NULL) { + Kit_SetError("Source must not be NULL"); + return -1; + } + switch(type) { + case KIT_STREAMTYPE_AUDIO: return src->astream_idx; + case KIT_STREAMTYPE_VIDEO: return src->vstream_idx; + default: + break; + } + return -1; +} + +int Kit_GetSourceStreamCount(const Kit_Source *src) { + if(src == NULL) { + Kit_SetError("Source must not be NULL"); + return -1; + } + return ((AVFormatContext *)src->format_ctx)->nb_streams; +} |