summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDidier Raboud <odyx@debian.org>2018-09-03 11:33:11 +0200
committerDidier Raboud <odyx@debian.org>2018-09-03 11:33:11 +0200
commit35bba61e2f3ac1441cdd35ee740e27af4f8666b4 (patch)
tree3cbd4029c852cabbaa325225f5cd0e4223d8b581
parenta9d0e05c8d95f0f648e26032f7c837226e5a4791 (diff)
parent4c38cd19867186bb97c179eab4cc72a426b795df (diff)
record new upstream branch and merge it
-rw-r--r--CMakeLists.txt6
-rw-r--r--README.md10
-rw-r--r--debian/.git-dpm14
-rw-r--r--examples/example_complex.c8
-rw-r--r--examples/example_custom.c26
-rw-r--r--examples/example_rwops.c223
-rw-r--r--examples/example_simple.c8
-rw-r--r--include/kitchensink/kitsource.h42
-rw-r--r--src/internal/audio/kitaudio.c7
-rw-r--r--src/internal/kitdecoder.c16
-rw-r--r--src/internal/video/kitvideo.c19
-rw-r--r--src/kitsource.c71
12 files changed, 383 insertions, 67 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index a822008..c89dbc3 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -5,7 +5,7 @@ set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake)
set(KIT_VERSION_MAJOR "1")
set(KIT_VERSION_MINOR "0")
-set(KIT_VERSION_PATCH "2")
+set(KIT_VERSION_PATCH "4")
set(KIT_VERSION ${KIT_VERSION_MAJOR}.${KIT_VERSION_MINOR}.${KIT_VERSION_PATCH})
add_definitions(
-DKIT_VERSION_MAJOR=${KIT_VERSION_MAJOR}
@@ -90,23 +90,27 @@ if(BUILD_EXAMPLES)
add_executable(complex examples/example_complex.c)
add_executable(simple examples/example_simple.c)
add_executable(custom examples/example_custom.c)
+ add_executable(rwops examples/example_rwops.c)
if(MINGW)
target_link_libraries(audio mingw32)
target_link_libraries(complex mingw32)
target_link_libraries(simple mingw32)
target_link_libraries(custom mingw32)
+ target_link_libraries(rwops mingw32)
endif()
set_property(TARGET audio PROPERTY C_STANDARD 99)
set_property(TARGET complex PROPERTY C_STANDARD 99)
set_property(TARGET simple PROPERTY C_STANDARD 99)
set_property(TARGET custom PROPERTY C_STANDARD 99)
+ set_property(TARGET rwops PROPERTY C_STANDARD 99)
target_link_libraries(audio SDL_kitchensink_static ${LIBRARIES})
target_link_libraries(complex SDL_kitchensink_static ${LIBRARIES})
target_link_libraries(simple SDL_kitchensink_static ${LIBRARIES})
target_link_libraries(custom SDL_kitchensink_static ${LIBRARIES})
+ target_link_libraries(rwops SDL_kitchensink_static ${LIBRARIES})
endif()
# documentation target
diff --git a/README.md b/README.md
index 789a053..3b9b467 100644
--- a/README.md
+++ b/README.md
@@ -9,7 +9,7 @@ Documentation is available at http://katajakasa.github.io/SDL_kitchensink/
Features:
* Decoding video, audio and subtitles via FFmpeg
-* Dumping video and subtitle data on SDL_textures/SDL_Surfaces
+* Dumping video and subtitle data on SDL_textures
* Dumping audio data in the usual mono/stereo interleaved formats
* Automatic audio and video conversion to SDL2 friendly formats
* Synchronizing video & audio to clock
@@ -80,13 +80,7 @@ Change CMAKE_INSTALL_PREFIX as necessary to change the installation path. The fi
Just add ```-DBUILD_EXAMPLES=1``` to cmake arguments and rebuild.
-### 2.4. Building unittests
-
-Make sure CUnit is installed, then add ```-DBUILD_UNITTESTS=1``` to the cmake arguments and rebuild.
-
-You can run unittests by running ```make unittest```.
-
-### 2.5. Building with AddressSanitizer
+### 2.4. Building with AddressSanitizer
This is for development/debugging use only!
diff --git a/debian/.git-dpm b/debian/.git-dpm
index 1d141f4..9074f07 100644
--- a/debian/.git-dpm
+++ b/debian/.git-dpm
@@ -1,8 +1,8 @@
# see git-dpm(1) from git-dpm package
-3a38a6b6fbb99a54bc0df48e26f0d333ec058c27
-3a38a6b6fbb99a54bc0df48e26f0d333ec058c27
-3a38a6b6fbb99a54bc0df48e26f0d333ec058c27
-3a38a6b6fbb99a54bc0df48e26f0d333ec058c27
-sdl-kitchensink_1.0.2.orig.tar.gz
-7bf4d5a92fa078f663e3257d4dc91c46cc5f5a93
-66889
+4c38cd19867186bb97c179eab4cc72a426b795df
+4c38cd19867186bb97c179eab4cc72a426b795df
+4c38cd19867186bb97c179eab4cc72a426b795df
+4c38cd19867186bb97c179eab4cc72a426b795df
+sdl-kitchensink_1.0.4.orig.tar.gz
+e82045206e9ca1b9478a5488ea31d4e5016cc161
+67884
diff --git a/examples/example_complex.c b/examples/example_complex.c
index 5bd0b19..b8dc6ee 100644
--- a/examples/example_complex.c
+++ b/examples/example_complex.c
@@ -224,6 +224,10 @@ int main(int argc, char *argv[]) {
// Make sure subtitle texture is in correct blendmode
SDL_SetTextureBlendMode(subtitle_tex, SDL_BLENDMODE_BLEND);
+ // Clear screen with black
+ SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
+ SDL_RenderClear(renderer);
+
// Start playback
Kit_PlayerPlay(player);
@@ -340,10 +344,6 @@ int main(int argc, char *argv[]) {
}
}
- // Clear screen with black
- SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
- SDL_RenderClear(renderer);
-
// Refresh videotexture and render it
Kit_GetPlayerVideoData(player, video_tex);
SDL_RenderCopy(renderer, video_tex, NULL, NULL);
diff --git a/examples/example_custom.c b/examples/example_custom.c
index 43ae40a..f99c94e 100644
--- a/examples/example_custom.c
+++ b/examples/example_custom.c
@@ -22,14 +22,6 @@ int read_callback(void *userdata, uint8_t *buf, int buf_size) {
return -1;
}
-int64_t seek_callback(void *userdata, int64_t offset, int whence) {
- FILE *fd = (FILE*)userdata;
- if(fseek(fd, offset, whence)) {
- return -1;
- }
- return ftell(fd);
-}
-
int main(int argc, char *argv[]) {
int err = 0, ret = 0;
const char* filename = NULL;
@@ -83,8 +75,8 @@ int main(int argc, char *argv[]) {
return 1;
}
- // Open up the custom source. Declare read & seek callbacks, and transport FD in userdata.
- src = Kit_CreateSourceFromCustom(read_callback, seek_callback, fd);
+ // Open up the custom source. Declare read callback, and transport FD in userdata.
+ src = Kit_CreateSourceFromCustom(read_callback, NULL, fd);
if(src == NULL) {
fprintf(stderr, "Unable to load file '%s': %s\n", filename, Kit_GetError());
return 1;
@@ -149,6 +141,10 @@ int main(int argc, char *argv[]) {
// Make sure subtitle texture is in correct blendmode
SDL_SetTextureBlendMode(subtitle_tex, SDL_BLENDMODE_BLEND);
+ // Clear screen with black
+ SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
+ SDL_RenderClear(renderer);
+
// Start playback
Kit_PlayerPlay(player);
@@ -171,6 +167,12 @@ int main(int argc, char *argv[]) {
case SDL_QUIT:
run = false;
break;
+ case SDL_KEYUP:
+ if(event.key.keysym.sym == SDLK_RIGHT)
+ Kit_PlayerSeek(player, Kit_GetPlayerPosition(player) + 10);
+ if(event.key.keysym.sym == SDLK_LEFT)
+ Kit_PlayerSeek(player, Kit_GetPlayerPosition(player) - 10);
+ break;
}
}
@@ -197,10 +199,6 @@ int main(int argc, char *argv[]) {
}
}
- // Clear screen with black
- SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
- SDL_RenderClear(renderer);
-
// Refresh videotexture and render it
Kit_GetPlayerVideoData(player, video_tex);
SDL_RenderCopy(renderer, video_tex, NULL, NULL);
diff --git a/examples/example_rwops.c b/examples/example_rwops.c
new file mode 100644
index 0000000..84370f1
--- /dev/null
+++ b/examples/example_rwops.c
@@ -0,0 +1,223 @@
+#include <kitchensink/kitchensink.h>
+#include <SDL.h>
+#include <stdio.h>
+#include <stdbool.h>
+
+/*
+* Note! This example does not do proper error handling etc.
+* It is for example use only!
+*/
+
+#define AUDIOBUFFER_SIZE (1024 * 64)
+#define ATLAS_WIDTH 4096
+#define ATLAS_HEIGHT 4096
+#define ATLAS_MAX 1024
+
+
+int main(int argc, char *argv[]) {
+ int err = 0, ret = 0;
+ const char* filename = NULL;
+ SDL_Window *window = NULL;
+ SDL_Renderer *renderer = NULL;
+ bool run = true;
+ Kit_Source *src = NULL;
+ Kit_Player *player = NULL;
+ SDL_AudioSpec wanted_spec, audio_spec;
+ SDL_AudioDeviceID audio_dev;
+
+ // Get filename to open
+ if(argc != 2) {
+ fprintf(stderr, "Usage: custom <filename>\n");
+ return 0;
+ }
+ filename = argv[1];
+
+ // 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);
+ if(window == NULL) {
+ fprintf(stderr, "Unable to create a renderer!\n");
+ return 1;
+ }
+
+ // Initialize Kitchensink with network and libass support.
+ err = Kit_Init(KIT_INIT_NETWORK|KIT_INIT_ASS);
+ if(err != 0) {
+ fprintf(stderr, "Unable to initialize Kitchensink: %s", Kit_GetError());
+ return 1;
+ }
+
+ // Open file with fopen. We then proceed to read this with our custom file handlers.
+ SDL_RWops *rw_ops = SDL_RWFromFile(filename, "rb");
+ if(rw_ops == NULL) {
+ fprintf(stderr, "Unable to open file '%s' for reading\n", filename);
+ return 1;
+ }
+
+ // Open up the SDL RWops source
+ src = Kit_CreateSourceFromRW(rw_ops);
+ if(src == NULL) {
+ fprintf(stderr, "Unable to load file '%s': %s\n", filename, Kit_GetError());
+ return 1;
+ }
+
+ // Create the player. Pick best video, audio and subtitle streams, and set subtitle
+ // rendering resolution to screen resolution.
+ 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;
+ }
+
+ // Print some information
+ Kit_PlayerInfo pinfo;
+ Kit_GetPlayerInfo(player, &pinfo);
+
+ // Make sure there is video in the file to play first.
+ if(Kit_GetPlayerVideoStream(player) == -1) {
+ fprintf(stderr, "File contains no video!\n");
+ return 1;
+ }
+
+ // Init audio
+ SDL_memset(&wanted_spec, 0, sizeof(wanted_spec));
+ wanted_spec.freq = pinfo.audio.output.samplerate;
+ wanted_spec.format = pinfo.audio.output.format;
+ wanted_spec.channels = pinfo.audio.output.channels;
+ audio_dev = SDL_OpenAudioDevice(NULL, 0, &wanted_spec, &audio_spec, 0);
+ SDL_PauseAudioDevice(audio_dev, 0);
+
+ // Initialize video texture. This will probably end up as YV12 most of the time.
+ SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear");
+ SDL_Texture *video_tex = SDL_CreateTexture(
+ renderer,
+ pinfo.video.output.format,
+ SDL_TEXTUREACCESS_STATIC,
+ pinfo.video.output.width,
+ pinfo.video.output.height);
+ if(video_tex == NULL) {
+ fprintf(stderr, "Error while attempting to create a video texture\n");
+ return 1;
+ }
+
+ // This is the subtitle texture atlas. This contains all the subtitle image fragments.
+ SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "nearest"); // Always nearest for atlas operations
+ SDL_Texture *subtitle_tex = SDL_CreateTexture(
+ renderer,
+ pinfo.subtitle.output.format,
+ SDL_TEXTUREACCESS_STATIC,
+ ATLAS_WIDTH, ATLAS_HEIGHT);
+ if(subtitle_tex == NULL) {
+ fprintf(stderr, "Error while attempting to create a subtitle texture atlas\n");
+ return 1;
+ }
+
+ // Make sure subtitle texture is in correct blendmode
+ SDL_SetTextureBlendMode(subtitle_tex, SDL_BLENDMODE_BLEND);
+
+ // Clear screen with black
+ SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
+ SDL_RenderClear(renderer);
+
+ // 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) {
+ if(Kit_GetPlayerState(player) == KIT_STOPPED) {
+ run = false;
+ continue;
+ }
+
+ SDL_Event event;
+ while(SDL_PollEvent(&event)) {
+ switch(event.type) {
+ case SDL_QUIT:
+ run = false;
+ break;
+ case SDL_KEYUP:
+ if(event.key.keysym.sym == SDLK_RIGHT)
+ Kit_PlayerSeek(player, Kit_GetPlayerPosition(player) + 10);
+ if(event.key.keysym.sym == SDLK_LEFT)
+ Kit_PlayerSeek(player, Kit_GetPlayerPosition(player) - 10);
+ break;
+
+ }
+ }
+
+ // Refresh audio
+ int queued = SDL_GetQueuedAudioSize(audio_dev);
+ if(queued < AUDIOBUFFER_SIZE) {
+ int need = AUDIOBUFFER_SIZE - queued;
+
+ while(need > 0) {
+ ret = Kit_GetPlayerAudioData(
+ player,
+ (unsigned char*)audiobuf,
+ AUDIOBUFFER_SIZE);
+ need -= ret;
+ if(ret > 0) {
+ SDL_QueueAudio(audio_dev, audiobuf, ret);
+ } else {
+ break;
+ }
+ }
+ // If we now have data, start playback (again)
+ if(SDL_GetQueuedAudioSize(audio_dev) > 0) {
+ SDL_PauseAudioDevice(audio_dev, 0);
+ }
+ }
+
+ // Refresh videotexture and render it
+ Kit_GetPlayerVideoData(player, video_tex);
+ SDL_RenderCopy(renderer, video_tex, NULL, NULL);
+
+ // Refresh subtitle texture atlas and render subtitle frames from it
+ // For subtitles, use screen size instead of video size for best quality
+ 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]);
+ }
+
+ // Render to screen + wait for vsync
+ SDL_RenderPresent(renderer);
+ }
+
+ Kit_ClosePlayer(player);
+ Kit_CloseSource(src);
+ SDL_RWclose(rw_ops);
+ Kit_Quit();
+
+ SDL_DestroyTexture(subtitle_tex);
+ SDL_DestroyTexture(video_tex);
+ SDL_CloseAudioDevice(audio_dev);
+
+ SDL_DestroyRenderer(renderer);
+ SDL_DestroyWindow(window);
+ SDL_Quit();
+ return 0;
+}
diff --git a/examples/example_simple.c b/examples/example_simple.c
index a7dbbfd..4c581c0 100644
--- a/examples/example_simple.c
+++ b/examples/example_simple.c
@@ -126,6 +126,10 @@ int main(int argc, char *argv[]) {
// Make sure subtitle texture is in correct blendmode
SDL_SetTextureBlendMode(subtitle_tex, SDL_BLENDMODE_BLEND);
+ // Clear screen with black
+ SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
+ SDL_RenderClear(renderer);
+
// Start playback
Kit_PlayerPlay(player);
@@ -174,10 +178,6 @@ int main(int argc, char *argv[]) {
}
}
- // Clear screen with black
- SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
- SDL_RenderClear(renderer);
-
// Refresh videotexture and render it
Kit_GetPlayerVideoData(player, video_tex);
SDL_RenderCopy(renderer, video_tex, NULL, NULL);
diff --git a/include/kitchensink/kitsource.h b/include/kitchensink/kitsource.h
index a9da78e..9b744ca 100644
--- a/include/kitchensink/kitsource.h
+++ b/include/kitchensink/kitsource.h
@@ -10,6 +10,7 @@
*/
#include <inttypes.h>
+#include <SDL_rwops.h>
#include "kitchensink/kitconfig.h"
#ifdef __cplusplus
@@ -64,7 +65,7 @@ typedef struct Kit_SourceStreamInfo {
* - 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.
+ * 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.
@@ -81,7 +82,15 @@ typedef int (*Kit_ReadCallback)(void *userdata, uint8_t *buf, int size);
* - offset, an seeking offset in bytes
* - whence, reference position for the offset.
*
- * The function must return the position (in bytes) we seeked to.
+ * 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.
@@ -124,7 +133,7 @@ KIT_API Kit_Source* Kit_CreateSourceFromUrl(const char *url);
*
* For example:
* ```
- * if(Kit_CreateSourceFromUrl(filename) == NULL) {
+ * if(Kit_CreateSourceFromCustom(read_fn, seek_fn, fp) == NULL) {
* fprintf(stderr, "Error: %s\n", Kit_GetError());
* return 1;
* }
@@ -138,6 +147,33 @@ KIT_API Kit_Source* Kit_CreateSourceFromUrl(const char *url);
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()
diff --git a/src/internal/audio/kitaudio.c b/src/internal/audio/kitaudio.c
index 7a3b0a4..b1a0fdc 100644
--- a/src/internal/audio/kitaudio.c
+++ b/src/internal/audio/kitaudio.c
@@ -117,6 +117,7 @@ static void dec_decode_audio_cb(Kit_Decoder *dec, AVPacket *in_packet) {
int dst_bufsize;
double pts;
unsigned char **dst_data;
+ Kit_AudioPacket *out_packet;
// Decode as long as there is data
while(in_packet->size > 0) {
@@ -154,11 +155,15 @@ static void dec_decode_audio_cb(Kit_Decoder *dec, AVPacket *in_packet) {
_FindAVSampleFormat(dec->output.format), 1);
// Get presentation timestamp
+#ifndef FF_API_FRAME_GET_SET
pts = av_frame_get_best_effort_timestamp(audio_dec->scratch_frame);
+#else
+ pts = audio_dec->scratch_frame->best_effort_timestamp;
+#endif
pts *= av_q2d(dec->format_ctx->streams[dec->stream_index]->time_base);
// Lock, write to audio buffer, unlock
- Kit_AudioPacket *out_packet = _CreateAudioPacket(
+ out_packet = _CreateAudioPacket(
(char*)dst_data[0], (size_t)dst_bufsize, pts);
Kit_WriteDecoderOutput(dec, out_packet);
diff --git a/src/internal/kitdecoder.c b/src/internal/kitdecoder.c
index e2d0a25..0855eee 100644
--- a/src/internal/kitdecoder.c
+++ b/src/internal/kitdecoder.c
@@ -47,11 +47,17 @@ Kit_Decoder* Kit_CreateDecoder(const Kit_Source *src, int stream_index,
// Allocate a context for the codec
codec_ctx = avcodec_alloc_context3(codec);
- if(avcodec_copy_context(codec_ctx, format_ctx->streams[stream_index]->codec) != 0) {
- Kit_SetError("Unable to copy audio codec context for stream %d", stream_index);
+ if(codec_ctx == NULL) {
+ Kit_SetError("Unable to allocate codec context for stream %d", stream_index);
goto exit_1;
}
+ // Copy context from stream to target codec context
+ if(avcodec_copy_context(codec_ctx, format_ctx->streams[stream_index]->codec) != 0) {
+ Kit_SetError("Unable to copy codec context for stream %d", stream_index);
+ goto exit_2;
+ }
+
// Set thread count
codec_ctx->thread_count = thread_count;
codec_ctx->thread_type = FF_THREAD_SLICE;
@@ -67,7 +73,7 @@ Kit_Decoder* Kit_CreateDecoder(const Kit_Source *src, int stream_index,
dec->codec_ctx = codec_ctx;
dec->format_ctx = format_ctx;
- // Allocate input/output ringbuffers and locks
+ // Allocate input/output ringbuffers
for(int i = 0; i < 2; i++) {
dec->buffer[i] = Kit_CreateBuffer(bsizes[i], free_hooks[i]);
if(dec->buffer[i] == NULL) {
@@ -80,14 +86,12 @@ Kit_Decoder* Kit_CreateDecoder(const Kit_Source *src, int stream_index,
dec->output_lock = SDL_CreateMutex();
if(dec->output_lock == NULL) {
Kit_SetError("Unable to allocate mutex for stream %d: %s", stream_index, SDL_GetError());
- goto exit_4;
+ goto exit_3;
}
// That's that
return dec;
-exit_4:
- SDL_DestroyMutex(dec->output_lock);
exit_3:
for(int i = 0; i < KIT_DEC_BUF_COUNT; i++) {
Kit_DestroyBuffer(dec->buffer[i]);
diff --git a/src/internal/video/kitvideo.c b/src/internal/video/kitvideo.c
index cdbf933..1629b05 100644
--- a/src/internal/video/kitvideo.c
+++ b/src/internal/video/kitvideo.c
@@ -19,7 +19,7 @@ enum AVPixelFormat supported_list[] = {
AV_PIX_FMT_YUYV422,
AV_PIX_FMT_UYVY422,
AV_PIX_FMT_NV12,
- AV_PIX_FMT_NV12,
+ AV_PIX_FMT_NV21,
AV_PIX_FMT_RGB24,
AV_PIX_FMT_BGR24,
AV_PIX_FMT_RGB555,
@@ -98,18 +98,21 @@ static void dec_decode_video_cb(Kit_Decoder *dec, AVPacket *in_packet) {
assert(in_packet != NULL);
Kit_VideoDecoder *video_dec = dec->userdata;
+ AVFrame *out_frame;
int frame_finished;
-
+ int len;
+ double pts;
+ Kit_VideoPacket *out_packet;
while(in_packet->size > 0) {
- int len = avcodec_decode_video2(dec->codec_ctx, video_dec->scratch_frame, &frame_finished, in_packet);
+ len = avcodec_decode_video2(dec->codec_ctx, video_dec->scratch_frame, &frame_finished, in_packet);
if(len < 0) {
return;
}
if(frame_finished) {
// Target frame
- AVFrame *out_frame = av_frame_alloc();
+ out_frame = av_frame_alloc();
av_image_alloc(
out_frame->data,
out_frame->linesize,
@@ -129,11 +132,15 @@ static void dec_decode_video_cb(Kit_Decoder *dec, AVPacket *in_packet) {
out_frame->linesize);
// Get presentation timestamp
- double pts = av_frame_get_best_effort_timestamp(video_dec->scratch_frame);
+#ifndef FF_API_FRAME_GET_SET
+ pts = av_frame_get_best_effort_timestamp(video_dec->scratch_frame);
+#else
+ pts = video_dec->scratch_frame->best_effort_timestamp;
+#endif
pts *= av_q2d(dec->format_ctx->streams[dec->stream_index]->time_base);
// Lock, write to audio buffer, unlock
- Kit_VideoPacket *out_packet = _CreateVideoPacket(out_frame, pts);
+ out_packet = _CreateVideoPacket(out_frame, pts);
Kit_WriteDecoderOutput(dec, out_packet);
}
in_packet->size -= len;
diff --git a/src/kitsource.c b/src/kitsource.c
index b13cde6..588f829 100644
--- a/src/kitsource.c
+++ b/src/kitsource.c
@@ -12,6 +12,16 @@
#define AVIO_BUF_SIZE 32768
+static int _ScanSource(AVFormatContext *format_ctx) {
+ av_opt_set_int(format_ctx, "probesize", INT_MAX, 0);
+ av_opt_set_int(format_ctx, "analyzeduration", INT_MAX, 0);
+ if(avformat_find_stream_info(format_ctx, NULL) < 0) {
+ Kit_SetError("Unable to fetch source information");
+ return 1;
+ }
+ return 0;
+}
+
Kit_Source* Kit_CreateSourceFromUrl(const char *url) {
assert(url != NULL);
@@ -27,14 +37,11 @@ Kit_Source* Kit_CreateSourceFromUrl(const char *url) {
goto exit_0;
}
- av_opt_set_int(src->format_ctx, "probesize", INT_MAX, 0);
- av_opt_set_int(src->format_ctx, "analyzeduration", INT_MAX, 0);
-
- // Fetch stream information. This may potentially take a while.
- if(avformat_find_stream_info((AVFormatContext *)src->format_ctx, NULL) < 0) {
- Kit_SetError("Unable to fetch source information");
+ // Scan source information (may seek forwards)
+ if(_ScanSource(src->format_ctx)) {
goto exit_1;
}
+
return src;
exit_1:
@@ -81,13 +88,8 @@ Kit_Source* Kit_CreateSourceFromCustom(Kit_ReadCallback read_cb, Kit_SeekCallbac
goto exit_3;
}
- // Set probe opts for input scanning
- av_opt_set_int(format_ctx, "probesize", INT_MAX, 0);
- av_opt_set_int(format_ctx, "analyzeduration", INT_MAX, 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");
+ // Scan source information (may seek forwards)
+ if(_ScanSource(format_ctx)) {
goto exit_4;
}
@@ -109,6 +111,49 @@ exit_0:
return NULL;
}
+static int _RWReadCallback(void *userdata, uint8_t *buf, int size) {
+ return SDL_RWread((SDL_RWops*)userdata, buf, 1, size);
+}
+
+static int64_t _RWGetSize(SDL_RWops *rw_ops) {
+ int64_t current_pos;
+ int64_t max_pos;
+
+ // First, see if tell works at all, and fail with -1 if it doesn't.
+ current_pos = SDL_RWtell(rw_ops);
+ if(current_pos < 0) {
+ return -1;
+ }
+
+ // Seek to end, get pos (this is the size), then return.
+ if(SDL_RWseek(rw_ops, 0, RW_SEEK_END) < 0) {
+ return -1; // Seek failed, never mind then
+ }
+ max_pos = SDL_RWtell(rw_ops);
+ SDL_RWseek(rw_ops, current_pos, RW_SEEK_SET);
+ return max_pos;
+}
+
+static int64_t _RWSeekCallback(void *userdata, int64_t offset, int whence) {
+ int rw_whence = 0;
+ if(whence & AVSEEK_SIZE)
+ return _RWGetSize(userdata);
+
+ if((whence & ~AVSEEK_FORCE) == SEEK_CUR)
+ rw_whence = RW_SEEK_CUR;
+ else if((whence & ~AVSEEK_FORCE) == SEEK_SET)
+ rw_whence = RW_SEEK_SET;
+ else if((whence & ~AVSEEK_FORCE) == SEEK_END)
+ rw_whence = RW_SEEK_END;
+
+ return SDL_RWseek((SDL_RWops*)userdata, offset, rw_whence);
+}
+
+
+Kit_Source* Kit_CreateSourceFromRW(SDL_RWops *rw_ops) {
+ return Kit_CreateSourceFromCustom(_RWReadCallback, _RWSeekCallback, rw_ops);
+}
+
void Kit_CloseSource(Kit_Source *src) {
assert(src != NULL);
AVFormatContext *format_ctx = src->format_ctx;