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