summaryrefslogtreecommitdiff
path: root/src/kitsource.c
blob: 075bcbdcf905b23adac224ccb190f6803f063f7d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
#include "kitchensink/kitsource.h"
#include "kitchensink/kiterror.h"

#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavutil/opt.h>

#include <stdlib.h>
#include <string.h>
#include <assert.h>

Kit_Source* Kit_CreateSourceFromUrl(const char *url) {
    assert(url != NULL);

    Kit_Source *src = calloc(1, sizeof(Kit_Source));
    if(src == NULL) {
        Kit_SetError("Unable to allocate source");
        return NULL;
    }

    // Attempt to open source
    if(avformat_open_input((AVFormatContext **)&src->format_ctx, url, NULL, NULL) < 0) {
        Kit_SetError("Unable to open source 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");
        goto exit_1;
    }

    // Find best streams for defaults
    src->astream_idx = Kit_GetBestSourceStream(src, KIT_STREAMTYPE_AUDIO);
    src->vstream_idx = Kit_GetBestSourceStream(src, KIT_STREAMTYPE_VIDEO);
    src->sstream_idx = Kit_GetBestSourceStream(src, KIT_STREAMTYPE_SUBTITLE);
    return src;

exit_1:
    avformat_close_input((AVFormatContext **)&src->format_ctx);
exit_0:
    free(src);
    return NULL;
}

void Kit_CloseSource(Kit_Source *src) {
    assert(src != NULL);
    avformat_close_input((AVFormatContext **)&src->format_ctx);
    free(src);
}

int Kit_GetSourceStreamInfo(const Kit_Source *src, Kit_StreamInfo *info, int index) {
    assert(src != NULL);
    assert(info != NULL);

    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;
    return 0;
}

int Kit_GetBestSourceStream(const Kit_Source *src, const Kit_StreamType type) {
    assert(src != NULL);
    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;
        case KIT_STREAMTYPE_SUBTITLE: avmedia_type = AVMEDIA_TYPE_SUBTITLE; break;
        default: return -1;
    }
    int ret = av_find_best_stream((AVFormatContext *)src->format_ctx, avmedia_type, -1, -1, NULL, 0);
    if(ret == AVERROR_STREAM_NOT_FOUND) {
        return -1;
    }
    if(ret == AVERROR_DECODER_NOT_FOUND) {
        Kit_SetError("Unable to find a decoder for the stream");
        return 1;
    }
    return ret;
}

int Kit_SetSourceStream(Kit_Source *src, const Kit_StreamType type, int index) {
    assert(src != NULL);
    switch(type) {
        case KIT_STREAMTYPE_AUDIO: src->astream_idx = index; break;
        case KIT_STREAMTYPE_VIDEO: src->vstream_idx = index; break;
        case KIT_STREAMTYPE_SUBTITLE: src->sstream_idx = 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->astream_idx;
        case KIT_STREAMTYPE_VIDEO: return src->vstream_idx;
        case KIT_STREAMTYPE_SUBTITLE: return src->sstream_idx;
        default:
            break;
    }
    return -1;
}

int Kit_GetSourceStreamCount(const Kit_Source *src) {
    assert(src != NULL);
    return ((AVFormatContext *)src->format_ctx)->nb_streams;
}