diff options
author | Tuomas Virtanen <katajakasa@gmail.com> | 2017-09-12 00:06:31 +0300 |
---|---|---|
committer | Tuomas Virtanen <katajakasa@gmail.com> | 2017-09-22 15:15:57 +0300 |
commit | fd7bbceb6321250ed5d80103d13e9d7584b552ac (patch) | |
tree | b8202cd4c110d3e93c1c7a4032252e66c3e11073 /src/kitplayer.c | |
parent | bf1d1e30ac4062a2f764193a865761161ec7fc6b (diff) |
Split kitplayer.c to multiple files
Diffstat (limited to 'src/kitplayer.c')
-rw-r--r-- | src/kitplayer.c | 632 |
1 files changed, 5 insertions, 627 deletions
diff --git a/src/kitplayer.c b/src/kitplayer.c index 9f8a963..480e815 100644 --- a/src/kitplayer.c +++ b/src/kitplayer.c @@ -4,16 +4,18 @@ #include "kitchensink/internal/kitringbuffer.h" #include "kitchensink/internal/kitlist.h" #include "kitchensink/internal/kitlibstate.h" +#include "kitchensink/internal/kitvideo.h" +#include "kitchensink/internal/kitaudio.h" +#include "kitchensink/internal/kitsubtitle.h" +#include "kitchensink/internal/kitcontrol.h" +#include "kitchensink/internal/kithelpers.h" #include <libavcodec/avcodec.h> #include <libavformat/avformat.h> #include <libswscale/swscale.h> #include <libswresample/swresample.h> #include <libavutil/pixfmt.h> -#include <libavutil/time.h> #include <libavutil/samplefmt.h> -#include <libavutil/avstring.h> -#include <libavutil/imgutils.h> #include <SDL2/SDL.h> #include <ass/ass.h> @@ -34,41 +36,6 @@ #define VIDEO_SYNC_THRESHOLD 0.01 #define AUDIO_SYNC_THRESHOLD 0.05 -// Buffersizes -#define KIT_VBUFFERSIZE 3 -#define KIT_ABUFFERSIZE 64 -#define KIT_CBUFFERSIZE 8 -#define KIT_SBUFFERSIZE 512 - -typedef enum Kit_ControlPacketType { - KIT_CONTROL_SEEK, - KIT_CONTROL_FLUSH -} Kit_ControlPacketType; - -typedef struct Kit_VideoPacket { - double pts; - AVFrame *frame; -} Kit_VideoPacket; - -typedef struct Kit_AudioPacket { - double pts; - size_t original_size; - Kit_RingBuffer *rb; -} Kit_AudioPacket; - -typedef struct Kit_ControlPacket { - Kit_ControlPacketType type; - double value1; -} Kit_ControlPacket; - -typedef struct Kit_SubtitlePacket { - double pts_start; - double pts_end; - SDL_Rect *rect; - SDL_Surface *surface; - SDL_Texture *texture; -} Kit_SubtitlePacket; - static int _InitCodecs(Kit_Player *player, const Kit_Source *src) { assert(player != NULL); assert(src != NULL); @@ -178,525 +145,6 @@ exit_0: return 1; } -static int reset_libass_track(Kit_Player *player) { - AVCodecContext *scodec_ctx = player->scodec_ctx; - - if(scodec_ctx == NULL) { - return 0; - } - - // Flush libass track events - ass_flush_events(player->ass_track); - return 0; -} - -static void _FindPixelFormat(enum AVPixelFormat fmt, unsigned int *out_fmt) { - switch(fmt) { - case AV_PIX_FMT_YUV420P9: - case AV_PIX_FMT_YUV420P10: - case AV_PIX_FMT_YUV420P12: - case AV_PIX_FMT_YUV420P14: - case AV_PIX_FMT_YUV420P16: - case AV_PIX_FMT_YUV420P: - *out_fmt = SDL_PIXELFORMAT_YV12; - break; - case AV_PIX_FMT_YUYV422: - *out_fmt = SDL_PIXELFORMAT_YUY2; - break; - case AV_PIX_FMT_UYVY422: - *out_fmt = SDL_PIXELFORMAT_UYVY; - break; - default: - *out_fmt = SDL_PIXELFORMAT_ABGR8888; - break; - } -} - -static void _FindAudioFormat(enum AVSampleFormat fmt, int *bytes, bool *is_signed, unsigned int *format) { - switch(fmt) { - case AV_SAMPLE_FMT_U8: - *bytes = 1; - *is_signed = false; - *format = AUDIO_U8; - break; - case AV_SAMPLE_FMT_S16: - *bytes = 2; - *is_signed = true; - *format = AUDIO_S16SYS; - break; - case AV_SAMPLE_FMT_S32: - *bytes = 4; - *is_signed = true; - *format = AUDIO_S32SYS; - break; - default: - *bytes = 2; - *is_signed = true; - *format = AUDIO_S16SYS; - break; - } -} - -static enum AVPixelFormat _FindAVPixelFormat(unsigned int fmt) { - switch(fmt) { - case SDL_PIXELFORMAT_IYUV: return AV_PIX_FMT_YUV420P; - case SDL_PIXELFORMAT_YV12: return AV_PIX_FMT_YUV420P; - case SDL_PIXELFORMAT_YUY2: return AV_PIX_FMT_YUYV422; - case SDL_PIXELFORMAT_UYVY: return AV_PIX_FMT_UYVY422; - case SDL_PIXELFORMAT_ARGB8888: return AV_PIX_FMT_BGRA; - case SDL_PIXELFORMAT_ABGR8888: return AV_PIX_FMT_RGBA; - default: - return AV_PIX_FMT_NONE; - } -} - -static enum AVSampleFormat _FindAVSampleFormat(int format) { - switch(format) { - case AUDIO_U8: return AV_SAMPLE_FMT_U8; - case AUDIO_S16SYS: return AV_SAMPLE_FMT_S16; - case AUDIO_S32SYS: return AV_SAMPLE_FMT_S32; - default: - return AV_SAMPLE_FMT_NONE; - } -} - -static unsigned int _FindAVChannelLayout(int channels) { - switch(channels) { - case 1: return AV_CH_LAYOUT_MONO; - case 2: return AV_CH_LAYOUT_STEREO; - case 4: return AV_CH_LAYOUT_QUAD; - case 6: return AV_CH_LAYOUT_5POINT1; - default: return AV_CH_LAYOUT_STEREO_DOWNMIX; - } -} - -static Kit_VideoPacket* _CreateVideoPacket(AVFrame *frame, double pts) { - Kit_VideoPacket *p = calloc(1, sizeof(Kit_VideoPacket)); - p->frame = frame; - p->pts = pts; - return p; -} - -static void _FreeVideoPacket(void *ptr) { - Kit_VideoPacket *packet = ptr; - av_freep(&packet->frame->data[0]); - av_frame_free(&packet->frame); - free(packet); -} - -static Kit_AudioPacket* _CreateAudioPacket(const char* data, size_t len, double pts) { - Kit_AudioPacket *p = calloc(1, sizeof(Kit_AudioPacket)); - p->rb = Kit_CreateRingBuffer(len); - Kit_WriteRingBuffer(p->rb, data, len); - p->pts = pts; - return p; -} - -static void _FreeAudioPacket(void *ptr) { - Kit_AudioPacket *packet = ptr; - Kit_DestroyRingBuffer(packet->rb); - free(packet); -} - -static Kit_ControlPacket* _CreateControlPacket(Kit_ControlPacketType type, double value1) { - Kit_ControlPacket *p = calloc(1, sizeof(Kit_ControlPacket)); - p->type = type; - p->value1 = value1; - return p; -} - -static void _FreeControlPacket(void *ptr) { - Kit_ControlPacket *packet = ptr; - free(packet); -} - - -static Kit_SubtitlePacket* _CreateSubtitlePacket(double pts_start, double pts_end, SDL_Rect *rect, SDL_Surface *surface) { - Kit_SubtitlePacket *p = calloc(1, sizeof(Kit_SubtitlePacket)); - p->pts_start = pts_start; - p->pts_end = pts_end; - p->surface = surface; - p->rect = rect; - p->texture = NULL; // Cached texture - return p; -} - -static void _FreeSubtitlePacket(void *ptr) { - Kit_SubtitlePacket *packet = ptr; - SDL_FreeSurface(packet->surface); - if(packet->texture) { - SDL_DestroyTexture(packet->texture); - } - free(packet->rect); - free(packet); -} - -static double _GetSystemTime() { - return (double)av_gettime() / 1000000.0; -} - -static void _HandleVideoPacket(Kit_Player *player, AVPacket *packet) { - assert(player != NULL); - assert(packet != NULL); - - int frame_finished; - AVCodecContext *vcodec_ctx = (AVCodecContext*)player->vcodec_ctx; - AVFormatContext *fmt_ctx = (AVFormatContext *)player->src->format_ctx; - AVFrame *iframe = player->tmp_vframe; - - while(packet->size > 0) { - int len = avcodec_decode_video2(vcodec_ctx, player->tmp_vframe, &frame_finished, packet); - if(len < 0) { - return; - } - - if(frame_finished) { - // Target frame - AVFrame *oframe = av_frame_alloc(); - av_image_alloc( - oframe->data, - oframe->linesize, - vcodec_ctx->width, - vcodec_ctx->height, - _FindAVPixelFormat(player->vformat.format), - 1); - - // Scale from source format to target format, don't touch the size - sws_scale( - (struct SwsContext *)player->sws, - (const unsigned char * const *)iframe->data, - iframe->linesize, - 0, - vcodec_ctx->height, - oframe->data, - oframe->linesize); - - // Get pts - double pts = 0; - if(packet->dts != AV_NOPTS_VALUE) { - pts = av_frame_get_best_effort_timestamp(player->tmp_vframe); - pts *= av_q2d(fmt_ctx->streams[player->src->vstream_idx]->time_base); - } - - // Just seeked, set sync clock & pos. - if(player->seek_flag == 1) { - player->vclock_pos = pts; - player->clock_sync = _GetSystemTime() - pts; - player->seek_flag = 0; - } - - // Lock, write to audio buffer, unlock - Kit_VideoPacket *vpacket = _CreateVideoPacket(oframe, pts); - bool done = false; - if(SDL_LockMutex(player->vmutex) == 0) { - if(Kit_WriteBuffer((Kit_Buffer*)player->vbuffer, vpacket) == 0) { - done = true; - } - SDL_UnlockMutex(player->vmutex); - } - - // Unable to write packet, free it. - if(!done) { - _FreeVideoPacket(vpacket); - } - } - packet->size -= len; - packet->data += len; - } -} - -static void _HandleAudioPacket(Kit_Player *player, AVPacket *packet) { - assert(player != NULL); - assert(packet != NULL); - - int frame_finished; - int len, len2; - int dst_linesize; - int dst_nb_samples, dst_bufsize; - unsigned char **dst_data; - AVCodecContext *acodec_ctx = (AVCodecContext*)player->acodec_ctx; - AVFormatContext *fmt_ctx = (AVFormatContext *)player->src->format_ctx; - struct SwrContext *swr = (struct SwrContext *)player->swr; - AVFrame *aframe = (AVFrame*)player->tmp_aframe; - - while(packet->size > 0) { - len = avcodec_decode_audio4(acodec_ctx, aframe, &frame_finished, packet); - if(len < 0) { - return; - } - - if(frame_finished) { - dst_nb_samples = av_rescale_rnd( - aframe->nb_samples, - player->aformat.samplerate, - acodec_ctx->sample_rate, - AV_ROUND_UP); - - av_samples_alloc_array_and_samples( - &dst_data, - &dst_linesize, - player->aformat.channels, - dst_nb_samples, - _FindAVSampleFormat(player->aformat.format), - 0); - - len2 = swr_convert( - swr, - dst_data, - aframe->nb_samples, - (const unsigned char **)aframe->extended_data, - aframe->nb_samples); - - dst_bufsize = av_samples_get_buffer_size( - &dst_linesize, - player->aformat.channels, - len2, - _FindAVSampleFormat(player->aformat.format), 1); - - // Get pts - double pts = 0; - if(packet->dts != AV_NOPTS_VALUE) { - pts = av_frame_get_best_effort_timestamp(player->tmp_aframe); - pts *= av_q2d(fmt_ctx->streams[player->src->astream_idx]->time_base); - } - - // Just seeked, set sync clock & pos. - if(player->seek_flag == 1) { - player->vclock_pos = pts; - player->clock_sync = _GetSystemTime() - pts; - player->seek_flag = 0; - } - - // Lock, write to audio buffer, unlock - Kit_AudioPacket *apacket = _CreateAudioPacket((char*)dst_data[0], (size_t)dst_bufsize, pts); - bool done = false; - if(SDL_LockMutex(player->amutex) == 0) { - if(Kit_WriteBuffer((Kit_Buffer*)player->abuffer, apacket) == 0) { - done = true; - } - SDL_UnlockMutex(player->amutex); - } - - // Couldn't write packet, free memory - if(!done) { - _FreeAudioPacket(apacket); - } - - av_freep(&dst_data[0]); - av_freep(&dst_data); - } - - packet->size -= len; - packet->data += len; - } -} - -static void _HandleBitmapSubtitle(Kit_SubtitlePacket** spackets, int *n, Kit_Player *player, double pts, AVSubtitle *sub, AVSubtitleRect *rect) { - if(rect->nb_colors == 256) { - // Paletted image based subtitles. Convert and set palette. - SDL_Surface *s = SDL_CreateRGBSurfaceFrom( - rect->data[0], - rect->w, rect->h, 8, - rect->linesize[0], - 0, 0, 0, 0); - - SDL_SetPaletteColors(s->format->palette, (SDL_Color*)rect->data[1], 0, 256); - - Uint32 rmask, gmask, bmask, amask; - #if SDL_BYTEORDER == SDL_BIG_ENDIAN - rmask = 0xff000000; - gmask = 0x00ff0000; - bmask = 0x0000ff00; - amask = 0x000000ff; - #else - rmask = 0x000000ff; - gmask = 0x0000ff00; - bmask = 0x00ff0000; - amask = 0xff000000; - #endif - SDL_Surface *tmp = SDL_CreateRGBSurface( - 0, rect->w, rect->h, 32, - rmask, gmask, bmask, amask); - SDL_BlitSurface(s, NULL, tmp, NULL); - SDL_FreeSurface(s); - - SDL_Rect *dst_rect = malloc(sizeof(SDL_Rect)); - dst_rect->x = rect->x; - dst_rect->y = rect->y; - dst_rect->w = rect->w; - dst_rect->h = rect->h; - - double start = pts + (sub->start_display_time / 1000.0f); - double end = -1; - if(sub->end_display_time < UINT_MAX) { - end = pts + (sub->end_display_time / 1000.0f); - } - - spackets[(*n)++] = _CreateSubtitlePacket(start, end, dst_rect, tmp); - } -} - -static void _ProcessAssSubtitleRect(Kit_Player *player, AVSubtitleRect *rect) { - ass_process_data((ASS_Track*)player->ass_track, rect->ass, strlen(rect->ass)); -} - -static void _ProcessAssImage(SDL_Surface *surface, const ASS_Image *img) { - int x, y; - // libass headers claim img->color is RGBA, but the alpha is 0. - unsigned char r = ((img->color) >> 24) & 0xFF; - unsigned char g = ((img->color) >> 16) & 0xFF; - unsigned char b = ((img->color) >> 8) & 0xFF; - unsigned char *src = img->bitmap; - unsigned char *dst = (unsigned char*)surface->pixels; - - 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] = src[x]; - } - src += img->stride; - dst += surface->pitch; - } -} - -static void _HandleAssSubtitle(Kit_SubtitlePacket** spackets, int *n, Kit_Player *player, double pts, AVSubtitle *sub) { - double start = pts + (sub->start_display_time / 1000.0f); - double end = pts + (sub->end_display_time / 1000.0f); - - // Process current chunk of data - unsigned int now = start * 1000; - int change = 0; - ASS_Image *images = ass_render_frame((ASS_Renderer*)player->ass_renderer, (ASS_Track*)player->ass_track, now, &change); - - // Convert to SDL_Surfaces - if(change > 0) { - ASS_Image *now = images; - if(now != NULL) { - do { - Uint32 rmask, gmask, bmask, amask; - #if SDL_BYTEORDER == SDL_BIG_ENDIAN - rmask = 0xff000000; - gmask = 0x00ff0000; - bmask = 0x0000ff00; - amask = 0x000000ff; - #else - rmask = 0x000000ff; - gmask = 0x0000ff00; - bmask = 0x00ff0000; - amask = 0xff000000; - #endif - SDL_Surface *tmp = SDL_CreateRGBSurface( - 0, now->w, now->h, 32, - rmask, gmask, bmask, amask); - - _ProcessAssImage(tmp, now); - - SDL_Rect *dst_rect = malloc(sizeof(SDL_Rect)); - dst_rect->x = now->dst_x; - dst_rect->y = now->dst_y; - dst_rect->w = now->w; - dst_rect->h = now->h; - - spackets[(*n)++] = _CreateSubtitlePacket(start, end, dst_rect, tmp); - } while((now = now->next) != NULL); - } - } -} - -static void _HandleSubtitlePacket(Kit_Player *player, AVPacket *packet) { - assert(player != NULL); - assert(packet != NULL); - - int frame_finished; - int len; - AVCodecContext *scodec_ctx = (AVCodecContext*)player->scodec_ctx; - AVFormatContext *fmt_ctx = (AVFormatContext *)player->src->format_ctx; - Kit_SubtitlePacket *tmp = NULL; - unsigned int it; - AVSubtitle sub; - memset(&sub, 0, sizeof(AVSubtitle)); - - if(packet->size > 0) { - len = avcodec_decode_subtitle2(scodec_ctx, &sub, &frame_finished, packet); - if(len < 0) { - return; - } - - if(frame_finished) { - // Get pts - double pts = 0; - if(packet->dts != AV_NOPTS_VALUE) { - pts = packet->pts; - pts *= av_q2d(fmt_ctx->streams[player->src->sstream_idx]->time_base); - } - - // Convert subtitles to SDL_Surface and create a packet - Kit_SubtitlePacket *spackets[KIT_SBUFFERSIZE]; - memset(spackets, 0, sizeof(Kit_SubtitlePacket*) * KIT_SBUFFERSIZE); - - int n = 0; - bool has_ass = false; - for(int r = 0; r < sub.num_rects; r++) { - switch(sub.rects[r]->type) { - case SUBTITLE_BITMAP: - _HandleBitmapSubtitle(spackets, &n, player, pts, &sub, sub.rects[r]); - break; - case SUBTITLE_ASS: - _ProcessAssSubtitleRect(player, sub.rects[r]); - has_ass = true; - break; - case SUBTITLE_TEXT: - break; - case SUBTITLE_NONE: - break; - } - } - - // Process libass content - if(has_ass) { - _HandleAssSubtitle(spackets, &n, player, pts, &sub); - } - - // Lock, write to subtitle buffer, unlock - if(SDL_LockMutex(player->smutex) == 0) { - if(has_ass) { - Kit_ClearList((Kit_List*)player->sbuffer); - } else { - // Clear out old subtitles that should only be valid until next (this) subtitle - it = 0; - while((tmp = Kit_IterateList((Kit_List*)player->sbuffer, &it)) != NULL) { - if(tmp->pts_end < 0) { - Kit_RemoveFromList((Kit_List*)player->sbuffer, it); - } - } - } - - // Add new subtitle - for(int i = 0; i < KIT_SBUFFERSIZE; i++) { - Kit_SubtitlePacket *spacket = spackets[i]; - if(spacket != NULL) { - if(Kit_WriteList((Kit_List*)player->sbuffer, spacket) == 0) { - spackets[i] = NULL; - } - } - } - - // Unlock subtitle buffer - SDL_UnlockMutex(player->smutex); - } - - // Couldn't write packet, free memory - for(int i = 0; i < KIT_SBUFFERSIZE; i++) { - if(spackets[i] != NULL) { - _FreeSubtitlePacket(spackets[i]); - } - } - } - } -} - static void _HandlePacket(Kit_Player *player, AVPacket *packet) { // Check if this is a packet we need to handle and pass it on if(player->vcodec_ctx != NULL && packet->stream_index == player->src->vstream_idx) { @@ -710,54 +158,6 @@ static void _HandlePacket(Kit_Player *player, AVPacket *packet) { } } -static void _HandleFlushCommand(Kit_Player *player, Kit_ControlPacket *packet) { - if(player->abuffer != NULL) { - if(SDL_LockMutex(player->amutex) == 0) { - Kit_ClearBuffer((Kit_Buffer*)player->abuffer); - SDL_UnlockMutex(player->amutex); - } - } - if(player->vbuffer != NULL) { - if(SDL_LockMutex(player->vmutex) == 0) { - Kit_ClearBuffer((Kit_Buffer*)player->vbuffer); - SDL_UnlockMutex(player->vmutex); - } - } - if(player->sbuffer != NULL) { - if(SDL_LockMutex(player->smutex) == 0) { - Kit_ClearList((Kit_List*)player->sbuffer); - SDL_UnlockMutex(player->smutex); - } - } - reset_libass_track(player); -} - -static void _HandleSeekCommand(Kit_Player *player, Kit_ControlPacket *packet) { - AVFormatContext *fmt_ctx = (AVFormatContext *)player->src->format_ctx; - - // Find and limit absolute position - double seek = packet->value1; - double duration = Kit_GetPlayerDuration(player); - if(player->vclock_pos + seek <= 0) { - seek = -player->vclock_pos; - } - if(player->vclock_pos + seek >= duration) { - seek = duration - player->vclock_pos; - } - double absolute_pos = player->vclock_pos + seek; - int64_t seek_target = absolute_pos * AV_TIME_BASE; - - // Seek to timestamp. - avformat_seek_file(fmt_ctx, -1, INT64_MIN, seek_target, INT64_MAX, 0); - if(player->vcodec_ctx != NULL) - avcodec_flush_buffers(player->vcodec_ctx); - if(player->acodec_ctx != NULL) - avcodec_flush_buffers(player->acodec_ctx); - - // On first packet, set clock and current position - player->seek_flag = 1; -} - static void _HandleControlPacket(Kit_Player *player, Kit_ControlPacket *packet) { switch(packet->type) { case KIT_CONTROL_FLUSH: @@ -859,28 +259,6 @@ static int _DecoderThread(void *ptr) { return 0; } -static const char * const font_mime[] = { - "application/x-font-ttf", - "application/x-font-truetype", - "application/x-truetype-font", - "application/x-font-opentype", - "application/vnd.ms-opentype", - "application/font-sfnt", - NULL -}; - -static bool attachment_is_font(AVStream *stream) { - AVDictionaryEntry *tag = av_dict_get(stream->metadata, "mimetype", NULL, AV_DICT_MATCH_CASE); - if(tag) { - for(int n = 0; font_mime[n]; n++) { - if(av_strcasecmp(font_mime[n], tag->value) == 0) { - return true; - } - } - } - return false; -} - Kit_Player* Kit_CreatePlayer(const Kit_Source *src) { assert(src != NULL); |