3 * Copyright (c) 2007 Konstantin Shishkov
5 * This file is part of FFmpeg.
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.
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.
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
24 #include "libavutil/intreadwrite.h"
29 #define DXA_EXTRA_SIZE 9
36 int64_t wavpos
, vidpos
;
40 static int dxa_probe(AVProbeData
*p
)
45 w
= AV_RB16(p
->buf
+ 11);
46 h
= AV_RB16(p
->buf
+ 13);
47 /* check file header */
48 if (p
->buf
[0] == 'D' && p
->buf
[1] == 'E' &&
49 p
->buf
[2] == 'X' && p
->buf
[3] == 'A' &&
50 w
&& w
<= 2048 && h
&& h
<= 2048)
51 return AVPROBE_SCORE_MAX
;
56 static int dxa_read_header(AVFormatContext
*s
)
58 AVIOContext
*pb
= s
->pb
;
59 DXAContext
*c
= s
->priv_data
;
69 if (tag
!= MKTAG('D', 'E', 'X', 'A'))
70 return AVERROR_INVALIDDATA
;
72 c
->frames
= avio_rb16(pb
);
74 av_log(s
, AV_LOG_ERROR
, "File contains no frames ???\n");
75 return AVERROR_INVALIDDATA
;
93 st
= avformat_new_stream(s
, NULL
);
95 return AVERROR(ENOMEM
);
97 // Parse WAV data header
98 if(avio_rl32(pb
) == MKTAG('W', 'A', 'V', 'E')){
101 size
= avio_rb32(pb
);
102 c
->vidpos
= avio_tell(pb
) + size
;
104 fsize
= avio_rl32(pb
);
106 ast
= avformat_new_stream(s
, NULL
);
108 return AVERROR(ENOMEM
);
109 ret
= ff_get_wav_header(pb
, ast
->codec
, fsize
);
112 if (ast
->codec
->sample_rate
> 0)
113 avpriv_set_pts_info(ast
, 64, 1, ast
->codec
->sample_rate
);
115 while(avio_tell(pb
) < c
->vidpos
&& !avio_feof(pb
)){
117 fsize
= avio_rl32(pb
);
118 if(tag
== MKTAG('d', 'a', 't', 'a')) break;
119 avio_skip(pb
, fsize
);
121 c
->bpc
= (fsize
+ c
->frames
- 1) / c
->frames
;
122 if(ast
->codec
->block_align
)
123 c
->bpc
= ((c
->bpc
+ ast
->codec
->block_align
- 1) / ast
->codec
->block_align
) * ast
->codec
->block_align
;
124 c
->bytes_left
= fsize
;
125 c
->wavpos
= avio_tell(pb
);
126 avio_seek(pb
, c
->vidpos
, SEEK_SET
);
129 /* now we are ready: build format streams */
130 st
->codec
->codec_type
= AVMEDIA_TYPE_VIDEO
;
131 st
->codec
->codec_id
= AV_CODEC_ID_DXA
;
132 st
->codec
->width
= w
;
133 st
->codec
->height
= h
;
134 av_reduce(&den
, &num
, den
, num
, (1UL<<31)-1);
135 avpriv_set_pts_info(st
, 33, num
, den
);
136 /* flags & 0x80 means that image is interlaced,
137 * flags & 0x40 means that image has double height
138 * either way set true height
141 st
->codec
->height
>>= 1;
143 c
->readvid
= !c
->has_sound
;
144 c
->vidpos
= avio_tell(pb
);
146 s
->duration
= (int64_t)c
->frames
* AV_TIME_BASE
* num
/ den
;
147 av_log(s
, AV_LOG_DEBUG
, "%d frame(s)\n",c
->frames
);
152 static int dxa_read_packet(AVFormatContext
*s
, AVPacket
*pkt
)
154 DXAContext
*c
= s
->priv_data
;
157 uint8_t buf
[DXA_EXTRA_SIZE
], pal
[768+4];
160 if(!c
->readvid
&& c
->has_sound
&& c
->bytes_left
){
162 avio_seek(s
->pb
, c
->wavpos
, SEEK_SET
);
163 size
= FFMIN(c
->bytes_left
, c
->bpc
);
164 ret
= av_get_packet(s
->pb
, pkt
, size
);
165 pkt
->stream_index
= 1;
168 c
->bytes_left
-= size
;
169 c
->wavpos
= avio_tell(s
->pb
);
172 avio_seek(s
->pb
, c
->vidpos
, SEEK_SET
);
173 while(!avio_feof(s
->pb
) && c
->frames
){
174 if ((ret
= avio_read(s
->pb
, buf
, 4)) != 4) {
175 av_log(s
, AV_LOG_ERROR
, "failed reading chunk type\n");
176 return ret
< 0 ? ret
: AVERROR_INVALIDDATA
;
178 switch(AV_RL32(buf
)){
179 case MKTAG('N', 'U', 'L', 'L'):
180 if(av_new_packet(pkt
, 4 + pal_size
) < 0)
181 return AVERROR(ENOMEM
);
182 pkt
->stream_index
= 0;
183 if(pal_size
) memcpy(pkt
->data
, pal
, pal_size
);
184 memcpy(pkt
->data
+ pal_size
, buf
, 4);
186 c
->vidpos
= avio_tell(s
->pb
);
189 case MKTAG('C', 'M', 'A', 'P'):
192 avio_read(s
->pb
, pal
+ 4, 768);
194 case MKTAG('F', 'R', 'A', 'M'):
195 if ((ret
= avio_read(s
->pb
, buf
+ 4, DXA_EXTRA_SIZE
- 4)) != DXA_EXTRA_SIZE
- 4) {
196 av_log(s
, AV_LOG_ERROR
, "failed reading dxa_extra\n");
197 return ret
< 0 ? ret
: AVERROR_INVALIDDATA
;
199 size
= AV_RB32(buf
+ 5);
201 av_log(s
, AV_LOG_ERROR
, "Frame size is too big: %"PRIu32
"\n",
203 return AVERROR_INVALIDDATA
;
205 if(av_new_packet(pkt
, size
+ DXA_EXTRA_SIZE
+ pal_size
) < 0)
206 return AVERROR(ENOMEM
);
207 memcpy(pkt
->data
+ pal_size
, buf
, DXA_EXTRA_SIZE
);
208 ret
= avio_read(s
->pb
, pkt
->data
+ DXA_EXTRA_SIZE
+ pal_size
, size
);
213 if(pal_size
) memcpy(pkt
->data
, pal
, pal_size
);
214 pkt
->stream_index
= 0;
216 c
->vidpos
= avio_tell(s
->pb
);
220 av_log(s
, AV_LOG_ERROR
, "Unknown tag %c%c%c%c\n", buf
[0], buf
[1], buf
[2], buf
[3]);
221 return AVERROR_INVALIDDATA
;
227 AVInputFormat ff_dxa_demuxer
= {
229 .long_name
= NULL_IF_CONFIG_SMALL("DXA"),
230 .priv_data_size
= sizeof(DXAContext
),
231 .read_probe
= dxa_probe
,
232 .read_header
= dxa_read_header
,
233 .read_packet
= dxa_read_packet
,