summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--examples/example_audio.c21
-rw-r--r--examples/example_cust_video.c50
-rw-r--r--examples/example_video.c48
-rw-r--r--include/kitchensink/internal/audio/kitaudio.h2
-rw-r--r--include/kitchensink/internal/kitdecoder.h1
-rw-r--r--include/kitchensink/internal/subtitle/kitatlas.h3
-rw-r--r--include/kitchensink/internal/subtitle/kitsubtitle.h3
-rw-r--r--include/kitchensink/internal/subtitle/renderers/kitsubrenderer.h7
-rw-r--r--include/kitchensink/internal/video/kitvideo.h2
-rw-r--r--include/kitchensink/kitplayer.h22
-rw-r--r--include/kitchensink/kitsource.h5
-rw-r--r--src/internal/audio/kitaudio.c9
-rw-r--r--src/internal/kitdecoder.c13
-rw-r--r--src/internal/subtitle/kitatlas.c31
-rw-r--r--src/internal/subtitle/kitsubtitle.c19
-rw-r--r--src/internal/subtitle/renderers/kitsubass.c65
-rw-r--r--src/internal/subtitle/renderers/kitsubimage.c4
-rw-r--r--src/internal/subtitle/renderers/kitsubrenderer.c7
-rw-r--r--src/internal/video/kitvideo.c9
-rw-r--r--src/kitplayer.c53
-rw-r--r--src/kitsource.c35
21 files changed, 250 insertions, 159 deletions
diff --git a/examples/example_audio.c b/examples/example_audio.c
index dae252a..461d54c 100644
--- a/examples/example_audio.c
+++ b/examples/example_audio.c
@@ -62,11 +62,6 @@ int main(int argc, char *argv[]) {
return 1;
}
- // Disable any video and subtitle streams. If we leave these enabled and then don't
- // clear the buffers for these sometimes, decoding will block.
- Kit_SetSourceStream(src, KIT_STREAMTYPE_SUBTITLE, -1);
- Kit_SetSourceStream(src, KIT_STREAMTYPE_VIDEO, -1);
-
// Print stream information
Kit_StreamInfo sinfo;
fprintf(stderr, "Source streams:\n");
@@ -79,8 +74,13 @@ int main(int argc, char *argv[]) {
fprintf(stderr, " * Stream #%d: %s\n", i, stream_types[sinfo.type]);
}
- // Create the player
- player = Kit_CreatePlayer(src);
+ // Create the player. No video, pick best audio stream, no subtitles, no screen
+ player = Kit_CreatePlayer(
+ src,
+ -1,
+ Kit_GetBestSourceStream(src, KIT_STREAMTYPE_AUDIO),
+ -1,
+ 0, 0);
if(player == NULL) {
fprintf(stderr, "Unable to create player: %s\n", Kit_GetError());
return 1;
@@ -127,7 +127,7 @@ int main(int argc, char *argv[]) {
// Refresh audio
int queued = SDL_GetQueuedAudioSize(audio_dev);
if(queued < AUDIOBUFFER_SIZE) {
- ret = Kit_GetAudioData(player, (unsigned char*)audiobuf, AUDIOBUFFER_SIZE - queued);
+ ret = Kit_GetPlayerAudioData(player, (unsigned char*)audiobuf, AUDIOBUFFER_SIZE - queued);
if(ret > 0) {
SDL_QueueAudio(audio_dev, audiobuf, ret);
}
@@ -136,12 +136,11 @@ int main(int argc, char *argv[]) {
SDL_Delay(1);
}
- SDL_CloseAudioDevice(audio_dev);
-
Kit_ClosePlayer(player);
Kit_CloseSource(src);
-
Kit_Quit();
+
+ SDL_CloseAudioDevice(audio_dev);
SDL_Quit();
return 0;
}
diff --git a/examples/example_cust_video.c b/examples/example_cust_video.c
index d163076..6af6564 100644
--- a/examples/example_cust_video.c
+++ b/examples/example_cust_video.c
@@ -4,8 +4,6 @@
#include <stdbool.h>
/*
-* Note! This is the video playback from memory example!
-*
* Note! This example does not do proper error handling etc.
* It is for example use only!
*/
@@ -146,8 +144,14 @@ int main(int argc, char *argv[]) {
fprintf(stderr, " * Stream #%d: %s\n", i, Kit_GetKitStreamTypeString(sinfo.type));
}
- // Create the player
- player = Kit_CreatePlayer(src);
+ // 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;
@@ -199,6 +203,7 @@ int main(int argc, char *argv[]) {
fflush(stderr);
// 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.format,
@@ -211,6 +216,7 @@ int main(int argc, char *argv[]) {
}
// 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.format,
@@ -231,8 +237,12 @@ int main(int argc, char *argv[]) {
Kit_PlayerPlay(player);
// Get movie area size
- int mouse_x = 0, mouse_y = 0;
- int size_w = 0, size_h = 0;
+ int mouse_x = 0;
+ int mouse_y = 0;
+ int size_w = 0;
+ int size_h = 0;
+ int screen_w = 0;
+ int screen_h = 0;
SDL_RenderGetLogicalSize(renderer, &size_w, &size_h);
bool gui_enabled = false;
bool fullscreen = false;
@@ -270,6 +280,15 @@ int main(int argc, char *argv[]) {
mouse_y = event.motion.y;
break;
+ case SDL_WINDOWEVENT:
+ switch(event.window.event) {
+ case SDL_WINDOWEVENT_SIZE_CHANGED:
+ SDL_GetWindowSize(window, &screen_w, &screen_h);
+ Kit_SetPlayerScreenSize(player, screen_w, screen_h);
+ break;
+ }
+ break;
+
case SDL_MOUSEBUTTONUP:
// Handle user clicking the progress bar
if(mouse_x >= 30 && mouse_x <= size_w-30 && mouse_y >= size_h - 60 && mouse_y <= size_h - 40) {
@@ -305,7 +324,7 @@ int main(int argc, char *argv[]) {
int need = AUDIOBUFFER_SIZE - queued;
while(need > 0) {
- ret = Kit_GetAudioData(
+ ret = Kit_GetPlayerAudioData(
player,
(unsigned char*)audiobuf,
AUDIOBUFFER_SIZE);
@@ -327,16 +346,19 @@ int main(int argc, char *argv[]) {
SDL_RenderClear(renderer);
// Refresh videotexture and render it
- Kit_GetVideoData(player, video_tex);
+ 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
+ SDL_RenderSetLogicalSize(renderer, screen_w, screen_h);
SDL_Rect sources[ATLAS_MAX];
SDL_Rect targets[ATLAS_MAX];
- int got = Kit_GetSubtitleData(player, subtitle_tex, sources, 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]);
}
+ SDL_RenderSetLogicalSize(renderer, pinfo.video.width, pinfo.video.height);
// Render GUI
if(gui_enabled) {
@@ -348,15 +370,15 @@ int main(int argc, char *argv[]) {
SDL_RenderPresent(renderer);
}
- SDL_DestroyTexture(subtitle_tex);
- SDL_DestroyTexture(video_tex);
- SDL_CloseAudioDevice(audio_dev);
-
Kit_ClosePlayer(player);
Kit_CloseSource(src);
fclose(fd);
-
Kit_Quit();
+
+ SDL_DestroyTexture(subtitle_tex);
+ SDL_DestroyTexture(video_tex);
+ SDL_CloseAudioDevice(audio_dev);
+
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
SDL_Quit();
diff --git a/examples/example_video.c b/examples/example_video.c
index cef613d..90c0a2e 100644
--- a/examples/example_video.c
+++ b/examples/example_video.c
@@ -121,8 +121,14 @@ int main(int argc, char *argv[]) {
fprintf(stderr, " * Stream #%d: %s\n", i, Kit_GetKitStreamTypeString(sinfo.type));
}
- // Create the player
- player = Kit_CreatePlayer(src);
+ // 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;
@@ -174,6 +180,7 @@ int main(int argc, char *argv[]) {
fflush(stderr);
// 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.format,
@@ -186,6 +193,7 @@ int main(int argc, char *argv[]) {
}
// 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.format,
@@ -206,8 +214,12 @@ int main(int argc, char *argv[]) {
Kit_PlayerPlay(player);
// Get movie area size
- int mouse_x = 0, mouse_y = 0;
- int size_w = 0, size_h = 0;
+ int mouse_x = 0;
+ int mouse_y = 0;
+ int size_w = 0;
+ int size_h = 0;
+ int screen_w = 0;
+ int screen_h = 0;
SDL_RenderGetLogicalSize(renderer, &size_w, &size_h);
bool gui_enabled = false;
bool fullscreen = false;
@@ -245,6 +257,15 @@ int main(int argc, char *argv[]) {
mouse_y = event.motion.y;
break;
+ case SDL_WINDOWEVENT:
+ switch(event.window.event) {
+ case SDL_WINDOWEVENT_SIZE_CHANGED:
+ SDL_GetWindowSize(window, &screen_w, &screen_h);
+ Kit_SetPlayerScreenSize(player, screen_w, screen_h);
+ break;
+ }
+ break;
+
case SDL_MOUSEBUTTONUP:
// Handle user clicking the progress bar
if(mouse_x >= 30 && mouse_x <= size_w-30 && mouse_y >= size_h - 60 && mouse_y <= size_h - 40) {
@@ -280,7 +301,7 @@ int main(int argc, char *argv[]) {
int need = AUDIOBUFFER_SIZE - queued;
while(need > 0) {
- ret = Kit_GetAudioData(
+ ret = Kit_GetPlayerAudioData(
player,
(unsigned char*)audiobuf,
AUDIOBUFFER_SIZE);
@@ -302,16 +323,19 @@ int main(int argc, char *argv[]) {
SDL_RenderClear(renderer);
// Refresh videotexture and render it
- Kit_GetVideoData(player, video_tex);
+ 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
+ SDL_RenderSetLogicalSize(renderer, screen_w, screen_h);
SDL_Rect sources[ATLAS_MAX];
SDL_Rect targets[ATLAS_MAX];
- int got = Kit_GetSubtitleData(player, subtitle_tex, sources, 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]);
}
+ SDL_RenderSetLogicalSize(renderer, pinfo.video.width, pinfo.video.height);
// Render GUI
if(gui_enabled) {
@@ -323,14 +347,14 @@ int main(int argc, char *argv[]) {
SDL_RenderPresent(renderer);
}
- SDL_DestroyTexture(subtitle_tex);
- SDL_DestroyTexture(video_tex);
- SDL_CloseAudioDevice(audio_dev);
-
Kit_ClosePlayer(player);
Kit_CloseSource(src);
-
Kit_Quit();
+
+ SDL_DestroyTexture(subtitle_tex);
+ SDL_DestroyTexture(video_tex);
+ SDL_CloseAudioDevice(audio_dev);
+
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
SDL_Quit();
diff --git a/include/kitchensink/internal/audio/kitaudio.h b/include/kitchensink/internal/audio/kitaudio.h
index ac6753b..105c9f6 100644
--- a/include/kitchensink/internal/audio/kitaudio.h
+++ b/include/kitchensink/internal/audio/kitaudio.h
@@ -6,7 +6,7 @@
#include "kitchensink/kitplayer.h"
#include "kitchensink/internal/kitdecoder.h"
-KIT_LOCAL Kit_Decoder* Kit_CreateAudioDecoder(const Kit_Source *src, Kit_AudioFormat *format);
+KIT_LOCAL Kit_Decoder* Kit_CreateAudioDecoder(const Kit_Source *src, int stream_index, Kit_AudioFormat *format);
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
index 89a293e..b4b3f36 100644
--- a/include/kitchensink/internal/kitdecoder.h
+++ b/include/kitchensink/internal/kitdecoder.h
@@ -38,6 +38,7 @@ KIT_LOCAL struct Kit_Decoder {
KIT_LOCAL Kit_Decoder* Kit_CreateDecoder(const Kit_Source *src, int stream_index,
int out_b_size, dec_free_packet_cb free_out_cb);
+KIT_LOCAL int Kit_SetDecoderStreamIndex(Kit_Decoder *dec, int stream_index);
KIT_LOCAL void Kit_SetDecoderClockSync(Kit_Decoder *dec, double sync);
KIT_LOCAL void Kit_ChangeDecoderClockSync(Kit_Decoder *dec, double sync);
KIT_LOCAL bool Kit_CanWriteDecoderInput(Kit_Decoder *dec);
diff --git a/include/kitchensink/internal/subtitle/kitatlas.h b/include/kitchensink/internal/subtitle/kitatlas.h
index ad583a1..7701966 100644
--- a/include/kitchensink/internal/subtitle/kitatlas.h
+++ b/include/kitchensink/internal/subtitle/kitatlas.h
@@ -27,14 +27,13 @@ typedef struct Kit_TextureAtlas {
int cur_items; //< Current items count
int max_items; //< Maximum items count
int max_shelves; //< Maximum shelf count
- int border; //< Cleared border between atlas items in texture
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(int w, int h);
+KIT_LOCAL Kit_TextureAtlas* Kit_CreateAtlas();
KIT_LOCAL void Kit_FreeAtlas(Kit_TextureAtlas *atlas);
KIT_LOCAL void Kit_RefreshAtlas(Kit_TextureAtlas *atlas, double current_pts);
KIT_LOCAL void Kit_ClearAtlasContent(Kit_TextureAtlas *atlas);
diff --git a/include/kitchensink/internal/subtitle/kitsubtitle.h b/include/kitchensink/internal/subtitle/kitsubtitle.h
index 25a6ecf..34b8103 100644
--- a/include/kitchensink/internal/subtitle/kitsubtitle.h
+++ b/include/kitchensink/internal/subtitle/kitsubtitle.h
@@ -8,7 +8,8 @@
#include "kitchensink/kitplayer.h"
#include "kitchensink/internal/kitdecoder.h"
-KIT_LOCAL Kit_Decoder* Kit_CreateSubtitleDecoder(const Kit_Source *src, Kit_SubtitleFormat *format, int w, int h);
+KIT_LOCAL Kit_Decoder* Kit_CreateSubtitleDecoder(const Kit_Source *src, int stream_index, Kit_SubtitleFormat *format, int w, int h);
KIT_LOCAL int Kit_GetSubtitleDecoderData(Kit_Decoder *dec, SDL_Texture *texture, SDL_Rect *sources, SDL_Rect *targets, int limit);
+KIT_LOCAL void Kit_SetSubtitleDecoderSize(Kit_Decoder *dec, int w, int h);
#endif // KITSUBTITLE_H
diff --git a/include/kitchensink/internal/subtitle/renderers/kitsubrenderer.h b/include/kitchensink/internal/subtitle/renderers/kitsubrenderer.h
index 5c1a5b6..84b815b 100644
--- a/include/kitchensink/internal/subtitle/renderers/kitsubrenderer.h
+++ b/include/kitchensink/internal/subtitle/renderers/kitsubrenderer.h
@@ -9,20 +9,23 @@ 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_db)(Kit_SubtitleRenderer *ren, Kit_TextureAtlas *atlas, double current_pts);
+typedef int (*ren_get_data_cb)(Kit_SubtitleRenderer *ren, Kit_TextureAtlas *atlas, 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_db ren_get_data; ///< Subtitle data getter 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, 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/video/kitvideo.h b/include/kitchensink/internal/video/kitvideo.h
index 5a5624f..1e158a7 100644
--- a/include/kitchensink/internal/video/kitvideo.h
+++ b/include/kitchensink/internal/video/kitvideo.h
@@ -6,7 +6,7 @@
#include "kitchensink/kitplayer.h"
#include "kitchensink/internal/kitdecoder.h"
-KIT_LOCAL Kit_Decoder* Kit_CreateVideoDecoder(const Kit_Source *src, Kit_VideoFormat *format);
+KIT_LOCAL Kit_Decoder* Kit_CreateVideoDecoder(const Kit_Source *src, int stream_index, Kit_VideoFormat *format);
KIT_LOCAL int Kit_GetVideoDecoderData(Kit_Decoder *dec, SDL_Texture *texture);
#endif // KITVIDEO_H
diff --git a/include/kitchensink/kitplayer.h b/include/kitchensink/kitplayer.h
index b38385a..04e1a0b 100644
--- a/include/kitchensink/kitplayer.h
+++ b/include/kitchensink/kitplayer.h
@@ -52,13 +52,27 @@ typedef struct Kit_PlayerInfo {
Kit_SubtitleFormat subtitle; ///< Subtitle format information
} Kit_PlayerInfo;
-KIT_API Kit_Player* Kit_CreatePlayer(const Kit_Source *src);
+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);
KIT_API void Kit_ClosePlayer(Kit_Player *player);
+KIT_API void Kit_SetPlayerScreenSize(Kit_Player *player, int w, int h);
+KIT_API int Kit_SetPlayerVideoStream(Kit_Player *player, int index);
+KIT_API int Kit_SetPlayerAudioStream(Kit_Player *player, int index);
+KIT_API int Kit_SetPlayerSubtitleStream(Kit_Player *player, int index);
+
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_Texture *texture, SDL_Rect *sources, SDL_Rect *targets, int limit);
-KIT_API int Kit_GetAudioData(Kit_Player *player, unsigned char *buffer, int length);
+KIT_API int Kit_GetPlayerVideoData(Kit_Player *player, SDL_Texture *texture);
+KIT_API int Kit_GetPlayerSubtitleData(Kit_Player *player,
+ SDL_Texture *texture,
+ SDL_Rect *sources,
+ SDL_Rect *targets,
+ int limit);
+KIT_API int Kit_GetPlayerAudioData(Kit_Player *player, unsigned char *buffer, int length);
KIT_API void Kit_GetPlayerInfo(const Kit_Player *player, Kit_PlayerInfo *info);
KIT_API Kit_PlayerState Kit_GetPlayerState(const Kit_Player *player);
diff --git a/include/kitchensink/kitsource.h b/include/kitchensink/kitsource.h
index e20dc8a..0ca8e26 100644
--- a/include/kitchensink/kitsource.h
+++ b/include/kitchensink/kitsource.h
@@ -21,9 +21,6 @@ typedef enum Kit_StreamType {
} Kit_StreamType;
typedef struct Kit_Source {
- int audio_stream_index; ///< Audio stream index
- int video_stream_index; ///< Video stream index
- int subtitle_stream_index; ///< Subtitle stream index
void *format_ctx; ///< FFmpeg: Videostream format context
void *avio_ctx; ///< FFmpeg: AVIO context
} Kit_Source;
@@ -43,8 +40,6 @@ KIT_API void Kit_CloseSource(Kit_Source *src);
KIT_API int Kit_GetSourceStreamInfo(const Kit_Source *src, Kit_StreamInfo *info, int index);
KIT_API int Kit_GetSourceStreamCount(const Kit_Source *src);
KIT_API int Kit_GetBestSourceStream(const Kit_Source *src, const Kit_StreamType type);
-KIT_API int Kit_SetSourceStream(Kit_Source *src, const Kit_StreamType type, int index);
-KIT_API int Kit_GetSourceStream(const Kit_Source *src, const Kit_StreamType type);
#ifdef __cplusplus
}
diff --git a/src/internal/audio/kitaudio.c b/src/internal/audio/kitaudio.c
index 74fd024..2071bc5 100644
--- a/src/internal/audio/kitaudio.c
+++ b/src/internal/audio/kitaudio.c
@@ -168,16 +168,17 @@ static void dec_close_audio_cb(Kit_Decoder *dec) {
free(audio_dec);
}
-Kit_Decoder* Kit_CreateAudioDecoder(const Kit_Source *src, Kit_AudioFormat *format) {
+Kit_Decoder* Kit_CreateAudioDecoder(const Kit_Source *src, int stream_index, Kit_AudioFormat *format) {
assert(src != NULL);
assert(format != NULL);
- if(src->audio_stream_index < 0) {
+ if(stream_index < 0) {
return NULL;
}
// First the generic decoder component ...
Kit_Decoder *dec = Kit_CreateDecoder(
- src, src->audio_stream_index,
+ src,
+ stream_index,
KIT_AUDIO_OUT_SIZE,
free_out_audio_packet_cb);
if(dec == NULL) {
@@ -187,7 +188,7 @@ Kit_Decoder* Kit_CreateAudioDecoder(const Kit_Source *src, Kit_AudioFormat *form
// Find formats
format->samplerate = dec->codec_ctx->sample_rate;
format->is_enabled = true;
- format->stream_index = src->audio_stream_index;
+ format->stream_index = stream_index;
format->channels = _FindChannelLayout(dec->codec_ctx->channel_layout);
_FindAudioFormat(dec->codec_ctx->sample_fmt, &format->bytes, &format->is_signed, &format->format);
diff --git a/src/internal/kitdecoder.c b/src/internal/kitdecoder.c
index a16663e..63cbb58 100644
--- a/src/internal/kitdecoder.c
+++ b/src/internal/kitdecoder.c
@@ -93,13 +93,22 @@ exit_0:
return NULL;
}
+int Kit_SetDecoderStreamIndex(Kit_Decoder *dec, int stream_index) {
+ if(dec == NULL)
+ return 1;
+ dec->stream_index = stream_index;
+ return 0;
+}
+
void Kit_SetDecoderClockSync(Kit_Decoder *dec, double sync) {
- if(dec == NULL) return;
+ if(dec == NULL)
+ return;
dec->clock_sync = sync;
}
void Kit_ChangeDecoderClockSync(Kit_Decoder *dec, double sync) {
- if(dec == NULL) return;
+ if(dec == NULL)
+ return;
dec->clock_sync += sync;
}
diff --git a/src/internal/subtitle/kitatlas.c b/src/internal/subtitle/kitatlas.c
index 34c88a8..42ddb43 100644
--- a/src/internal/subtitle/kitatlas.c
+++ b/src/internal/subtitle/kitatlas.c
@@ -10,10 +10,7 @@ static int min(int a, int b) {
}
-Kit_TextureAtlas* Kit_CreateAtlas(int w, int h) {
- assert(w >= 1024);
- assert(h >= 1024);
-
+Kit_TextureAtlas* Kit_CreateAtlas() {
Kit_TextureAtlas *atlas = calloc(1, sizeof(Kit_TextureAtlas));
if(atlas == NULL) {
goto exit_0;
@@ -21,9 +18,8 @@ Kit_TextureAtlas* Kit_CreateAtlas(int w, int h) {
atlas->cur_items = 0;
atlas->max_items = 1024;
atlas->max_shelves = 256;
- atlas->border = 1;
- atlas->w = w;
- atlas->h = h;
+ atlas->w = 0;
+ atlas->h = 0;
// Allocate items. These hold the surfaces that should be in atlas
atlas->items = calloc(atlas->max_items, sizeof(Kit_TextureAtlasItem));
@@ -115,7 +111,7 @@ int Kit_FindFreeAtlasSlot(Kit_TextureAtlas *atlas, Kit_TextureAtlasItem *item) {
total_reserved_h += shelf_h;
// If the item fits, check if the space is better than previous one
- if(item->surface->w <= (atlas->w - shelf_w) && (item->surface->h + atlas->border) <= shelf_h) {
+ if(item->surface->w <= (atlas->w - shelf_w) && (item->surface->h) <= shelf_h) {
if(shelf_h < best_shelf_h) {
best_shelf_h = shelf_h;
best_shelf_idx = shelf_idx;
@@ -130,21 +126,21 @@ int Kit_FindFreeAtlasSlot(Kit_TextureAtlas *atlas, Kit_TextureAtlasItem *item) {
item,
best_shelf_idx,
atlas->shelves[best_shelf_idx].count,
- atlas->shelves[best_shelf_idx].width + atlas->border,
+ atlas->shelves[best_shelf_idx].width,
best_shelf_y);
- atlas->shelves[best_shelf_idx].width += item->surface->w + atlas->border;
+ atlas->shelves[best_shelf_idx].width += item->surface->w;
atlas->shelves[best_shelf_idx].count += 1;
return 0;
} else if(total_remaining_h >= item->surface->h) {
- atlas->shelves[shelf_idx].width = item->surface->w + atlas->border;
- atlas->shelves[shelf_idx].height = item->surface->h + atlas->border;
+ atlas->shelves[shelf_idx].width = item->surface->w;
+ atlas->shelves[shelf_idx].height = item->surface->h;
atlas->shelves[shelf_idx].count = 1;
Kit_SetItemAllocation(
item,
shelf_idx,
0,
- atlas->border,
- total_reserved_h + atlas->border);
+ 0,
+ total_reserved_h);
return 0;
}
@@ -188,6 +184,7 @@ void Kit_BlitAtlasSurfaces(Kit_TextureAtlas *atlas, SDL_Texture *texture) {
int Kit_UpdateAtlasTexture(Kit_TextureAtlas *atlas, SDL_Texture *texture) {
assert(atlas != NULL);
assert(texture != NULL);
+ int ret = 0;
// Check if texture size has changed
int texture_w, texture_h;
@@ -199,13 +196,15 @@ int Kit_UpdateAtlasTexture(Kit_TextureAtlas *atlas, SDL_Texture *texture) {
atlas->h = texture_h;
}
+ // Allocate spots for all surfaces in the result texture. If there is not enough room for
+ // everything, we need to show it to the caller.
if(Kit_AllocateAtlasSurfaces(atlas) != 0) {
- LOG("WARNING! FULL ATLAS, CANNOT MAKE MORE ROOM!\n");
+ ret = 1;
}
// Blit unblitted surfaces to texture
Kit_BlitAtlasSurfaces(atlas, texture);
- return 0;
+ return ret;
}
int Kit_GetAtlasItems(const Kit_TextureAtlas *atlas, SDL_Rect *sources, SDL_Rect *targets, int limit) {
diff --git a/src/internal/subtitle/kitsubtitle.c b/src/internal/subtitle/kitsubtitle.c
index 8935efc..d6641fc 100644
--- a/src/internal/subtitle/kitsubtitle.c
+++ b/src/internal/subtitle/kitsubtitle.c
@@ -83,10 +83,10 @@ static void dec_close_subtitle_cb(Kit_Decoder *dec) {
free(subtitle_dec);
}
-Kit_Decoder* Kit_CreateSubtitleDecoder(const Kit_Source *src, Kit_SubtitleFormat *format, int w, int h) {
+Kit_Decoder* Kit_CreateSubtitleDecoder(const Kit_Source *src, int stream_index, Kit_SubtitleFormat *format, int w, int h) {
assert(src != NULL);
assert(format != NULL);
- if(src->subtitle_stream_index < 0) {
+ if(stream_index < 0) {
return NULL;
}
@@ -94,7 +94,8 @@ Kit_Decoder* Kit_CreateSubtitleDecoder(const Kit_Source *src, Kit_SubtitleFormat
// First the generic decoder component
Kit_Decoder *dec = Kit_CreateDecoder(
- src, src->subtitle_stream_index,
+ src,
+ stream_index,
KIT_SUBTITLE_OUT_SIZE,
free_out_subtitle_packet_cb);
if(dec == NULL) {
@@ -103,7 +104,7 @@ Kit_Decoder* Kit_CreateSubtitleDecoder(const Kit_Source *src, Kit_SubtitleFormat
// Set format. Note that is_enabled may be changed below ...
format->is_enabled = true;
- format->stream_index = src->subtitle_stream_index;
+ format->stream_index = stream_index;
format->format = SDL_PIXELFORMAT_RGBA32; // Always this
// ... then allocate the subtitle decoder
@@ -143,7 +144,7 @@ Kit_Decoder* Kit_CreateSubtitleDecoder(const Kit_Source *src, Kit_SubtitleFormat
}
// Allocate texture atlas for subtitle rectangles
- Kit_TextureAtlas *atlas = Kit_CreateAtlas(1024, 1024);
+ Kit_TextureAtlas *atlas = Kit_CreateAtlas();
if(atlas == NULL) {
Kit_SetError("Unable to allocate subtitle texture atlas");
goto exit_3;
@@ -170,6 +171,14 @@ exit_0:
return NULL;
}
+void Kit_SetSubtitleDecoderSize(Kit_Decoder *dec, int w, int h) {
+ assert(dec != NULL);
+ Kit_SubtitleDecoder *subtitle_dec = dec->userdata;
+ subtitle_dec->w = w;
+ subtitle_dec->h = h;
+ Kit_SetSubtitleRendererSize(subtitle_dec->renderer, w, h);
+}
+
int Kit_GetSubtitleDecoderData(Kit_Decoder *dec, SDL_Texture *texture, SDL_Rect *sources, SDL_Rect *targets, int limit) {
assert(dec != NULL);
assert(texture != NULL);
diff --git a/src/internal/subtitle/renderers/kitsubass.c b/src/internal/subtitle/renderers/kitsubass.c
index 88efcb6..9be834f 100644
--- a/src/internal/subtitle/renderers/kitsubass.c
+++ b/src/internal/subtitle/renderers/kitsubass.c
@@ -23,14 +23,15 @@ static void Kit_ProcessAssImage(SDL_Surface *surface, const ASS_Image *img) {
unsigned char a = (img->color) & 0xFF;
unsigned char *src = img->bitmap;
unsigned char *dst = surface->pixels;
- unsigned int x, y;
+ unsigned int x, y, rx;
for(y = 0; y < img->h; y++) {
for(x = 0; x < img->w; x++) {
- dst[x * 4 + 0] = r;
- dst[x * 4 + 1] = g;
- dst[x * 4 + 2] = b;
- dst[x * 4 + 3] = ((255 - a) * src[x]) >> 8;
+ rx = x * 4;
+ dst[rx + 0] = r;
+ dst[rx + 1] = g;
+ dst[rx + 2] = b;
+ dst[rx + 3] = ((255 - a) * src[x]) >> 8;
}
src += img->stride;
dst += surface->pitch;
@@ -64,44 +65,51 @@ static void ren_close_ass_cb(Kit_SubtitleRenderer *ren) {
free(ass_ren);
}
-static int ren_get_data_cb(Kit_SubtitleRenderer *ren, Kit_TextureAtlas *atlas, double current_pts) {
+static int ren_get_ass_data_cb(Kit_SubtitleRenderer *ren, Kit_TextureAtlas *atlas, double current_pts) {
Kit_ASSSubtitleRenderer *ass_ren = ren->userdata;
SDL_Surface *dst = NULL;
ASS_Image *src = NULL;
int change = 0;
unsigned int now = current_pts * 1000;
- // First, we tell ASS to render images for us
if(Kit_LockDecoderOutput(ren->dec) == 0) {
+ // Tell ASS to render some images
src = ass_render_frame(ass_ren->renderer, ass_ren->track, now, &change);
- Kit_UnlockDecoderOutput(ren->dec);
- }
- // If there was no change, stop here
- if(change == 0) {
- return 0;
- }
+ // If there was no change, stop here
+ if(change == 0) {
+ Kit_UnlockDecoderOutput(ren->dec);
+ return 0;
+ }
- // There was some change, process images and add them to atlas
- Kit_ClearAtlasContent(atlas);
- for(; src; src = src->next) {
- if(src->w == 0 || src->h == 0)
- continue;
- dst = SDL_CreateRGBSurfaceWithFormat(0, src->w, src->h, 32, SDL_PIXELFORMAT_RGBA32);
- Kit_ProcessAssImage(dst, src);
- SDL_Rect target;
- target.x = src->dst_x;
- target.y = src->dst_y;
- target.w = src->w;
- target.h = src->h;
- Kit_AddAtlasItem(atlas, dst, &target);
- SDL_FreeSurface(dst);
+ // There was some change, process images and add them to atlas
+ Kit_ClearAtlasContent(atlas);
+ for(; src; src = src->next) {
+ if(src->w == 0 || src->h == 0)
+ continue;
+ dst = SDL_CreateRGBSurfaceWithFormat(0, src->w, src->h, 32, SDL_PIXELFORMAT_RGBA32);
+ Kit_ProcessAssImage(dst, src);
+ SDL_Rect target;
+ target.x = src->dst_x;
+ target.y = src->dst_y;
+ target.w = dst->w;
+ target.h = dst->h;
+ Kit_AddAtlasItem(atlas, dst, &target);
+ SDL_FreeSurface(dst);
+ }
+
+ Kit_UnlockDecoderOutput(ren->dec);
}
ren->dec->clock_pos = current_pts;
return 0;
}
+static void ren_set_ass_size_cb(Kit_SubtitleRenderer *ren, int w, int h) {
+ Kit_ASSSubtitleRenderer *ass_ren = ren->userdata;
+ ass_set_frame_size(ass_ren->renderer, w, h);
+}
+
Kit_SubtitleRenderer* Kit_CreateASSSubtitleRenderer(Kit_Decoder *dec, int w, int h) {
assert(dec != NULL);
assert(w >= 0);
@@ -181,7 +189,8 @@ Kit_SubtitleRenderer* Kit_CreateASSSubtitleRenderer(Kit_Decoder *dec, int w, int
ass_ren->track = ass_track;
ren->ren_render = ren_render_ass_cb;
ren->ren_close = ren_close_ass_cb;
- ren->ren_get_data = ren_get_data_cb;
+ ren->ren_get_data = ren_get_ass_data_cb;
+ ren->ren_set_size = ren_set_ass_size_cb;
ren->userdata = ass_ren;
return ren;
diff --git a/src/internal/subtitle/renderers/kitsubimage.c b/src/internal/subtitle/renderers/kitsubimage.c
index 4cc14c4..318c389 100644
--- a/src/internal/subtitle/renderers/kitsubimage.c
+++ b/src/internal/subtitle/renderers/kitsubimage.c
@@ -49,7 +49,7 @@ static void ren_render_image_cb(Kit_SubtitleRenderer *ren, void *sub_src, double
}
}
-static int ren_get_data_cb(Kit_SubtitleRenderer *ren, Kit_TextureAtlas *atlas, double current_pts) {
+static int ren_get_img_data_cb(Kit_SubtitleRenderer *ren, Kit_TextureAtlas *atlas, double current_pts) {
// Read any new packets to atlas
Kit_SubtitlePacket *packet = NULL;
@@ -96,7 +96,7 @@ Kit_SubtitleRenderer* Kit_CreateImageSubtitleRenderer(Kit_Decoder *dec, int w, i
// Only renderer required, no other data.
ren->ren_render = ren_render_image_cb;
- ren->ren_get_data = ren_get_data_cb;
+ ren->ren_get_data = ren_get_img_data_cb;
ren->ren_close = NULL;
ren->userdata = NULL;
return ren;
diff --git a/src/internal/subtitle/renderers/kitsubrenderer.c b/src/internal/subtitle/renderers/kitsubrenderer.c
index e63cad1..f998899 100644
--- a/src/internal/subtitle/renderers/kitsubrenderer.c
+++ b/src/internal/subtitle/renderers/kitsubrenderer.c
@@ -32,6 +32,13 @@ int Kit_GetSubtitleRendererData(Kit_SubtitleRenderer *ren, Kit_TextureAtlas *atl
return 0;
}
+void Kit_SetSubtitleRendererSize(Kit_SubtitleRenderer *ren, int w, int h) {
+ if(ren == NULL)
+ return;
+ if(ren->ren_set_size != NULL)
+ ren->ren_set_size(ren, w, h);
+}
+
void Kit_CloseSubtitleRenderer(Kit_SubtitleRenderer *ren) {
if(ren == NULL)
return;
diff --git a/src/internal/video/kitvideo.c b/src/internal/video/kitvideo.c
index 5254d9e..e41614b 100644
--- a/src/internal/video/kitvideo.c
+++ b/src/internal/video/kitvideo.c
@@ -132,16 +132,17 @@ static void dec_close_video_cb(Kit_Decoder *dec) {
free(video_dec);
}
-Kit_Decoder* Kit_CreateVideoDecoder(const Kit_Source *src, Kit_VideoFormat *format) {
+Kit_Decoder* Kit_CreateVideoDecoder(const Kit_Source *src, int stream_index, Kit_VideoFormat *format) {
assert(src != NULL);
assert(format != NULL);
- if(src->video_stream_index < 0) {
+ if(stream_index < 0) {
return NULL;
}
// First the generic decoder component ...
Kit_Decoder *dec = Kit_CreateDecoder(
- src, src->video_stream_index,
+ src,
+ stream_index,
KIT_VIDEO_OUT_SIZE,
free_out_video_packet_cb);
if(dec == NULL) {
@@ -152,7 +153,7 @@ Kit_Decoder* Kit_CreateVideoDecoder(const Kit_Source *src, Kit_VideoFormat *form
format->is_enabled = true;
format->width = dec->codec_ctx->width;
format->height = dec->codec_ctx->height;
- format->stream_index = src->video_stream_index;
+ format->stream_index = stream_index;
format->format = _FindPixelFormat(dec->codec_ctx->pix_fmt);
// ... then allocate the video decoder
diff --git a/src/kitplayer.c b/src/kitplayer.c
index 9658670..45488d4 100644
--- a/src/kitplayer.c
+++ b/src/kitplayer.c
@@ -125,7 +125,12 @@ static int _DecoderThread(void *ptr) {
return 0;
}
-Kit_Player* Kit_CreatePlayer(const Kit_Source *src) {
+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) {
assert(src != NULL);
Kit_Player *player = calloc(1, sizeof(Kit_Player));
@@ -135,21 +140,21 @@ Kit_Player* Kit_CreatePlayer(const Kit_Source *src) {
}
// Initialize audio decoder
- player->audio_dec = Kit_CreateAudioDecoder(src, &player->aformat);
- if(player->audio_dec == NULL && src->audio_stream_index >= 0) {
+ player->audio_dec = Kit_CreateAudioDecoder(src, audio_stream_index, &player->aformat);
+ if(player->audio_dec == NULL && audio_stream_index >= 0) {
goto exit_0;
}
// Initialize video decoder
- player->video_dec = Kit_CreateVideoDecoder(src, &player->vformat);
- if(player->video_dec == NULL && src->video_stream_index >= 0) {
+ player->video_dec = Kit_CreateVideoDecoder(src, video_stream_index, &player->vformat);
+ if(player->video_dec == NULL && video_stream_index >= 0) {
goto exit_1;
}
// Initialize subtitle decoder
player->subtitle_dec = Kit_CreateSubtitleDecoder(
- src, &player->sformat, player->vformat.width, player->vformat.height);
- if(player->subtitle_dec == NULL && src->subtitle_stream_index >= 0) {
+ src, subtitle_stream_index, &player->sformat, screen_w, screen_h);
+ if(player->subtitle_dec == NULL && subtitle_stream_index >= 0) {
goto exit_2;
}
@@ -200,7 +205,35 @@ void Kit_ClosePlayer(Kit_Player *player) {
free(player);
}
-int Kit_GetVideoData(Kit_Player *player, SDL_Texture *texture) {
+void Kit_SetPlayerScreenSize(Kit_Player *player, int w, int h) {
+ assert(player != NULL);
+ if(player->subtitle_dec == NULL)
+ return;
+ Kit_SetSubtitleDecoderSize(player->subtitle_dec, w, h);
+}
+
+int Kit_SetPlayerVideoStream(Kit_Player *player, int index) {
+ assert(player != NULL);
+ if(player->video_dec == NULL)
+ return 1;
+ return Kit_SetDecoderStreamIndex(player->video_dec, index);
+}
+
+int Kit_SetPlayerAudioStream(Kit_Player *player, int index) {
+ assert(player != NULL);
+ if(player->audio_dec == NULL)
+ return 1;
+ return Kit_SetDecoderStreamIndex(player->audio_dec, index);
+}
+
+int Kit_SetPlayerSubtitleStream(Kit_Player *player, int index) {
+ assert(player != NULL);
+ if(player->subtitle_dec == NULL)
+ return 1;
+ return Kit_SetDecoderStreamIndex(player->subtitle_dec, index);
+}
+
+int Kit_GetPlayerVideoData(Kit_Player *player, SDL_Texture *texture) {
assert(player != NULL);
if(player->video_dec == NULL) {
return 0;
@@ -217,7 +250,7 @@ int Kit_GetVideoData(Kit_Player *player, SDL_Texture *texture) {
return Kit_GetVideoDecoderData(player->video_dec, texture);
}
-int Kit_GetAudioData(Kit_Player *player, unsigned char *buffer, int length) {
+int Kit_GetPlayerAudioData(Kit_Player *player, unsigned char *buffer, int length) {
assert(player != NULL);
assert(buffer != NULL);
if(player->audio_dec == NULL) {
@@ -240,7 +273,7 @@ int Kit_GetAudioData(Kit_Player *player, unsigned char *buffer, int length) {
return Kit_GetAudioDecoderData(player->audio_dec, buffer, length);
}
-int Kit_GetSubtitleData(Kit_Player *player, SDL_Texture *texture, SDL_Rect *sources, SDL_Rect *targets, int limit) {
+int Kit_GetPlayerSubtitleData(Kit_Player *player, SDL_Texture *texture, SDL_Rect *sources, SDL_Rect *targets, int limit) {
assert(player != NULL);
assert(texture != NULL);
assert(sources != NULL);
diff --git a/src/kitsource.c b/src/kitsource.c
index 082691f..ef24900 100644
--- a/src/kitsource.c
+++ b/src/kitsource.c
@@ -35,11 +35,6 @@ Kit_Source* Kit_CreateSourceFromUrl(const char *url) {
Kit_SetError("Unable to fetch source information");
goto exit_1;
}
-
- // Find best streams for defaults
- src->audio_stream_index = Kit_GetBestSourceStream(src, KIT_STREAMTYPE_AUDIO);
- src->video_stream_index = Kit_GetBestSourceStream(src, KIT_STREAMTYPE_VIDEO);
- src->subtitle_stream_index = Kit_GetBestSourceStream(src, KIT_STREAMTYPE_SUBTITLE);
return src;
exit_1:
@@ -99,11 +94,6 @@ Kit_Source* Kit_CreateSourceFromCustom(Kit_ReadCallback read_cb, Kit_SeekCallbac
// Set internals
src->format_ctx = format_ctx;
src->avio_ctx = avio_ctx;
-
- // Find best streams for defaults
- src->audio_stream_index = Kit_GetBestSourceStream(src, KIT_STREAMTYPE_AUDIO);
- src->video_stream_index = Kit_GetBestSourceStream(src, KIT_STREAMTYPE_VIDEO);
- src->subtitle_stream_index = Kit_GetBestSourceStream(src, KIT_STREAMTYPE_SUBTITLE);
return src;
exit_4:
@@ -178,31 +168,6 @@ int Kit_GetBestSourceStream(const Kit_Source *src, const Kit_StreamType type) {
return ret;
}
-int Kit_SetSourceStream(Kit_Source *src, const Kit_StreamType type, int index) {
- assert(src != NULL);
- switch(type) {
- case KIT_STREAMTYPE_AUDIO: src->audio_stream_index = index; break;
- case KIT_STREAMTYPE_VIDEO: src->video_stream_index = index; break;
- case KIT_STREAMTYPE_SUBTITLE: src->subtitle_stream_index = index; break;
- default:
- Kit_SetError("Invalid stream type");
- return 1;
- }
- return 0;
-}
-
-int Kit_GetSourceStream(const Kit_Source *src, const Kit_StreamType type) {
- assert(src != NULL);
- switch(type) {
- case KIT_STREAMTYPE_AUDIO: return src->audio_stream_index;
- case KIT_STREAMTYPE_VIDEO: return src->video_stream_index;
- case KIT_STREAMTYPE_SUBTITLE: return src->subtitle_stream_index;
- default:
- break;
- }
- return -1;
-}
-
int Kit_GetSourceStreamCount(const Kit_Source *src) {
assert(src != NULL);
return ((AVFormatContext *)src->format_ctx)->nb_streams;