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
31 typedef struct DXAContext
{
36 int64_t wavpos
, vidpos
;
40 static int dxa_probe(const 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
;
82 }else if (fps
< 0 && fps
> INT_MIN
){
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(s
, pb
, ast
->codecpar
, fsize
, 0);
112 if (ast
->codecpar
->sample_rate
> 0)
113 avpriv_set_pts_info(ast
, 64, 1, ast
->codecpar
->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
+ (int64_t)c
->frames
- 1) / c
->frames
;
123 return AVERROR_INVALIDDATA
;
124 if(ast
->codecpar
->block_align
) {
125 if (c
->bpc
> INT_MAX
- ast
->codecpar
->block_align
+ 1)
126 return AVERROR_INVALIDDATA
;
127 c
->bpc
= ((c
->bpc
- 1 + ast
->codecpar
->block_align
) / ast
->codecpar
->block_align
) * ast
->codecpar
->block_align
;
129 c
->bytes_left
= fsize
;
130 c
->wavpos
= avio_tell(pb
);
131 avio_seek(pb
, c
->vidpos
, SEEK_SET
);
134 /* now we are ready: build format streams */
135 st
->codecpar
->codec_type
= AVMEDIA_TYPE_VIDEO
;
136 st
->codecpar
->codec_id
= AV_CODEC_ID_DXA
;
137 st
->codecpar
->width
= w
;
138 st
->codecpar
->height
= h
;
139 av_reduce(&den
, &num
, den
, num
, (1UL<<31)-1);
140 avpriv_set_pts_info(st
, 33, num
, den
);
141 /* flags & 0x80 means that image is interlaced,
142 * flags & 0x40 means that image has double height
143 * either way set true height
146 st
->codecpar
->height
>>= 1;
148 c
->readvid
= !c
->has_sound
;
149 c
->vidpos
= avio_tell(pb
);
151 s
->duration
= av_rescale(c
->frames
, AV_TIME_BASE
* (int64_t)num
, den
);
152 av_log(s
, AV_LOG_DEBUG
, "%d frame(s)\n",c
->frames
);
157 static int dxa_read_packet(AVFormatContext
*s
, AVPacket
*pkt
)
159 DXAContext
*c
= s
->priv_data
;
162 uint8_t buf
[DXA_EXTRA_SIZE
], pal
[768+4];
165 if(!c
->readvid
&& c
->has_sound
&& c
->bytes_left
){
167 avio_seek(s
->pb
, c
->wavpos
, SEEK_SET
);
168 size
= FFMIN(c
->bytes_left
, c
->bpc
);
169 ret
= av_get_packet(s
->pb
, pkt
, size
);
170 pkt
->stream_index
= 1;
173 c
->bytes_left
-= size
;
174 c
->wavpos
= avio_tell(s
->pb
);
177 avio_seek(s
->pb
, c
->vidpos
, SEEK_SET
);
178 while(!avio_feof(s
->pb
) && c
->frames
){
180 if ((ret
= avio_read(s
->pb
, buf
, 4)) != 4) {
181 av_log(s
, AV_LOG_ERROR
, "failed reading chunk type\n");
182 return ret
< 0 ? ret
: AVERROR_INVALIDDATA
;
186 case MKTAG('N', 'U', 'L', 'L'):
187 if ((ret
= av_new_packet(pkt
, 4 + pal_size
)) < 0)
189 pkt
->stream_index
= 0;
190 if(pal_size
) memcpy(pkt
->data
, pal
, pal_size
);
191 memcpy(pkt
->data
+ pal_size
, buf
, 4);
193 c
->vidpos
= avio_tell(s
->pb
);
196 case MKTAG('C', 'M', 'A', 'P'):
199 avio_read(s
->pb
, pal
+ 4, 768);
201 case MKTAG('F', 'R', 'A', 'M'):
202 if ((ret
= avio_read(s
->pb
, buf
+ 4, DXA_EXTRA_SIZE
- 4)) != DXA_EXTRA_SIZE
- 4) {
203 av_log(s
, AV_LOG_ERROR
, "failed reading dxa_extra\n");
204 return ret
< 0 ? ret
: AVERROR_INVALIDDATA
;
206 size
= AV_RB32(buf
+ 5);
208 av_log(s
, AV_LOG_ERROR
, "Frame size is too big: %"PRIu32
"\n",
210 return AVERROR_INVALIDDATA
;
212 ret
= av_new_packet(pkt
, size
+ DXA_EXTRA_SIZE
+ pal_size
);
215 memcpy(pkt
->data
+ pal_size
, buf
, DXA_EXTRA_SIZE
);
216 ret
= avio_read(s
->pb
, pkt
->data
+ DXA_EXTRA_SIZE
+ pal_size
, size
);
220 if(pal_size
) memcpy(pkt
->data
, pal
, pal_size
);
221 pkt
->stream_index
= 0;
223 c
->vidpos
= avio_tell(s
->pb
);
227 av_log(s
, AV_LOG_ERROR
, "Unknown tag %s\n", av_fourcc2str(tag
));
228 return AVERROR_INVALIDDATA
;
234 AVInputFormat ff_dxa_demuxer
= {
236 .long_name
= NULL_IF_CONFIG_SMALL("DXA"),
237 .priv_data_size
= sizeof(DXAContext
),
238 .read_probe
= dxa_probe
,
239 .read_header
= dxa_read_header
,
240 .read_packet
= dxa_read_packet
,