Coverage Report

Created: 2024-09-06 07:53

/src/ffmpeg/libavformat/dxa.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * DXA demuxer
3
 * Copyright (c) 2007 Konstantin Shishkov
4
 *
5
 * This file is part of FFmpeg.
6
 *
7
 * FFmpeg is free software; you can redistribute it and/or
8
 * modify it under the terms of the GNU Lesser General Public
9
 * License as published by the Free Software Foundation; either
10
 * version 2.1 of the License, or (at your option) any later version.
11
 *
12
 * FFmpeg is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15
 * Lesser General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU Lesser General Public
18
 * License along with FFmpeg; if not, write to the Free Software
19
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20
 */
21
22
#include <inttypes.h>
23
24
#include "libavutil/intreadwrite.h"
25
#include "avformat.h"
26
#include "demux.h"
27
#include "internal.h"
28
#include "riff.h"
29
30
4.85k
#define DXA_EXTRA_SIZE  9
31
32
typedef struct DXAContext {
33
    int frames;
34
    int has_sound;
35
    int bpc;
36
    uint32_t bytes_left;
37
    int64_t wavpos, vidpos;
38
    int readvid;
39
}DXAContext;
40
41
static int dxa_probe(const AVProbeData *p)
42
358k
{
43
358k
    int w, h;
44
358k
    if (p->buf_size < 15)
45
53.7k
        return 0;
46
304k
    w = AV_RB16(p->buf + 11);
47
304k
    h = AV_RB16(p->buf + 13);
48
    /* check file header */
49
304k
    if (p->buf[0] == 'D' && p->buf[1] == 'E' &&
50
304k
        p->buf[2] == 'X' && p->buf[3] == 'A' &&
51
304k
        w && w <= 2048 && h && h <= 2048)
52
74
        return AVPROBE_SCORE_MAX;
53
304k
    else
54
304k
        return 0;
55
304k
}
56
57
static int dxa_read_header(AVFormatContext *s)
58
7.28k
{
59
7.28k
    AVIOContext *pb = s->pb;
60
7.28k
    DXAContext *c = s->priv_data;
61
7.28k
    AVStream *st, *ast;
62
7.28k
    uint32_t tag;
63
7.28k
    int32_t fps;
64
7.28k
    int w, h;
65
7.28k
    int num, den;
66
7.28k
    int flags;
67
7.28k
    int ret;
68
69
7.28k
    tag = avio_rl32(pb);
70
7.28k
    if (tag != MKTAG('D', 'E', 'X', 'A'))
71
4.16k
        return AVERROR_INVALIDDATA;
72
3.12k
    flags = avio_r8(pb);
73
3.12k
    c->frames = avio_rb16(pb);
74
3.12k
    if(!c->frames){
75
3
        av_log(s, AV_LOG_ERROR, "File contains no frames ???\n");
76
3
        return AVERROR_INVALIDDATA;
77
3
    }
78
79
3.11k
    fps = avio_rb32(pb);
80
3.11k
    if(fps > 0){
81
1.84k
        den = 1000;
82
1.84k
        num = fps;
83
1.84k
    }else if (fps < 0 && fps > INT_MIN){
84
978
        den = 100000;
85
978
        num = -fps;
86
978
    }else{
87
295
        den = 10;
88
295
        num = 1;
89
295
    }
90
3.11k
    w = avio_rb16(pb);
91
3.11k
    h = avio_rb16(pb);
92
3.11k
    c->has_sound = 0;
93
94
3.11k
    st = avformat_new_stream(s, NULL);
95
3.11k
    if (!st)
96
0
        return AVERROR(ENOMEM);
97
98
    // Parse WAV data header
99
3.11k
    if(avio_rl32(pb) == MKTAG('W', 'A', 'V', 'E')){
100
2.04k
        uint32_t size, fsize;
101
2.04k
        c->has_sound = 1;
102
2.04k
        size = avio_rb32(pb);
103
2.04k
        c->vidpos = avio_tell(pb) + size;
104
2.04k
        avio_skip(pb, 16);
105
2.04k
        fsize = avio_rl32(pb);
106
107
2.04k
        ast = avformat_new_stream(s, NULL);
108
2.04k
        if (!ast)
109
0
            return AVERROR(ENOMEM);
110
2.04k
        ret = ff_get_wav_header(s, pb, ast->codecpar, fsize, 0);
111
2.04k
        if (ret < 0)
112
224
            return ret;
113
1.82k
        if (ast->codecpar->sample_rate > 0)
114
1.80k
            avpriv_set_pts_info(ast, 64, 1, ast->codecpar->sample_rate);
115
        // find 'data' chunk
116
3.14k
        while(avio_tell(pb) < c->vidpos && !avio_feof(pb)){
117
1.39k
            tag = avio_rl32(pb);
118
1.39k
            fsize = avio_rl32(pb);
119
1.39k
            if(tag == MKTAG('d', 'a', 't', 'a')) break;
120
1.32k
            avio_skip(pb, fsize);
121
1.32k
        }
122
1.82k
        c->bpc = (fsize + (int64_t)c->frames - 1) / c->frames;
123
1.82k
        if(ast->codecpar->block_align) {
124
1.05k
            if (c->bpc > INT_MAX - ast->codecpar->block_align + 1)
125
1
                return AVERROR_INVALIDDATA;
126
1.05k
            c->bpc = ((c->bpc - 1 + ast->codecpar->block_align) / ast->codecpar->block_align) * ast->codecpar->block_align;
127
1.05k
        }
128
1.82k
        c->bytes_left = fsize;
129
1.82k
        c->wavpos = avio_tell(pb);
130
1.82k
        avio_seek(pb, c->vidpos, SEEK_SET);
131
1.82k
    }
132
133
    /* now we are ready: build format streams */
134
2.89k
    st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
135
2.89k
    st->codecpar->codec_id   = AV_CODEC_ID_DXA;
136
2.89k
    st->codecpar->width      = w;
137
2.89k
    st->codecpar->height     = h;
138
2.89k
    av_reduce(&den, &num, den, num, (1UL<<31)-1);
139
2.89k
    avpriv_set_pts_info(st, 33, num, den);
140
    /* flags & 0x80 means that image is interlaced,
141
     * flags & 0x40 means that image has double height
142
     * either way set true height
143
     */
144
2.89k
    if(flags & 0xC0){
145
1.12k
        st->codecpar->height >>= 1;
146
1.12k
    }
147
2.89k
    c->readvid = !c->has_sound;
148
2.89k
    c->vidpos  = avio_tell(pb);
149
2.89k
    s->start_time = 0;
150
2.89k
    s->duration = av_rescale(c->frames, AV_TIME_BASE * (int64_t)num, den);
151
2.89k
    av_log(s, AV_LOG_DEBUG, "%d frame(s)\n",c->frames);
152
153
2.89k
    return 0;
154
3.11k
}
155
156
static int dxa_read_packet(AVFormatContext *s, AVPacket *pkt)
157
182k
{
158
182k
    DXAContext *c = s->priv_data;
159
182k
    int ret;
160
182k
    uint32_t size;
161
182k
    uint8_t buf[DXA_EXTRA_SIZE], pal[768+4];
162
182k
    int pal_size = 0;
163
164
182k
    if(!c->readvid && c->has_sound && c->bytes_left){
165
55.3k
        c->readvid = 1;
166
55.3k
        avio_seek(s->pb, c->wavpos, SEEK_SET);
167
55.3k
        size = FFMIN(c->bytes_left, c->bpc);
168
55.3k
        ret = av_get_packet(s->pb, pkt, size);
169
55.3k
        pkt->stream_index = 1;
170
55.3k
        if(ret != size)
171
915
            return AVERROR(EIO);
172
54.4k
        c->bytes_left -= size;
173
54.4k
        c->wavpos = avio_tell(s->pb);
174
54.4k
        return 0;
175
55.3k
    }
176
127k
    avio_seek(s->pb, c->vidpos, SEEK_SET);
177
128k
    while(!avio_feof(s->pb) && c->frames){
178
128k
        uint32_t tag;
179
128k
        if ((ret = avio_read(s->pb, buf, 4)) != 4) {
180
2.98k
            av_log(s, AV_LOG_ERROR, "failed reading chunk type\n");
181
2.98k
            return ret < 0 ? ret : AVERROR_INVALIDDATA;
182
2.98k
        }
183
125k
        tag = AV_RL32(buf);
184
125k
        switch (tag) {
185
122k
        case MKTAG('N', 'U', 'L', 'L'):
186
122k
            if ((ret = av_new_packet(pkt, 4 + pal_size)) < 0)
187
0
                return ret;
188
122k
            pkt->stream_index = 0;
189
122k
            if(pal_size) memcpy(pkt->data, pal, pal_size);
190
122k
            memcpy(pkt->data + pal_size, buf, 4);
191
122k
            c->frames--;
192
122k
            c->vidpos = avio_tell(s->pb);
193
122k
            c->readvid = 0;
194
122k
            return 0;
195
732
        case MKTAG('C', 'M', 'A', 'P'):
196
732
            pal_size = 768+4;
197
732
            memcpy(pal, buf, 4);
198
732
            avio_read(s->pb, pal + 4, 768);
199
732
            break;
200
982
        case MKTAG('F', 'R', 'A', 'M'):
201
982
            if ((ret = avio_read(s->pb, buf + 4, DXA_EXTRA_SIZE - 4)) != DXA_EXTRA_SIZE - 4) {
202
7
                av_log(s, AV_LOG_ERROR, "failed reading dxa_extra\n");
203
7
                return ret < 0 ? ret : AVERROR_INVALIDDATA;
204
7
            }
205
975
            size = AV_RB32(buf + 5);
206
975
            if(size > 0xFFFFFF){
207
13
                av_log(s, AV_LOG_ERROR, "Frame size is too big: %"PRIu32"\n",
208
13
                       size);
209
13
                return AVERROR_INVALIDDATA;
210
13
            }
211
962
            ret = av_new_packet(pkt, size + DXA_EXTRA_SIZE + pal_size);
212
962
            if (ret < 0)
213
0
                return ret;
214
962
            memcpy(pkt->data + pal_size, buf, DXA_EXTRA_SIZE);
215
962
            ret = avio_read(s->pb, pkt->data + DXA_EXTRA_SIZE + pal_size, size);
216
962
            if(ret != size){
217
50
                return AVERROR(EIO);
218
50
            }
219
912
            if(pal_size) memcpy(pkt->data, pal, pal_size);
220
912
            pkt->stream_index = 0;
221
912
            c->frames--;
222
912
            c->vidpos = avio_tell(s->pb);
223
912
            c->readvid = 0;
224
912
            return 0;
225
1.17k
        default:
226
1.17k
            av_log(s, AV_LOG_ERROR, "Unknown tag %s\n", av_fourcc2str(tag));
227
1.17k
            return AVERROR_INVALIDDATA;
228
125k
        }
229
125k
    }
230
240
    return AVERROR_EOF;
231
127k
}
232
233
const FFInputFormat ff_dxa_demuxer = {
234
    .p.name         = "dxa",
235
    .p.long_name    = NULL_IF_CONFIG_SMALL("DXA"),
236
    .priv_data_size = sizeof(DXAContext),
237
    .read_probe     = dxa_probe,
238
    .read_header    = dxa_read_header,
239
    .read_packet    = dxa_read_packet,
240
};